From 31b4767c875bdb1ab7ecd4d4044cc812ae1b00ad Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 27 Jan 2022 01:06:03 -0500 Subject: [PATCH 01/14] handle Void Name 2 in modifiers instead --- descriptions/rep/en_us.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/descriptions/rep/en_us.lua b/descriptions/rep/en_us.lua index 06a05636..2ac8d706 100644 --- a/descriptions/rep/en_us.lua +++ b/descriptions/rep/en_us.lua @@ -1012,9 +1012,6 @@ EID.descriptions[languageCode].GlitchedItemText = { ---------- Misc. Text ---------- --- Void stat names: Replace "Tears" with "Fire Rate" -EID.descriptions[languageCode].VoidNames[2] = EID.descriptions[languageCode].GlitchedItemText[1] - EID.descriptions[languageCode].spindownError = "Item disappears" EID.descriptions[languageCode].CraftingBagContent = "Bag:" From cdabf4de661ec7c09862bb230f3f3a82f91814de Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 27 Jan 2022 01:11:24 -0500 Subject: [PATCH 02/14] Prevent double Void text on tab previews --- eid_api.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eid_api.lua b/eid_api.lua index abdb26ea..0a64ad35 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -328,6 +328,8 @@ function EID:getDescriptionObj(Type, Variant, SubType, entity) if type(result) == "table" then for _,callback in ipairs(result) do description = callback(description) + -- If the modifier loads a different description obj (which also goes through the modifier checks), we should stop our checks so text doesn't get printed twice + if description.ObjSubType ~= SubType then break end end elseif result then description = modifier.callback(description) From 6bd6a4d1f53e325d3e7569a039cb07c214ce5132 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 27 Jan 2022 01:11:47 -0500 Subject: [PATCH 03/14] reset our tab preview ID each render --- main.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/main.lua b/main.lua index c4f3a0e1..67550bd0 100644 --- a/main.lua +++ b/main.lua @@ -995,6 +995,7 @@ local function onRender(t) EID.isDisplaying = false EID:setPlayer() + EID.TabPreviewID = 0 if Input.IsButtonTriggered(EID.Config["HideKey"], 0) or Input.IsButtonTriggered(EID.Config["HideButton"], EID.player.ControllerIndex) then EID.isHidden = not EID.isHidden From 2abef7b52ca7e53e4e3edf3ce567a672f66dfd46 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 27 Jan 2022 01:12:34 -0500 Subject: [PATCH 04/14] Use new Tab ID system for achievement lock preview --- eid_bagofcrafting.lua | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/eid_bagofcrafting.lua b/eid_bagofcrafting.lua index ff3cfd2c..09d374ee 100644 --- a/eid_bagofcrafting.lua +++ b/eid_bagofcrafting.lua @@ -830,21 +830,16 @@ function EID:handleBagOfCraftingRendering() --Display the result of the 8 items in our bag if (showCraftingResult or EID.Config["BagOfCraftingDisplayMode"] == "Preview Only") and #EID.BagItems >= 8 then local craftingResult, backupResult = EID:calculateBagOfCrafting(EID.BagItems) - if Input.IsActionPressed(ButtonAction.ACTION_MAP, EID.player.ControllerIndex) then - local descriptionObj = EID:getDescriptionObj(5, 100, backupResult) - descriptionObj.Description = getHotkeyString() .. descriptionObj.Description - EID:printDescription(descriptionObj) - return true - end + if (backupResult ~= craftingResult) then EID.TabPreviewID = backupResult end local descriptionObj = EID:getDescriptionObj(5, 100, craftingResult) - local infoText = EID:getDescriptionEntry("FlipItemToggleInfo") --prepend the Hide/Preview hotkeys to the description descriptionObj.Description = getHotkeyString() .. descriptionObj.Description - local backupObjName = EID:getObjectName(5, 100, backupResult) - if (backupResult ~= craftingResult) then + if (backupResult ~= craftingResult and descriptionObj.ObjSubType == craftingResult) then local backupDesc = EID:getDescriptionEntry("CraftingPreviewBackup") + local backupObjName = EID:getObjectName(5, 100, backupResult) + local tabText = EID:getDescriptionEntry("FlipItemToggleInfo") EID:appendToDescription(descriptionObj,"#" .. backupDesc .. "#{{Collectible" .. backupResult .. "}} " .. - backupObjName .. "#{{Blank}} " .. infoText) + backupObjName .. "#{{Blank}} " .. tabText) end EID:printDescription(descriptionObj) return true From 4ff8c90fa4c37cbf127b14935b9d2dd82f79b0bf Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 27 Jan 2022 01:17:44 -0500 Subject: [PATCH 05/14] add Tab ID system, fix Void bugs --- eid_modifiers.lua | 71 ++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/eid_modifiers.lua b/eid_modifiers.lua index 20cbb65c..19d84327 100644 --- a/eid_modifiers.lua +++ b/eid_modifiers.lua @@ -1,5 +1,9 @@ local game = Game() +EID.TabPreviewID = 0 +-- Modifiers switching the previewed description can cause infinite loops or undesired text, use this to help prevent it +local inPreview = false + -- Afterbirth+ modifiers local collectiblesToCheck = { CollectibleType.COLLECTIBLE_VOID, } -- Repentance modifiers @@ -52,21 +56,34 @@ local function CheckPlayersCollectibles() end end +function EID:TabCallback(descObj) + if EID.TabPreviewID == 0 then return descObj end + inPreview = true + local descEntry = EID:getDescriptionObj(5, 100, EID.TabPreviewID) + inPreview = false + return descEntry +end + -- Handle Void (the only modifier that is applied to AB+ at the moment) --- Speed, Tears, Damage, Range, Shot Speed, Luck -local voidIntro = EID:getDescriptionEntry("VoidText") -local voidNames = EID:getDescriptionEntry("VoidNames") local voidStatUps = { 0.2, 0.5, 1, 0.5, 0.2, 1 } if REPENTANCE then voidStatUps[4] = 1.5 end -local function VoidCallback(descObj) - if EID.itemConfig:GetCollectible(descObj.ObjSubType).Type ~= 3 then - EID:appendToDescription(descObj, "#{{Collectible477}} " .. voidIntro .. "#") +local function VoidCallback(descObj, isRune) + local voidIntro = EID:getDescriptionEntry("VoidText") + local voidNames = EID:getDescriptionEntry("VoidNames") + -- Replace "Tears" with "Fire Rate" + if REPENTANCE then voidNames[2] = EID:getDescriptionEntry("GlitchedItemText", 1) end + local prefix = "{{Collectible477}} " + if isRune then prefix = "{{Card41}} " end + if EID.itemConfig:GetCollectible(descObj.ObjSubType).Type ~= 3 or isRune then + EID:appendToDescription(descObj, "#" .. prefix .. voidIntro .. "#") for i,v in ipairs(EID.VoidStatIncreases) do if v > 0 then - EID:appendToDescription(descObj, "{{Collectible477}} +" .. v*voidStatUps[i] .. " " .. voidNames[i] .. "#") + EID:appendToDescription(descObj, prefix .. "+" .. v*voidStatUps[i] .. " " .. voidNames[i] .. "#") end end + else + -- unique Void interactions with active items? end return descObj end @@ -151,12 +168,12 @@ if REPENTANCE then return descObj end - local inSpindownPreview = false -- Handle Spindown Dice description addition local function SpindownDiceCallback(descObj) EID:appendToDescription(descObj, "#{{Collectible723}} :") local refID = descObj.ObjSubType local hasCarBattery = EID.player:HasCollectible(CollectibleType.COLLECTIBLE_CAR_BATTERY) + local firstID = 0 for i = 1,EID.Config["SpindownDiceResults"] do local spinnedID = EID:getSpindownResult(refID) if hasCarBattery then @@ -165,12 +182,7 @@ if REPENTANCE then end refID = spinnedID if refID > 0 and refID < 4294960000 then - if i == 1 and Input.IsActionPressed(ButtonAction.ACTION_MAP, EID.player.ControllerIndex) then - inSpindownPreview = true - local descEntry = EID:getDescriptionObj(5, 100, refID) - inSpindownPreview = false - return descEntry - end + if i == 1 then firstID = refID end EID:appendToDescription(descObj, "{{Collectible"..refID.."}}") if EID.itemUnlockStates[refID] == false then EID:appendToDescription(descObj, "?") end if i ~= EID.Config["SpindownDiceResults"] then @@ -185,7 +197,10 @@ if REPENTANCE then if hasCarBattery then EID:appendToDescription(descObj, " (Results with {{Collectible356}})") end - EID:appendToDescription(descObj, "#{{Blank}} ".. EID:getDescriptionEntry("FlipItemToggleInfo")) + if firstID ~= 0 and EID.TabPreviewID == 0 then + EID.TabPreviewID = firstID + EID:appendToDescription(descObj, "#{{Blank}} ".. EID:getDescriptionEntry("FlipItemToggleInfo")) + end return descObj end @@ -353,23 +368,24 @@ if REPENTANCE then -- Handle Flip description addition local function FlipCallback(descObj) local flipItemID = EID:getEntityData(descObj.Entity, "EID_FlipItemID") - if flipItemID <= 0 then return descObj end - if descObj.ObjSubType == 0 or Input.IsActionPressed(ButtonAction.ACTION_MAP, EID.player.ControllerIndex) then - local descEntry = EID:getDescriptionObj(5, 100, flipItemID) - return descEntry + if not flipItemID or flipItemID <= 0 then return descObj end + -- Empty pedestal + if descObj.ObjSubType == 0 then + return EID:getDescriptionObj(5, 100, flipItemID) end - + local infoText = EID:getDescriptionEntry("FlipItemToggleInfo") - if flipItemID ~= nil or infoText ~= nil then - local itemName = EID:getObjectName(5, 100, flipItemID) - local appendText = "#{{Collectible711}} -> {{Collectible"..flipItemID.."}} "..itemName + local itemName = EID:getObjectName(5, 100, flipItemID) + local appendText = "#{{Collectible711}} -> {{Collectible"..flipItemID.."}} "..itemName + if EID.TabPreviewID == 0 then + EID.TabPreviewID = flipItemID appendText = appendText .. "#{{Blank}} "..infoText - EID:appendToDescription(descObj, appendText) end + EID:appendToDescription(descObj, appendText) + return descObj end - -------------------------------- -- Although individual conditions/callbacks work well for mods to be able to add through the API, -- As we kept adding callbacks for vanilla items, a lot of code got repeated over and over @@ -395,8 +411,11 @@ if REPENTANCE then if collectiblesOwned[584] then table.insert(callbacks, BookOfVirtuesCallback) end if collectiblesOwned[706] then table.insert(callbacks, AbyssCallback) end - if (collectiblesOwned[723] or (EID.absorbedSpindown and collectiblesOwned[477])) and not inSpindownPreview then table.insert(callbacks, SpindownDiceCallback) end if collectiblesOwned[711] and EID:getEntityData(descObj.Entity, "EID_FlipItemID") then table.insert(callbacks, FlipCallback) end + if (collectiblesOwned[723] or (EID.absorbedSpindown and collectiblesOwned[477])) then table.insert(callbacks, SpindownDiceCallback) end + -- currently, only Repentance collectible modifiers have Tab previews so put it here + if Input.IsActionPressed(ButtonAction.ACTION_MAP, EID.player.ControllerIndex) and not inPreview then table.insert(callbacks, TabCallback) end + -- Card / Rune Callbacks elseif descObj.ObjVariant == PickupVariant.PICKUP_TAROTCARD then if collectiblesOwned[451] then table.insert(callbacks, TarotClothCallback) end From 5965b40a9288e5ebc5a881de58917b9ff0684dec Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 27 Jan 2022 22:55:14 -0500 Subject: [PATCH 06/14] Void improvements --- eid_modifiers.lua | 125 ++++++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 61 deletions(-) diff --git a/eid_modifiers.lua b/eid_modifiers.lua index 19d84327..0ed49003 100644 --- a/eid_modifiers.lua +++ b/eid_modifiers.lua @@ -6,13 +6,18 @@ local inPreview = false -- Afterbirth+ modifiers local collectiblesToCheck = { CollectibleType.COLLECTIBLE_VOID, } +local maxSlot = 1 -- Repentance modifiers -if REPENTANCE then collectiblesToCheck = { CollectibleType.COLLECTIBLE_VOID, - CollectibleType.COLLECTIBLE_BINGE_EATER, CollectibleType.COLLECTIBLE_BOOK_OF_VIRTUES, CollectibleType.COLLECTIBLE_SPINDOWN_DICE, - CollectibleType.COLLECTIBLE_TAROT_CLOTH, CollectibleType.COLLECTIBLE_MOMS_BOX, - CollectibleType.COLLECTIBLE_BLANK_CARD, CollectibleType.COLLECTIBLE_CLEAR_RUNE, CollectibleType.COLLECTIBLE_PLACEBO, - CollectibleType.COLLECTIBLE_FALSE_PHD, CollectibleType.COLLECTIBLE_ABYSS, CollectibleType.COLLECTIBLE_FLIP, -} end +if REPENTANCE then + maxSlot = 3 + --include the AB+ collectiblesToCheck in this table! + collectiblesToCheck = { CollectibleType.COLLECTIBLE_VOID, + CollectibleType.COLLECTIBLE_BINGE_EATER, CollectibleType.COLLECTIBLE_BOOK_OF_VIRTUES, CollectibleType.COLLECTIBLE_SPINDOWN_DICE, + CollectibleType.COLLECTIBLE_TAROT_CLOTH, CollectibleType.COLLECTIBLE_MOMS_BOX, 59, --Birthright Belial + CollectibleType.COLLECTIBLE_BLANK_CARD, CollectibleType.COLLECTIBLE_CLEAR_RUNE, CollectibleType.COLLECTIBLE_PLACEBO, + CollectibleType.COLLECTIBLE_FALSE_PHD, CollectibleType.COLLECTIBLE_ABYSS, CollectibleType.COLLECTIBLE_FLIP, + } +end local collectiblesOwned = {} local blackRuneOwned = false local lastCheck = 0 @@ -27,28 +32,16 @@ local function CheckPlayersCollectibles() collectiblesOwned[v] = false for i = 0, numPlayers - 1 do if players[i]:HasCollectible(v) then - collectiblesOwned[v] = true + collectiblesOwned[v] = i break end end end blackRuneOwned = false for i = 0, numPlayers - 1 do - for j = 0, 1 do + for j = 0, maxSlot do if players[i]:GetCard(j) == Card.RUNE_BLACK then - blackRuneOwned = true - break - end - end - end - -- Birthright Book of Belial - -- Could this be changed to just checking for having Collectible 59? (Check interaction with Clicker etc) - if REPENTANCE then - collectiblesOwned[59] = false - for i = 0, numPlayers - 1 do - local playerType = players[i]:GetPlayerType() - if (playerType == PlayerType.PLAYER_JUDAS or playerType == PlayerType.PLAYER_BLACKJUDAS) and players[i]:HasCollectible(CollectibleType.COLLECTIBLE_BIRTHRIGHT) then - collectiblesOwned[59] = true + blackRuneOwned = i break end end @@ -56,7 +49,7 @@ local function CheckPlayersCollectibles() end end -function EID:TabCallback(descObj) +local function TabCallback(descObj) if EID.TabPreviewID == 0 then return descObj end inPreview = true local descEntry = EID:getDescriptionObj(5, 100, EID.TabPreviewID) @@ -69,17 +62,30 @@ local voidStatUps = { 0.2, 0.5, 1, 0.5, 0.2, 1 } if REPENTANCE then voidStatUps[4] = 1.5 end local function VoidCallback(descObj, isRune) - local voidIntro = EID:getDescriptionEntry("VoidText") - local voidNames = EID:getDescriptionEntry("VoidNames") - -- Replace "Tears" with "Fire Rate" - if REPENTANCE then voidNames[2] = EID:getDescriptionEntry("GlitchedItemText", 1) end - local prefix = "{{Collectible477}} " - if isRune then prefix = "{{Card41}} " end - if EID.itemConfig:GetCollectible(descObj.ObjSubType).Type ~= 3 or isRune then + if isRune or EID.itemConfig:GetCollectible(descObj.ObjSubType).Type ~= 3 then + -- Determine our text and tables to read from based on the desc entity and if this is Void or Black Rune + -- Afterbirth+ can't really do anything with Void and a shop item, so just return + local shopItem = descObj.Entity and descObj.Entity:ToPickup():IsShopItem() + if (not REPENTANCE and shopItem) then return descObj end + + local voidIntro = (shopItem and EID:getDescriptionEntry("VoidShopText")) or EID:getDescriptionEntry("VoidText") + local voidNames = EID:getDescriptionEntry("VoidNames") + -- Replace "Tears" with "Fire Rate" + if REPENTANCE then voidNames[2] = EID:getDescriptionEntry("GlitchedItemText", 1) end + + local prefix = (isRune and "{{Card41}} ") or "{{Collectible477}} " + + --still need to figure out best way to not check RNG every frame + local player = (isRune and Isaac.GetPlayer(blackRuneOwned)) or Isaac.GetPlayer(collectiblesOwned[477]) + EID:VoidRNGCheck(player, isRune) + + local eidTable = (isRune and EID.BlackRuneStatIncreases) or EID.VoidStatIncreases + local increases = (inPreview and eidTable[3]) or (shopItem and eidTable[2]) or eidTable[1] + EID:appendToDescription(descObj, "#" .. prefix .. voidIntro .. "#") - for i,v in ipairs(EID.VoidStatIncreases) do + for i,v in ipairs(increases) do if v > 0 then - EID:appendToDescription(descObj, prefix .. "+" .. v*voidStatUps[i] .. " " .. voidNames[i] .. "#") + EID:appendToDescription(descObj, prefix .. "+" .. string.format("%.4g",v*voidStatUps[i]) .. " " .. voidNames[i] .. "#") end end else @@ -87,35 +93,10 @@ local function VoidCallback(descObj, isRune) end return descObj end -local function BlackRuneCallback(descObj) - EID:appendToDescription(descObj, "#{{Card41}} " .. voidIntro .. "#") - for i,v in ipairs(EID.BlackRuneStatIncreases) do - if v > 0 then - EID:appendToDescription(descObj, "{{Card41}} +" .. v*voidStatUps[i] .. " " .. voidNames[i] .. "#") - end - end - return descObj -end -local function EIDConditionsAB(descObj) - -- currently, only pickup descriptions have modifiers - if descObj.ObjType ~= 5 then return false end - - CheckPlayersCollectibles() - - local callbacks = {} - - -- Collectible Pedestal Callbacks - if descObj.ObjVariant == PickupVariant.PICKUP_COLLECTIBLE then - if EID.Config["DisplayVoidStatInfo"] then - if collectiblesOwned[477] then table.insert(callbacks, VoidCallback) end - if blackRuneOwned then table.insert(callbacks, BlackRuneCallback) end - end - end - - return callbacks +local function BlackRuneCallback(descObj) + return VoidCallback(descObj, true) end -EID:addDescriptionModifier("EID Afterbirth+", EIDConditionsAB, nil) if REPENTANCE then @@ -170,9 +151,11 @@ if REPENTANCE then -- Handle Spindown Dice description addition local function SpindownDiceCallback(descObj) + -- get the ID of the player that owns the Spindown Dice + local playerID = (collectiblesOwned[723] or (EID.absorbedItems[723] and collectiblesOwned[477])) EID:appendToDescription(descObj, "#{{Collectible723}} :") local refID = descObj.ObjSubType - local hasCarBattery = EID.player:HasCollectible(CollectibleType.COLLECTIBLE_CAR_BATTERY) + local hasCarBattery = Isaac.GetPlayer(playerID):HasCollectible(CollectibleType.COLLECTIBLE_CAR_BATTERY) local firstID = 0 for i = 1,EID.Config["SpindownDiceResults"] do local spinnedID = EID:getSpindownResult(refID) @@ -409,10 +392,10 @@ if REPENTANCE then if collectiblesOwned[664] then table.insert(callbacks, BingeEaterCallback) end if collectiblesOwned[59] then table.insert(callbacks, BookOfBelialCallback) end if collectiblesOwned[584] then table.insert(callbacks, BookOfVirtuesCallback) end - if collectiblesOwned[706] then table.insert(callbacks, AbyssCallback) end + if collectiblesOwned[706] or (EID.absorbedItems[706] and collectiblesOwned[477]) then table.insert(callbacks, AbyssCallback) end if collectiblesOwned[711] and EID:getEntityData(descObj.Entity, "EID_FlipItemID") then table.insert(callbacks, FlipCallback) end - if (collectiblesOwned[723] or (EID.absorbedSpindown and collectiblesOwned[477])) then table.insert(callbacks, SpindownDiceCallback) end + if collectiblesOwned[723] or (EID.absorbedItems[723] and collectiblesOwned[477]) then table.insert(callbacks, SpindownDiceCallback) end -- currently, only Repentance collectible modifiers have Tab previews so put it here if Input.IsActionPressed(ButtonAction.ACTION_MAP, EID.player.ControllerIndex) and not inPreview then table.insert(callbacks, TabCallback) end @@ -440,3 +423,23 @@ if REPENTANCE then EID:addDescriptionModifier("EID Repentance", EIDConditions, nil) end + +local function EIDConditionsAB(descObj) + -- currently, only pickup descriptions have modifiers + if descObj.ObjType ~= 5 then return false end + + CheckPlayersCollectibles() + + local callbacks = {} + + -- Collectible Pedestal Callbacks + if descObj.ObjVariant == PickupVariant.PICKUP_COLLECTIBLE then + if EID.Config["DisplayVoidStatInfo"] then + if collectiblesOwned[477] then table.insert(callbacks, VoidCallback) end + if blackRuneOwned then table.insert(callbacks, BlackRuneCallback) end + end + end + + return callbacks +end +EID:addDescriptionModifier("EID Afterbirth+", EIDConditionsAB, nil) From 5d81fe7655ee5640e5564122e0addf5e9e047795 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 27 Jan 2022 22:56:18 -0500 Subject: [PATCH 07/14] Track any Absorbed Items, Void functions --- main.lua | 89 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/main.lua b/main.lua index 67550bd0..d7190a5f 100644 --- a/main.lua +++ b/main.lua @@ -28,7 +28,7 @@ EID.sacrificeCounter = {} EID.itemConfig = Isaac.GetItemConfig() EID.itemUnlockStates = {} EID.CraneItemType = {} -EID.absorbedSpindown = false +EID.absorbedItems = {} local pathsChecked = {} local altPathItemChecked = {} @@ -362,13 +362,13 @@ if REPENTANCE then end EID:AddCallback(ModCallbacks.MC_PRE_USE_ITEM, EID.CheckFlipGridIndexes, CollectibleType.COLLECTIBLE_FLIP) - -- Watch for a Void absorbing a Spindown Dice + -- Watch for a Void absorbing active items + -- (Note: Doesn't differentiate between different players if both players have Void...) function EID:CheckVoidAbsorbs(collectibleType) local pedestals = Isaac.FindByType(5, 100, -1, true, false) for _, pedestal in ipairs(pedestals) do - if pedestal.SubType == CollectibleType.COLLECTIBLE_SPINDOWN_DICE then - EID.absorbedSpindown = true - return + if pedestal.SubType > 0 and EID.itemConfig:GetCollectible(pedestal.SubType).Type == 3 then + EID.absorbedItems[pedestal.SubType] = true end end end @@ -843,21 +843,58 @@ local function GetTwoIncreases(rng, tbl) return rng end +local numVoidable = 0 +local numRunable = 0 + +-- Count the number of absorbable pedestals in the room +function EID:VoidRoomCheck() + numVoidable = 0 + numRunable = 0 + local indexesFound = {} + for _, entity in ipairs(Isaac.FindByType(5, 100, -1, true, false)) do + local pickup = entity:ToPickup() + -- Count this pedestal if it's not an active (or this is Black Rune), not a shop item, and (in Repentance) the first of its option index + -- TEST IF VOID ALWAYS ABSORBS THE FIRST OF ITS OPTION INDEX + if entity.SubType > 0 and not pickup:IsShopItem() and + (not REPENTANCE or pickup.OptionsPickupIndex == 0 or indexesFound[pickup.OptionsPickupIndex] ~= true) then + numRunable = numRunable + 1 + indexesFound[pickup.OptionsPickupIndex] = true + if (EID.itemConfig:GetCollectible(entity.SubType).Type ~= ItemType.ITEM_ACTIVE) then numVoidable = numVoidable + 1 end + end + end +end +function EID:VoidRNGCheck(player, isRune) + -- increases = the stats from the absorbable pedestals in the room + local increases = {0, 0, 0, 0, 0, 0} + -- absorbing after buying a shop item can need 1 extra stat increase set; Tab previews need only 1 stat increase + local shopItemIncreases = {}; local singleIncreases = {} + + local startRNG = (isRune and player:GetCardRNG(Card.RUNE_BLACK):GetSeed()) or player:GetCollectibleRNG(CollectibleType.COLLECTIBLE_VOID):GetSeed() + local count = (isRune and numRunable) or numVoidable + local eidTable = (isRune and EID.BlackRuneStatIncreases) or EID.VoidStatIncreases + + -- in Repentance, an additional RNG call is done before the 5 for stat ups when using Void + if REPENTANCE and not isRune then startRNG = VoidRNGNext(startRNG) end + for i = 1, count do + startRNG = GetTwoIncreases(startRNG, increases) + if i == 1 then eidTable[3] = {table.unpack(increases)} end + end + eidTable[1] = {table.unpack(increases)} + -- do an extra check for what you'd get if you Void with a shop item above your head + GetTwoIncreases(startRNG, increases) + eidTable[2] = {table.unpack(increases)} + -- if there were no absorbable pedestals, the "single increase" stats are the same as the "one extra" stats + if count == 0 then eidTable[3] = {table.unpack(increases)} end +end + function EID:onGameUpdate() EID.GameUpdateCount = EID.GameUpdateCount + 1 if collSpawned then collSpawned = false - local numVoidable = 0 - local numBlackRunable = 0 - -- THIS INCLUDES UNPURCHASED SHOP ITEMS??? and both choice items also, which is OK for AB+ but not for Rep! + local curPositions = {} for _, entity in ipairs(Isaac.FindByType(5, 100, -1, true, false)) do - if entity.SubType > 0 then - numBlackRunable = numBlackRunable + 1 - if EID.itemConfig:GetCollectible(entity.SubType).Type ~= 3 then numVoidable = numVoidable + 1 end - end - -- Fix Overlapping Pedestals if a collectible spawned this frame (needed for Mega Chest) local pos = entity.Position for _, otherPos in ipairs(curPositions) do @@ -871,23 +908,7 @@ function EID:onGameUpdate() -- Recalculate our total Void stat-ups if a collectible spawned this frame -- THIS COULD APPLY TO BLACK RUNE AS WELL - if EID:PlayersHaveCollectible(CollectibleType.COLLECTIBLE_VOID) then - local curRoomIndex = game:GetLevel():GetCurrentRoomIndex() - local increases = {0, 0, 0, 0, 0, 0} - local runeIncreases = {0, 0, 0, 0, 0, 0} - --CHANGE THIS TO THE PLAYER THAT HAS VOID - local startRNG = Isaac.GetPlayer(0):GetCollectibleRNG(CollectibleType.COLLECTIBLE_VOID):GetSeed() - local runeRNG = Isaac.GetPlayer(0):GetCardRNG(Card.RUNE_BLACK):GetSeed() - -- in Repentance, an additional RNG call is done before the 5 for stat ups - if REPENTANCE then startRNG = VoidRNGNext(startRNG) end - for pedestals = 1, 1 do - startRNG = GetTwoIncreases(startRNG, increases) - runeRNG = GetTwoIncreases(runeRNG, runeIncreases) - break -- only doing 1 preview for now - end - EID.VoidStatIncreases = increases - EID.BlackRuneStatIncreases = runeIncreases - end + EID:VoidRoomCheck() end -- Remove Crane Game item data if it's giving the prize out @@ -1261,7 +1282,7 @@ if EID.MCMLoaded or REPENTANCE then ["BagFloorContent"] = true, ["CraneItemType"] = true, ["FlipItemPositions"] = true, - ["AbsorbedSpindownDice"] = true, + ["AbsorbedItems"] = true, } if EID:HasData() then @@ -1270,13 +1291,13 @@ if EID.MCMLoaded or REPENTANCE then EID.BagItems = {} EID.CraneItemType = {} EID.flipItemPositions = {} - EID.absorbedSpindown = false + EID.absorbedItems = {} if isSave then EID.BagItems = savedEIDConfig["BagContent"] or {} EID.bagOfCraftingRoomQueries = savedEIDConfig["BagFloorContent"] or {} EID.CraneItemType = savedEIDConfig["CraneItemType"] or {} - EID.absorbedSpindown = savedEIDConfig["AbsorbedSpindownDice"] or false + EID.absorbedItems = savedEIDConfig["AbsorbedItems"] or {} -- turn list back into dict because json cant save dict indices. local flipItemTable = {} @@ -1338,7 +1359,7 @@ if EID.MCMLoaded or REPENTANCE then EID.Config["BagContent"] = EID.BagItems or {} EID.Config["BagFloorContent"] = EID.bagOfCraftingRoomQueries or {} EID.Config["CraneItemType"] = EID.CraneItemType or {} - EID.Config["AbsorbedSpindownDice"] = EID.absorbedSpindown or false + EID.Config["AbsorbedItems"] = EID.absorbedItems or {} -- turn dictionary into list because json cant save dict indices. local flipItemTable = {} From 3d01fb5cc2e904883570ca4c3b4797e7d7a0d2bd Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 27 Jan 2022 22:57:00 -0500 Subject: [PATCH 08/14] Void shop text --- descriptions/rep/en_us.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/descriptions/rep/en_us.lua b/descriptions/rep/en_us.lua index 2ac8d706..65e57bc6 100644 --- a/descriptions/rep/en_us.lua +++ b/descriptions/rep/en_us.lua @@ -1012,6 +1012,8 @@ EID.descriptions[languageCode].GlitchedItemText = { ---------- Misc. Text ---------- +EID.descriptions[languageCode].VoidShopText = "If absorbed after purchase, gain:" + EID.descriptions[languageCode].spindownError = "Item disappears" EID.descriptions[languageCode].CraftingBagContent = "Bag:" From e98c94f7d4f5b95fa8d2279861d835c4a444ce1e Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 28 Jan 2022 00:32:45 -0500 Subject: [PATCH 09/14] make Dataminer sfw --- descriptions/ab+/en_us.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/descriptions/ab+/en_us.lua b/descriptions/ab+/en_us.lua index f6798ff3..88ad54d8 100644 --- a/descriptions/ab+/en_us.lua +++ b/descriptions/ab+/en_us.lua @@ -500,7 +500,7 @@ EID.descriptions[languageCode].collectibles={ {"478", "Pause", "Freezes all enemies in the room until you start shooting again#Touching a frozen enemy will hurt you#Enemies unfreeze after 30 seconds"}, {"479", "Smelter", "Consumes your trinket and gives you the effect permanently#More trinkets appear"}, {"480", "Compost", "Converts pickups into blue flies or spiders#Doubles your current blue flies/spiders#Spawns 1 blue fly or spider when you don't have any"}, - {"481", "Dataminer", "When used, ↑/↓ small amount on random stat#Random tear effect for current room#Fucks up all sprites"}, + {"481", "Dataminer", "When used, ↑/↓ small amount on random stat#Random tear effect for current room#Corrupts all sprites and music for current room"}, {"482", "Clicker", "Transforms you into a different character#Removes the last item you collected"}, {"483", "Mama Mega!", "!!! SINGLE USE !!!#Affects whole floor#Explodes all objects#Deals 200 damage to all enemies#Opens the door to Boss Rush, Hush and all secret rooms#!!! If you have a Golden Bomb, consumes it on use instead of Mama Mega"}, {"484", "Wait What?", "Upon use, pushes enemies away and spawn a wave of rocks#Can open rooms and break rocks"}, From fda4576271c349c5b980e55e286a3e1e0d2bfade Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 28 Jan 2022 00:53:40 -0500 Subject: [PATCH 10/14] move Void RNG functions --- eid_api.lua | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/eid_api.lua b/eid_api.lua index 0a64ad35..97ccf1c6 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -922,6 +922,71 @@ function EID:CheckGlitchedItemConfig(id) return attributes end +-- Void stat prediction helper functions (called from eid_modifiers when needed) +-- Didn't seem right to put them in main or eid_modifiers +local numVoidable = 0 +local numRunable = 0 +local function VoidRNGNext(num) + num = num ~ ((num >> 5) & 4294967295) + num = num ~ ((num << 9) & 4294967295) + num = num ~ ((num >> 7) & 4294967295) + return num >> 0; +end +local function GetTwoIncreases(rng, tbl) + local statTable = {1,2,3,4,5,6} + -- perform 5 random swaps of our stat table + for i = 6, 2, -1 do + rng = VoidRNGNext(rng) + local result = (rng % i) + 1 + local temp = statTable[i] + statTable[i] = statTable[result] + statTable[result] = temp + end + -- the first two entries in the stat table get increased + tbl[statTable[1]] = tbl[statTable[1]] + 1 + tbl[statTable[2]] = tbl[statTable[2]] + 1 + return rng +end +-- Count the number of absorbable pedestals in the room +function EID:VoidRoomCheck() + numVoidable = 0 + numRunable = 0 + EID.VoidOptionIndexes = {} + for _, entity in ipairs(Isaac.FindByType(5, 100, -1, true, false)) do + local pickup = entity:ToPickup() + -- Count this pedestal if it's not an active (or this is Black Rune), not a shop item, and (in Repentance) the first of its option index + -- TEST IF VOID ALWAYS ABSORBS THE FIRST OF ITS OPTION INDEX + if entity.SubType > 0 and not pickup:IsShopItem() and + (not REPENTANCE or pickup.OptionsPickupIndex == 0 or EID.VoidOptionIndexes[pickup.OptionsPickupIndex] == nil) then + numRunable = numRunable + 1 + EID.VoidOptionIndexes[pickup.OptionsPickupIndex] = entity.SubType + if (EID.itemConfig:GetCollectible(entity.SubType).Type ~= ItemType.ITEM_ACTIVE) then numVoidable = numVoidable + 1 end + end + end +end +-- Determine what stats will be increased after 1 absorption, the whole room's absorption, and whole room + a purchased item above your head +function EID:VoidRNGCheck(player, isRune) + local increases = {0, 0, 0, 0, 0, 0} + local shopItemIncreases = {}; local singleIncreases = {} + + local startRNG = (isRune and player:GetCardRNG(Card.RUNE_BLACK):GetSeed()) or player:GetCollectibleRNG(CollectibleType.COLLECTIBLE_VOID):GetSeed() + local count = (isRune and numRunable) or numVoidable + local eidTable = (isRune and EID.BlackRuneStatIncreases) or EID.VoidStatIncreases + + -- in Repentance, an additional RNG call is done before the 5 for stat ups when using Void + if REPENTANCE and not isRune then startRNG = VoidRNGNext(startRNG) end + for i = 1, count do + startRNG = GetTwoIncreases(startRNG, increases) + if i == 1 then eidTable[3] = {table.unpack(increases)} end + end + eidTable[1] = {table.unpack(increases)} + -- do an extra check for what you'd get if you Void with a shop item above your head + GetTwoIncreases(startRNG, increases) + eidTable[2] = {table.unpack(increases)} + -- if there were no absorbable pedestals, the "single increase" stats are the same as the "one extra" stats + if count == 0 then eidTable[3] = {table.unpack(increases)} end +end + -- Converts a given CollectibleID into the respective Spindown dice result function EID:getSpindownResult(collectibleID) if collectibleID <= 0 or collectibleID > 4294960000 then return 0 end From d0cc136e7975dea28b00339dec4a39457938617a Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 28 Jan 2022 00:54:07 -0500 Subject: [PATCH 11/14] Move Void RNG functions --- main.lua | 75 +++----------------------------------------------------- 1 file changed, 3 insertions(+), 72 deletions(-) diff --git a/main.lua b/main.lua index d7190a5f..e8c252d5 100644 --- a/main.lua +++ b/main.lua @@ -818,74 +818,7 @@ end -- Runs 30 times a second; doesn't update while paused local collSpawned = false - -EID.VoidStatIncreases = {} -EID.BlackRuneStatIncreases = {} -local function VoidRNGNext(num) - num = num ~ ((num >> 5) & 4294967295) - num = num ~ ((num << 9) & 4294967295) - num = num ~ ((num >> 7) & 4294967295) - return num >> 0; -end -local function GetTwoIncreases(rng, tbl) - local statTable = {1,2,3,4,5,6} - -- perform 5 random swaps of our stat table - for i = 6, 2, -1 do - rng = VoidRNGNext(rng) - local result = (rng % i) + 1 - local temp = statTable[i] - statTable[i] = statTable[result] - statTable[result] = temp - end - -- the first two entries in the stat table get increased - tbl[statTable[1]] = tbl[statTable[1]] + 1 - tbl[statTable[2]] = tbl[statTable[2]] + 1 - return rng -end - -local numVoidable = 0 -local numRunable = 0 - --- Count the number of absorbable pedestals in the room -function EID:VoidRoomCheck() - numVoidable = 0 - numRunable = 0 - local indexesFound = {} - for _, entity in ipairs(Isaac.FindByType(5, 100, -1, true, false)) do - local pickup = entity:ToPickup() - -- Count this pedestal if it's not an active (or this is Black Rune), not a shop item, and (in Repentance) the first of its option index - -- TEST IF VOID ALWAYS ABSORBS THE FIRST OF ITS OPTION INDEX - if entity.SubType > 0 and not pickup:IsShopItem() and - (not REPENTANCE or pickup.OptionsPickupIndex == 0 or indexesFound[pickup.OptionsPickupIndex] ~= true) then - numRunable = numRunable + 1 - indexesFound[pickup.OptionsPickupIndex] = true - if (EID.itemConfig:GetCollectible(entity.SubType).Type ~= ItemType.ITEM_ACTIVE) then numVoidable = numVoidable + 1 end - end - end -end -function EID:VoidRNGCheck(player, isRune) - -- increases = the stats from the absorbable pedestals in the room - local increases = {0, 0, 0, 0, 0, 0} - -- absorbing after buying a shop item can need 1 extra stat increase set; Tab previews need only 1 stat increase - local shopItemIncreases = {}; local singleIncreases = {} - - local startRNG = (isRune and player:GetCardRNG(Card.RUNE_BLACK):GetSeed()) or player:GetCollectibleRNG(CollectibleType.COLLECTIBLE_VOID):GetSeed() - local count = (isRune and numRunable) or numVoidable - local eidTable = (isRune and EID.BlackRuneStatIncreases) or EID.VoidStatIncreases - - -- in Repentance, an additional RNG call is done before the 5 for stat ups when using Void - if REPENTANCE and not isRune then startRNG = VoidRNGNext(startRNG) end - for i = 1, count do - startRNG = GetTwoIncreases(startRNG, increases) - if i == 1 then eidTable[3] = {table.unpack(increases)} end - end - eidTable[1] = {table.unpack(increases)} - -- do an extra check for what you'd get if you Void with a shop item above your head - GetTwoIncreases(startRNG, increases) - eidTable[2] = {table.unpack(increases)} - -- if there were no absorbable pedestals, the "single increase" stats are the same as the "one extra" stats - if count == 0 then eidTable[3] = {table.unpack(increases)} end -end +EID.RecheckVoid = false function EID:onGameUpdate() EID.GameUpdateCount = EID.GameUpdateCount + 1 @@ -906,9 +839,7 @@ function EID:onGameUpdate() table.insert(curPositions, {entity, entity.Position}) end - -- Recalculate our total Void stat-ups if a collectible spawned this frame - -- THIS COULD APPLY TO BLACK RUNE AS WELL - EID:VoidRoomCheck() + EID.RecheckVoid = true end -- Remove Crane Game item data if it's giving the prize out @@ -924,7 +855,7 @@ function EID:onGameUpdate() end EID:AddCallback(ModCallbacks.MC_POST_UPDATE, EID.onGameUpdate) --- Wait until all collectibles spawning this frame have spawned before checking if there's an overlap +-- Wait until all collectibles spawning this frame have spawned before checking what we need to check about them function EID:CollectibleSpawnedThisFrame(entity) collSpawned = true end From 4a7cea87bcec386d3b68ecec462cee98b8a15854 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 28 Jan 2022 00:54:44 -0500 Subject: [PATCH 12/14] Void modifier is much better and faster now --- eid_modifiers.lua | 48 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/eid_modifiers.lua b/eid_modifiers.lua index 0ed49003..52a0b1cf 100644 --- a/eid_modifiers.lua +++ b/eid_modifiers.lua @@ -60,27 +60,48 @@ end -- Handle Void (the only modifier that is applied to AB+ at the moment) local voidStatUps = { 0.2, 0.5, 1, 0.5, 0.2, 1 } if REPENTANCE then voidStatUps[4] = 1.5 end +local lastVoidCheck = -30 +EID.VoidStatIncreases = {{},{},{}} +EID.BlackRuneStatIncreases = {{},{},{}} +EID.VoidOptionIndexes = {} local function VoidCallback(descObj, isRune) + -- Recheck RNG periodically (picking up passive collectibles will change the Void results without any easy trigger to track) + -- Do both Void and Rune here since they could both be requested in the same frame + if EID.GameUpdateCount >= lastVoidCheck + 30 or EID.RecheckVoid then + EID:VoidRoomCheck() + if collectiblesOwned[477] then EID:VoidRNGCheck(Isaac.GetPlayer(collectiblesOwned[477]), false) end + if blackRuneOwned then EID:VoidRNGCheck(Isaac.GetPlayer(blackRuneOwned), true) end + lastVoidCheck = EID.GameUpdateCount + EID.RecheckVoid = false + end + + local prefix = (isRune and "{{Card41}} ") or "{{Collectible477}} " + local pickup = descObj.Entity and descObj.Entity:ToPickup() + local isAltOption = false + -- Test if this is an Option pedestal, Repentance only absorbs the lowest index one + if REPENTANCE then + local optionIndex = pickup and pickup.OptionsPickupIndex + local firstOption = EID.VoidOptionIndexes[optionIndex] + if (REPENTANCE and optionIndex and optionIndex ~= 0 and descObj.ObjSubType ~= firstOption) then + EID:appendToDescription(descObj, "#" .. prefix .. "{{Collectible"..firstOption.. + "}}" .. EID:getObjectName(5, 100, firstOption) .. EID:getDescriptionEntry("VoidOptionText")) + isAltOption = true + end + end + -- Print Stat up info if Black Rune or non-active item if isRune or EID.itemConfig:GetCollectible(descObj.ObjSubType).Type ~= 3 then - -- Determine our text and tables to read from based on the desc entity and if this is Void or Black Rune - -- Afterbirth+ can't really do anything with Void and a shop item, so just return - local shopItem = descObj.Entity and descObj.Entity:ToPickup():IsShopItem() + local shopItem = pickup and pickup:IsShopItem() + -- Afterbirth+ really can't do anything with Void and a shop item, so just return if (not REPENTANCE and shopItem) then return descObj end - local voidIntro = (shopItem and EID:getDescriptionEntry("VoidShopText")) or EID:getDescriptionEntry("VoidText") + local voidIntro = ((shopItem or isAltOption) and EID:getDescriptionEntry("VoidShopText")) or EID:getDescriptionEntry("VoidText") local voidNames = EID:getDescriptionEntry("VoidNames") -- Replace "Tears" with "Fire Rate" if REPENTANCE then voidNames[2] = EID:getDescriptionEntry("GlitchedItemText", 1) end - local prefix = (isRune and "{{Card41}} ") or "{{Collectible477}} " - - --still need to figure out best way to not check RNG every frame - local player = (isRune and Isaac.GetPlayer(blackRuneOwned)) or Isaac.GetPlayer(collectiblesOwned[477]) - EID:VoidRNGCheck(player, isRune) - local eidTable = (isRune and EID.BlackRuneStatIncreases) or EID.VoidStatIncreases - local increases = (inPreview and eidTable[3]) or (shopItem and eidTable[2]) or eidTable[1] + local increases = ((inPreview or isAltOption) and eidTable[3]) or (shopItem and eidTable[2]) or eidTable[1] EID:appendToDescription(descObj, "#" .. prefix .. voidIntro .. "#") for i,v in ipairs(increases) do @@ -88,8 +109,9 @@ local function VoidCallback(descObj, isRune) EID:appendToDescription(descObj, prefix .. "+" .. string.format("%.4g",v*voidStatUps[i]) .. " " .. voidNames[i] .. "#") end end - else - -- unique Void interactions with active items? + -- Print unique synergies with Void and Active Items + elseif not isRune then + end return descObj end From e839827da077ee27b9ce0fc79840b502bf1b0d9b Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 28 Jan 2022 01:01:17 -0500 Subject: [PATCH 13/14] fix Afterbirth+ nil index --- eid_api.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eid_api.lua b/eid_api.lua index 97ccf1c6..d0fbe402 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -959,7 +959,7 @@ function EID:VoidRoomCheck() if entity.SubType > 0 and not pickup:IsShopItem() and (not REPENTANCE or pickup.OptionsPickupIndex == 0 or EID.VoidOptionIndexes[pickup.OptionsPickupIndex] == nil) then numRunable = numRunable + 1 - EID.VoidOptionIndexes[pickup.OptionsPickupIndex] = entity.SubType + if REPENTANCE then EID.VoidOptionIndexes[pickup.OptionsPickupIndex] = entity.SubType end if (EID.itemConfig:GetCollectible(entity.SubType).Type ~= ItemType.ITEM_ACTIVE) then numVoidable = numVoidable + 1 end end end From 6e4deb8026a3e5f8e281e5c3fd1e368f7aabe6c0 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 28 Jan 2022 01:02:34 -0500 Subject: [PATCH 14/14] add Alt Option Void text --- descriptions/rep/en_us.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/descriptions/rep/en_us.lua b/descriptions/rep/en_us.lua index 65e57bc6..a24d1062 100644 --- a/descriptions/rep/en_us.lua +++ b/descriptions/rep/en_us.lua @@ -1012,7 +1012,8 @@ EID.descriptions[languageCode].GlitchedItemText = { ---------- Misc. Text ---------- -EID.descriptions[languageCode].VoidShopText = "If absorbed after purchase, gain:" +EID.descriptions[languageCode].VoidShopText = "If absorbed right after pickup, gain:" +EID.descriptions[languageCode].VoidOptionText = " will be absorbed instead" EID.descriptions[languageCode].spindownError = "Item disappears"