From f16ced3186ca830f66698cba9cf69d6b26f448dc Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 18:31:50 -0400 Subject: [PATCH 01/39] Rebindable Flip desc --- descriptions/rep/en_us.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/descriptions/rep/en_us.lua b/descriptions/rep/en_us.lua index 602c26cd..d1126f47 100644 --- a/descriptions/rep/en_us.lua +++ b/descriptions/rep/en_us.lua @@ -1072,7 +1072,7 @@ EID.descriptions[languageCode].BlankCardCharge = "Blank Card charge:" EID.descriptions[languageCode].BlankCardQCard = "Teleport to I AM ERROR Room#Blank Card and ?-Card will be destroyed" EID.descriptions[languageCode].ClearRuneCharge = "Clear Rune charge:" EID.descriptions[languageCode].PlaceboCharge = "Placebo charge:" -EID.descriptions[languageCode].FlipItemToggleInfo = "(Hold {{ButtonSelect}} (Map) to show description)" +EID.descriptions[languageCode].FlipItemToggleInfo = "(Hold {{CONFIG_BoC_Toggle}} to show description)" EID.descriptions[languageCode].FalsePHDHeart = "{{BlackHeart}} Spawns 1 Black Heart" From 0e00f5fa7f2b7343dbe19158e003ac4d28d425fe Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 18:34:24 -0400 Subject: [PATCH 02/39] return player pressing the button --- eid_api.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eid_api.lua b/eid_api.lua index 522c1084..2cddd3a3 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -1520,7 +1520,7 @@ end function EID:PlayersActionPressed(button, inputFunc) inputFunc = inputFunc or Input.IsActionPressed for k,_ in pairs(EID.controllerIndexes) do - if inputFunc(button, k) then return true end + if inputFunc(button, k) then return true, k end end return false end From cb7a063aa5da1ef63d86f2acdde0facfa7d1a917 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 18:36:54 -0400 Subject: [PATCH 03/39] return the player num, not the controller num --- eid_api.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eid_api.lua b/eid_api.lua index 2cddd3a3..c48facca 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -1519,8 +1519,8 @@ end -- Returns true if any player is pressing the given button (you can also specify any of the input functions) function EID:PlayersActionPressed(button, inputFunc) inputFunc = inputFunc or Input.IsActionPressed - for k,_ in pairs(EID.controllerIndexes) do - if inputFunc(button, k) then return true, k end + for k,v in pairs(EID.controllerIndexes) do + if inputFunc(button, k) then return true, v end end return false end From b4e74fbb217a2a4730e7a8fb41766268fc446df0 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 19:33:25 -0400 Subject: [PATCH 04/39] Hold Tab Desc prevention --- eid_bagofcrafting.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/eid_bagofcrafting.lua b/eid_bagofcrafting.lua index 554d4f72..e553fbdf 100644 --- a/eid_bagofcrafting.lua +++ b/eid_bagofcrafting.lua @@ -907,6 +907,7 @@ function EID:handleBagOfCraftingUpdating() -- Check for Hold Tab key inputs if displayingRecipeList and Input.IsActionPressed(EID.Config["BagOfCraftingToggleKey"], EID.bagPlayer.ControllerIndex) then + EID.TabDescThisFrame = true EID.bagPlayer.ControlsCooldown = 2 if Input.IsActionTriggered(ButtonAction.ACTION_SHOOTDOWN, EID.bagPlayer.ControllerIndex) then bagOfCraftingOffset = math.min(numResults-(numResults%EID.Config["BagOfCraftingResults"]), bagOfCraftingOffset + EID.Config["BagOfCraftingResults"]) From c76005b6578f84765043d0bac50c7e5e3b863b42 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 19:33:40 -0400 Subject: [PATCH 05/39] BoC toggle does more things now --- eid_config.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eid_config.lua b/eid_config.lua index a2890969..f13bf3a8 100644 --- a/eid_config.lua +++ b/eid_config.lua @@ -315,7 +315,7 @@ EID.UserConfig = { -- Higher numbers will cause lag spikes on new pickup sets! -- Default = 400 ["BagOfCraftingRandomResults"] = 400, - -- Set the keybinding to toggle the scroll feature of the Bag of Crafting descriptions + -- Set the keybinding that's held to show the Item Reminder description, Flip/Spindown Dice preview descriptions, and interacting with the Bag of Crafting recipe list -- Look into the AB+ or Repentance documentation for the key names here: https://wofsauge.github.io/IsaacDocs/rep/enums/ButtonAction.html -- Default = ButtonAction.ACTION_MAP ["BagOfCraftingToggleKey"] = ButtonAction.ACTION_MAP, From 9e8ffbf1706ac32fae17e550f8e8e7eb81b26119 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 19:34:28 -0400 Subject: [PATCH 06/39] Hold Map Description starts --- eid_modifiers.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/eid_modifiers.lua b/eid_modifiers.lua index ff18d41a..a6ca29cc 100644 --- a/eid_modifiers.lua +++ b/eid_modifiers.lua @@ -3,6 +3,8 @@ local game = Game() EID.TabPreviewID = 0 -- Modifiers switching the previewed description can cause infinite loops or undesired text, use this to help prevent it 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 -- 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, } @@ -60,8 +62,15 @@ function EID:CheckPlayersCollectibles() end end +function EID:getHoldMapDescription() + return "Yo" +end + +-- Handle description changes that occur while holding Map, and the Hold Map Helper (name pending) local function TabCallback(descObj) if EID.TabPreviewID == 0 then return descObj end + EID.TabDescThisFrame = true + EID.inModifierPreview = true local descEntry = EID:getDescriptionObj(5, 100, EID.TabPreviewID) EID.inModifierPreview = false @@ -614,7 +623,7 @@ EID:addDescriptionModifier("EID Afterbirth+", EIDConditionsAB, nil) -- should this be done differently so that mods can add tab previews? (tab conditions is done last, but would be done before callbacks mods add, maybe tab should be checked in EID:getDescriptionObj local function TabConditions(descObj) - if EID:PlayersActionPressed(ButtonAction.ACTION_MAP) and not EID.inModifierPreview then return true end + if EID:PlayersActionPressed(EID.Config["BagOfCraftingToggleKey"]) and not EID.inModifierPreview then return true end EID.TabPreviewID = 0 return false end From 0fdce2e90a90530b895c979e0be0b7f6653b67e5 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 19:35:19 -0400 Subject: [PATCH 07/39] Hold Tab description for active descs --- main.lua | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/main.lua b/main.lua index b46e7c7c..62227f83 100644 --- a/main.lua +++ b/main.lua @@ -41,6 +41,8 @@ local altPathItemChecked = {} local alwaysUseLocalMode = false -- set to true after drawing a non-local mode description this frame EID.ForceRefreshCache = false -- set to true to force-refresh descriptions, currently used for potential transformation text changes local preHourglassStatus = {} +EID.holdTabPlayer = 0 +EID.holdTabCounter = 0 EID.GameUpdateCount = 0 EID.GameRenderCount = 0 @@ -460,10 +462,11 @@ local function resetDescCache() end -function EID:addDescriptionToPrint(desc) +function EID:addDescriptionToPrint(desc, insertLoc) if desc.Entity and EID.entitiesToPrint[GetPtrHash(desc.Entity)] then return end if #EID.descriptionsToPrint == EID.Config["MaxDescriptionsToDisplay"] then return end - table.insert(EID.descriptionsToPrint, desc) + if insertLoc then table.insert(EID.descriptionsToPrint, insertLoc, desc) + else table.insert(EID.descriptionsToPrint, desc) end if desc.Entity then EID.entitiesToPrint[GetPtrHash(desc.Entity)] = true end end @@ -1203,6 +1206,7 @@ local function onRender(t) end end EID.TabPreviewID = 0 + EID.TabDescThisFrame = 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 @@ -1244,6 +1248,15 @@ local function onRender(t) return end + local tabHeld, playerHoldingTab = EID:PlayersActionPressed(EID.Config["BagOfCraftingToggleKey"]) + if tabHeld then + EID.holdTabPlayer = EID.coopMainPlayers[playerHoldingTab] + EID.holdTabCounter = EID.holdTabCounter + 1 + else + EID.holdTabPlayer = nil + EID.holdTabCounter = 0 + end + if EID.ForceRefreshCache then resetDescCache() end @@ -1482,6 +1495,19 @@ local function onRender(t) end end + -- handle showing the Hold Map Helper description + if EID.holdTabCounter >= 30 and EID.TabDescThisFrame == false and EID.holdTabPlayer ~= nil then + -- at the moment, just show the description of the player's active item + --local demoDescObj = EID:getDescriptionObj(-999, -1, 1) + --demoDescObj.Name = "" + --demoDescObj.Description = EID:getHoldMapDescription() + local heldActive = EID.holdTabPlayer:GetActiveItem() + if heldActive then + local demoDescObj = EID:getDescriptionObj(5, 100, heldActive) + EID:addDescriptionToPrint(demoDescObj, 1) + end + end + EID:printDescriptions() end From 4f92b58968c6dc7999ea0389346ece49be31192d Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 22:32:58 -0400 Subject: [PATCH 08/39] proper Hold Tab desc --- main.lua | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/main.lua b/main.lua index 62227f83..b93a6f86 100644 --- a/main.lua +++ b/main.lua @@ -1497,15 +1497,10 @@ local function onRender(t) -- handle showing the Hold Map Helper description if EID.holdTabCounter >= 30 and EID.TabDescThisFrame == false and EID.holdTabPlayer ~= nil then - -- at the moment, just show the description of the player's active item - --local demoDescObj = EID:getDescriptionObj(-999, -1, 1) - --demoDescObj.Name = "" - --demoDescObj.Description = EID:getHoldMapDescription() - local heldActive = EID.holdTabPlayer:GetActiveItem() - if heldActive then - local demoDescObj = EID:getDescriptionObj(5, 100, heldActive) - EID:addDescriptionToPrint(demoDescObj, 1) - end + local demoDescObj = EID:getDescriptionObj(-999, -1, 1) + demoDescObj.Name = "" + demoDescObj.Description = EID:getHoldMapDescription(EID.holdTabPlayer) + EID:addDescriptionToPrint(demoDescObj, 1) end EID:printDescriptions() From 97030cf390b0baf1d1aeb4f7f12bc18c7c847638 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 22:33:18 -0400 Subject: [PATCH 09/39] Hold Map description --- eid_modifiers.lua | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/eid_modifiers.lua b/eid_modifiers.lua index a6ca29cc..1d0779b9 100644 --- a/eid_modifiers.lua +++ b/eid_modifiers.lua @@ -62,8 +62,29 @@ function EID:CheckPlayersCollectibles() end end -function EID:getHoldMapDescription() - return "Yo" +local holdMapDesc = "" +local function appendToMapDesc(icon, title, newDesc) + holdMapDesc = holdMapDesc .. "#" .. (icon or "{{Blank}}") .. " {{ColorEIDObjName}}" .. title .. "#" .. newDesc +end + +function EID:getHoldMapDescription(player) + holdMapDesc = "" + + -- Tainted ??? Poop Preview + local nextPoop = player:GetPoopSpell(0) + if player:GetPoopMana() > 0 then + local poopInfo = EID:getDescriptionEntry("poopSpells") + appendToMapDesc(nil, poopInfo[nextPoop][1], poopInfo[nextPoop][2]) + end + + -- Active Item Description + local heldActive = player:GetActiveItem() + if heldActive > 0 then + local demoDescObj = EID:getDescriptionObj(5, 100, heldActive) + appendToMapDesc("{{Collectible"..heldActive.."}}", demoDescObj.Name, demoDescObj.Description) + end + + return holdMapDesc end -- Handle description changes that occur while holding Map, and the Hold Map Helper (name pending) From da6deba5da6c7b76ca97ff63db88bdd44444569c Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 22:33:42 -0400 Subject: [PATCH 10/39] Poop Spell descriptions --- descriptions/rep/en_us.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/descriptions/rep/en_us.lua b/descriptions/rep/en_us.lua index d1126f47..870952ff 100644 --- a/descriptions/rep/en_us.lua +++ b/descriptions/rep/en_us.lua @@ -1048,6 +1048,20 @@ EID.descriptions[languageCode].GlitchedItemText = { ---------- Misc. Text ---------- +EID.descriptions[languageCode].poopSpells = { + {"Poop", "Normal poop that can drop pickups"}, + {"Corny Poop", "Spawns blue flies while intact"}, + {"Burning Poop", "Deals contact damage while intact#Leaves a fire behind when destroyed"}, + {"Stone Poop", "Can deal damage 3 times when thrown#Takes a lot of hits to destroy"}, + {"Stinky Poop", "Emits a toxic cloud#!!! The cloud will explode if it touches fire!"}, + {"Black Poop", "Creates slowing creep#Deals 10 damage and confuses all enemies when destroyed"}, + {"Holy Poop", "{{Collectible543}} Create a white poop#While inside the poop's aura:#↑ {{Damage}} +20% Damage up#↑ {{Tears}} +150% Fire Rate up#Homing tears#Chance to block damage"}, + {"Brown Creep", "Leave a trail of creep#Standing on the creep increases your fire rate and damage#If the creep is touching other poops, it gains their attribute"}, + {"Fart", "Push nearby enemies and bullets back, and spawn a toxic cloud#!!! The cloud will explode if it touches fire!"}, + {"Bomb", "Normal throwable bomb"}, + {"Explosive Diarrhea", "Spawn 5 lit bombs at your position over the next few seconds"}, +} + EID.descriptions[languageCode].VoidShopText = "If absorbed right after pickup, gain:" EID.descriptions[languageCode].VoidOptionText = " will be absorbed instead" EID.descriptions[languageCode].VoidNames = {"Speed up", "Fire Rate up", "Damage up", "Range up", "Shot Speed up", "Luck up"} From 6bf586b6ee80d2054632ffdbf79a3a054d43573e Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 4 Jun 2022 22:37:50 -0400 Subject: [PATCH 11/39] reminder comments --- main.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.lua b/main.lua index b93a6f86..4a90f572 100644 --- a/main.lua +++ b/main.lua @@ -1497,6 +1497,8 @@ local function onRender(t) -- handle showing the Hold Map Helper description if EID.holdTabCounter >= 30 and EID.TabDescThisFrame == false and EID.holdTabPlayer ~= nil then + --hey wait, Esau's getting screwed by how we're handling holdTabPlayer right now + --also, have we done anything that makes AB+ get angry? local demoDescObj = EID:getDescriptionObj(-999, -1, 1) demoDescObj.Name = "" demoDescObj.Description = EID:getHoldMapDescription(EID.holdTabPlayer) From 3deef5e4764c38ac3c7dff84d692967c70c88e17 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Mon, 6 Jun 2022 13:39:42 -0400 Subject: [PATCH 12/39] Poop spells and error room icon --- resources/gfx/eid_inline_icons.anm2 | 28 +++++++++++++++++++++++++++- resources/gfx/eid_inline_icons.png | Bin 25558 -> 29622 bytes 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/resources/gfx/eid_inline_icons.anm2 b/resources/gfx/eid_inline_icons.anm2 index 4d97581c..2ee40b43 100644 --- a/resources/gfx/eid_inline_icons.anm2 +++ b/resources/gfx/eid_inline_icons.anm2 @@ -1,5 +1,5 @@ - + @@ -191,6 +191,7 @@ + @@ -241,6 +242,7 @@ + @@ -601,5 +603,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/gfx/eid_inline_icons.png b/resources/gfx/eid_inline_icons.png index f42f355c2fa8e60172e80f15a346b28888ac0ad0..369ca426a82c60a16ebd1be7dc15ba24c72f2de7 100644 GIT binary patch literal 29622 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�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 QPzUf%T2ZR Date: Mon, 6 Jun 2022 13:40:32 -0400 Subject: [PATCH 13/39] Hold Map Header / Teleport 2 / etc. --- descriptions/ab+/en_us.lua | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/descriptions/ab+/en_us.lua b/descriptions/ab+/en_us.lua index 418f48ce..9393e604 100644 --- a/descriptions/ab+/en_us.lua +++ b/descriptions/ab+/en_us.lua @@ -256,7 +256,7 @@ EID.descriptions[languageCode].collectibles={ {"234", "Infestation 2", "Spawn spiders when you kill an enemy"}, {"235", "", ""}, {"236", "E. Coli", "On touch, turn enemies into poop"}, - {"237", "Death's Touch", "Scythe tears!#↑ +1.5 Damage up#↓ -0.3 Tears down#Piercing tears"}, + {"237", "Death's Touch", "Scythe tears!#↑ +1.5 Damage up#↑ Tear size up#↓ -0.3 Tears down#Piercing tears"}, {"238", "Key Piece 1", "!!! Key piece for Mega Satan door!#{{AngelChance}} 25% higher Angel Room chance"}, {"239", "Key Piece 2", "!!! Key piece for Mega Satan door!#{{AngelChance}} 25% higher Angel Room chance"}, {"240", "Experimental Treatment", "All Stats ↑/↓ a random number"}, @@ -345,7 +345,7 @@ EID.descriptions[languageCode].collectibles={ {"321", "Samson's Chains", "Draggable ball that can destroy rocks#Deals 10.7 contact damage per second"}, {"322", "Mongo Baby", "Copies the effect of one of your familiars#Deals double its damage"}, {"323", "Isaac's Tears", "Shoot 8 tears in all directions when used#Recharges by shooting"}, - {"324", "Undefined", "Teleports you to the {{TreasureRoom}} Treasure, {{SecretRoom}} Secret, {{SuperSecretRoom}} Super Secret or I AM ERROR Room"}, + {"324", "Undefined", "Teleports you to the {{TreasureRoom}} Treasure, {{SecretRoom}} Secret, {{SuperSecretRoom}} Super Secret or {{ErrorRoom}} I AM ERROR Room"}, {"325", "Scissors", "Cut off your head#Head turns into stationary familiar#Control your body separately"}, {"326", "Breath of Life", "Hold down space until chargebar is empty for invincibility#!!! Don't hold it for too long or you will start taking damage!"}, {"327", "The Polaroid", "Invincibility when getting hit and at half a Red Heart or none"}, @@ -440,7 +440,7 @@ EID.descriptions[languageCode].collectibles={ {"416", "Deep Pockets", "Allows you to carry two cards/pills/runes"}, {"417", "Succubus", "Bounces around the room with a damaging aura, dealing 129% of your damage every second#↑ {{Damage}} +50% Damage while standing in the aura"}, {"418", "Fruit Cake", "Gives you a different tear effect with every tear that you fire"}, - {"419", "Teleport 2.0", "Teleports you to another random room that has not been cleared yet#Hierarchy: {{Room}}>{{BossRoom}}>{{SuperSecretRoom}}>{{Shop}}>{{TreasureRoom}}>{{SacrificeRoom}}> {{DiceRoom}}>{{Library}}>{{CursedRoom}}>{{MiniBoss}}>{{ChallengeRoom}}>{{IsaacsRoom}}> {{ArcadeRoom}}>{{ChestRoom}}>{{SecretRoom}}>{{DevilRoom}}{{AngelRoom}}> Error-Room"}, + {"419", "Teleport 2.0", "Teleports you to another random room that has not been cleared yet#Hierarchy: {{Room}}>{{BossRoom}}>{{SuperSecretRoom}}>{{Shop}}>{{TreasureRoom}}>{{SacrificeRoom}}> {{DiceRoom}}>{{Library}}>{{CursedRoom}}>{{MiniBoss}}>{{ChallengeRoom}}{{BossRushRoom}}>{{IsaacsRoom}}{{BarrenRoom}}> {{ArcadeRoom}}>{{ChestRoom}}>{{SecretRoom}}>{{DevilRoom}}{{AngelRoom}}>{{ErrorRoom}}"}, {"420", "Black Powder", "Walking in a circle will spawn a pentagram symbol on the floor, which deals 10 damage per tick"}, {"421", "Kidney Bean", "{{Charm}} Applies charm effect to any enemies in close range and deals 5 damage to them"}, {"422", "Glowing Hour Glass", "Rewind time and put you back in the previous room, in the same state you were in at that moment"}, @@ -508,7 +508,7 @@ EID.descriptions[languageCode].collectibles={ {"484", "Wait What?", "Upon use, pushes enemies away and spawn a wave of rocks#Can open rooms and break rocks"}, {"485", "Crooked Penny", "50% chance to double all items, consumables and chests in room#50% chance to remove items / pickups in room and spawn 1 coin"}, {"486", "Dull Razor", "Hurts you without damaging you#Can trigger item effects"}, - {"487", "Potato Peeler", "Removes one Red Heart Container and gives you: #↑ {{Damage}} +0.2 Damage#{{Collectible73}} A Cube of Meat"}, + {"487", "Potato Peeler", "Removes one Red Heart Container and gives you: #↑ {{Damage}} +0.2 Damage up#{{Collectible73}} A Cube of Meat#↑ {{Range}} +5 Range and leave a trail of blood creep for the current room"}, {"488", "Metronome", "Grants a random item's effect for the current room"}, {"489", "D Infinity", "Random dice effect each use"}, {"490", "Eden's Soul", "!!! SINGLE USE !!!#Spawns 2 random items depending on the current room's item pool#Starts with no charges"}, @@ -789,7 +789,7 @@ EID.descriptions[languageCode].pills={ {"16", "Tears Up", "↑ {{Tears}} +0.35 Tears up"}, {"17", "Luck Down", "↓ {{Luck}} -1 Luck down"}, {"18", "Luck Up", "↑ {{Luck}} +1 Luck up"}, - {"19", "Telepills", "Teleports you to a random room#Small chance to teleport you to the I AM ERROR room"}, + {"19", "Telepills", "Teleports you to a random room#{{ErrorRoom}} Small chance to teleport you to the I AM ERROR room"}, {"20", "48 Hour Energy!", "Fully recharges your active item#Drops 1-2 batteries"}, {"21", "Hematemesis", "Drains all but one heart container#Spawns 1-4 Red Hearts"}, {"22", "Paralysis", "You can't move for 2 seconds"}, @@ -882,3 +882,9 @@ EID.descriptions[languageCode].MCM = { DemoObjectTransformation = "Demo Transformation", 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", } + +-- the Hold Map description will predict the abilities of items with a header like "Item Name Result" +EID.descriptions[languageCode].HoldMapHeader = " Result" +-- includes Planetarium even though it's unused in AB+ for convenience +EID.descriptions[languageCode].Teleport2RoomNames = { "Normal Room","Boss Room","Super Secret Room","Shop","Treasure Room","Sacrifice Room","Dice Room","Library","Curse Room","Miniboss Room","Challenge/Boss Challenge Room","Isaac's Room","Barren Room","Arcade Room","Chest Room","Planetarium","Secret Room","Special Red Room","Angel/Devil Room","I AM ERROR Room" } +EID.descriptions[languageCode].Teleport2GreedRoomNames = { "Main Room", "Boss Room", "Shop", "Silver/Gold Treasure Room", "Curse Room", "Exit Room", "Super Secret Room", "Angel/Devil Room", "I AM ERROR Room" } From d75ef7c4fed1b03bed68a6f0af09b8aef3932aad Mon Sep 17 00:00:00 2001 From: Buurazu Date: Mon, 6 Jun 2022 13:44:51 -0400 Subject: [PATCH 14/39] misc improvements --- descriptions/rep/en_us.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/descriptions/rep/en_us.lua b/descriptions/rep/en_us.lua index 870952ff..5610e4da 100644 --- a/descriptions/rep/en_us.lua +++ b/descriptions/rep/en_us.lua @@ -177,7 +177,7 @@ local repCollectibles={ [415] = {"415", "Crown Of Light", "{{SoulHeart}} +2 Soul Hearts#If you don't have any damaged Red Heart containers:#↑ {{Damage}} +100% Damage up#↑ {{Range}} +1.5 Range up#↓ {{Shotspeed}} -0.3 Shot Speed down#Deactivates for the current room when damaged at all"}, -- Crown Of Light [416] = {"416", "Deep Pockets", "Spawns 1-3 coins if a room didn't yield a reward#{{Coin}} Increases coin cap to 999"}, -- Deep Pockets [417] = {"417", "Succubus", "Bounces around the room with a damaging aura, dealing 7.5-10 damage every second#↑ {{Damage}} +50% Damage while standing in the aura"}, -- Succubus - [419] = {"419", "Teleport 2.0", "Teleports you to another random room that has not been cleared yet#Hierarchy: {{Room}}>{{BossRoom}}>{{SuperSecretRoom}}>{{Shop}}>{{TreasureRoom}}>{{SacrificeRoom}}> {{DiceRoom}}>{{Library}}>{{CursedRoom}}>{{MiniBoss}}>{{ChallengeRoom}}>{{IsaacsRoom}}> {{ArcadeRoom}}>{{ChestRoom}}>{{Planetarium}}>{{SecretRoom}}>{{DevilRoom}}{{AngelRoom}}> Error-Room"}, -- Teleport 2.0 + [419] = {"419", "Teleport 2.0", "Teleports you to another random room that has not been cleared yet#Hierarchy: {{Room}}>{{BossRoom}}>{{SuperSecretRoom}}>{{Shop}}>{{TreasureRoom}}>{{SacrificeRoom}}> {{DiceRoom}}>{{Library}}>{{CursedRoom}}>{{MiniBoss}}>{{ChallengeRoom}}{{BossRushRoom}}>{{IsaacsRoom}}{{BarrenRoom}}> {{ArcadeRoom}}>{{ChestRoom}}>{{Planetarium}}>{{SecretRoom}}>{{DevilRoom}}{{AngelRoom}}>{{ErrorRoom}}"}, -- Teleport 2.0 [421] = {"421", "Kidney Bean", "{{Charm}} Applies charm effect to any enemies in close range"}, -- Kidney Bean [426] = {"426", "Obsessed Fan", "Follows your exact movement on a 0.66 second delay#Deals 30 contact damage per second"}, -- Obsessed Fan [430] = {"430", "Papa Fly", "Follows your movement pattern on a 0.66 second delay#Fires tears at nearby enemies that deal damage equal to your damage"}, -- Papa Fly @@ -199,6 +199,7 @@ local repCollectibles={ [474] = {"474", "Broken Glass Cannon", "Turns into Glass Cannon when used"}, -- Broken Glass Cannon [476] = {"476", "D1", "Duplicates 1 random pickup in the current room#Duplicated pickups may not be identical to the original"}, -- D1 [477] = {"477", "Void", "!!! When used, consumes all pedestal items in the room#Active item: Its effect will activate every future use of Void#↑ Passive item: Small stat upgrade to two random stats"}, + [487] = {"487", "Potato Peeler", "Removes one Red Heart Container and gives you: #↑ {{Damage}} +0.2 Damage up#{{Collectible73}} A Cube of Meat#↑ {{Range}} +1.5 Range and leave a trail of blood creep for the current room"}, [489] = {"489", "D Infinity", "Acts as any die item except for {{Collectible723}} Spindown Dice#Change the current die with {{ButtonRT}}#Charge time varies based on the current die and updates when used"}, -- D Infinity [491] = {"491", "Acid Baby", "{{Pill}} Drops a random pill every 7 rooms#Using a pill poisons all enemies in the room"}, -- Acid Baby [493] = {"493", "Adrenaline", "↑ {{Damage}} Damage up for every empty Red Heart container#Follows a formula, some examples are:#+0.3 at 1#+0.92 at 2#+1.76 at 3#+2.79 at 4#+3.98 at 5"}, -- Adrenaline @@ -249,12 +250,12 @@ local repCollectibles={ [577] = {"577", "Damocles", "{{Warning}} SINGLE USE {{Warning}}#Spawns a sword above your head, which doubles all item pedestals#Does not double Shop, Chest, or Devil deal items#!!! Kills you at a random time after taking damage from an enemy"}, -- Damocles [578] = {"578", "Free Lemonade", "Creates a large pool of yellow creep"}, -- Free Lemonade [579] = {"579", "Spirit Sword", "Instead of tears, Isaac swings a sword#Deals 3x your damage#{{Chargeable}} Does a spin attack + projectile shot on charge up#Fire projectiles with normal swings on full health"}, -- Spirit Sword - [580] = {"580", "Red Key", "Creates a new room adjacent to a viable wall, indicated by an outline of a door#Rooms can be special rooms#A room outside the 13x13 floor map will teleport you to the I AM ERROR room"}, -- Red Key + [580] = {"580", "Red Key", "Creates a new room adjacent to a viable wall, indicated by an outline of a door#Rooms can be special rooms#{{ErrorRoom}} A room outside the 13x13 floor map will teleport you to the I AM ERROR room"}, -- Red Key [581] = {"581", "Psy Fly", "Fly orbital familiar#Chases and deflects projectiles#Deals 15 contact damage per second"}, -- Psy Fly [582] = {"582", "Wavy Cap", "↑ {{Tears}} +0.75 Fire Rate up#↓ {{Speed}} -0.03 Speed down#Distorts the screen#Effect can be stacked"}, -- Wavy Cap [583] = {"583", "Rocket in a Jar", "{{Bomb}} +5 bombs#If shooting, placed bombs turn into rockets that fire in the shooting direction"}, -- Rocket in a Jar [584] = {"584", "Book of Virtues", "Spawns an orbital wisp familiar that fires spectral tears but can be destroyed#Can be combined with a second active item to create themed wisps#{{DevilRoom}} Turns the first Devil Room into an {{AngelRoom}} Angel Room#{{AngelChance}} 12.5% higher Angel Room chance#{{AngelChance}} Allows Angel Rooms to spawn even if you've taken a Devil deal"}, -- Book of Virtues - [585] = {"585", "Alabaster Box", "Upon use, Spawns: #{{SoulHeart}} Three Soul Hearts#{{AngelRoom}} Two Angel Room items#{{SoulHeart}} Must be charged by picking up Soul Hearts#{{DevilRoom}} Only spawns 2 Soul Hearts and 1 Angel item if a Devil deal was taken previously"}, -- Alabaster Box + [585] = {"585", "Alabaster Box", "Upon use, spawns: #{{SoulHeart}} Three Soul Hearts#{{AngelRoom}} Two Angel Room items#Must be charged by picking up Soul Hearts#{{DevilRoom}} Only spawns 2 Soul Hearts and 1 Angel item if a Devil deal was taken previously"}, -- Alabaster Box [586] = {"586", "The Stairway", "Spawns a ladder at the start of every floor#It leads to a unique {{AngelRoom}} Angel Room shop with items and consumables"}, -- The Stairway [587] = {"587", "Menorah (Unused but scripted)", ""}, -- Menorah (Unused but scripted) [588] = {"588", "Sol", "{{BossRoom}} Reveals the location of the Boss Room#Upon defeating a boss, for the rest of the floor: #{{Card20}} Activates The Sun#{{Battery}} Fully recharges your active item#{{CurseBlind}} Removes any Curses#↑ {{Damage}} +3 Damage#↑ {{Luck}} +1 Luck"}, -- Sol @@ -361,7 +362,7 @@ local repCollectibles={ [689] = {"689", "Glitched Crown", "Item pedestals quickly cycle between 5 random items"}, -- Glitched Crown [690] = {"690", "Belly Jelly", "Causes enemies to bounce off of Isaac#Bouncing them against obstacles deals damage#50% chance that Isaac ignores contact damage#50% chance to deflect enemy projectiles"}, -- Belly Jelly [691] = {"691", "Sacred Orb", "Prevents Quality {{Quality0}}/{{Quality1}} items from spawning#33% chance to reroll items with Quality {{Quality2}} to Quality {{Quality3}} or {{Quality4}}"}, -- Sacred Orb - [692] = {"692", "Sanguine Bond", "Spawns a set of spikes in the {{DevilRoom}}Devil Room#Taking damage from the spikes can grant a reward:#35%: Nothing#33%: ↑ {{Damage}} +0.5 Damage up#15%: {{Coin}} 6 pennies#10%: {{BlackHeart}} 2 Black Hearts#5%: {{DevilRoom}} Random Devil item#2%: Leviathan transformation"}, -- Sanguine Bond //PERCENTAGES NOT CONFIRMED, updated in patch, taken from Wiki + [692] = {"692", "Sanguine Bond", "Spawns a set of spikes in the {{DevilRoom}}Devil Room#Take damage on the spikes to get a reward:#35%: Nothing#33%: ↑ {{Damage}} +0.5 Damage up#15%: {{Coin}} 6 pennies#10%: {{BlackHeart}} 2 Black Hearts#5%: {{DevilRoom}} Random Devil item#2%: Leviathan transformation"}, -- Sanguine Bond [693] = {"693", "The Swarm", "Grants 8 orbital flies which turn into Blue Flies after they block a shot#Spawns a new fly every room cleared"}, -- The Swarm [694] = {"694", "Heartbreak", "{{BrokenHeart}} Grants 3 broken hearts#↑ {{Damage}} +0.25 Damage for every broken heart#Every fatal hit will add 2 more broken hearts#You die at 12 broken hearts"}, -- Heartbreak [695] = {"695", "Bloody Gust", "When taking damage, gain {{Speed}} speed and {{Tears}} tears up for the current floor#Up to +1.02 Speed and +3 Fire Rate possible"}, -- Bloody Gust @@ -373,7 +374,7 @@ local repCollectibles={ [701] = {"701", "Isaac's Tomb", "Spawns an {{DirtyChest}} Old Chest at the start of every floor which requires a key to unlock#Can contain {{SoulHeart}} Soul Hearts, trinkets or items#Items are from the {{AngelRoom}} Angel Room pool and Mom and Dad themed"}, -- Isaac's Tomb [702] = {"702", "Vengeful Spirit", "After taking damage, spawns an orbital wisp that lasts for the entire floor#Maximum of 6#They fire tears but do not block shots"}, -- Vengeful Spirit [703] = {"703", "Esau Jr.", "Swaps between the current character and Esau Jr., who has {{BlackHeart}} 3 Black Hearts, {{Damage}} +2 Damage and flight#Characters have independent items and health#On first use, he gains random passive items equal to how many you have#{{Warning}} Dying as either character ends the run"}, -- Esau Jr. - [704] = {"704", "Berserk!", "On use, enter Berserk mode for 5 seconds:#↑ {{Speed}} +0.4 Speed up#↑ {{Tears}} Tears up#↑ {{Damage}} +3 Damage up#Restricts attacks to a melee weapon"}, -- Berserk! + [704] = {"704", "Berserk!", "Item charges by dealing damage#On use, go berserk for 5 seconds:#↑ {{Speed}} +0.4 Speed up#↑ {{Damage}} +3 Damage up#Restricts attacks to a melee weapon#Kills while berserk increase its duration by 1 second"}, -- Berserk! [705] = {"705", "Dark Arts", "On use, gain {{Speed}} +1 Speed and walk through enemies and bullets for 1 second#On touch, deal 2x your damage + 3.5 damage per touched enemy#Explosion on effect end that deals damage equal to how much you dealt"}, -- Dark Arts [706] = {"706", "Abyss", "Destroys all items in the room and spawns an attack fly familiar for each#Effects of fly depends on the items"}, -- Abyss [707] = {"707", "Supper", "↑ {{Heart}} +1 Health up#{{Heart}} Heals 1 Red Heart"}, -- Supper @@ -865,7 +866,7 @@ local repCards={ [84] = {"84", "Soul of Judas", "Turns Isaac into a phantom that can pass through enemies to paralyze them#After a few seconds, will attack them all, gaining damage bonus per target"}, -- Soul of Judas [85] = {"85", "Soul of ???", "{{Poison}} Causes 8 poison farts with brown creep#Then plants trail of 7 Butt Bombs#Standing in the creep gives: # {{Tears}} +1.35 Tears#↑ {{Damage}} +1 Damage"}, -- Soul of ??? [86] = {"86", "Soul of Eve", "14 Dead Bird familiars fly in and attack enemies# Lasts for current room"}, -- Soul of Eve - [87] = {"87", "Soul of Samson", "Turn into a berserk Samson with melee attack for 10 seconds#↑ +0.4 Speed up#↑ Tears up#↑ +3 Damage up"}, -- Soul of Samson + [87] = {"87", "Soul of Samson", "Go berserk for 10 seconds:#↑ {{Speed}} +0.4 Speed up#↑ {{Damage}} +3 Damage up#Restricts attacks to a melee weapon#Kills while berserk increase its duration by 1 second"}, -- Soul of Samson [88] = {"88", "Soul of Azazel", "{{Collectible441}} Activates Mega Blast for 7.5 seconds"}, -- Soul of Azazel [89] = {"89", "Soul of Lazarus", "Die and immediately revive at half a heart with some invincibility time#Item is automatically used upon taking fatal damage (like an extra life)"}, -- Soul of Lazarus [90] = {"90", "Soul of Eden", "Rerolls pedestals and pickups in current room#The rerolled items use random pools"}, -- Soul of Eden @@ -962,7 +963,7 @@ EID.descriptions[languageCode].horsepills={ {"22", "Paralysis", "You can't move for 4 seconds"}, -- Paralysis {"23", "I can see forever!", "{{SecretRoom}} Opens secret room entrances on current floor#Grants full mapping"}, -- I can see forever! {"24", "Pheromones", "{{Charm}} Turns every enemy in the room permanently friendly"}, -- Pheromones - {"25", "Amnesia", "Hides the floor map"}, -- Amnesia + {"25", "Amnesia", "{{CurseLost}} Hides the floor map"}, -- Amnesia {"26", "Lemon Party", "Spawns room filling puddle on the ground which damages enemies"}, -- Lemon Party {"27", "R U a Wizard?", "Shoot diagonally for 60 seconds"}, -- R U a Wizard? {"28", "Percs!", "Take only half the damage for current room"}, -- Percs! @@ -1066,7 +1067,6 @@ EID.descriptions[languageCode].VoidShopText = "If absorbed right after pickup, g EID.descriptions[languageCode].VoidOptionText = " will be absorbed instead" EID.descriptions[languageCode].VoidNames = {"Speed up", "Fire Rate up", "Damage up", "Range up", "Shot Speed up", "Luck up"} - EID.descriptions[languageCode].spindownError = "Item disappears" EID.descriptions[languageCode].CraftingBagContent = "Bag:" From 363499742301c2a7d9ebaf427d64d9f5f801a82c Mon Sep 17 00:00:00 2001 From: Buurazu Date: Mon, 6 Jun 2022 13:45:30 -0400 Subject: [PATCH 15/39] Moved to its own file --- eid_modifiers.lua | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/eid_modifiers.lua b/eid_modifiers.lua index 1d0779b9..70a8d83e 100644 --- a/eid_modifiers.lua +++ b/eid_modifiers.lua @@ -62,32 +62,7 @@ function EID:CheckPlayersCollectibles() end end -local holdMapDesc = "" -local function appendToMapDesc(icon, title, newDesc) - holdMapDesc = holdMapDesc .. "#" .. (icon or "{{Blank}}") .. " {{ColorEIDObjName}}" .. title .. "#" .. newDesc -end - -function EID:getHoldMapDescription(player) - holdMapDesc = "" - - -- Tainted ??? Poop Preview - local nextPoop = player:GetPoopSpell(0) - if player:GetPoopMana() > 0 then - local poopInfo = EID:getDescriptionEntry("poopSpells") - appendToMapDesc(nil, poopInfo[nextPoop][1], poopInfo[nextPoop][2]) - end - - -- Active Item Description - local heldActive = player:GetActiveItem() - if heldActive > 0 then - local demoDescObj = EID:getDescriptionObj(5, 100, heldActive) - appendToMapDesc("{{Collectible"..heldActive.."}}", demoDescObj.Name, demoDescObj.Description) - end - - return holdMapDesc -end - --- Handle description changes that occur while holding Map, and the Hold Map Helper (name pending) +-- Handle description changes that occur while holding Map local function TabCallback(descObj) if EID.TabPreviewID == 0 then return descObj end EID.TabDescThisFrame = true From bfe8b47d3537081c2752a336c909c57edb8e13f0 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Mon, 6 Jun 2022 13:46:10 -0400 Subject: [PATCH 16/39] publicize ismirror/deathcertroom --- main.lua | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/main.lua b/main.lua index 4a90f572..68a032e9 100644 --- a/main.lua +++ b/main.lua @@ -105,6 +105,7 @@ require("eid_data") require("eid_xmldata") require("eid_api") require("eid_modifiers") +require("eid_holdmapdesc") -- load Repentence descriptions if REPENTANCE then @@ -729,8 +730,8 @@ function EID:printBulletPoints(description, renderPos) end --------------------------------------------------------------------------- ----------------------------Handle New Room-------------------------------- -local isMirrorRoom = false -local isDeathCertRoom = false +EID.isMirrorRoom = false +EID.isDeathCertRoom = false if REPENTANCE then function EID:AssignFlipItems() EID.flipMaxIndex = -1 @@ -748,8 +749,8 @@ if REPENTANCE then end function EID:onNewRoomRep() local level = game:GetLevel() - isMirrorRoom = level:GetCurrentRoom():IsMirrorWorld() - isDeathCertRoom = EID:GetDimension(level) == 2 + EID.isMirrorRoom = level:GetCurrentRoom():IsMirrorWorld() + EID.isDeathCertRoom = EID:GetDimension(level) == 2 -- Handle Flip Item initialItemNext = false @@ -843,7 +844,7 @@ function EID:renderIndicator(entity, playerNum) local sprite = entity:GetSprite() if REPENTANCE then repDiv = 255 - if isMirrorRoom then + if EID.isMirrorRoom then local screenCenter = EID:getScreenSize()/2 entityPos.X = entityPos.X - (entityPos-screenCenter).X * 2 arrowPos.X = arrowPos.X - (arrowPos-screenCenter).X * 2 @@ -881,7 +882,7 @@ function EID:renderIndicator(entity, playerNum) EID:renderEntity(entity, sprite, entityPos) end end - if isMirrorRoom then + if EID.isMirrorRoom then sprite.FlipX = false end end @@ -894,7 +895,7 @@ function EID:PositionLocalMode(entity) local textBoxWidth = EID.Config["LocalModeCentered"] and tonumber(EID.Config["TextboxWidth"])/2 * EID.Scale or -30 local textPosOffset = Vector(-textBoxWidth, 20) EID:alterTextPos(Isaac.WorldToScreen(entity.Position + textPosOffset)) - if isMirrorRoom then + if EID.isMirrorRoom then EID:alterTextPos(Isaac.WorldToScreen(entity.Position + textPosOffset * Vector(-1,0))) local screenCenter = EID:getScreenSize()/2 EID.UsedPosition.X = EID.UsedPosition.X - (EID.UsedPosition-screenCenter).X * 2 @@ -1362,7 +1363,7 @@ local function onRender(t) -- Handle Glitched Items elseif closest.Type == 5 and closest.Variant == 100 and closest.SubType > 4294960000 then if EID:getEntityData(closest, "EID_DontHide") ~= true then - if (EID:hasCurseBlind() and not closest:ToPickup().Touched and EID.Config["DisableOnCurse"] and not isDeathCertRoom) or (EID.Config["DisableOnAltPath"] and not closest:ToPickup().Touched and EID:IsAltChoice(closest)) or (game.Challenge == Challenge.CHALLENGE_APRILS_FOOL and EID.Config["DisableOnAprilFoolsChallenge"]) then + if (EID:hasCurseBlind() and not closest:ToPickup().Touched and EID.Config["DisableOnCurse"] and not EID.isDeathCertRoom) or (EID.Config["DisableOnAltPath"] and not closest:ToPickup().Touched and EID:IsAltChoice(closest)) or (game.Challenge == Challenge.CHALLENGE_APRILS_FOOL and EID.Config["DisableOnAprilFoolsChallenge"]) then EID:addDescriptionToPrint({ Description = "QuestionMark", Entity = closest}) end end @@ -1420,7 +1421,7 @@ local function onRender(t) elseif closest.Variant == PickupVariant.PICKUP_COLLECTIBLE then --Handle Collectibles if EID:getEntityData(closest, "EID_DontHide") ~= true then - if (EID:hasCurseBlind() and not closest:ToPickup().Touched and EID.Config["DisableOnCurse"] and not isDeathCertRoom) or (EID.Config["DisableOnAltPath"] and not closest:ToPickup().Touched and EID:IsAltChoice(closest)) or (game.Challenge == Challenge.CHALLENGE_APRILS_FOOL and EID.Config["DisableOnAprilFoolsChallenge"]) then + if (EID:hasCurseBlind() and not closest:ToPickup().Touched and EID.Config["DisableOnCurse"] and not EID.isDeathCertRoom) or (EID.Config["DisableOnAltPath"] and not closest:ToPickup().Touched and EID:IsAltChoice(closest)) or (game.Challenge == Challenge.CHALLENGE_APRILS_FOOL and EID.Config["DisableOnAprilFoolsChallenge"]) then EID:addDescriptionToPrint({ Description = "QuestionMark", Entity = closest}) end end @@ -1502,7 +1503,7 @@ local function onRender(t) local demoDescObj = EID:getDescriptionObj(-999, -1, 1) demoDescObj.Name = "" demoDescObj.Description = EID:getHoldMapDescription(EID.holdTabPlayer) - EID:addDescriptionToPrint(demoDescObj, 1) + if (demoDescObj.Description ~= "") then EID:addDescriptionToPrint(demoDescObj, 1) end end EID:printDescriptions() From a62b02c2537edd1d087a9f0622855cfd40e0082b Mon Sep 17 00:00:00 2001 From: Buurazu Date: Mon, 6 Jun 2022 13:46:30 -0400 Subject: [PATCH 17/39] Error Room, Red Room, Poop Spells --- eid_data.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/eid_data.lua b/eid_data.lua index 8e12e15e..1a866bd0 100644 --- a/eid_data.lua +++ b/eid_data.lua @@ -278,6 +278,7 @@ EID.InlineIcons = { ["HolyChestRoomIcon"] = {"roomicons", 32, 6, 9, 0, 4}, ["WoodenChestRoomIcon"] = {"roomicons", 33, 6, 9, 0, 4}, ["Teleporter"] = {"roomicons", 34, 9, 9, 0, 2}, + ["ErrorRoom"] = {"roomicons", 35, 9, 9, 0, 2}, -- Roomshape Icons ["Room"] = {"roomshape", 0, 10, 9, 0, 2}, @@ -292,6 +293,7 @@ EID.InlineIcons = { ["RoomLTopLeft"] = {"roomshape", 9, 11, 10, 0, 1}, ["RoomLBottomLeft"] = {"roomshape", 10, 11, 10, 0, 1}, ["RoomLBottomRight"] = {"roomshape", 11, 11, 10, 0, 1}, + ["RedRoom"] = {"roomshape", 12, 10, 9, 0, 2}, -- Transformation Icons ["CustomTransformation"] = {"TransformationCustom", 0, 16, 16, -5, -1, EID.IconSprite}, @@ -371,6 +373,19 @@ EID.InlineIcons = { ["Crafting29"] = {"Crafting", 29, 14, 16, 0, -1}, ["Crafting30"] = {"Crafting", 30, 14, 16, 0}, + --Poop Spells + ["PoopSpell1"] = {"PoopSpells", 1, 16, 16, -2, -2}, --Normal + ["PoopSpell2"] = {"PoopSpells", 2, 16, 16, -2, -2}, --Corn + ["PoopSpell3"] = {"PoopSpells", 3, 16, 16, -2, -2}, --Burning + ["PoopSpell4"] = {"PoopSpells", 4, 16, 16, -2, -2}, --Stone + ["PoopSpell5"] = {"PoopSpells", 5, 16, 16, -2, -2}, --Stinky + ["PoopSpell6"] = {"PoopSpells", 6, 16, 16, -2, -2}, --Black + ["PoopSpell7"] = {"PoopSpells", 7, 16, 16, -2, -2}, --Holy + ["PoopSpell8"] = {"PoopSpells", 8, 16, 16, -2, -2}, --Creep + ["PoopSpell9"] = {"PoopSpells", 9, 16, 16, -2, -2}, --Fart + ["PoopSpell10"] = {"PoopSpells", 10, 16, 16, -2, -2}, --Bomb + ["PoopSpell11"] = {"PoopSpells", 11, 16, 16, -2, -2}, --Explosive Diarrhea + -- Use the Stat Icon name without REP or AB to display the stat icon for the dlc the user is using right now. Example: {{Damage}} -- Stats (Repentance) ["DamageREP"] = {"Stats", 0, 12, 16, 0, -1}, From 00c369c3044659ad53efa1bc5410ee71ab9a02b5 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Mon, 6 Jun 2022 13:46:40 -0400 Subject: [PATCH 18/39] Add files via upload --- eid_holdmapdesc.lua | 140 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 eid_holdmapdesc.lua diff --git a/eid_holdmapdesc.lua b/eid_holdmapdesc.lua new file mode 100644 index 00000000..7ac88b06 --- /dev/null +++ b/eid_holdmapdesc.lua @@ -0,0 +1,140 @@ +local game = Game() +local level +local currentRoom + +local function append(icon, title, newDesc) + return (icon or "{{Blank}}") .. " {{ColorEIDObjName}}" .. title .. "#" .. newDesc .. "#" +end + +local function RNGNext(num, shift1, shift2, shift3) + num = num ~ ((num >> shift1) & 4294967295) + num = num ~ ((num << shift2) & 4294967295) + num = num ~ ((num >> shift3) & 4294967295) + return num >> 0; +end +local function SeedToFloat(seed) + local multi = 2.3283061589829401E-10; + return seed * multi; +end + +-- Teleport 2 Destination Prediction -- +local teleport2Order = { 1,5,8,2,4,13,21,12,10,6,11,18,19,9,20,24,7,666,14,3 } +local teleport2GreedOrder = { 1,5,2,4,10,23,8,14,3 } +local teleport2Icons = { "{{Room}}","{{BossRoom}}","{{SuperSecretRoom}}","{{Shop}}","{{TreasureRoom}}","{{SacrificeRoom}}","{{DiceRoom}}","{{Library}}","{{CursedRoom}}","{{MiniBoss}}","{{ChallengeRoom}}","{{IsaacsRoom}}","{{BarrenRoom}}","{{ArcadeRoom}}","{{ChestRoom}}","{{Planetarium}}","{{SecretRoom}}","{{RedRoom}}","{{AngelDevilChance}}","{{ErrorRoom}}" } +local teleport2GreedIcons = { "{{RoomLongVertical}}","{{BossRoom}}","{{Shop}}","{{TreasureRoom}}","{{CursedRoom}}","{{Room}}","{{SuperSecretRoom}}","{{AngelDevilChance}}","{{ErrorRoom}}" } + +local function teleport2Prediction(holdMapDesc) + 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 + if room.Data.Type ~= 1 and room.Flags & 1024 == 1024 then unclearedTypes[666] = 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[14] = true end + + local greed = game:IsGreedMode() + local roomOrder = (greed and teleport2GreedOrder) or teleport2Order + local roomIcons = (greed and teleport2GreedIcons) or teleport2Icons + local roomNames = (greed and EID:getDescriptionEntry("Teleport2GreedRoomNames")) or EID:getDescriptionEntry("Teleport2RoomNames") + + for i,v in ipairs(roomOrder) do + if unclearedTypes[v] then return append("{{Collectible419}}", EID:getObjectName(5, 100, 419) .. EID:getDescriptionEntry("HoldMapHeader"), roomIcons[i] .. " " .. roomNames[i]) end + end +end +-- + +--order of checking: 15, 48, 58, 63, 65 +--(pennies, damage, hearts, item, leviathan, nothing) +local sanguineResults = { { 0.15, 3 }, { 0.48, 2 }, { 0.58, 4 }, { 0.63, 5 }, { 0.65, 6 }, { 1, 1 } } + +function EID:getHoldMapDescription(player, checkingTwin) + local holdMapDesc = "" + local activeBlacklist = {} + level = game:GetLevel() + currentRoom = level:GetCurrentRoom() + + -- TODO: "you just picked up" desc (great for curse of blind) + -- D1, crooked penny cheats. 404/liberty cap/etc. "what item is it" + -- pandora's box? it shows the whole desc which is kinda useful + + + if REPENTANCE then + -- Sanguine Bond reward reminder + if player:HasCollectible(CollectibleType.COLLECTIBLE_SANGUINE_BOND) and game:GetRoom():GetType() == RoomType.ROOM_DEVIL then + local spikes = currentRoom:GetGridEntity(67) + local cheatResult = nil + -- we haven't made the setting for this stuff yet + if spikes and EID.TheSettingThatAllowsCheating then + local spikeSeed = currentRoom:GetGridEntity(67):GetRNG():GetSeed() + spikeSeed = RNGNext(spikeSeed, 5, 9, 7) + spikeSeed = RNGNext(spikeSeed, 1, 5, 0x13) + + for k,v in ipairs(sanguineResults) do + if SeedToFloat(spikeSeed) < v[1] then cheatResult = v[2] break end + end + end + + local descObj = EID:getDescriptionObj(5, 100, 692) + 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 .. "{{ColorGreen}}" end + resultsDesc = resultsDesc .. w .. "#" + end + end + + holdMapDesc = holdMapDesc .. append("{{Collectible692}}", descObj.Name, resultsDesc) + end + + -- Tainted ??? Poop Preview + local nextPoop = player:GetPoopSpell(0) + if player:GetPoopMana() > 0 then + local poopInfo = EID:getDescriptionEntry("poopSpells") + holdMapDesc = holdMapDesc .. append("{{PoopSpell" .. nextPoop .. "}}", poopInfo[nextPoop][1], poopInfo[nextPoop][2]) + end + end + + -- Teleport 2.0 location + if player:HasCollectible(CollectibleType.COLLECTIBLE_TELEPORT_2) and not EID.isMirrorRoom then + holdMapDesc = holdMapDesc .. teleport2Prediction(holdMapDesc) + activeBlacklist[CollectibleType.COLLECTIBLE_TELEPORT_2] = true + end + + -- Active Item Description + local heldActive = player:GetActiveItem() + if heldActive > 0 and not activeBlacklist[heldActive] then + local demoDescObj = EID:getDescriptionObj(5, 100, heldActive) + holdMapDesc = holdMapDesc .. append("{{Collectible"..heldActive.."}}", demoDescObj.Name, demoDescObj.Description) + end + + -- + + -- Finally, check the twin player of this controller + -- If both twins have a desc, show their player icon / name to separate the two descs + if REPENTANCE and not checkingTwin then + local twin = player:GetOtherTwin() + local otherTwinDesc = "" + if twin then otherTwinDesc = EID:getHoldMapDescription(twin, true) end + if otherTwinDesc ~= "" then + if holdMapDesc == "" then holdMapDesc = otherTwinDesc + else + holdMapDesc = (EID:getIcon("Player"..player:GetPlayerType()) ~= EID.InlineIcons["ERROR"] and "{{Player"..player:GetPlayerType().."}}" or "{{CustomTransformation}}") .. " {{ColorGray}}" .. player:GetName() .. "#" .. holdMapDesc .. "#" + holdMapDesc = holdMapDesc .. (EID:getIcon("Player"..twin:GetPlayerType()) ~= EID.InlineIcons["ERROR"] and "{{Player"..twin:GetPlayerType().."}}" or "{{CustomTransformation}}") .. " {{ColorGray}}" .. twin:GetName() .. "#" .. otherTwinDesc + end + end + end + + return holdMapDesc +end \ No newline at end of file From bab22041311844ca321bea5e42950f893d21bf69 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 10 Jun 2022 04:48:21 -0400 Subject: [PATCH 19/39] Chaos Card update --- descriptions/ab+/en_us.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/descriptions/ab+/en_us.lua b/descriptions/ab+/en_us.lua index 9393e604..20923546 100644 --- a/descriptions/ab+/en_us.lua +++ b/descriptions/ab+/en_us.lua @@ -234,7 +234,7 @@ EID.descriptions[languageCode].collectibles={ {"212", "Guppy's Collar", "50% chance to revive with half a heart on death"}, {"213", "Lost Contact", "Shielded tears#Tears block enemy shots#↓ {{Shotspeed}} -0.15 Shot Speed down"}, {"214", "Anemic", "↑ {{Range}} +5 Range up#Leave a trail of damaging creep after taking damage"}, - {"215", "Goat Head", "{{AngelDevilChance}} 100% chance for Devil/Angel Rooms"}, + {"215", "Goat Head", "{{AngelDevilChance}} 100% chance for Devil/Angel Rooms to spawn"}, {"216", "Ceremonial Robes", "↑ {{Damage}} +1 Damage up#{{BlackHeart}} +3 Black Hearts"}, {"217", "Mom's Wig", "Random chance to spawn blue spider when shooting tears#{{Heart}} Heals 1 Red Heart"}, {"218", "Placenta", "↑ {{Heart}} +1 Health up#{{HalfHeart}} Chance to heal half a heart every minute"}, @@ -520,7 +520,7 @@ EID.descriptions[languageCode].collectibles={ {"496", "Euthanasia", "3.33% chance to shoot needles#100% chance at 15 Luck#Needles kill normal enemies instantly, bursting them into 10 tears#Needles deal 3x damage against bosses"}, {"497", "Camo Undies", "When you enter a room, camouflage yourself and confuse all enemies until you start shooting"}, {"498", "Duality", "{{AngelDevilChance}} If an Angel or Devil room would spawn, both will spawn#When entering one, the other disappears"}, - {"499", "Eucharist", "{{AngelChance}} 100% chance to find an {{AngelRoom}}Angel Room"}, + {"499", "Eucharist", "{{AngelChance}} 100% chance for Angel Rooms to spawn"}, {"500", "Sack of Sacks", "Spawns a sack every 5-6 rooms"}, {"501", "Greed's Gullet", "Gain 1 Heart Container for every 25 coins you gain after picking up Greed's Gullet#{{Player14}} Keeper can gain additional Coin Hearts"}, {"502", "Large Zit", "While firing, occasionally shoot a white creep tear that deals double damage#Shoot a white creep tear when damaged"}, @@ -751,7 +751,7 @@ EID.descriptions[languageCode].cards={ {"39", "Algiz", "Invincibility for 30 seconds"}, {"40", "Blank Rune", "Random rune effect#25% chance to drop itself again"}, {"41", "Black Rune", "Deals 40 damage to all enemies#Converts all pedestal items in the room into random stat ups#Converts all pickups in the room into blue flies"}, - {"42", "Chaos Card", "Throwable instant kill-card"}, + {"42", "Chaos Card", "Upon use, throw the card in the direction you're moving#Instantly kills ANY enemy it touches (except Delirium)"}, {"43", "Credit Card", "Removes the price from all items in the current {{Shop}} shop or {{DevilRoom}} Devil deal, making everything free"}, {"44", "Rules Card", "Displays \"helpful\" tips on use"}, {"45", "A Card Against Humanity", "Fills the whole room with poop"}, From b527cf344eabdd596e1d7f9fc88012c2c710074a Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 10 Jun 2022 04:48:41 -0400 Subject: [PATCH 20/39] Chaos Card --- 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 5610e4da..f6b91569 100644 --- a/descriptions/rep/en_us.lua +++ b/descriptions/rep/en_us.lua @@ -385,7 +385,7 @@ local repCollectibles={ [712] = {"712", "Lemegeton", "Spawns an orbital wisp familiar that grants an item's effect but can be destroyed#The items have a 25% chance to be from the current room's item pool, or from the Treasure, Boss or Shop pools otherwise"}, -- Lemegeton [713] = {"713", "Sumptorium", "Removes half a heart and creates a Clot familiar#Each type of heart generates a Clot with different HP, damage and tear effect"}, -- Sumptorium [714] = {"714", "Recall", "Retrieves the Forgotten's body from any distance"}, -- Recall - [715] = {"715", "Hold", "Preserves one poop bomb inside that can be used later"}, -- Hold + [715] = {"715", "Hold", "Preserves one Poop spell inside that can be used later"}, -- Hold [716] = {"716", "Keeper's Sack", "Spawns {{Coin}} 3 random coins and {{Key}} 1 key#{{Shop}} Every 3 coins spent when buying items gives one of the following:#↑ {{Damage}} +0.5 Damage up#↑ {{Range}} +0.25 Range up#↑ {{Speed}} +0.03 Speed up"}, -- Keeper's Sack [717] = {"717", "Keeper's Kin", "Rocks and props spawn 2 blue spiders when destroyed#Rocks can occasionally spawn blue spiders when in a hostile room"}, -- Keeper's Kin [718] = {"718", "Keeper's Rope (Cut item)", ""}, -- Keepers Rope (Cut item) @@ -831,6 +831,7 @@ local repCards={ [30] = {"30", "Ace of Hearts", "{{Heart}} Turns all pickups, chests and non-boss enemies into hearts"}, -- Ace of Hearts [34] = {"34", "Ehwaz", "Spawns a trapdoor to the next floor#Spawns a {{LadderRoom}} crawlspace if used on a decorative floor tile (grass, small rocks, papers, gems, etc.)"}, [39] = {"39", "Algiz", "Invincibility for 20 seconds"}, -- Algiz + [42] = {"42", "Chaos Card", "Upon use, throw the card in the direction you're moving#Instantly kills ANY enemy it touches (except Delirium or The Beast)"}, -- Chaos Card [51] = {"51", "Holy Card", "{{HolyMantle}} Grants the Holy Mantle effect#(Prevents damage once)#Effect lasts until damage is taken"}, -- Holy Card [52] = {"52", "Huge Growth", "↑ {{Damage}} +7 Damage up#↑ {{Range}} +3 Range up#Destroy rocks when walking over them#Size up#Effect lasts for current room"}, -- Huge Growth [54] = {"54", "Era Walk", "{{Slow}} Slow down enemies#↑ {{Speed}} +0.5 Speed up#↓ {{Shotspeed}} -1 Shot Speed down#Effect lasts for current room"}, From 39c631804206edb4ecf72ee37f19d0aa539cd126 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 10 Jun 2022 04:49:42 -0400 Subject: [PATCH 21/39] Item Reminder config settings --- eid_config.lua | 49 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/eid_config.lua b/eid_config.lua index f13bf3a8..663425c5 100644 --- a/eid_config.lua +++ b/eid_config.lua @@ -281,7 +281,38 @@ EID.UserConfig = { -- Toggle display of what stats will increase on Void absorption -- Default = false ["DisplayVoidStatInfo"] = false, - + + ---------- Item Reminder Description ------------ + --Hold Map (or the button action chosen below) to show a description of your active item's effect, recently picked up items, and things like Teleport 2.0's destination and Void's absorbed items + ["ItemReminderEnabled"] = true, + -- Set the keybinding that's held to show the Item Reminder description, Flip/Spindown Dice preview descriptions, and interacting with the Bag of Crafting recipe list + -- Look into the AB+ or Repentance documentation for the key names here: https://wofsauge.github.io/IsaacDocs/rep/enums/ButtonAction.html + -- Default = ButtonAction.ACTION_MAP + ["BagOfCraftingToggleKey"] = ButtonAction.ACTION_MAP, + -- Show recently acquired item descriptions in the Item Reminder (good for Curse of the Blind!) + -- Default = 1 + ["ItemReminderShowRecentItem"] = 1, + -- Show your active item description(s) in the Item Reminder + -- Default = 1, max = 2 + ["ItemReminderShowActiveDesc"] = 1, + -- Show your pocket item (card, pill, active) description in the Item Reminder + -- Default = 1, max = 4 (2 in AB+) + ["ItemReminderShowPocketDesc"] = 1, + -- Show your trinket description(s) in the Item Reminder + -- Default = 2, max = 2 + ["ItemReminderShowTrinketDesc"] = 2, + -- Show your next Poop Spell's description in the Item Reminder + -- REPENTANCE ONLY!!! + -- Default = 1, max = 6 + ["ItemReminderShowPoopDesc"] = 1, + -- Items that grant you items without saying what they are (like Zodiac, Liberty Cap) can have their current granted item revealed in the Item Reminder + -- Default = false + ["ItemReminderShowHiddenInfo"] = false, + -- Some items (like Crooked Penny) can have their next result predicted and shown in the Item Reminder + -- Default = false + ["ItemReminderShowRNGCheats"] = false, + + ---------- Bag of Crafting ------------ -- REPENTANCE ONLY!!! @@ -315,10 +346,6 @@ EID.UserConfig = { -- Higher numbers will cause lag spikes on new pickup sets! -- Default = 400 ["BagOfCraftingRandomResults"] = 400, - -- Set the keybinding that's held to show the Item Reminder description, Flip/Spindown Dice preview descriptions, and interacting with the Bag of Crafting recipe list - -- Look into the AB+ or Repentance documentation for the key names here: https://wofsauge.github.io/IsaacDocs/rep/enums/ButtonAction.html - -- Default = ButtonAction.ACTION_MAP - ["BagOfCraftingToggleKey"] = ButtonAction.ACTION_MAP, -- Display craftable item names, moving the recipe to a new line -- Default = false ["BagOfCraftingDisplayNames"] = false, @@ -492,7 +519,6 @@ EID.DefaultConfig = { ["BagOfCraftingResults"] = 7, ["BagOfCraftingCombinationMax"] = 12, ["BagOfCraftingRandomResults"] = 400, - ["BagOfCraftingToggleKey"] = ButtonAction.ACTION_MAP, ["BagOfCraftingDisplayNames"] = false, ["BagOfCraftingDisplayIcons"] = false, ["BagOfCraftingHideInBattle"] = true, @@ -502,6 +528,17 @@ EID.DefaultConfig = { ["CraftingHideButton"] = -1, ["CraftingResultKey"] = Keyboard.KEY_F4, ["CraftingResultButton"] = -1, + + ["ItemReminderEnabled"] = true, + ["BagOfCraftingToggleKey"] = ButtonAction.ACTION_MAP, + ["ItemReminderShowRecentItem"] = 1, + ["ItemReminderShowActiveDesc"] = 1, + ["ItemReminderShowPocketDesc"] = 1, + ["ItemReminderShowTrinketDesc"] = 2, + ["ItemReminderShowPoopDesc"] = 1, + ["ItemReminderShowHiddenInfo"] = false, + ["ItemReminderShowRNGCheats"] = false, + ["SpindownDiceResults"] = 3, ["SpindownDiceDisplayID"] = false, ["SpindownDiceDisplayName"] = false, From 53650de5649017aa01484ef736a2f3d6e44550f9 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 10 Jun 2022 04:50:01 -0400 Subject: [PATCH 22/39] Item Reminder settings --- eid_mcm.lua | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/eid_mcm.lua b/eid_mcm.lua index a7ef9dbc..b23683ec 100644 --- a/eid_mcm.lua +++ b/eid_mcm.lua @@ -389,6 +389,35 @@ if MCMLoaded then --------------------------------------------------------------------------- ---------------------------------Display----------------------------------- + + -- Item Reminder Settings -- + + EID:AddBooleanSetting("Display", "ItemReminderEnabled", "Item Reminder Description", {offText = "Disabled", onText = "Enabled", infoText = "Hold Map to show your active item's effect, recently picked up items, and much more"}) + + local actionToName = { [0] = "Move Left", "Move Right", "Move Up", "Move Down", "Shoot Left", "Shoot Right", "Shoot Up", "Shoot Down", "Bomb", "Item", "Pill/Card", "Drop", "Pause", "Map" } + + EID:AddNumberSetting("Display", "BagOfCraftingToggleKey", "Hold to Show", 8, 13, {displayTable = actionToName, + infoText = {"Hold this key to display the Item Reminder description, show Flip/Spindown previews and control the Bag of Crafting recipe list"}}) + + local itemSlotReminders = { [0] = "No", "Yes (max 1)", "Yes (max 2)", "Yes (max 3)", "Yes (max 4)", "Yes (max 5)", + "Yes (max 6)", "Yes (max 7)", "Yes (max 8)" } + + + -- should these be organized in the order they're shown in the map desc code? + EID:AddNumberSetting("Display", "ItemReminderShowRecentItem", "Recent Item Descriptions", 0, 4, { displayTable = itemSlotReminders, infoText = {"Show recently acquired item descriptions in the Item Reminder (good for Curse of the Blind!)"}}) + EID:AddNumberSetting("Display", "ItemReminderShowActiveDesc", "Active Item Descriptions", 0, 2, { displayTable = itemSlotReminders, infoText = "Show your active item descriptions in the Item Reminder"}) + EID:AddNumberSetting("Display", "ItemReminderShowPocketDesc", "Pocket Item Descriptions", 0, 4, { displayTable = itemSlotReminders, infoText = "Show your pocket item (card, pill, active) descriptions in the Item Reminder"}) + EID:AddNumberSetting("Display", "ItemReminderShowTrinketDesc", "Trinket Descriptions", 0, 2, { displayTable = itemSlotReminders, infoText = "Show your trinket descriptions in the Item Reminder"}) + + EID:AddNumberSetting("Display", "ItemReminderShowPoopDesc", "Poop Descriptions", 0, 6, { repOnly = true, displayTable = itemSlotReminders, infoText = "Show Tainted ???'s next Poop Spell descriptions in the Item Reminder"}) + + EID:AddBooleanSetting("Display", "ItemReminderShowHiddenInfo", "Show Hidden Information", { infoText = "Items that grant you items without saying what they are (like Zodiac, Liberty Cap) can have their current granted item revealed in the Item Reminder"}) + EID:AddBooleanSetting("Display", "ItemReminderShowRNGCheats", "Show RNG Predictions", { infoText = "Some items (like Crooked Penny) can have their next result predicted and shown in the Item Reminder"}) + MCM.AddSpace("EID", "Display") + + -- + + local refreshRateSteps = {1, 2, 3, 4, 6, 10, 12, 15, 20, 30, 60} EID:AddScrollSetting("Display", "RefreshRate", "Description Refresh Rate", refreshRateSteps, {infoText = "How many times per second that EID updates what description to show"}) From 0b09986ee1b7eddd05887b179d0a4788ae764427 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 10 Jun 2022 04:50:21 -0400 Subject: [PATCH 23/39] Update eid_holdmapdesc.lua --- eid_holdmapdesc.lua | 81 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 13 deletions(-) diff --git a/eid_holdmapdesc.lua b/eid_holdmapdesc.lua index 7ac88b06..96472bd5 100644 --- a/eid_holdmapdesc.lua +++ b/eid_holdmapdesc.lua @@ -62,16 +62,21 @@ function EID:getHoldMapDescription(player, checkingTwin) -- TODO: "you just picked up" desc (great for curse of blind) -- D1, crooked penny cheats. 404/liberty cap/etc. "what item is it" - -- pandora's box? it shows the whole desc which is kinda useful + -- pandora's box? it shows the whole desc which is kinda useful + -- Void's absorbed items list + -- Luna beam effect? + -- D Infinity current dice; track our Drop presses and resync it each time D Infinity is used by watching for the next dice effect triggered (Predict its next dice in AB+?) + -- test how this works in co-op when co-op baby holds map! they should be ignored! + if REPENTANCE then -- Sanguine Bond reward reminder if player:HasCollectible(CollectibleType.COLLECTIBLE_SANGUINE_BOND) and game:GetRoom():GetType() == RoomType.ROOM_DEVIL then local spikes = currentRoom:GetGridEntity(67) local cheatResult = nil -- we haven't made the setting for this stuff yet - if spikes and EID.TheSettingThatAllowsCheating then + if spikes and EID.Config["ItemReminderShowRNGCheats"] then local spikeSeed = currentRoom:GetGridEntity(67):GetRNG():GetSeed() spikeSeed = RNGNext(spikeSeed, 5, 9, 7) spikeSeed = RNGNext(spikeSeed, 1, 5, 0x13) @@ -98,11 +103,14 @@ function EID:getHoldMapDescription(player, checkingTwin) holdMapDesc = holdMapDesc .. append("{{Collectible692}}", descObj.Name, resultsDesc) end - -- Tainted ??? Poop Preview - local nextPoop = player:GetPoopSpell(0) - if player:GetPoopMana() > 0 then - local poopInfo = EID:getDescriptionEntry("poopSpells") - holdMapDesc = holdMapDesc .. append("{{PoopSpell" .. nextPoop .. "}}", poopInfo[nextPoop][1], poopInfo[nextPoop][2]) + -- Tainted ??? Poop Descriptions + if EID.Config["ItemReminderShowPoopDesc"] > 0 and player:GetPlayerType() == 25 then + activeBlacklist[715] = true --blacklist Hold + for i = 0, EID.Config["ItemReminderShowPoopDesc"]-1 do + local poopInfo = EID:getDescriptionEntry("poopSpells") + local nextPoop = player:GetPoopSpell(i) + holdMapDesc = holdMapDesc .. append("{{PoopSpell" .. nextPoop .. "}}", poopInfo[nextPoop][1], poopInfo[nextPoop][2]) + end end end @@ -112,11 +120,58 @@ function EID:getHoldMapDescription(player, checkingTwin) activeBlacklist[CollectibleType.COLLECTIBLE_TELEPORT_2] = true end - -- Active Item Description - local heldActive = player:GetActiveItem() - if heldActive > 0 and not activeBlacklist[heldActive] then - local demoDescObj = EID:getDescriptionObj(5, 100, heldActive) - holdMapDesc = holdMapDesc .. append("{{Collectible"..heldActive.."}}", demoDescObj.Name, demoDescObj.Description) + --TODO: RECENT ITEMS TRACKING (reset per room clear? or just use timestamps?) + + -- Active Item Descriptions + if EID.Config["ItemReminderShowActiveDesc"] > 0 then + for i = 0, EID.Config["ItemReminderShowActiveDesc"]-1 do + local heldActive = player:GetActiveItem(i) + if heldActive > 0 and not activeBlacklist[heldActive] then + local demoDescObj = EID:getDescriptionObj(5, 100, heldActive) + holdMapDesc = holdMapDesc .. append("{{Collectible"..heldActive.."}}", demoDescObj.Name, demoDescObj.Description) + end + end + end + + -- Pocket Item Descriptions + -- Annoying because there's no easy way to just get the info of a slot + if EID.Config["ItemReminderShowPocketDesc"] > 0 then + local numPrinted = 0 + -- I don't think we can actually know what slot the player is on, so, save these to display (if they exist) for when Card and Pill in a slot are both 0, to attempt to always show them in slot order + local dicePrinted = false + local diceBag = REPENTANCE and player:GetActiveItem(3) or 0 + local pocketPrinted = false + local pocketActive = REPENTANCE and player:GetActiveItem(2) or 0 + for i = 0, EID.Config["ItemReminderShowPocketDesc"]-1 do + local heldCard = player:GetCard(i) + local heldPill = player:GetPill(i) + if heldCard > 0 then + -- Get the card desc + elseif heldPill > 0 then + -- Get the pill effect + elseif diceBag > 0 and not activeBlacklist[diceBag] and not dicePrinted then + dicePrinted = true + local demoDescObj = EID:getDescriptionObj(5, 100, diceBag) + holdMapDesc = holdMapDesc .. append("{{Trinket154}}", demoDescObj.Name, demoDescObj.Description) + elseif pocketActive > 0 and not activeBlacklist[heldActive] and not pocketPrinted then + pocketPrinted = true + local demoDescObj = EID:getDescriptionObj(5, 100, pocketActive) + holdMapDesc = holdMapDesc .. append("{{Collectible"..pocketActive.."}}", demoDescObj.Name, demoDescObj.Description) + -- we'll have to add tainted char specific text for their actives with unique effects for that character! + end + end + end + + -- Trinket Descriptions + if EID.Config["ItemReminderShowTrinketDesc"] > 0 then + for i = 0, EID.Config["ItemReminderShowTrinketDesc"]-1 do + local heldActive = player:GetTrinket(i) + if heldActive > 0 and not activeBlacklist[heldActive] then + -- test this with golden trinkets / mom's box!!! + local demoDescObj = EID:getDescriptionObj(5, 350, heldActive) + holdMapDesc = holdMapDesc .. append("{{Trinket"..heldActive.."}}", demoDescObj.Name, demoDescObj.Description) + end + end end -- @@ -137,4 +192,4 @@ function EID:getHoldMapDescription(player, checkingTwin) end return holdMapDesc -end \ No newline at end of file +end From 360c1239cbfc72613afd875f41b4959f688626b1 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 10 Jun 2022 06:03:28 -0400 Subject: [PATCH 24/39] check the new config setting --- main.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/main.lua b/main.lua index 68a032e9..99bbef9c 100644 --- a/main.lua +++ b/main.lua @@ -1497,9 +1497,8 @@ local function onRender(t) end -- handle showing the Hold Map Helper description - if EID.holdTabCounter >= 30 and EID.TabDescThisFrame == false and EID.holdTabPlayer ~= nil then - --hey wait, Esau's getting screwed by how we're handling holdTabPlayer right now - --also, have we done anything that makes AB+ get angry? + if EID.Config["ItemReminderEnabled"] and EID.holdTabCounter >= 30 and EID.TabDescThisFrame == false and EID.holdTabPlayer ~= nil then + --have we done anything that makes AB+ get angry? still need to test AB+! local demoDescObj = EID:getDescriptionObj(-999, -1, 1) demoDescObj.Name = "" demoDescObj.Description = EID:getHoldMapDescription(EID.holdTabPlayer) From 21791b87f0ae3ceabd1bc2727ab001332a51799d Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 10 Jun 2022 19:59:23 -0400 Subject: [PATCH 25/39] reset recently touched items each room --- main.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.lua b/main.lua index 99bbef9c..41fb4cad 100644 --- a/main.lua +++ b/main.lua @@ -762,6 +762,8 @@ end -- On new room, save the status of any variables that need to be rewound upon Glowing Hourglass usage function EID:onNewRoom() + EID.RecentlyTouchedItems = {} + local curRoomIndex = game:GetLevel():GetCurrentRoomIndex() preHourglassStatus = {} From 02c32bd2a925e0982db920c1c8700cec14233218 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 10 Jun 2022 20:00:06 -0400 Subject: [PATCH 26/39] Don't check co-op pill effects in Item Reminder --- eid_modifiers.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eid_modifiers.lua b/eid_modifiers.lua index 70a8d83e..2fc6f58e 100644 --- a/eid_modifiers.lua +++ b/eid_modifiers.lua @@ -481,6 +481,8 @@ if REPENTANCE then -- Handle co-op players seeing different pill effects local function CoopPillCallback(descObj) + -- Don't do this check when holding Tab for pill effects + if not descObj.Entity then return descObj end local printedDescs = { [descObj.Name] = true } for i = 1,#EID.coopAllPlayers do From 04477507bb97df02f01a294ca831d4aa8e2a3e58 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 10 Jun 2022 20:00:27 -0400 Subject: [PATCH 27/39] Track recently touched items --- eid_api.lua | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/eid_api.lua b/eid_api.lua index c48facca..f2c076b7 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -1624,7 +1624,9 @@ function EID:evaluateTransformationProgress(transformation) end -- Watch for a player's queued item (holding an item over their head) to track active item touches +-- Used for Transformation Progress and for tracking Recently Touched Items EID.PlayerItemInteractions = {} +EID.RecentlyTouchedItems = {} local hadQueuedItem = {} function EID:evaluateQueuedItems() --initialize the interactions table for all players if it isn't already @@ -1633,6 +1635,7 @@ function EID:evaluateQueuedItems() if not EID.PlayerItemInteractions[i] then EID.PlayerItemInteractions[i] = {LastTouch = 0, actives = {}, pills = {}, altActives = {}, altPills = {}} end + EID.RecentlyTouchedItems[i] = EID.RecentlyTouchedItems[i] or {} end for i = 0, game:GetNumPlayers() - 1 do local player = Isaac.GetPlayer(i) @@ -1647,25 +1650,31 @@ function EID:evaluateQueuedItems() else EID.PlayerItemInteractions[i].LastTouch = 0 end - - if not player.QueuedItem.Touched and player.QueuedItem.Item and player.QueuedItem.Item.Type == ItemType.ITEM_ACTIVE then - local itemID = tostring(player.QueuedItem.Item.ID) - -- A new active item was touched; initiate its touch count to 0 for all players - -- (Fixes co-op bugs, compared to only initiating it for the toucher) - for j = 0, game:GetNumPlayers() - 1 do - local player = Isaac.GetPlayer(j) - EID.PlayerItemInteractions[j].actives[itemID] = EID.PlayerItemInteractions[j].actives[itemID] or 0 - EID.PlayerItemInteractions[j].altActives[itemID] = EID.PlayerItemInteractions[j].altActives[itemID] or 0 - end - - -- Dead Tainted Lazarus exceptions - local activesTable = EID.PlayerItemInteractions[i].actives - if player:GetPlayerType() == 38 then - activesTable = EID.PlayerItemInteractions[i].altActives or activesTable - end - EID.ForceRefreshCache = true - activesTable[itemID] = activesTable[itemID] + 1 + + if not player.QueuedItem.Touched and player.QueuedItem.Item then EID.PlayerItemInteractions[i].LastTouch = game:GetFrameCount() + + if player.QueuedItem.Item.Type == ItemType.ITEM_ACTIVE then + local itemID = tostring(player.QueuedItem.Item.ID) + -- A new active item was touched; initiate its touch count to 0 for all players + -- (Fixes co-op bugs, compared to only initiating it for the toucher) + for j = 0, game:GetNumPlayers() - 1 do + local player = Isaac.GetPlayer(j) + EID.PlayerItemInteractions[j].actives[itemID] = EID.PlayerItemInteractions[j].actives[itemID] or 0 + EID.PlayerItemInteractions[j].altActives[itemID] = EID.PlayerItemInteractions[j].altActives[itemID] or 0 + end + + -- Dead Tainted Lazarus exceptions + local activesTable = EID.PlayerItemInteractions[i].actives + if player:GetPlayerType() == 38 then + activesTable = EID.PlayerItemInteractions[i].altActives or activesTable + end + EID.ForceRefreshCache = true + activesTable[itemID] = activesTable[itemID] + 1 + elseif player.QueuedItem.Item.Type ~= ItemType.ITEM_TRINKET then + -- Put non-active item pickups into the recent item list, for printing in the Item Reminder + table.insert(EID.RecentlyTouchedItems[i], player.QueuedItem.Item.ID) + end end end end From 5a36153dafd2500540b84f3632fcf5979b4c9d93 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Fri, 10 Jun 2022 20:00:50 -0400 Subject: [PATCH 28/39] Update eid_holdmapdesc.lua --- eid_holdmapdesc.lua | 82 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 9 deletions(-) diff --git a/eid_holdmapdesc.lua b/eid_holdmapdesc.lua index 96472bd5..a11df4a2 100644 --- a/eid_holdmapdesc.lua +++ b/eid_holdmapdesc.lua @@ -54,21 +54,29 @@ end --(pennies, damage, hearts, item, leviathan, nothing) local sanguineResults = { { 0.15, 3 }, { 0.48, 2 }, { 0.58, 4 }, { 0.63, 5 }, { 0.65, 6 }, { 1, 1 } } +-- 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) local holdMapDesc = "" local activeBlacklist = {} + local trinketBlacklist = {} level = game:GetLevel() currentRoom = level:GetCurrentRoom() - -- TODO: "you just picked up" desc (great for curse of blind) + -- TODO: -- D1, crooked penny cheats. 404/liberty cap/etc. "what item is it" - -- pandora's box? it shows the whole desc which is kinda useful + -- (Zodiac and Modeling Clay have functions for it?) + -- pandora's box? it shows the whole desc which is kinda useful but too big -- Void's absorbed items list -- Luna beam effect? -- D Infinity current dice; track our Drop presses and resync it each time D Infinity is used by watching for the next dice effect triggered (Predict its next dice in AB+?) - -- test how this works in co-op when co-op baby holds map! they should be ignored! + -- test how this works in co-op when co-op baby holds map! they should be ignored? + if REPENTANCE then -- Sanguine Bond reward reminder @@ -114,19 +122,63 @@ function EID:getHoldMapDescription(player, checkingTwin) end end + -- Show Hidden Info + if EID.Config["ItemReminderShowHiddenInfo"] then + -- Rainbow Worm + if player:HasTrinket(64) then + trinketBlacklist[64] = true + local rainbowWormEffect = rainbowWormEffects[math.floor(game.TimeCounter / 30 / 3) % (REPENTANCE and 10 or 8)] + if not trinketBlacklist[rainbowWormEffect] then + trinketBlacklist[rainbowWormEffect] = true + local demoDescObj = EID:getDescriptionObj(5, 350, rainbowWormEffect) + holdMapDesc = holdMapDesc .. append("{{Trinket64}}", "{{Trinket"..rainbowWormEffect.."}} " .. demoDescObj.Name, demoDescObj.Description) + end + end + -- 404 Error (And any other temporary trinket givers, such as Glitched Items) + if player:HasTrinket(75) then + trinketBlacklist[75] = true + -- Don't display Mysterious Paper's 1-frame temporary trinket granting + local hasPaper = player:HasTrinket(21) + -- is this var in AB+? + for i = 1, TrinketType.NUM_TRINKETS - 1 do + local tempTrinketFound = EID.player:HasTrinket(i, true) ~= EID.player:HasTrinket(i, false) + if tempTrinketFound and not trinketBlacklist[i] and (not mysteriousPaperBlacklist[i] or not hasPaper) then + trinketBlacklist[i] = true + local demoDescObj = EID:getDescriptionObj(5, 350, i) + holdMapDesc = holdMapDesc .. append("{{Trinket"..i.."}}", demoDescObj.Name, demoDescObj.Description) + end + end + end + end + -- Teleport 2.0 location if player:HasCollectible(CollectibleType.COLLECTIBLE_TELEPORT_2) and not EID.isMirrorRoom then holdMapDesc = holdMapDesc .. teleport2Prediction(holdMapDesc) activeBlacklist[CollectibleType.COLLECTIBLE_TELEPORT_2] = true end - --TODO: RECENT ITEMS TRACKING (reset per room clear? or just use timestamps?) + -- Recently Acquired Item Descriptions + if EID.Config["ItemReminderShowRecentItem"] > 0 then + local printedItems = 0 + local playerNum = EID:getPlayerID(player) + if EID.RecentlyTouchedItems[playerNum] then + for i = #EID.RecentlyTouchedItems[playerNum], 1, -1 do + if printedItems >= EID.Config["ItemReminderShowRecentItem"] then break end + printedItems = printedItems + 1 + local recentID = EID.RecentlyTouchedItems[playerNum][i] % 4294967296 + activeBlacklist[recentID] = true + local demoDescObj = EID:getDescriptionObj(5, 100, recentID) + holdMapDesc = holdMapDesc .. append("{{Collectible"..recentID.."}}", demoDescObj.Name, demoDescObj.Description) + end + end + end -- Active Item Descriptions if EID.Config["ItemReminderShowActiveDesc"] > 0 then for i = 0, EID.Config["ItemReminderShowActiveDesc"]-1 do - local heldActive = player:GetActiveItem(i) + local heldActive = player:GetActiveItem(i) % 4294967296 if heldActive > 0 and not activeBlacklist[heldActive] then + activeBlacklist[heldActive] = true local demoDescObj = EID:getDescriptionObj(5, 100, heldActive) holdMapDesc = holdMapDesc .. append("{{Collectible"..heldActive.."}}", demoDescObj.Name, demoDescObj.Description) end @@ -146,15 +198,26 @@ function EID:getHoldMapDescription(player, checkingTwin) local heldCard = player:GetCard(i) local heldPill = player:GetPill(i) if heldCard > 0 then - -- Get the card desc + local demoDescObj = EID:getDescriptionObj(5, 300, heldCard) + holdMapDesc = holdMapDesc .. append("{{Card"..heldCard.."}}", demoDescObj.Name, demoDescObj.Description) elseif heldPill > 0 then - -- Get the pill effect + -- Check if our held pill is identified + EID.pillPlayer = player + local identified = game:GetItemPool():IsPillIdentified(heldPill) + if REPENTANCE and heldPill % PillColor.PILL_GIANT_FLAG == PillColor.PILL_GOLD then identified = true end + if (identified or EID.Config["ShowUnidentifiedPillDescriptions"]) then + local demoDescObj = EID:getDescriptionObj(5, 70, heldPill) + holdMapDesc = holdMapDesc .. append("{{Pill"..heldPill.."}}", demoDescObj.Name, demoDescObj.Description) + end + EID.pillPlayer = nil elseif diceBag > 0 and not activeBlacklist[diceBag] and not dicePrinted then dicePrinted = true + activeBlacklist[diceBag] = true local demoDescObj = EID:getDescriptionObj(5, 100, diceBag) holdMapDesc = holdMapDesc .. append("{{Trinket154}}", demoDescObj.Name, demoDescObj.Description) - elseif pocketActive > 0 and not activeBlacklist[heldActive] and not pocketPrinted then + elseif pocketActive > 0 and not activeBlacklist[pocketActive] and not pocketPrinted then pocketPrinted = true + activeBlacklist[pocketActive] = true local demoDescObj = EID:getDescriptionObj(5, 100, pocketActive) holdMapDesc = holdMapDesc .. append("{{Collectible"..pocketActive.."}}", demoDescObj.Name, demoDescObj.Description) -- we'll have to add tainted char specific text for their actives with unique effects for that character! @@ -166,8 +229,9 @@ function EID:getHoldMapDescription(player, checkingTwin) if EID.Config["ItemReminderShowTrinketDesc"] > 0 then for i = 0, EID.Config["ItemReminderShowTrinketDesc"]-1 do local heldActive = player:GetTrinket(i) - if heldActive > 0 and not activeBlacklist[heldActive] then + if heldActive > 0 and not trinketBlacklist[heldActive] then -- test this with golden trinkets / mom's box!!! + trinketBlacklist[heldActive] = true local demoDescObj = EID:getDescriptionObj(5, 350, heldActive) holdMapDesc = holdMapDesc .. append("{{Trinket"..heldActive.."}}", demoDescObj.Name, demoDescObj.Description) end From 39874d28866c404000188f7b14da0c88b9976de9 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 11 Jun 2022 16:47:09 -0400 Subject: [PATCH 29/39] Add files via upload --- eid_holdmapdesc.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/eid_holdmapdesc.lua b/eid_holdmapdesc.lua index a11df4a2..dc0e9b17 100644 --- a/eid_holdmapdesc.lua +++ b/eid_holdmapdesc.lua @@ -32,7 +32,8 @@ local function teleport2Prediction(holdMapDesc) local room = rooms:Get(i) if not room.Clear then - if room.Data.Type ~= 1 and room.Flags & 1024 == 1024 then unclearedTypes[666] = true + -- 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[666] = true else unclearedTypes[room.Data.Type] = true end end end @@ -125,6 +126,7 @@ function EID:getHoldMapDescription(player, checkingTwin) -- Show Hidden Info if EID.Config["ItemReminderShowHiddenInfo"] then -- Rainbow Worm + -- should move this down to the normal trinket displaying code? if player:HasTrinket(64) then trinketBlacklist[64] = true local rainbowWormEffect = rainbowWormEffects[math.floor(game.TimeCounter / 30 / 3) % (REPENTANCE and 10 or 8)] @@ -135,7 +137,8 @@ function EID:getHoldMapDescription(player, checkingTwin) end end -- 404 Error (And any other temporary trinket givers, such as Glitched Items) - if player:HasTrinket(75) then + -- Unfortunately, HasTrinket can't differentiate between real and fake trinkets in AB+ + if REPENTANCE and player:HasTrinket(75) then trinketBlacklist[75] = true -- Don't display Mysterious Paper's 1-frame temporary trinket granting local hasPaper = player:HasTrinket(21) @@ -256,4 +259,4 @@ function EID:getHoldMapDescription(player, checkingTwin) end return holdMapDesc -end +end \ No newline at end of file From 6ee341e82842080fe5459facb8f620fd1b25d317 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 11 Jun 2022 16:47:48 -0400 Subject: [PATCH 30/39] Nil check --- eid_tmtrainer.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/eid_tmtrainer.lua b/eid_tmtrainer.lua index 74607da9..3aa93111 100644 --- a/eid_tmtrainer.lua +++ b/eid_tmtrainer.lua @@ -113,6 +113,7 @@ local function CheckLogForItems(_) local eidDesc = "" local theLog = io.open(logLocation, "r") + if theLog == nil then return end theLog:seek("set", logCursor) local line = theLog:read() From e0cffded59ab48d763373000f8129b8bf576d16c Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 11 Jun 2022 16:48:14 -0400 Subject: [PATCH 31/39] Remove accidental global variable --- eid_bagofcrafting.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/eid_bagofcrafting.lua b/eid_bagofcrafting.lua index e553fbdf..769afb19 100644 --- a/eid_bagofcrafting.lua +++ b/eid_bagofcrafting.lua @@ -610,6 +610,7 @@ end) --Tainted Cain "hold to craft" check local holdCounter = 0 +local icount = 0 local function trackBagHolding() if not IsTaintedCain() then return end local isCardHold = Input.IsActionPressed(ButtonAction.ACTION_PILLCARD, EID.bagPlayer.ControllerIndex) From d6194f8970719d9733a7e15d89441218a76c4b2a Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 11 Jun 2022 16:48:31 -0400 Subject: [PATCH 32/39] Remove accidental global variable --- eid_api.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eid_api.lua b/eid_api.lua index f2c076b7..27c2795e 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -30,7 +30,7 @@ local dynamicSpriteCache = {} -- used to store sprite objects of collectible ico function EID:addCollectible(id, description, itemName, language) itemName = itemName or nil language = language or "en_us" - modName = EID._currentMod + local modName = EID._currentMod -- Glitched Items exception so they don't have a mod name if id > 4294960000 then modName = nil end EID.descriptions[language].custom["5.100." .. id] = {id, itemName, description, modName} From e3f955d3fb47642e8afe9b93eadf7111ea5b0e7e Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 11 Jun 2022 16:49:20 -0400 Subject: [PATCH 33/39] Update eid_mcm.lua --- eid_mcm.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eid_mcm.lua b/eid_mcm.lua index b23683ec..7028af11 100644 --- a/eid_mcm.lua +++ b/eid_mcm.lua @@ -411,8 +411,8 @@ if MCMLoaded then EID:AddNumberSetting("Display", "ItemReminderShowPoopDesc", "Poop Descriptions", 0, 6, { repOnly = true, displayTable = itemSlotReminders, infoText = "Show Tainted ???'s next Poop Spell descriptions in the Item Reminder"}) - EID:AddBooleanSetting("Display", "ItemReminderShowHiddenInfo", "Show Hidden Information", { infoText = "Items that grant you items without saying what they are (like Zodiac, Liberty Cap) can have their current granted item revealed in the Item Reminder"}) - EID:AddBooleanSetting("Display", "ItemReminderShowRNGCheats", "Show RNG Predictions", { infoText = "Some items (like Crooked Penny) can have their next result predicted and shown in the Item Reminder"}) + EID:AddBooleanSetting("Display", "ItemReminderShowHiddenInfo", "Show Hidden Information", { infoText = "Items like 404 Error can have their current granted item revealed in the Item Reminder"}) + EID:AddBooleanSetting("Display", "ItemReminderShowRNGCheats", "Show RNG Predictions", { infoText = "Some items can have their next result predicted and shown in the Item Reminder"}) MCM.AddSpace("EID", "Display") -- @@ -420,7 +420,7 @@ if MCMLoaded then local refreshRateSteps = {1, 2, 3, 4, 6, 10, 12, 15, 20, 30, 60} EID:AddScrollSetting("Display", "RefreshRate", "Description Refresh Rate", refreshRateSteps, - {infoText = "How many times per second that EID updates what description to show"}) + {displayingTab = "", infoText = "How many times per second that EID updates what description to show"}) EID:AddBooleanSetting("Display", "CoopDescriptions", "Co-op Player Descriptions", {infoText = "Allow Players 2, 3, and 4 to display descriptions in Co-op"}) EID:AddBooleanSetting("Display", "PairedPlayerDescriptions", "Paired Player Descriptions", {repOnly = true, From bc313a41c334a30dd1ab38ab8d8239e2a453809f Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 11 Jun 2022 16:49:43 -0400 Subject: [PATCH 34/39] Unused var, nil check --- main.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.lua b/main.lua index 41fb4cad..664b52fe 100644 --- a/main.lua +++ b/main.lua @@ -1342,7 +1342,7 @@ local function onRender(t) inRangeEntities = { EID.lastDescriptionEntity } end -- Only display the indicator for the primary (closest / crafting) description - if EID.lastDescriptionEntity and not displayedCrafting then + if EID.lastDescriptionEntity then EID:renderIndicator(EID.lastDescriptionEntity, EID.controllerIndexes[player.ControllerIndex] or 1) table.insert(EID.CachedIndicators, {EID.lastDescriptionEntity, EID.controllerIndexes[player.ControllerIndex]}) end @@ -1353,7 +1353,7 @@ local function onRender(t) if EID.Config["EnableEntityDescriptions"] and EID:getEntityData(closest, "EID_Description") then local desc = EID:getEntityData(closest, "EID_Description") local origDesc = EID:getDescriptionObjByEntity(closest) - if type(desc) == "table" then + if desc ~= nil and type(desc) == "table" then origDesc.Description = desc.Description or origDesc.Description origDesc.Name = desc.Name or origDesc.Name origDesc.Transformation = desc.Transformation or origDesc.Transformation From c2f92a19aca4f8ed04881cc96bd97f7ef5bf8d09 Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 11 Jun 2022 16:50:46 -0400 Subject: [PATCH 35/39] More certainty --- descriptions/rep/en_us.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/descriptions/rep/en_us.lua b/descriptions/rep/en_us.lua index f6b91569..1c23d20e 100644 --- a/descriptions/rep/en_us.lua +++ b/descriptions/rep/en_us.lua @@ -836,7 +836,7 @@ local repCards={ [52] = {"52", "Huge Growth", "↑ {{Damage}} +7 Damage up#↑ {{Range}} +3 Range up#Destroy rocks when walking over them#Size up#Effect lasts for current room"}, -- Huge Growth [54] = {"54", "Era Walk", "{{Slow}} Slow down enemies#↑ {{Speed}} +0.5 Speed up#↓ {{Shotspeed}} -1 Shot Speed down#Effect lasts for current room"}, [55] = {"55", "Rune Shard", "{{Rune}} Activates a random rune effect#The rune effect is weaker"}, -- Rune Shard - [56] = {"56", "0 - The Fool?", "Drops all your hearts and pickups on the floor, leaving you with half a heart#Coins and bombs may be dropped as {{Collectible74}}The Quarter or {{Collectible19}}Boom! if possible"}, -- 0 - The Fool? + [56] = {"56", "0 - The Fool?", "Drops all your hearts and pickups on the floor, leaving you with half a heart#Coins and bombs are dropped as {{Collectible74}}The Quarter or {{Collectible19}}Boom! if possible"}, -- 0 - The Fool? [57] = {"57", "I - The Magician?", "Grants an aura that repels enemies and projectiles for 1 minute"}, -- I - The Magician? [58] = {"58", "II - The High Priestess?", "Mom's Foot stomps down repeatedly for 1 minute"}, -- II - The High Priestess? [59] = {"59", "III - The Empress?", "Grants for 1 minute: #↑ {{Heart}} +2 Health up#↑ {{Tears}} +1.35 Tears up"}, -- III - The Empress? From 827144e848e6037b054d754774eb23e47009f0df Mon Sep 17 00:00:00 2001 From: Buurazu Date: Sat, 11 Jun 2022 22:24:36 -0400 Subject: [PATCH 36/39] Fix AB+ True Co-op's icons being wack --- main.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main.lua b/main.lua index 664b52fe..3a276360 100644 --- a/main.lua +++ b/main.lua @@ -670,9 +670,10 @@ function EID:printDescription(desc, cachedID) EID:evaluateTransformationProgress(transform) transformationName = transformationName .. " " for _, player in ipairs(EID.coopAllPlayers) do - if player:GetPlayerType() ~= PlayerType.PLAYER_THESOUL_B then + local playerType = player:GetPlayerType() + if playerType ~= PlayerType.PLAYER_THESOUL_B then if #EID.coopAllPlayers > 1 then - local playerIcon = EID:getIcon("Player"..player.SubType) ~= EID.InlineIcons["ERROR"] and "{{Player"..player.SubType.."}}" or "{{CustomTransformation}}" + local playerIcon = EID:getIcon("Player"..playerType) ~= EID.InlineIcons["ERROR"] and "{{Player"..playerType.."}}" or "{{CustomTransformation}}" transformationName = transformationName .. playerIcon end local numCollected = EID.TransformationProgress[EID:getPlayerID(player)] and EID.TransformationProgress[EID:getPlayerID(player)][transform] or 0 From 1b2c77fdd8a730cd3b212242cf6e4c8563cb04df Mon Sep 17 00:00:00 2001 From: Buurazu Date: Mon, 13 Jun 2022 03:24:41 -0400 Subject: [PATCH 37/39] Fix babies having transform progress --- main.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.lua b/main.lua index 3a276360..d9aefb9f 100644 --- a/main.lua +++ b/main.lua @@ -671,7 +671,7 @@ function EID:printDescription(desc, cachedID) transformationName = transformationName .. " " for _, player in ipairs(EID.coopAllPlayers) do local playerType = player:GetPlayerType() - if playerType ~= PlayerType.PLAYER_THESOUL_B then + if playerType ~= PlayerType.PLAYER_THESOUL_B and player:GetBabySkin() == -1 then if #EID.coopAllPlayers > 1 then local playerIcon = EID:getIcon("Player"..playerType) ~= EID.InlineIcons["ERROR"] and "{{Player"..playerType.."}}" or "{{CustomTransformation}}" transformationName = transformationName .. playerIcon @@ -976,6 +976,7 @@ function EID:setPlayer() EID.coopMainPlayers = { EID.player } EID.coopAllPlayers = EID.players EID.controllerIndexes[p.ControllerIndex] = 1 + EID.isMultiplayer = false return end From 12e072e2d0387b02819756eaacc2b0782ffab30c Mon Sep 17 00:00:00 2001 From: Buurazu Date: Mon, 13 Jun 2022 03:25:09 -0400 Subject: [PATCH 38/39] Luna rewrite --- descriptions/rep/en_us.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/descriptions/rep/en_us.lua b/descriptions/rep/en_us.lua index 1c23d20e..2784c7d2 100644 --- a/descriptions/rep/en_us.lua +++ b/descriptions/rep/en_us.lua @@ -259,7 +259,7 @@ local repCollectibles={ [586] = {"586", "The Stairway", "Spawns a ladder at the start of every floor#It leads to a unique {{AngelRoom}} Angel Room shop with items and consumables"}, -- The Stairway [587] = {"587", "Menorah (Unused but scripted)", ""}, -- Menorah (Unused but scripted) [588] = {"588", "Sol", "{{BossRoom}} Reveals the location of the Boss Room#Upon defeating a boss, for the rest of the floor: #{{Card20}} Activates The Sun#{{Battery}} Fully recharges your active item#{{CurseBlind}} Removes any Curses#↑ {{Damage}} +3 Damage#↑ {{Luck}} +1 Luck"}, -- Sol - [589] = {"589", "Luna", "Adds an extra {{SecretRoom}} Secret Room and {{SuperSecretRoom}} Super Secret Room to each floor#{{SecretRoom}} Secret Rooms contain a beam of light that give: #{{Tears}} Tears up for the current floor#{{HalfSoulHeart}} Half soul heart#{{SecretRoom}} Reveals one Secret Room each floor"}, -- Luna + [589] = {"589", "Luna", "Adds an extra {{SecretRoom}} Secret Room and {{SuperSecretRoom}} Super Secret Room to each floor#Reveals one Secret Room each floor#Secret Rooms contain a beam of light that give:#{{HalfSoulHeart}} A Half Soul Heart#↑ {{Tears}} +0.5 Fire Rate up for the current floor#↑ {{Tears}} Additional +0.5 Fire Rate up from the first beam per floor"}, -- Luna [590] = {"590", "Mercurius", "↑ {{Speed}} +0.4 Speed up#Doors stay open after entering a room"}, -- Mercurius [591] = {"591", "Venus", "↑ {{Heart}} +1 Health up#{{Heart}} Heals 1 Red Heart#{{Charm}} Close enemies become charmed"}, -- Venus [592] = {"592", "Terra", "↑ {{Damage}} +1 Damage up#Replaces tears with rocks#They deal variable damage#Can destroy obstacles#Increased knockback"}, -- Terra @@ -975,7 +975,7 @@ EID.descriptions[languageCode].horsepills={ {"33", "One makes you small", "You get a lot smaller#Your hitbox gets smaller"}, -- One makes you small {"34", "Infested!", "Spawn 2 blue spiders per poop in room"}, -- Infested! {"35", "Infested?", "Spawn 2 blue spiders per enemy in room#Spawns 2-6 blue spiders when no enemy is in the room"}, -- Infested? - {"36", "Power Pill!", "Short invincibility effect#↑ {{Damage}} 7 Damage up#↑ {{Range}} +3 Range up#Persists for current room"}, -- Power Pill! + {"36", "Power Pill!", "Short invincibility effect#↑ {{Damage}} +7 Damage up#↑ {{Range}} +3 Range up#Persists for current room"}, -- Power Pill! {"37", "Retro Vision", "Pixelates the screen for 90 seconds"}, -- Retro Vision {"38", "Friends Till The End!", "Spawns 6 blue flies"}, -- Friends Till The End! {"39", "X-Lax", "Spawn pool of long lasting slippery creep"}, -- X-Lax From 4ae52df3efb3d99c07f2d60f89b1c2b714252bbf Mon Sep 17 00:00:00 2001 From: Buurazu Date: Mon, 13 Jun 2022 03:39:38 -0400 Subject: [PATCH 39/39] Rewrite to simplify adding descs --- eid_holdmapdesc.lua | 238 ++++++++++++++++++++++---------------------- 1 file changed, 120 insertions(+), 118 deletions(-) diff --git a/eid_holdmapdesc.lua b/eid_holdmapdesc.lua index dc0e9b17..bf1f4847 100644 --- a/eid_holdmapdesc.lua +++ b/eid_holdmapdesc.lua @@ -1,11 +1,35 @@ local game = Game() local level local currentRoom +local blacklist +local holdMapDesc +-- 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) - return (icon or "{{Blank}}") .. " {{ColorEIDObjName}}" .. title .. "#" .. newDesc .. "#" + holdMapDesc = holdMapDesc .. (icon or "{{Blank}}") .. " {{ColorEIDObjName}}" .. title .. "#" .. newDesc .. "#" 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}}) +local variantToName = { [70] = "Pill", [100] = "Collectible", [300] = "Card", [350] = "Trinket" } +local function addObjectDesc(type, variant, subtype, extraIcon) + local objectID = type .. "." .. variant .. "." .. subtype + if not blacklist[objectID] then + blacklist[objectID] = true + local demoDescObj = EID:getDescriptionObj(type, variant, subtype) + local iconString = "{{" .. variantToName[variant] .. subtype .. "}}" + if extraIcon then iconString = extraIcon .. " " .. iconString end + append(iconString, demoDescObj.Name, demoDescObj.Description) + end +end + +-- General RNG functions for RNG predicting local function RNGNext(num, shift1, shift2, shift3) num = num ~ ((num >> shift1) & 4294967295) num = num ~ ((num << shift2) & 4294967295) @@ -23,7 +47,7 @@ local teleport2GreedOrder = { 1,5,2,4,10,23,8,14,3 } local teleport2Icons = { "{{Room}}","{{BossRoom}}","{{SuperSecretRoom}}","{{Shop}}","{{TreasureRoom}}","{{SacrificeRoom}}","{{DiceRoom}}","{{Library}}","{{CursedRoom}}","{{MiniBoss}}","{{ChallengeRoom}}","{{IsaacsRoom}}","{{BarrenRoom}}","{{ArcadeRoom}}","{{ChestRoom}}","{{Planetarium}}","{{SecretRoom}}","{{RedRoom}}","{{AngelDevilChance}}","{{ErrorRoom}}" } local teleport2GreedIcons = { "{{RoomLongVertical}}","{{BossRoom}}","{{Shop}}","{{TreasureRoom}}","{{CursedRoom}}","{{Room}}","{{SuperSecretRoom}}","{{AngelDevilChance}}","{{ErrorRoom}}" } -local function teleport2Prediction(holdMapDesc) +local function teleport2Prediction() local level = game:GetLevel() local rooms = level:GetRooms() --I AM ERROR Room always considered uncleared @@ -46,24 +70,54 @@ local function teleport2Prediction(holdMapDesc) local roomNames = (greed and EID:getDescriptionEntry("Teleport2GreedRoomNames")) or EID:getDescriptionEntry("Teleport2RoomNames") for i,v in ipairs(roomOrder) do - if unclearedTypes[v] then return append("{{Collectible419}}", EID:getObjectName(5, 100, 419) .. EID:getDescriptionEntry("HoldMapHeader"), roomIcons[i] .. " " .. roomNames[i]) end + if unclearedTypes[v] then + append("{{Collectible419}}", EID:getObjectName(5, 100, 419) .. EID:getDescriptionEntry("HoldMapHeader"), roomIcons[i] .. " " .. roomNames[i]) + return + end end end --- ---order of checking: 15, 48, 58, 63, 65 ---(pennies, damage, hearts, item, leviathan, nothing) +-- 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 } } --- 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 } +local function sanguinePrediction() + 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["ItemReminderShowRNGCheats"] then + local spikeSeed = currentRoom:GetGridEntity(67):GetRNG():GetSeed() + spikeSeed = RNGNext(spikeSeed, 5, 9, 7) + spikeSeed = RNGNext(spikeSeed, 1, 5, 0x13) + local nextFloat = SeedToFloat(spikeSeed) + + for _,v in ipairs(sanguineResults) do + if nextFloat < v[1] then cheatResult = v[2] break end + end + end + + local descObj = EID:getDescriptionObj(5, 100, 692) + 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 + + append("{{Collectible692}}", descObj.Name, resultsDesc) +end function EID:getHoldMapDescription(player, checkingTwin) - local holdMapDesc = "" - local activeBlacklist = {} - local trinketBlacklist = {} + -- Starting Blacklist: Recall, Hold + blacklist = { ["5.100.714"] = true, ["5.100.715"] = true, } + holdMapDesc = "" + level = game:GetLevel() currentRoom = level:GetCurrentRoom() @@ -72,92 +126,26 @@ function EID:getHoldMapDescription(player, checkingTwin) -- (Zodiac and Modeling Clay have functions for it?) -- pandora's box? it shows the whole desc which is kinda useful but too big -- Void's absorbed items list - -- Luna beam effect? -- D Infinity current dice; track our Drop presses and resync it each time D Infinity is used by watching for the next dice effect triggered (Predict its next dice in AB+?) - - -- test how this works in co-op when co-op baby holds map! they should be ignored? - - - if REPENTANCE then - -- Sanguine Bond reward reminder - if player:HasCollectible(CollectibleType.COLLECTIBLE_SANGUINE_BOND) and game:GetRoom():GetType() == RoomType.ROOM_DEVIL then - local spikes = currentRoom:GetGridEntity(67) - local cheatResult = nil - -- we haven't made the setting for this stuff yet - if spikes and EID.Config["ItemReminderShowRNGCheats"] then - local spikeSeed = currentRoom:GetGridEntity(67):GetRNG():GetSeed() - spikeSeed = RNGNext(spikeSeed, 5, 9, 7) - spikeSeed = RNGNext(spikeSeed, 1, 5, 0x13) - - for k,v in ipairs(sanguineResults) do - if SeedToFloat(spikeSeed) < v[1] then cheatResult = v[2] break end - end - end - - local descObj = EID:getDescriptionObj(5, 100, 692) - 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 .. "{{ColorGreen}}" end - resultsDesc = resultsDesc .. w .. "#" - end - end - - holdMapDesc = holdMapDesc .. append("{{Collectible692}}", descObj.Name, resultsDesc) - end - - -- Tainted ??? Poop Descriptions - if EID.Config["ItemReminderShowPoopDesc"] > 0 and player:GetPlayerType() == 25 then - activeBlacklist[715] = true --blacklist Hold - for i = 0, EID.Config["ItemReminderShowPoopDesc"]-1 do - local poopInfo = EID:getDescriptionEntry("poopSpells") - local nextPoop = player:GetPoopSpell(i) - holdMapDesc = holdMapDesc .. append("{{PoopSpell" .. nextPoop .. "}}", poopInfo[nextPoop][1], poopInfo[nextPoop][2]) - end + -- Tainted ??? Poop Descriptions + if REPENTANCE and EID.Config["ItemReminderShowPoopDesc"] > 0 and player:GetPlayerType() == 25 then + for i = 0, EID.Config["ItemReminderShowPoopDesc"]-1 do + local poopInfo = EID:getDescriptionEntry("poopSpells") + local nextPoop = player:GetPoopSpell(i) + append("{{PoopSpell" .. nextPoop .. "}}", poopInfo[nextPoop][1], poopInfo[nextPoop][2]) end end - - -- Show Hidden Info - if EID.Config["ItemReminderShowHiddenInfo"] then - -- Rainbow Worm - -- should move this down to the normal trinket displaying code? - if player:HasTrinket(64) then - trinketBlacklist[64] = true - local rainbowWormEffect = rainbowWormEffects[math.floor(game.TimeCounter / 30 / 3) % (REPENTANCE and 10 or 8)] - if not trinketBlacklist[rainbowWormEffect] then - trinketBlacklist[rainbowWormEffect] = true - local demoDescObj = EID:getDescriptionObj(5, 350, rainbowWormEffect) - holdMapDesc = holdMapDesc .. append("{{Trinket64}}", "{{Trinket"..rainbowWormEffect.."}} " .. demoDescObj.Name, demoDescObj.Description) - end - end - -- 404 Error (And any other temporary trinket givers, such as Glitched Items) - -- Unfortunately, HasTrinket can't differentiate between real and fake trinkets in AB+ - if REPENTANCE and player:HasTrinket(75) then - trinketBlacklist[75] = true - -- Don't display Mysterious Paper's 1-frame temporary trinket granting - local hasPaper = player:HasTrinket(21) - -- is this var in AB+? - for i = 1, TrinketType.NUM_TRINKETS - 1 do - local tempTrinketFound = EID.player:HasTrinket(i, true) ~= EID.player:HasTrinket(i, false) - if tempTrinketFound and not trinketBlacklist[i] and (not mysteriousPaperBlacklist[i] or not hasPaper) then - trinketBlacklist[i] = true - local demoDescObj = EID:getDescriptionObj(5, 350, i) - holdMapDesc = holdMapDesc .. append("{{Trinket"..i.."}}", demoDescObj.Name, demoDescObj.Description) - end - end - end + + -- Sanguine Bond Possible Results + if REPENTANCE and player:HasCollectible(CollectibleType.COLLECTIBLE_SANGUINE_BOND) and game:GetRoom():GetType() == RoomType.ROOM_DEVIL then + sanguinePrediction() end -- Teleport 2.0 location if player:HasCollectible(CollectibleType.COLLECTIBLE_TELEPORT_2) and not EID.isMirrorRoom then - holdMapDesc = holdMapDesc .. teleport2Prediction(holdMapDesc) - activeBlacklist[CollectibleType.COLLECTIBLE_TELEPORT_2] = true + blacklist["5.100.419"] = true + teleport2Prediction() end -- Recently Acquired Item Descriptions @@ -169,9 +157,7 @@ function EID:getHoldMapDescription(player, checkingTwin) if printedItems >= EID.Config["ItemReminderShowRecentItem"] then break end printedItems = printedItems + 1 local recentID = EID.RecentlyTouchedItems[playerNum][i] % 4294967296 - activeBlacklist[recentID] = true - local demoDescObj = EID:getDescriptionObj(5, 100, recentID) - holdMapDesc = holdMapDesc .. append("{{Collectible"..recentID.."}}", demoDescObj.Name, demoDescObj.Description) + addObjectDesc(5, 100, recentID) end end end @@ -180,10 +166,8 @@ function EID:getHoldMapDescription(player, checkingTwin) if EID.Config["ItemReminderShowActiveDesc"] > 0 then for i = 0, EID.Config["ItemReminderShowActiveDesc"]-1 do local heldActive = player:GetActiveItem(i) % 4294967296 - if heldActive > 0 and not activeBlacklist[heldActive] then - activeBlacklist[heldActive] = true - local demoDescObj = EID:getDescriptionObj(5, 100, heldActive) - holdMapDesc = holdMapDesc .. append("{{Collectible"..heldActive.."}}", demoDescObj.Name, demoDescObj.Description) + if heldActive > 0 then + addObjectDesc(5, 100, heldActive) end end end @@ -201,28 +185,22 @@ function EID:getHoldMapDescription(player, checkingTwin) local heldCard = player:GetCard(i) local heldPill = player:GetPill(i) if heldCard > 0 then - local demoDescObj = EID:getDescriptionObj(5, 300, heldCard) - holdMapDesc = holdMapDesc .. append("{{Card"..heldCard.."}}", demoDescObj.Name, demoDescObj.Description) + addObjectDesc(5, 300, heldCard) elseif heldPill > 0 then -- Check if our held pill is identified EID.pillPlayer = player local identified = game:GetItemPool():IsPillIdentified(heldPill) if REPENTANCE and heldPill % PillColor.PILL_GIANT_FLAG == PillColor.PILL_GOLD then identified = true end if (identified or EID.Config["ShowUnidentifiedPillDescriptions"]) then - local demoDescObj = EID:getDescriptionObj(5, 70, heldPill) - holdMapDesc = holdMapDesc .. append("{{Pill"..heldPill.."}}", demoDescObj.Name, demoDescObj.Description) + addObjectDesc(5, 70, heldPill) end EID.pillPlayer = nil - elseif diceBag > 0 and not activeBlacklist[diceBag] and not dicePrinted then + elseif diceBag > 0 and not dicePrinted then dicePrinted = true - activeBlacklist[diceBag] = true - local demoDescObj = EID:getDescriptionObj(5, 100, diceBag) - holdMapDesc = holdMapDesc .. append("{{Trinket154}}", demoDescObj.Name, demoDescObj.Description) - elseif pocketActive > 0 and not activeBlacklist[pocketActive] and not pocketPrinted then + addObjectDesc(5, 100, diceBag, "{{Trinket154}}") + elseif pocketActive > 0 and not pocketPrinted then pocketPrinted = true - activeBlacklist[pocketActive] = true - local demoDescObj = EID:getDescriptionObj(5, 100, pocketActive) - holdMapDesc = holdMapDesc .. append("{{Collectible"..pocketActive.."}}", demoDescObj.Name, demoDescObj.Description) + addObjectDesc(5, 100, pocketActive) -- we'll have to add tainted char specific text for their actives with unique effects for that character! end end @@ -232,11 +210,29 @@ function EID:getHoldMapDescription(player, checkingTwin) if EID.Config["ItemReminderShowTrinketDesc"] > 0 then for i = 0, EID.Config["ItemReminderShowTrinketDesc"]-1 do local heldActive = player:GetTrinket(i) - if heldActive > 0 and not trinketBlacklist[heldActive] then - -- test this with golden trinkets / mom's box!!! - trinketBlacklist[heldActive] = true - local demoDescObj = EID:getDescriptionObj(5, 350, heldActive) - holdMapDesc = holdMapDesc .. append("{{Trinket"..heldActive.."}}", demoDescObj.Name, demoDescObj.Description) + if heldActive > 0 and not blacklist["5.350." .. heldActive] then + -- Rainbow Worm + if EID.Config["ItemReminderShowHiddenInfo"] and heldActive == 64 then + blacklist["5.350.64"] = true + local rainbowWormEffect = rainbowWormEffects[math.floor(game.TimeCounter / 30 / 3) % (REPENTANCE and 10 or 8)] + addObjectDesc(5, 350, rainbowWormEffect, "{{Trinket64}}") + -- 404 Error + -- Unfortunately, includes other temporary trinket givers, such as Glitched Items. We'd need to predict 404's result using RNG to actually know which it specifically is granting + -- And unfortunately, HasTrinket can't differentiate between real and fake trinkets in AB+ + elseif EID.Config["ItemReminderShowHiddenInfo"] and REPENTANCE and heldActive == 75 then + blacklist["5.350.75"] = true + -- Don't display Mysterious Paper's 1-frame temporary trinket granting + local hasPaper = player:HasTrinket(21) + for i = 1, TrinketType.NUM_TRINKETS - 1 do + local tempTrinketFound = EID.player:HasTrinket(i, true) ~= EID.player:HasTrinket(i, false) + if tempTrinketFound and (not mysteriousPaperBlacklist[i] or not hasPaper) then + addObjectDesc(5, 350, i, "{{Trinket75}}") + end + end + else + addObjectDesc(5, 350, heldActive) + end + end end end @@ -247,16 +243,22 @@ function EID:getHoldMapDescription(player, checkingTwin) -- If both twins have a desc, show their player icon / name to separate the two descs if REPENTANCE and not checkingTwin then local twin = player:GetOtherTwin() + local mainTwinDesc = holdMapDesc local otherTwinDesc = "" if twin then otherTwinDesc = EID:getHoldMapDescription(twin, true) end if otherTwinDesc ~= "" then - if holdMapDesc == "" then holdMapDesc = otherTwinDesc + -- Only the other twin had a desc + if mainTwinDesc == "" then holdMapDesc = otherTwinDesc else - holdMapDesc = (EID:getIcon("Player"..player:GetPlayerType()) ~= EID.InlineIcons["ERROR"] and "{{Player"..player:GetPlayerType().."}}" or "{{CustomTransformation}}") .. " {{ColorGray}}" .. player:GetName() .. "#" .. holdMapDesc .. "#" + -- Both twins had a desc; merge them with player icon headers + holdMapDesc = (EID:getIcon("Player"..player:GetPlayerType()) ~= EID.InlineIcons["ERROR"] and "{{Player"..player:GetPlayerType().."}}" or "{{CustomTransformation}}") .. " {{ColorGray}}" .. player:GetName() .. "#" .. mainTwinDesc .. "#" holdMapDesc = holdMapDesc .. (EID:getIcon("Player"..twin:GetPlayerType()) ~= EID.InlineIcons["ERROR"] and "{{Player"..twin:GetPlayerType().."}}" or "{{CustomTransformation}}") .. " {{ColorGray}}" .. twin:GetName() .. "#" .. otherTwinDesc end + else + -- Only the main twin had a desc + holdMapDesc = mainTwinDesc end end return holdMapDesc -end \ No newline at end of file +end