diff --git a/eid_api.lua b/eid_api.lua index 080fd93c..0b17b4c7 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -533,7 +533,11 @@ function EID:hasDescription(entity) if entity.Type == 6 and entity.Variant == 16 and EID.Config["DisplayCraneInfo"] and REPENTANCE then isAllowed = not entity:GetSprite():IsPlaying("Broken") and not entity:GetSprite():IsPlaying("Prize") and EID.CraneItemType[tostring(entity.InitSeed)] end - isAllowed = isAllowed or (entity.Type == 1000 and entity.Variant == EffectVariant.DICE_FLOOR and EID.Config["DisplayDiceInfo"]) + if entity.Type == 1000 then + if (entity.Variant == 161 and entity.SubType <= 2) or (entity.Variant == EffectVariant.DICE_FLOOR and EID.Config["DisplayDiceInfo"]) then + isAllowed = true + end + end return isAllowed end @@ -999,10 +1003,12 @@ local function GetTwoIncreases(rng, tbl) 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 @@ -1011,9 +1017,14 @@ function EID:VoidRoomCheck() (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 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) @@ -1328,6 +1339,17 @@ function EID:checkPlayersForMissingItems() end end +function EID:getPlayerID(entityPlayer) + if not entityPlayer then return 0 end + for i = 0, game:GetNumPlayers() - 1 do + local player = Isaac.GetPlayer(i) + if GetPtrHash(player) == GetPtrHash(entityPlayer) then + return i + end + end + return 0 +end + function EID:getLanguage() local lang = EID.Config["Language"] if lang == "auto" then diff --git a/eid_data.lua b/eid_data.lua index 68c0ca45..66a2757d 100644 --- a/eid_data.lua +++ b/eid_data.lua @@ -18,6 +18,7 @@ EID.ButtonToIconMap = { -- List of Effect variants that should be handled for descriptions EID.effectList = { ["76"] = true, + ["161"] = true, } -- List of HUD elements, their position and usage diff --git a/eid_modifiers.lua b/eid_modifiers.lua index 9582ae40..cdc69bf9 100644 --- a/eid_modifiers.lua +++ b/eid_modifiers.lua @@ -2,13 +2,66 @@ 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 +EID.inModifierPreview = 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, } +local maxSlot = 1 +-- Repentance modifiers +if REPENTANCE then + maxSlot = 3 + --include the AB+ collectiblesToCheck in this table! (wish there was an easy way to merge two tables) + EID.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 +EID.collectiblesOwned = {} +EID.collectiblesAbsorbed = {} +EID.blackRuneOwned = false +local lastCheck = 0 + +function EID:CheckPlayersCollectibles() + -- recheck the players' owned collectibles periodically, not every frame + -- (has to be checked regularly due to mechanics like D4 / Tainted Eden) + if EID.GameUpdateCount >= lastCheck + 15 then + lastCheck = EID.GameUpdateCount + local numPlayers = game:GetNumPlayers() + local players = {}; for i = 0, numPlayers - 1 do players[i] = Isaac.GetPlayer(i) end + for _,v in ipairs(EID.collectiblesToCheck) do + EID.collectiblesOwned[v] = false + EID.collectiblesAbsorbed[v] = false + for i = 0, numPlayers - 1 do + if players[i]:HasCollectible(v) then + EID.collectiblesOwned[v] = i + break + -- Check for the item being inside this player's Void + -- note: currently Absorb checks are only done as a backup, will always be false if it's owned legitimately + elseif EID.absorbedItems[tostring(i)] and EID.absorbedItems[tostring(i)][tostring(v)] and players[i]:HasCollectible(477) then + EID.collectiblesAbsorbed[v] = i + end + end + end + -- other Card in inventory checks could be done in this loop here if ever desired + EID.blackRuneOwned = false + for i = 0, numPlayers - 1 do + for j = 0, maxSlot do + if players[i]:GetCard(j) == Card.RUNE_BLACK then + EID.blackRuneOwned = i + break + end + end + end + end +end local function TabCallback(descObj) if EID.TabPreviewID == 0 then return descObj end - inPreview = true + EID.inModifierPreview = true local descEntry = EID:getDescriptionObj(5, 100, EID.TabPreviewID) - inPreview = false + EID.inModifierPreview = false return descEntry end @@ -26,7 +79,7 @@ local function VoidCallback(descObj, isRune) if EID.GameUpdateCount >= lastVoidCheck + 30 or EID.RecheckVoid then EID:VoidRoomCheck() if EID.collectiblesOwned[477] then EID:VoidRNGCheck(Isaac.GetPlayer(EID.collectiblesOwned[477]), false) end - if blackRuneOwned then EID:VoidRNGCheck(Isaac.GetPlayer(blackRuneOwned), true) end + if EID.blackRuneOwned then EID:VoidRNGCheck(Isaac.GetPlayer(EID.blackRuneOwned), true) end lastVoidCheck = EID.GameUpdateCount EID.RecheckVoid = false end @@ -436,7 +489,7 @@ local function EIDConditionsAB(descObj) if EID.Config["DisplayVoidStatInfo"] then if EID.collectiblesOwned[477] then table.insert(callbacks, VoidCallback) end - if blackRuneOwned then table.insert(callbacks, BlackRuneCallback) end + if EID.blackRuneOwned then table.insert(callbacks, BlackRuneCallback) end end end @@ -444,8 +497,9 @@ local function EIDConditionsAB(descObj) end EID:addDescriptionModifier("EID Afterbirth+", EIDConditionsAB, nil) +-- should this be done differently so that mods can add tab previews? local function TabConditions(descObj) - if EID.player and Input.IsActionPressed(ButtonAction.ACTION_MAP, EID.player.ControllerIndex) and not inPreview then return true end + if EID.player and Input.IsActionPressed(ButtonAction.ACTION_MAP, EID.player.ControllerIndex) and not EID.inModifierPreview then return true end return false end diff --git a/main.lua b/main.lua index 9a4a8626..9f6d490f 100644 --- a/main.lua +++ b/main.lua @@ -364,21 +364,19 @@ if REPENTANCE then end end EID:AddCallback(ModCallbacks.MC_PRE_USE_ITEM, EID.CheckFlipGridIndexes, CollectibleType.COLLECTIBLE_FLIP) - - -- Watch for a Void absorbing active items - -- (Note: Doesn't differentiate between different players if both players have Void...) - -- (Note: Doesn't care about shop / choice items yet either) - function EID:CheckVoidAbsorbs(collectibleType) - local pedestals = Isaac.FindByType(5, 100, -1, true, false) - for _, pedestal in ipairs(pedestals) do - if pedestal.SubType > 0 and EID.itemConfig:GetCollectible(pedestal.SubType).Type == 3 then - EID.absorbedItems[pedestal.SubType] = true - end - end - end - EID:AddCallback(ModCallbacks.MC_PRE_USE_ITEM, EID.CheckVoidAbsorbs, CollectibleType.COLLECTIBLE_VOID) end +-- Watch for a Void absorbing active items +function EID:CheckVoidAbsorbs(collectibleType, rng, player) + local playerID = EID:getPlayerID(player) + EID.absorbedItems[tostring(playerID)] = EID.absorbedItems[tostring(playerID)] or {} + for _,v in ipairs(EID:VoidRoomCheck()) do + EID.absorbedItems[tostring(playerID)][tostring(v)] = true + end + EID.RecheckVoid = true +end +EID:AddCallback(ModCallbacks.MC_PRE_USE_ITEM, EID.CheckVoidAbsorbs, CollectibleType.COLLECTIBLE_VOID) + --------------------------------------------------------------------------- --------------------------Handle Scale Shortcut---------------------------- @@ -691,7 +689,7 @@ function EID:renderIndicator(entity) end -- Move highlights a bit to fit onto the alt Item layout of Flip / Tainted Laz if REPENTANCE then - if entity.Variant == 100 and EID.player:HasCollectible(CollectibleType.COLLECTIBLE_FLIP) then + if entity.Variant == 100 and EID.player:HasCollectible(CollectibleType.COLLECTIBLE_FLIP) and EID:getEntityData(entity, "EID_FlipItemID") then entityPos = entityPos + Vector(2.5,2.5) elseif entity.Type == 6 and entity.Variant == 16 then entityPos = entityPos + Vector(0,-5) @@ -707,27 +705,31 @@ function EID:renderIndicator(entity) sprite.FlipX = true end end - if EID.Config["Indicator"] == "blink" then - local c = 255 - math.floor(255 * ((entity.FrameCount % 40) / 40)) - sprite.Color = Color(1, 1, 1, 1, c/repDiv, c/repDiv, c/repDiv) - EID:renderEntity(entity, sprite, entityPos) - sprite.Color = Color(1, 1, 1, 1, 0, 0, 0) - elseif EID.Config["Indicator"] == "arrow" then + + -- Don't apply sprite.Color changes to Effects (Dice Floors, Card Reading Portals), use Arrow instead + if EID.Config["Indicator"] == "arrow" or entity.Type == 1000 then ArrowSprite:Update() ArrowSprite:Render(arrowPos, nullVector, nullVector) else - if EID.Config["Indicator"] == "border" then + if EID.Config["Indicator"] == "blink" then local c = 255 - math.floor(255 * ((entity.FrameCount % 40) / 40)) sprite.Color = Color(1, 1, 1, 1, c/repDiv, c/repDiv, c/repDiv) - elseif EID.Config["Indicator"] == "highlight" then - sprite.Color = Color(1, 1, 1, 1, 255/repDiv, 255/repDiv, 255/repDiv) + EID:renderEntity(entity, sprite, entityPos) + sprite.Color = Color(1, 1, 1, 1, 0, 0, 0) + else + if EID.Config["Indicator"] == "border" then + local c = 255 - math.floor(255 * ((entity.FrameCount % 40) / 40)) + sprite.Color = Color(1, 1, 1, 1, c/repDiv, c/repDiv, c/repDiv) + elseif EID.Config["Indicator"] == "highlight" then + sprite.Color = Color(1, 1, 1, 1, 255/repDiv, 255/repDiv, 255/repDiv) + end + EID:renderEntity(entity, sprite, entityPos + Vector(0, 1)) + EID:renderEntity(entity, sprite, entityPos + Vector(0, -1)) + EID:renderEntity(entity, sprite, entityPos + Vector(1, 0)) + EID:renderEntity(entity, sprite, entityPos + Vector(-1, 0)) + sprite.Color = Color(1, 1, 1, 1, 0, 0, 0) + EID:renderEntity(entity, sprite, entityPos) end - EID:renderEntity(entity, sprite, entityPos + Vector(0, 1)) - EID:renderEntity(entity, sprite, entityPos + Vector(0, -1)) - EID:renderEntity(entity, sprite, entityPos + Vector(1, 0)) - EID:renderEntity(entity, sprite, entityPos + Vector(-1, 0)) - sprite.Color = Color(1, 1, 1, 1, 0, 0, 0) - EID:renderEntity(entity, sprite, entityPos) end if isMirrorRoom then sprite.FlipX = false @@ -1133,6 +1135,15 @@ local function onRender(t) elseif closest.Type == 1000 and closest.Variant == 76 then EID:printDescription(EID:getDescriptionObj(closest.Type, closest.Variant, closest.SubType+1, closest)) return + -- Handle Card Reading Portals + elseif closest.Type == 1000 and closest.Variant == 161 and closest.SubType <= 2 then + local subtypeToCard = {18, 5, 19} + -- Reuse the descriptions of The Emperor/Stars/Moon, so no localization needed + local descriptionObj = EID:getDescriptionObj(5, 300, subtypeToCard[closest.SubType+1], closest) + -- Card Reading's name + descriptionObj.Name = EID:getObjectName(5, 100, 660) + EID:printDescription(descriptionObj) + return -- Handle Crane Game elseif closest.Type == 6 and closest.Variant == 16 then if EID.CraneItemType[tostring(closest.InitSeed)] then