From c316b9a392816d89e7d929f88a0f135512e516cd Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 16 Jun 2022 16:47:16 -0400 Subject: [PATCH 01/10] change to InsideItemReminder --- eid_modifiers.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eid_modifiers.lua b/eid_modifiers.lua index da5a57a4..4a1dca14 100644 --- a/eid_modifiers.lua +++ b/eid_modifiers.lua @@ -5,8 +5,6 @@ EID.TabPreviewID = 0 EID.inModifierPreview = false -- The "Hold Map Helper" needs to know if it shouldn't display because we're in a Hold Tab desc EID.TabDescThisFrame = false --- ...and likewise we need to know when we're in the Item Reminder (this is getting out of hand) -EID.ReminderThisFrame = false -- List of collectible IDs for us to check if a player owns them; feel free to add to this in mods that add description modifiers! EID.collectiblesToCheck = { CollectibleType.COLLECTIBLE_VOID, } @@ -87,6 +85,7 @@ EID.BlackRuneStatIncreases = {{},{},{}} EID.VoidOptionIndexes = {} local function VoidCallback(descObj, isRune) + if EID.InsideItemReminder then return descObj end -- 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 @@ -281,6 +280,7 @@ if REPENTANCE then -- Handle Spindown Dice description addition local function SpindownDiceCallback(descObj) + if EID.InsideItemReminder then return descObj end -- get the ID of the player that owns the Spindown Dice local playerID = (EID.collectiblesOwned[723] or EID.collectiblesAbsorbed[723]) EID:appendToDescription(descObj, "#{{Collectible723}} :") @@ -322,7 +322,7 @@ if REPENTANCE then if hasCarBattery then EID:appendToDescription(descObj, " (Results with {{Collectible356}})") end - if not EID.ReminderThisFrame and firstID ~= 0 and EID.TabPreviewID == 0 then + if firstID ~= 0 and EID.TabPreviewID == 0 then EID.TabPreviewID = firstID EID:appendToDescription(descObj, "#{{Blank}} ".. EID:getDescriptionEntry("FlipItemToggleInfo")) end From a2334ce899419670ad1810faf58c62905e7af0dc Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 16 Jun 2022 16:47:46 -0400 Subject: [PATCH 02/10] Change to InsideItemReminder, give it a title --- main.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/main.lua b/main.lua index d5667697..e2ca356d 100644 --- a/main.lua +++ b/main.lua @@ -1213,7 +1213,6 @@ local function onRender(t) end EID.TabPreviewID = 0 EID.TabDescThisFrame = false - EID.ReminderThisFrame = false -- If MCM is open, don't show anything unless we're in a tab labeled as "Visuals" or "Crafting" if ModConfigMenu and ModConfigMenu.IsVisible and ModConfigMenu.Config["Mod Config Menu"].HideHudInMenu and EID.MCMCompat_isDisplayingEIDTab ~= "Visuals" and EID.MCMCompat_isDisplayingEIDTab ~= "Crafting" then @@ -1516,9 +1515,9 @@ local function onRender(t) -- handle showing the Hold Map Helper description if EID.Config["ItemReminderEnabled"] and EID.holdTabCounter >= 30 and EID.TabDescThisFrame == false and EID.holdTabPlayer ~= nil then - EID.ReminderThisFrame = true local demoDescObj = EID:getDescriptionObj(-999, -1, 1) - demoDescObj.Name = "" + demoDescObj.Name = EID:getDescriptionEntry("HoldMapTitle") + -- check for scrolling being enabled here and append scroll controls to the title? demoDescObj.Description = EID:getHoldMapDescription(EID.holdTabPlayer) if (demoDescObj.Description ~= "") then EID:addDescriptionToPrint(demoDescObj, 1) end end From 507f9f32ee9abf7a3a19b3c97cc1373d37547e3e Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 16 Jun 2022 16:48:22 -0400 Subject: [PATCH 03/10] WIP --- eid_holdmapdesc.lua | 68 ++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/eid_holdmapdesc.lua b/eid_holdmapdesc.lua index 24ee5741..f7d27653 100644 --- a/eid_holdmapdesc.lua +++ b/eid_holdmapdesc.lua @@ -4,6 +4,7 @@ local currentRoom local blacklist local holdMapDesc local currentPlayer +EID.InsideItemReminder = false -- Rainbow Worm's trinket IDs it grants, in order local rainbowWormEffects = { [0] = 9, 11, 65, 27, 10, 12, 26, 66, 96, 144 } @@ -30,6 +31,21 @@ local function addObjectDesc(type, variant, subtype, extraIcon) end end +-- AB+'s D Infinity RNG modulo order +local dinfinityList = { [0] = 105, 166, 284, 283, 285, 406, 386 } +-- Repentance's D Infinity order: D1, D4, D6, Eternal D6, D7, D8, D10, D12, D20, D100 +if REPENTANCE then dinfinityList = { 476, 284, 105, 609, 437, 406, 285, 386, 166, 283 } end +function EID:CurrentDInfinity() + if not REPENTANCE then + local rng = currentPlayer:GetCollectibleRNG(489):GetSeed() + rng = EID:RNGNext(rng, 0x1, 0x9, 0x1D) + local nextDice = dinfinityList[rng % 7] + addObjectDesc(5, 100, nextDice, "{{Collectible489}}") + else + -- track our current selected dinfinity dice! test if it is preserved between pickups of it + end +end + -- Banned items: Metronome, Plan C, Glowing Hour Glass, Breath of Life, Clicker, R Key -- Reduced chance: Death Certificate (15%), Genesis (25%) -- I saw something in the code about rerolling Forget Me Now but not sure what the criteria was @@ -59,16 +75,16 @@ function EID:MetronomePrediction() local rerollFloat = EID:SeedToFloat(rerollChance) if rerollFloat < 1 - metronomeBlacklist[sel] then -- We succeeded the reroll chance - return "{{Collectible" .. sel .. "}} {{ColorGray}}" .. EID:getObjectName(5,100,sel) .. "#" .. EID:getDescriptionObj(5,100,sel).Description + return sel end end else - return "{{Collectible" .. sel .. "}} {{ColorGray}}" .. EID:getObjectName(5,100,sel) .. "#" .. EID:getDescriptionObj(5,100,sel).Description + return sel end end end -- as the code puts it, [warn] No Collectible found for Metronome! - return "None" + return 488 end -- Teleport! Destination Prediction -- @@ -190,6 +206,7 @@ function EID:trimSanguineDesc(descObj) end function EID:getHoldMapDescription(player, checkingTwin) + EID.InsideItemReminder = true -- Starting Blacklist: Recall, Hold blacklist = { ["5.100.714"] = true, ["5.100.715"] = true, } holdMapDesc = "" @@ -214,24 +231,6 @@ function EID:getHoldMapDescription(player, checkingTwin) end end - -- Metronome result - if player:HasCollectible(CollectibleType.COLLECTIBLE_METRONOME) and EID.Config["ItemReminderShowRNGCheats"] then - blacklist["5.100.488"] = true - append("{{Collectible488}}", EID:getObjectName(5,100,488) .. EID:getDescriptionEntry("HoldMapHeader"), EID:MetronomePrediction()) - end - - -- Teleport! location - if player:HasCollectible(CollectibleType.COLLECTIBLE_TELEPORT) and EID.Config["ItemReminderShowRNGCheats"] then - blacklist["5.100.44"] = true - teleport1Prediction() - end - - -- Teleport 2.0 location - if player:HasCollectible(CollectibleType.COLLECTIBLE_TELEPORT_2) and not EID.isMirrorRoom then - blacklist["5.100.419"] = true - teleport2Prediction() - end - -- Recently Acquired Item Descriptions if EID.Config["ItemReminderShowRecentItem"] > 0 then local printedItems = 0 @@ -249,9 +248,31 @@ function EID:getHoldMapDescription(player, checkingTwin) -- Active Item Descriptions if EID.Config["ItemReminderShowActiveDesc"] > 0 then for i = 0, EID.Config["ItemReminderShowActiveDesc"]-1 do + -- the modulo is to convert negative IDs (glitched items) to positive IDs local heldActive = player:GetActiveItem(i) % 4294967296 - if heldActive > 0 then - addObjectDesc(5, 100, heldActive) + if heldActive > 0 and not blacklist["5.100." .. heldActive] then + -- Metronome result + if heldActive == 488 and EID.Config["ItemReminderShowRNGCheats"] then + blacklist["5.100.488"] = true + addObjectDesc(5, 100, EID:MetronomePrediction(), "{{Collectible488}}") + --append("{{Collectible488}}", EID:getObjectName(5,100,488) .. EID:getDescriptionEntry("HoldMapHeader"), EID:MetronomePrediction()) + + -- Teleport! location + elseif heldActive == 44 and EID.Config["ItemReminderShowRNGCheats"] then + blacklist["5.100.44"] = true + teleport1Prediction() + + -- Teleport 2.0 location + elseif heldActive == 419 and not EID.isMirrorRoom then + blacklist["5.100.419"] = true + teleport2Prediction() + + elseif heldActive == 489 then + blacklist["5.100.489"] = true + EID:CurrentDInfinity() + else + addObjectDesc(5, 100, heldActive) + end end end end @@ -344,5 +365,6 @@ function EID:getHoldMapDescription(player, checkingTwin) end end + EID.InsideItemReminder = false return holdMapDesc end From a6b54642014890935a7e7a149c9f2d9bcc8f27ed Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 16 Jun 2022 16:48:39 -0400 Subject: [PATCH 04/10] HoldMapTitle --- descriptions/ab+/en_us.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/descriptions/ab+/en_us.lua b/descriptions/ab+/en_us.lua index da281ce0..cbb8cde0 100644 --- a/descriptions/ab+/en_us.lua +++ b/descriptions/ab+/en_us.lua @@ -884,6 +884,7 @@ EID.descriptions[languageCode].MCM = { DemoObjectText = "This text is in english#A very cool and long description to simulate linebreaks caused by EID textbox width!#{{Collectible4}} This is also a cool line#{{Heart}} This line loves you#{{AngelDevilChance}} This line can be your angel or your devil#\1 {{Damage}} +1 Stat Change up", } +EID.descriptions[languageCode].HoldMapTitle = "Item Reminder" -- the Hold Map description will predict the abilities of items with a header like "Item Name Result" EID.descriptions[languageCode].HoldMapHeader = " Result" From 235bff18af722c37f7f9f37e7eb05ddbce1ab143 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 16 Jun 2022 18:55:57 -0400 Subject: [PATCH 05/10] Include Item Prediction file --- main.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/main.lua b/main.lua index e2ca356d..24110f8c 100644 --- a/main.lua +++ b/main.lua @@ -107,6 +107,7 @@ require("eid_xmldata") require("eid_api") require("eid_modifiers") require("eid_holdmapdesc") +require("eid_itemprediction") -- load Repentence descriptions if REPENTANCE then From c380a77c3715d0b9096df5bc1b6c6798199076f9 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 16 Jun 2022 21:36:09 -0400 Subject: [PATCH 06/10] Still need to move Void functions --- eid_holdmapdesc.lua | 206 ++++------------------------------------- eid_itemprediction.lua | 176 +++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+), 186 deletions(-) create mode 100644 eid_itemprediction.lua diff --git a/eid_holdmapdesc.lua b/eid_holdmapdesc.lua index f7d27653..c586c885 100644 --- a/eid_holdmapdesc.lua +++ b/eid_holdmapdesc.lua @@ -6,16 +6,19 @@ local holdMapDesc local currentPlayer EID.InsideItemReminder = false --- Rainbow Worm's trinket IDs it grants, in order -local rainbowWormEffects = { [0] = 9, 11, 65, 27, 10, 12, 26, 66, 96, 144 } --- Mysterious Paper does not play well with displaying Error 404's effect -local mysteriousPaperBlacklist = { [23] = true, [48] = true } - -- Simple function to help with adding properly formatted sections to the desc local function append(icon, title, newDesc) holdMapDesc = holdMapDesc .. (icon or "{{Blank}}") .. " {{ColorEIDObjName}}" .. title .. "#" .. newDesc .. "#" end +-- Simple function to quickly get an item's RNG seed. We have no use for the RNG object itself because every other function it can do will advance the item's RNG, altering the game state +local function getSeed(id, variant) + if variant == nil or variant == 100 then return currentPlayer:GetCollectibleRNG(id):GetSeed() + elseif variant == 350 then return currentPlayer:GetTrinketRNG(id):GetSeed() + elseif variant == 300 then return currentPlayer:GetCardRNG(id):GetSeed() + elseif variant == 70 then return currentPlayer:GetPillRNG(id):GetSeed() end +end + -- Helper function to easily add an item's stock description to the desc -- Don't use if you need to customize the desc! (Like Sanguine Bond's result highlighting) -- extraIcon is for when we want a special icon before the line (like {{Dice Bag Icon}} {{Dice Item Icon}}) @@ -31,179 +34,11 @@ local function addObjectDesc(type, variant, subtype, extraIcon) end end --- AB+'s D Infinity RNG modulo order -local dinfinityList = { [0] = 105, 166, 284, 283, 285, 406, 386 } --- Repentance's D Infinity order: D1, D4, D6, Eternal D6, D7, D8, D10, D12, D20, D100 -if REPENTANCE then dinfinityList = { 476, 284, 105, 609, 437, 406, 285, 386, 166, 283 } end -function EID:CurrentDInfinity() - if not REPENTANCE then - local rng = currentPlayer:GetCollectibleRNG(489):GetSeed() - rng = EID:RNGNext(rng, 0x1, 0x9, 0x1D) - local nextDice = dinfinityList[rng % 7] - addObjectDesc(5, 100, nextDice, "{{Collectible489}}") - else - -- track our current selected dinfinity dice! test if it is preserved between pickups of it - end -end - --- Banned items: Metronome, Plan C, Glowing Hour Glass, Breath of Life, Clicker, R Key --- Reduced chance: Death Certificate (15%), Genesis (25%) --- I saw something in the code about rerolling Forget Me Now but not sure what the criteria was -local metronomeBlacklist = {[488] = 1, [475] = 1, [422] = 1} --AB+ can choose Clicker lol rip -if REPENTANCE then metronomeBlacklist = {[488] = 1, [475] = 1, [422] = 1, [326] = 1, [482] = 1, [636] = 1, [628] = 0.85, [622] = 0.75 } end - --- Should we account for Car Battery? (Both if we have it, and if it grants it which immediately uses it again) -function EID:MetronomePrediction() - local itemConfig = Isaac.GetItemConfig() - local numCollectibles = EID:GetMaxCollectibleID() - local metronomeRNG = currentPlayer:GetCollectibleRNG(CollectibleType.COLLECTIBLE_METRONOME):GetSeed() - local rerollChance = 0 - if REPENTANCE then - metronomeRNG = EID:RNGNext(metronomeRNG) - rerollChance = metronomeRNG - end - local attempts = 15 - while attempts > 0 do - attempts = attempts - 1 - metronomeRNG = EID:RNGNext(metronomeRNG) - local sel = metronomeRNG % numCollectibles + 1 - if itemConfig:GetCollectible(sel) ~= nil then - if metronomeBlacklist[sel] then - -- A few items have a reroll chance in Repentance - if metronomeBlacklist[sel] < 1 then - rerollChance = EID:RNGNext(rerollChance, 0x02, 0x0F, 0x11) - local rerollFloat = EID:SeedToFloat(rerollChance) - if rerollFloat < 1 - metronomeBlacklist[sel] then - -- We succeeded the reroll chance - return sel - end - end - else - return sel - end - end - end - -- as the code puts it, [warn] No Collectible found for Metronome! - return 488 -end - --- Teleport! Destination Prediction -- -local function teleport1Prediction() - if REPENTANCE and currentPlayer:GetSprite():GetAnimation() == "TeleportUp" then return end - local level = game:GetLevel() - local currentRoomIndex = level:GetCurrentRoomDesc().SafeGridIndex - local possibleRooms = {} - for i = 0, 168 do - local room = level:GetRoomByIdx(i) - -- Currently, any non-red room on the grid that we aren't in is a valid choice - -- Is there more criteria to look out for? - if room.GridIndex >= 0 and room.SafeGridIndex ~= currentRoomIndex and room.Data.Type ~= 29 and (not REPENTANCE or room.Flags & 1024 ~= 1024) then - table.insert(possibleRooms, i) - end - end - local teleSeed = currentPlayer:GetCollectibleRNG(CollectibleType.COLLECTIBLE_TELEPORT):GetSeed() - teleSeed = EID:RNGNext(teleSeed, 5, 9, 7) - teleSeed = EID:RNGNext(teleSeed, 0x02, 0x0F, 0x19) -- magic disassembled numbers! - - local resultRoomIndex = possibleRooms[(teleSeed % #possibleRooms) + 1] - local resultRoom = level:GetRoomByIdx(resultRoomIndex) - local resultSafeIndex = resultRoom.SafeGridIndex - - local roomIcon = EID.RoomTypeToMarkup[resultRoom.Data.Type] - if resultRoom.Data.Type == 1 then roomIcon = EID.RoomShapeToMarkup[resultRoom.Data.Shape] end - local roomNames = EID:getDescriptionEntry("RoomTypeNames") - local roomName = roomNames[resultRoom.Data.Type] - -- Find our X/Y difference from the target location, if we're on the map - local d = "" - if currentRoomIndex >= 0 then - local myPos = Vector(currentRoomIndex % 13, math.floor(currentRoomIndex / 13)) - local newPos = Vector(resultSafeIndex % 13, math.floor(resultSafeIndex / 13)) - local diffX = math.floor(newPos.X - myPos.X) - local diffY = math.floor(newPos.Y - myPos.Y) - - if diffY > 0 then d = d .. "{{ArrowGrayDown}} " .. diffY - elseif diffY < 0 then d = d .. "{{ArrowGrayUp}} " .. math.abs(diffY) end - if d ~= "" and diffX ~= 0 then d = d .. "," end - if diffX > 0 then d = d .. "{{ArrowGrayRight}} " .. diffX - elseif diffX < 0 then d = d .. "{{ArrowGrayLeft}} " .. math.abs(diffX) end - end - if d ~= "" then d = "#{{Blank}} " .. d end - - append("{{Collectible44}}", EID:getObjectName(5, 100, 44) .. EID:getDescriptionEntry("HoldMapHeader"), roomIcon .. " " .. roomName .. d) -end - --- Teleport 2 Destination Prediction -- -local teleport2Order = { 1,5,8,2,4,13,21,12,10,6,11,18,19,9,20,24,7,1025,666,3 } -local teleport2GreedOrder = { 1,5,2,4,10,23,8,666,3 } -local teleport2Icons = { [1025] = "{{RedRoom}}", [666] = "{{AngelDevilChance}}" } - -local function teleport2Prediction() - local level = game:GetLevel() - local rooms = level:GetRooms() - --I AM ERROR Room always considered uncleared - local unclearedTypes = {[3] = true} - for i = 0, rooms.Size - 1 do - local room = rooms:Get(i) - - if not room.Clear then - -- Check for Special Red Rooms, which get ordered differently than their non-red version - if REPENTANCE and room.Data.Type ~= 1 and room.Flags & 1024 == 1024 then unclearedTypes[1025] = true - else unclearedTypes[room.Data.Type] = true end - end - end - --Angel/Devil Room check (it lives off the map) - if not level:GetRoomByIdx(-1).Clear then unclearedTypes[666] = true end - - local greed = game:IsGreedMode() - local roomOrder = (greed and teleport2GreedOrder) or teleport2Order - local roomNames = EID:getDescriptionEntry("RoomTypeNames") - - for i,v in ipairs(roomOrder) do - if unclearedTypes[v] then - local descString = (teleport2Icons[v] or EID.RoomTypeToMarkup[v]) .. " " .. roomNames[v] - -- Tall Vertical Main Greed Room exception, because why not, attention to detail - if v == 1 and greed then descString = "{{RoomLongVertical}} " .. roomNames[v] end - append("{{Collectible419}}", EID:getObjectName(5, 100, 419) .. EID:getDescriptionEntry("HoldMapHeader"), descString) - return - end - end -end - --- Sanguine Bond Chance Display / Prediction -- ---order of checking: 15% Pennies, 48% Damage, 58% Hearts, 63% Item, 65% Leviathan, 100% Nothing -local sanguineResults = { { 0.15, 3 }, { 0.48, 2 }, { 0.58, 4 }, { 0.63, 5 }, { 0.65, 6 }, { 1, 1 } } - --- this isn't even used in this file anymore, it's in main, but there isn't really a better place to put it yet -function EID:trimSanguineDesc(descObj) - local currentRoom = game:GetLevel():GetCurrentRoom() - local spikes = currentRoom:GetGridEntity(67) - if not spikes then return "" end -- don't display anything if we can't find the spikes! - local cheatResult = nil - if spikes and EID.Config["PredictionSanguineBond"] then - local spikeSeed = currentRoom:GetGridEntity(67):GetRNG():GetSeed() - spikeSeed = EID:RNGNext(spikeSeed, 5, 9, 7) - spikeSeed = EID:RNGNext(spikeSeed, 0x01, 0x05, 0x13) -- magic disassembled numbers! - local nextFloat = EID:SeedToFloat(spikeSeed) - - for _,v in ipairs(sanguineResults) do - if nextFloat < v[1] then cheatResult = v[2] break end - end - end - - local resultsDesc = "" - - local lineCount = 0 - -- separate sanguine's description by # or semicolons - for w in string.gmatch(descObj.Description, "([^#;]+)") do - -- we only care about groups that contain a percent sign - if string.find(w,"%%") then - lineCount = lineCount + 1 - if cheatResult == lineCount then resultsDesc = resultsDesc .. "{{ColorBagComplete}}" end - resultsDesc = resultsDesc .. w .. "#" - end - end - return resultsDesc -end +-- Data Tables -- +-- Rainbow Worm's trinket IDs it grants, in order +local rainbowWormEffects = { [0] = 9, 11, 65, 27, 10, 12, 26, 66, 96, 144 } +-- Mysterious Paper does not play well with displaying Error 404's effect +local mysteriousPaperBlacklist = { [23] = true, [48] = true } function EID:getHoldMapDescription(player, checkingTwin) EID.InsideItemReminder = true @@ -254,22 +89,21 @@ function EID:getHoldMapDescription(player, checkingTwin) -- Metronome result if heldActive == 488 and EID.Config["ItemReminderShowRNGCheats"] then blacklist["5.100.488"] = true - addObjectDesc(5, 100, EID:MetronomePrediction(), "{{Collectible488}}") - --append("{{Collectible488}}", EID:getObjectName(5,100,488) .. EID:getDescriptionEntry("HoldMapHeader"), EID:MetronomePrediction()) - + addObjectDesc(5, 100, EID:MetronomePrediction(getSeed(488)), "{{Collectible488}}") -- Teleport! location elseif heldActive == 44 and EID.Config["ItemReminderShowRNGCheats"] then blacklist["5.100.44"] = true - teleport1Prediction() - + -- The result preview changes as soon as we activate Teleport, which looks awkward, so try to not display the result while mid-teleport. Doesn't work perfectly and only in Rep + if not REPENTANCE or currentPlayer:GetSprite():GetAnimation() ~= "TeleportUp" then + append("{{Collectible44}}", EID:getObjectName(5,100,44) .. EID:getDescriptionEntry("HoldMapHeader"), EID:Teleport1Prediction(getSeed(44))) + end -- Teleport 2.0 location elseif heldActive == 419 and not EID.isMirrorRoom then blacklist["5.100.419"] = true - teleport2Prediction() - + append("{{Collectible419}}", EID:getObjectName(5,100,419) .. EID:getDescriptionEntry("HoldMapHeader"), EID:Teleport2Prediction()) elseif heldActive == 489 then blacklist["5.100.489"] = true - EID:CurrentDInfinity() + addObjectDesc(5, 100, EID:CurrentDInfinity(getSeed(489)), "{{Collectible489}}") else addObjectDesc(5, 100, heldActive) end diff --git a/eid_itemprediction.lua b/eid_itemprediction.lua new file mode 100644 index 00000000..87a903a7 --- /dev/null +++ b/eid_itemprediction.lua @@ -0,0 +1,176 @@ +-- This file is for various functions that are able to calculate the result effect that an item will have +local game = Game() + +-- D Infinity -- +local dinfinityList = { [0] = 105, 166, 284, 283, 285, 406, 386 } +-- Repentance's D Infinity order: D1, D4, D6, Eternal D6, D7, D8, D10, D12, D20, D100 +if REPENTANCE then dinfinityList = { 476, 284, 105, 609, 437, 406, 285, 386, 166, 283 } end +-- Returns the item ID of D Infinity's current die +-- For Repentance, the Drop button is tracked, which is probably not 100% successful, and handled elsewhere +function EID:CurrentDInfinity(rng) + if not REPENTANCE then + rng = EID:RNGNext(rng, 0x1, 0x9, 0x1D) -- magic disassembled numbers! + return dinfinityList[rng % 7] + else + -- track our current selected dinfinity dice! test if it is preserved between pickups of it + -- TBA + return 489 + end +end + +-- Metronome -- +-- Banned items: Metronome, Plan C, Glowing Hour Glass, Breath of Life, Clicker, R Key +-- Reduced chance: Death Certificate (15%), Genesis (25%) +-- I saw something in the code about rerolling Forget Me Now but not sure what the criteria was +local metronomeBlacklist = {[488] = 1, [475] = 1, [422] = 1} --AB+ can choose Clicker lol rip +if REPENTANCE then metronomeBlacklist = {[488] = 1, [475] = 1, [422] = 1, [326] = 1, [482] = 1, [636] = 1, [628] = 0.85, [622] = 0.75 } end +-- TODO: Account for Car Battery +-- (If we have it, display multiple results? Also, if the result is Car Battery, it's immediately triggered again) +function EID:MetronomePrediction(rng) + local itemConfig = Isaac.GetItemConfig() + local numCollectibles = EID:GetMaxCollectibleID() + local rerollChance = 0 + if REPENTANCE then --Rep advances the RNG an extra time to use for its Death Cert/Genesis reroll + rng = EID:RNGNext(rng) + rerollChance = rng + end + local attempts = 15 + while attempts > 0 do + attempts = attempts - 1 + rng = EID:RNGNext(rng) + local sel = rng % numCollectibles + 1 + if itemConfig:GetCollectible(sel) ~= nil then + if metronomeBlacklist[sel] then + -- A few items have a reroll chance in Repentance + if metronomeBlacklist[sel] < 1 then + rerollChance = EID:RNGNext(rerollChance, 0x02, 0x0F, 0x11) + local rerollFloat = EID:SeedToFloat(rerollChance) + if rerollFloat < 1 - metronomeBlacklist[sel] then + -- We succeeded the reroll chance + return sel + end + end + else + return sel + end + end + end + -- as the code puts it, [warn] No Collectible found for Metronome! + return 488 +end + +-- Sanguine Bond -- +--order of checking: 15% Pennies, 48% Damage, 58% Hearts, 63% Item, 65% Leviathan, 100% Nothing +local sanguineResults = { { 0.15, 3 }, { 0.48, 2 }, { 0.58, 4 }, { 0.63, 5 }, { 0.65, 6 }, { 1, 1 } } +-- This function both trims the desc to just a list of chances, and highlights the next result if allowed, since those two actions are very intertwined +function EID:trimSanguineDesc(descObj) + local currentRoom = game:GetLevel():GetCurrentRoom() + local spikes = currentRoom:GetGridEntity(67) + if not spikes then return "" end -- don't display anything if we can't find the spikes! + local cheatResult = nil + if spikes and EID.Config["PredictionSanguineBond"] then + local spikeSeed = currentRoom:GetGridEntity(67):GetRNG():GetSeed() + spikeSeed = EID:RNGNext(spikeSeed, 5, 9, 7) + spikeSeed = EID:RNGNext(spikeSeed, 0x01, 0x05, 0x13) -- magic disassembled numbers! + local nextFloat = EID:SeedToFloat(spikeSeed) + + for _,v in ipairs(sanguineResults) do + if nextFloat < v[1] then cheatResult = v[2] break end + end + end + + local resultsDesc = "" + + local lineCount = 0 + -- separate sanguine's description by # or semicolons + for w in string.gmatch(descObj.Description, "([^#;]+)") do + -- we only care about groups that contain a percent sign + if string.find(w,"%%") then + lineCount = lineCount + 1 + if cheatResult == lineCount then resultsDesc = resultsDesc .. "{{ColorBagComplete}}" end + resultsDesc = resultsDesc .. w .. "#" + end + end + return resultsDesc +end + +-- Teleport! Destination Prediction -- +-- Returns text like "{{RoomIcon}} Room Type Name#Up 3, Left 2" +function EID:Teleport1Prediction(rng) + local level = game:GetLevel() + local currentRoomIndex = level:GetCurrentRoomDesc().SafeGridIndex + local possibleRooms = {} + -- Search the 13x13 grid for valid teleport locations + -- Currently, that's any room on the grid besides the one we're in, and Red Rooms or Ultra Secret Rooms + for i = 0, 168 do + local room = level:GetRoomByIdx(i) + if room.GridIndex >= 0 and room.SafeGridIndex ~= currentRoomIndex and room.Data.Type ~= 29 and (not REPENTANCE or room.Flags & 1024 ~= 1024) then + table.insert(possibleRooms, i) + end + end + rng = EID:RNGNext(rng, 5, 9, 7) + rng = EID:RNGNext(rng, 0x02, 0x0F, 0x19) -- magic disassembled numbers! + + local resultRoomIndex = possibleRooms[(rng % #possibleRooms) + 1] + local resultRoom = level:GetRoomByIdx(resultRoomIndex) + local resultSafeIndex = resultRoom.SafeGridIndex + + local roomIcon = EID.RoomTypeToMarkup[resultRoom.Data.Type] + if resultRoom.Data.Type == 1 then roomIcon = EID.RoomShapeToMarkup[resultRoom.Data.Shape] end + local roomNames = EID:getDescriptionEntry("RoomTypeNames") + local roomName = roomNames[resultRoom.Data.Type] + -- Find our X/Y difference from the target location, if we're on the map + local d = "" + if currentRoomIndex >= 0 then + local myPos = Vector(currentRoomIndex % 13, math.floor(currentRoomIndex / 13)) + local newPos = Vector(resultSafeIndex % 13, math.floor(resultSafeIndex / 13)) + local diffX = math.floor(newPos.X - myPos.X) + local diffY = math.floor(newPos.Y - myPos.Y) + + if diffY > 0 then d = d .. "{{ArrowGrayDown}} " .. diffY + elseif diffY < 0 then d = d .. "{{ArrowGrayUp}} " .. math.abs(diffY) end + if d ~= "" and diffX ~= 0 then d = d .. "," end + if diffX > 0 then d = d .. "{{ArrowGrayRight}} " .. diffX + elseif diffX < 0 then d = d .. "{{ArrowGrayLeft}} " .. math.abs(diffX) end + end + if d ~= "" then d = "#{{Blank}} " .. d end + + return roomIcon .. " " .. roomName .. d +end + +-- Teleport 2 Destination Prediction -- +local teleport2Order = { 1,5,8,2,4,13,21,12,10,6,11,18,19,9,20,24,7,1025,666,3 } +local teleport2GreedOrder = { 1,5,2,4,10,23,8,666,3 } +local teleport2Icons = { [1025] = "{{RedRoom}}", [666] = "{{AngelDevilChance}}" } + +function EID:Teleport2Prediction() + local level = game:GetLevel() + local rooms = level:GetRooms() + --I AM ERROR Room always considered uncleared + local unclearedTypes = {[3] = true} + for i = 0, rooms.Size - 1 do + local room = rooms:Get(i) + + if not room.Clear then + -- Check for Special Red Rooms, which get ordered differently than their non-red version + if REPENTANCE and room.Data.Type ~= 1 and room.Flags & 1024 == 1024 then unclearedTypes[1025] = true + else unclearedTypes[room.Data.Type] = true end + end + end + --Angel/Devil Room check (it lives off the map) + if not level:GetRoomByIdx(-1).Clear then unclearedTypes[666] = true end + + local greed = game:IsGreedMode() + local roomOrder = (greed and teleport2GreedOrder) or teleport2Order + local roomNames = EID:getDescriptionEntry("RoomTypeNames") + + -- Return a string for the first uncleared room type that we find + for i,v in ipairs(roomOrder) do + if unclearedTypes[v] then + local descString = (teleport2Icons[v] or EID.RoomTypeToMarkup[v]) .. " " .. roomNames[v] + -- Tall Vertical Main Greed Room exception, because why not, attention to detail + if v == 1 and greed then descString = "{{RoomLongVertical}} " .. roomNames[v] end + return descString + end + end +end \ No newline at end of file From 24a19f5af179d241c387a2435233edc01b7a8202 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Thu, 16 Jun 2022 22:00:05 -0400 Subject: [PATCH 07/10] move Void and RNGNext --- eid_api.lua | 82 +---------------------------------------- eid_itemprediction.lua | 83 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 83 deletions(-) diff --git a/eid_api.lua b/eid_api.lua index 825b7524..67503d49 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -1051,71 +1051,6 @@ 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 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 = EID:RNGNext(rng, 5, 9, 7) - 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 --- Returns a table of active items that will be absorbed -function EID:VoidRoomCheck() - numVoidable = 0 - numRunable = 0 - EID.VoidOptionIndexes = {} - local activesAbsorbed = {} - 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 - if REPENTANCE then EID.VoidOptionIndexes[pickup.OptionsPickupIndex] = entity.SubType end - if (EID.itemConfig:GetCollectible(entity.SubType).Type ~= ItemType.ITEM_ACTIVE) then - numVoidable = numVoidable + 1 - else - table.insert(activesAbsorbed, entity.SubType) - end - end - end - return activesAbsorbed -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 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 = EID:RNGNext(startRNG, 5, 9, 7) 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 @@ -1708,19 +1643,4 @@ end -- Adds an EID Icon to an Object function EID:AddIconToObject(eType, eVariant, eSubType, iconName) EID.ObjectIcon[eType.."."..eVariant.."."..eSubType] = EID.InlineIcons[iconName] -end - --- reimplementation of RNG Seed shift feature used by the game. Mostly used for RNG Prediction features --- Default RNG shift values for many things are 5, 9, 7 -function EID:RNGNext(rngNum, shift1, shift2, shift3) - rngNum = rngNum ~ ((rngNum >> (shift1 or 5)) & 4294967295) - rngNum = rngNum ~ ((rngNum << (shift2 or 9)) & 4294967295) - rngNum = rngNum ~ ((rngNum >> (shift3 or 7)) & 4294967295) - return rngNum >> 0; -end - --- General RNG functions for RNG predicting -function EID:SeedToFloat(seed) - local multi = 2.3283061589829401E-10; - return seed * multi; -end +end \ No newline at end of file diff --git a/eid_itemprediction.lua b/eid_itemprediction.lua index 87a903a7..c33c9cb4 100644 --- a/eid_itemprediction.lua +++ b/eid_itemprediction.lua @@ -1,6 +1,22 @@ -- This file is for various functions that are able to calculate the result effect that an item will have local game = Game() +-- reimplementation of RNG:Next() +-- Default RNG shift values for many things are 5, 9, 7 +function EID:RNGNext(rngNum, shift1, shift2, shift3) + rngNum = rngNum ~ ((rngNum >> (shift1 or 5)) & 4294967295) + rngNum = rngNum ~ ((rngNum << (shift2 or 9)) & 4294967295) + rngNum = rngNum ~ ((rngNum >> (shift3 or 7)) & 4294967295) + return rngNum >> 0; +end + +-- Convert a seed int into a float between 0 and 1 +function EID:SeedToFloat(seed) + local multi = 2.3283061589829401E-10; + return seed * multi; +end + + -- D Infinity -- local dinfinityList = { [0] = 105, 166, 284, 283, 285, 406, 386 } -- Repentance's D Infinity order: D1, D4, D6, Eternal D6, D7, D8, D10, D12, D20, D100 @@ -27,7 +43,6 @@ if REPENTANCE then metronomeBlacklist = {[488] = 1, [475] = 1, [422] = 1, [326] -- TODO: Account for Car Battery -- (If we have it, display multiple results? Also, if the result is Car Battery, it's immediately triggered again) function EID:MetronomePrediction(rng) - local itemConfig = Isaac.GetItemConfig() local numCollectibles = EID:GetMaxCollectibleID() local rerollChance = 0 if REPENTANCE then --Rep advances the RNG an extra time to use for its Death Cert/Genesis reroll @@ -39,7 +54,7 @@ function EID:MetronomePrediction(rng) attempts = attempts - 1 rng = EID:RNGNext(rng) local sel = rng % numCollectibles + 1 - if itemConfig:GetCollectible(sel) ~= nil then + if EID.itemConfig:GetCollectible(sel) ~= nil then if metronomeBlacklist[sel] then -- A few items have a reroll chance in Repentance if metronomeBlacklist[sel] < 1 then @@ -173,4 +188,68 @@ function EID:Teleport2Prediction() return descString end end +end + +-- Void Stat Increases -- +local numVoidable = 0 +local numRunable = 0 +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 = EID:RNGNext(rng, 5, 9, 7) + 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 +-- Returns a table of active items that will be absorbed +function EID:VoidRoomCheck() + numVoidable = 0 + numRunable = 0 + EID.VoidOptionIndexes = {} + local activesAbsorbed = {} + 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 + if REPENTANCE then EID.VoidOptionIndexes[pickup.OptionsPickupIndex] = entity.SubType end + if (EID.itemConfig:GetCollectible(entity.SubType).Type ~= ItemType.ITEM_ACTIVE) then + numVoidable = numVoidable + 1 + else + table.insert(activesAbsorbed, entity.SubType) + end + end + end + return activesAbsorbed +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 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 = EID:RNGNext(startRNG, 5, 9, 7) 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 \ No newline at end of file From 38ceafe967f425a09218c0858d72e2aecdefb296 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 18 Jun 2022 02:38:16 -0400 Subject: [PATCH 08/10] Track pressing Drop for D Infinity --- main.lua | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/main.lua b/main.lua index 24110f8c..ad0aab4a 100644 --- a/main.lua +++ b/main.lua @@ -44,6 +44,8 @@ EID.ForceRefreshCache = false -- set to true to force-refresh descriptions, curr local preHourglassStatus = {} EID.holdTabPlayer = 0 EID.holdTabCounter = 0 +EID.DInfinityState = {} +local forgottenDropTimer = 0 EID.GameUpdateCount = 0 EID.GameRenderCount = 0 @@ -1255,14 +1257,40 @@ local function onRender(t) return end - local tabHeld, playerHoldingTab = EID:PlayersActionPressed(EID.Config["BagOfCraftingToggleKey"]) + -- Check for Tab (or user setting) being held, for the Item Reminder + local tabHeld, playerNumHoldingTab = EID:PlayersActionPressed(EID.Config["BagOfCraftingToggleKey"]) if tabHeld then - EID.holdTabPlayer = EID.coopMainPlayers[playerHoldingTab] + EID.holdTabPlayer = EID.coopMainPlayers[playerNumHoldingTab] EID.holdTabCounter = EID.holdTabCounter + 1 else EID.holdTabPlayer = nil EID.holdTabCounter = 0 end + -- Check for Drop being pressed, for Repentance D Infinity tracking + if REPENTANCE then + local dropTriggered, playerNumPressingDrop = EID:PlayersActionPressed(ButtonAction.ACTION_DROP, Input.IsActionTriggered) + if dropTriggered then + local playerPressingDrop = EID.coopMainPlayers[playerNumPressingDrop] + local playerID = EID:getPlayerID(playerPressingDrop) + local playerType = playerPressingDrop:GetPlayerType() + -- Forgotten's drop requires a double tap to actually count for this + if (playerType == 16 or playerType == 17) then + -- technically we should track a forgotten drop timer for each player but forget it + if EID.GameUpdateCount > forgottenDropTimer then + -- the actual interval here seems to be 6.5. 7 has false positives, 6 has false negatives + forgottenDropTimer = EID.GameUpdateCount + 7 + dropTriggered = false + else + forgottenDropTimer = 0 + end + end + + if dropTriggered and playerPressingDrop:GetActiveItem(0) == 489 then + EID.DInfinityState[playerID] = EID.DInfinityState[playerID] or 0 + EID.DInfinityState[playerID] = (EID.DInfinityState[playerID] + 1) % 10 + end + end + end if EID.ForceRefreshCache then resetDescCache() @@ -1564,6 +1592,7 @@ local function OnGameStartGeneral(_,isSave) EID:buildTransformationTables() if not isSave then EID.PlayerItemInteractions = {} + EID.DInfinityState = {} end end EID:AddCallback(ModCallbacks.MC_POST_GAME_STARTED, OnGameStartGeneral) From 282b81bf388e8b673714a5317b146d8fc9f6576f Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 18 Jun 2022 02:38:44 -0400 Subject: [PATCH 09/10] Pass in player to D Infinity --- eid_holdmapdesc.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eid_holdmapdesc.lua b/eid_holdmapdesc.lua index c586c885..e14017b8 100644 --- a/eid_holdmapdesc.lua +++ b/eid_holdmapdesc.lua @@ -103,7 +103,7 @@ function EID:getHoldMapDescription(player, checkingTwin) append("{{Collectible419}}", EID:getObjectName(5,100,419) .. EID:getDescriptionEntry("HoldMapHeader"), EID:Teleport2Prediction()) elseif heldActive == 489 then blacklist["5.100.489"] = true - addObjectDesc(5, 100, EID:CurrentDInfinity(getSeed(489)), "{{Collectible489}}") + addObjectDesc(5, 100, EID:CurrentDInfinity(getSeed(489), currentPlayer), "{{Collectible489}}") else addObjectDesc(5, 100, heldActive) end From 8036d30a8b9b8f602760142fda0cd5d114a03712 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 18 Jun 2022 02:39:16 -0400 Subject: [PATCH 10/10] D Infinity Rep support --- eid_itemprediction.lua | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/eid_itemprediction.lua b/eid_itemprediction.lua index c33c9cb4..f409bdb6 100644 --- a/eid_itemprediction.lua +++ b/eid_itemprediction.lua @@ -16,23 +16,38 @@ function EID:SeedToFloat(seed) return seed * multi; end - -- D Infinity -- local dinfinityList = { [0] = 105, 166, 284, 283, 285, 406, 386 } -- Repentance's D Infinity order: D1, D4, D6, Eternal D6, D7, D8, D10, D12, D20, D100 -if REPENTANCE then dinfinityList = { 476, 284, 105, 609, 437, 406, 285, 386, 166, 283 } end +if REPENTANCE then dinfinityList = { [0] = 476, 284, 105, 609, 437, 406, 285, 386, 166, 283 } end -- Returns the item ID of D Infinity's current die -- For Repentance, the Drop button is tracked, which is probably not 100% successful, and handled elsewhere -function EID:CurrentDInfinity(rng) +function EID:CurrentDInfinity(rng, player) if not REPENTANCE then rng = EID:RNGNext(rng, 0x1, 0x9, 0x1D) -- magic disassembled numbers! return dinfinityList[rng % 7] else - -- track our current selected dinfinity dice! test if it is preserved between pickups of it - -- TBA - return 489 + local playerID = EID:getPlayerID(player) + return dinfinityList[EID.DInfinityState[playerID]] or 476 end end +local justDidD = false +if REPENTANCE then + -- To help with Rep tracking, watch for D Infinity to get used and resync its current dice + function EID:WatchForDInfinity() + justDidD = true + end + EID:AddCallback(ModCallbacks.MC_PRE_USE_ITEM, EID.WatchForDInfinity, CollectibleType.COLLECTIBLE_D_INFINITY) + function EID:WatchForDice(collectibleType, rng, player) + if not justDidD or collectibleType == 489 then return end + justDidD = false + local playerID = EID:getPlayerID(player) + for i,v in ipairs(dinfinityList) do + if v == collectibleType then EID.DInfinityState[playerID] = i end + end + end + EID:AddCallback(ModCallbacks.MC_PRE_USE_ITEM, EID.WatchForDice) +end -- Metronome -- -- Banned items: Metronome, Plan C, Glowing Hour Glass, Breath of Life, Clicker, R Key @@ -252,4 +267,4 @@ function EID:VoidRNGCheck(player, isRune) 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 \ No newline at end of file +end