diff --git a/descriptions/ab+/en_us.lua b/descriptions/ab+/en_us.lua index f4357342..0e2c3244 100644 --- a/descriptions/ab+/en_us.lua +++ b/descriptions/ab+/en_us.lua @@ -450,7 +450,7 @@ EID.descriptions["en_us"].collectibles={ {"435", "Lil Loki", "Shoots 4 tears in a cross pattern#Deals 3.5 damage per shot"}, {"436", "Milk!", "After taking damage, you gain a Tears up for the rest of the room"}, {"437", "D7", "Respawn all enemies of the room#Allows you to farm room clear rewards#!!! If used in a Greed fight, it can reroll the room into a Shop"}, - {"438", "Binky", "+1 Soul Heart#↑ +0.7 Tears up#↑ Makes Isaac very small, reducing his hitbox size"}, + {"438", "Binky", "+1 Soul Heart#↑ +0.75 Tears up#↑ Makes Isaac very small, reducing his hitbox size"}, {"439", "Mom's Box", "Spawns a random trinket#↑ +1 Luck while held#While held, doubles the effect of trinkets"}, {"440", "Kidney Stone", "Randomly while firing you will stop firing and release a burst of tears and a kidney stone#↓ -0.2 Speed down#↓ -17 Range down#↑ +2 Tear Height"}, {"441", "Mega Blast", "Fires a huge Mega Satan laser for 15 seconds#The laser persists between rooms and floors"}, diff --git a/descriptions/rep/en_us.lua b/descriptions/rep/en_us.lua index 517a08ad..06e837da 100644 --- a/descriptions/rep/en_us.lua +++ b/descriptions/rep/en_us.lua @@ -138,7 +138,7 @@ local repCollectibles={ [345] = {"345", "Synthoil", "↑ +1 Damage up#↑ +1.5 Range up"}, -- Synthoil [346] = {"346", "A Snack", "↑ +1 Health up#Heals 1 Red Heart"}, -- A Snack [350] = {"350", "Toxic Shock", "At the start of every room every enemy gets a poison effect#Killed enemies leave puddle of creep#Grants immunity for toxic clouds"}, -- Toxic Shock - [352] = {"352", "Glass Cannon", "Fires one large piercing spectral tear ((DMG x 10) + 10)#!!! When you take damage:#↓ You will lose an extra 2 hearts of health#↑ + 1.5 Range up#Self-damage does not count"}, -- Glass Cannon + [352] = {"352", "Glass Cannon", "Fires one large piercing spectral tear ((DMG x 10) + 10)#!!! When you take damage:#↓ You will lose an extra 2 hearts of health#↑ +1.5 Range up and leave blood creep for the room#The extra damage can't kill you#Self-damage does not count"}, -- Glass Cannon [354] = {"354", "Crack Jacks", "↑ +1 Health up#Spawns random trinket on the floor#Heals 1 Red Heart"}, -- Crack Jacks [355] = {"355", "Mom's Pearls", "↑ +0.38 Range up#↑ +1 Luck up#+1 Soul Heart"}, -- Mom's Pearls [360] = {"360", "Incubus", "Gain a demonic familiar that shoots the same tears as Isaac#Deals 75% of your damage unless playing as Lilith"}, -- Incubus @@ -290,7 +290,7 @@ local repCollectibles={ [639] = {"639", "Yuck Heart", "Grants a Rotten Heart upon use"}, -- Yuck Heart [640] = {"640", "Urn of Souls", "Spews a stream of flames#Gains charges each time an enemy dies"}, -- Urn of Souls [641] = {"641", "Akeldama", "Creates a chain of tears behind you while in combat#The tears deal 3.5 damage"}, -- Akeldama - [642] = {"642", "Magic Skin", "Consumes 1 Heart Container or 2 Soul Hearts and replaces them with a Broken Heart#Spawns an item from the current room's item pool#The more times it's used, the higher the chance it replaces future items if Isaac isn't holding it#Lower chance if Magic Skin is on a pedestal on the current floor#{{Warning}} Single use item for The Lost, doesn't replace future items"}, -- Magic Skin + [642] = {"642", "Magic Skin", "Turns 1 Heart Container or 2 Soul Hearts into a Broken Heart#Spawns an item from the current room's item pool#The more times it's used, the higher the chance it replaces future items if Isaac isn't holding it#33% after 1 use, 50% after 2, 100% after 3#Lower chance if Magic Skin is on a pedestal on the current floor#{{Warning}} Single use item for The Lost"}, -- Magic Skin [643] = {"643", "Revelation", "Grants flight and 2 Soul Hearts#Shooting for 2.5 seconds will fire a holy laser when fire button is released"}, -- Revelation [644] = {"644", "Consolation Prize", "Increases your lowest stat#Drops either 3 coins, 1 bomb or 1 key depending on what you have the least of"}, -- Consolation Prize [645] = {"645", "Tinytoma", "Teratoma orbital#Blocks shots#Deals contact damage#Splits into smaller versions of itself upon taking 3 hits#The smaller versions break into blue spiders#Respawns 5 seconds after it's fully gone"}, -- Tinytoma @@ -350,8 +350,8 @@ local repCollectibles={ [699] = {"699", "Azazel's Rage", "Build rage every time a room is cleared#After 4 rooms, fires a large Brimstone laser when entering the next room"}, -- Azazel's Rage [700] = {"700", "Echo Chamber", "When Isaac uses a Card, Pill, or Rune, he also uses a copy of the last 3 Cards/Pills/Runes he used after picking up Echo Chamber"}, -- Echo Chamber [701] = {"701", "Isaac's Tomb", "Spawns an Old Chest at the start of every floor which requires a key to unlock#Can contain 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 3 Black Hearts, +2 damage and flight#Characters have independent items and health#{{Warning}} Dying as either character ends the run"}, -- Esau Jr. + [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 3 Black Hearts, +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!", "Berserk mode for 5 seconds:#↑ +0.4 Speed up#↑ Tears up#↑ +3 Damage up#Restricts attacks to a melee weapon"}, -- Berserk! [705] = {"705", "Dark Arts", "Gain +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 @@ -844,7 +844,7 @@ local repCards={ [94] = {"94", "Soul of Apollyon", "Spawn 15 random locust flies"}, -- Soul of Apollyon [95] = {"95", "Soul of the Forgotten", "Spawns The Forgotten as a temporary secondary character for current room"}, -- Soul of the Forgotten [96] = {"96", "Soul of Bethany", "Spawns 6 {{Collectible584}}Book of Virtues wisps with random properties"}, -- Soul of Bethany - [97] = {"97", "Soul of Jacob and Esau", "Spawns Esau as a temporary secondary character for current room"}, -- Soul of Jacob and Esau + [97] = {"97", "Soul of Jacob and Esau", "Spawns Esau as a temporary secondary character for current room#He spawns with random passive items equal to how many you have"}, -- Soul of Jacob and Esau } EID:updateDescriptionsViaTable(repCards, EID.descriptions["en_us"].cards) @@ -981,4 +981,4 @@ EID.descriptions["en_us"].AchievementWarningText = "Achievements are disabled!#I EID.descriptions["en_us"].OldGameVersionWarningText = "Your version of Repentance is not up-to-date!#Only the newest version is officially supported#(This warning can be disabled in the config)" -EID.descriptions["en_us"].ModdedRecipesWarningText = "Modded items are likely to make the crafting recipe calculation inaccurate!#Use the No Recipes display mode or turn off the Bag of Crafting display if your recipes are incorrect#(This warning can be disabled in the config)" +EID.descriptions["en_us"].ModdedRecipesWarningText = "Modded items could make the crafting recipe calculation inaccurate!#Use the No Recipes display mode or turn off the Bag of Crafting display if your recipes are incorrect#(This warning can be disabled in the config)" diff --git a/eid_bagofcrafting.lua b/eid_bagofcrafting.lua index 5f7e5472..ef833211 100644 --- a/eid_bagofcrafting.lua +++ b/eid_bagofcrafting.lua @@ -170,6 +170,14 @@ local componentShifts = { {0x00000011, 0x0000000F, 0x0000001A} } +local poolToIcon = { [0]="{{TreasureRoom}}",[1]="{{Shop}}",[2]="{{BossRoom}}",[3]="{{DevilRoom}}",[4]="{{AngelRoom}}", +[5]="{{SecretRoom}}",[7]="{{PoopRoomIcon}}",[8]="{{GoldenChestRoomIcon}}",[9]="{{RedChestRoomIcon}}",[12]="{{CursedRoom}}",[26]="{{Planetarium}}" } + +local CraftingMaxItemID = EID.XMLMaxItemID +local CraftingFixedRecipes = EID.XMLRecipes +local CraftingItemPools = EID.XMLItemPools +local CraftingItemQualities = EID.XMLItemQualities + --These are recipes that have already been calculated, plus the contents of recipes.xml local calculatedRecipes = {} --Backup recipes in case of potential achievement lock @@ -179,19 +187,26 @@ local lastSeedUsed = 0 --A list of item IDs, sorted by quality, then by name, to help with sorting our recipe list faster local sortedIDs = {} -for i = 1, EID.XMLMaxItemID do - if EID.XMLItemQualities[i] ~= nil then - table.insert(sortedIDs, i) - end -end -table.sort(sortedIDs, function(a, b) - if EID.XMLItemQualities[a] == EID.XMLItemQualities[b] then - return (EID:getObjectName(5, 100, a) < EID:getObjectName(5, 100, b)) - else - return (EID.XMLItemQualities[a] > EID.XMLItemQualities[b]) +local function sortAllItems() + sortedIDs = {} + + for i = 1, CraftingMaxItemID do + if CraftingItemQualities[i] ~= nil then + table.insert(sortedIDs, i) + end end -end) + + table.sort(sortedIDs, function(a, b) + if CraftingItemQualities[a] == CraftingItemQualities[b] then + return (EID:getObjectName(5, 100, a) < EID:getObjectName(5, 100, b)) + else + return (CraftingItemQualities[a] > CraftingItemQualities[b]) + end + end) +end +-- delay the initial sort until needed, as it's a tad slow +local sortNeeded = true local customRNGSeed = 0x77777770 local customRNGShift = {0,0,0} @@ -226,9 +241,6 @@ function EID:getBagOfCraftingID(Variant, SubType) return nil end -local poolToIcon = { [0]="{{TreasureRoom}}",[1]="{{Shop}}",[2]="{{BossRoom}}",[3]="{{DevilRoom}}",[4]="{{AngelRoom}}", -[5]="{{SecretRoom}}",[7]="{{PoopRoomIcon}}",[8]="{{GoldenChestRoomIcon}}",[9]="{{RedChestRoomIcon}}",[12]="{{CursedRoom}}",[26]="{{Planetarium}}" } - function EID:simulateBagOfCrafting(componentsTable) local components = componentsTable local compTotalWeight = 0 @@ -292,10 +304,10 @@ function EID:simulateBagOfCrafting(componentsTable) qualityMin = 0 qualityMax = 2 end - local pool = EID.XMLItemPools[poolWeight.idx + 1] + local pool = CraftingItemPools[poolWeight.idx + 1] for _, item in ipairs(pool) do - local quality = EID.XMLItemQualities[item[1]] + local quality = CraftingItemQualities[item[1]] if quality >= qualityMin and quality <= qualityMax then local w = item[2] * poolWeight.weight poolWeight.totalWeight = poolWeight.totalWeight + w @@ -339,7 +351,7 @@ function EID:calculateBagOfCrafting(componentsTable) local componentsAsString = table.concat(components, ",") --Check the fixed recipes. Currently, the fixed recipes ignore item unlock status - local cacheResult = EID.XMLRecipes[componentsAsString] + local cacheResult = CraftingFixedRecipes[componentsAsString] if cacheResult ~= nil then return cacheResult, cacheResult end @@ -382,7 +394,7 @@ function EID:calculateBagOfCrafting(componentsTable) local itemWeights = {} - local maxItemID = EID.XMLMaxItemID + local maxItemID = CraftingMaxItemID for i = 1, maxItemID do itemWeights[i] = 0 end @@ -414,10 +426,10 @@ function EID:calculateBagOfCrafting(componentsTable) qualityMin = 0 qualityMax = 2 end - local pool = EID.XMLItemPools[poolWeight.idx + 1] + local pool = CraftingItemPools[poolWeight.idx + 1] for _, item in ipairs(pool) do - local quality = EID.XMLItemQualities[item[1]] + local quality = CraftingItemQualities[item[1]] if quality >= qualityMin and quality <= qualityMax then local w = item[2] * poolWeight.weight itemWeights[item[1]] = itemWeights[item[1]] + w @@ -459,6 +471,64 @@ function EID:calculateBagOfCrafting(componentsTable) end end +-- simple table of tables copy function +local function deepcopy(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[deepcopy(orig_key)] = deepcopy(orig_value) + end + setmetatable(copy, deepcopy(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy +end + +local moddedCrafting = false +-- Check for modded items past the known max item ID on game start (can also support game updates) +-- Only works if the new items are at Weight 1.0 in their item pools, but better than nothing +local function GameStartCrafting() + if EID.itemConfig:GetCollectible(EID.XMLMaxItemID+1) ~= nil then + -- Items past max ID detected; copy our XML tables so we can add to them + CraftingMaxItemID = EID.XMLMaxItemID + CraftingItemPools = deepcopy(EID.XMLItemPools) + CraftingItemQualities = deepcopy(EID.XMLItemQualities) + -- Add new item qualities + local coll = EID.itemConfig:GetCollectible(CraftingMaxItemID+1) + while coll ~= nil do + CraftingMaxItemID = CraftingMaxItemID + 1 + CraftingItemQualities[coll.ID] = coll.Quality + coll = EID.itemConfig:GetCollectible(CraftingMaxItemID+1) + end + local itemPool = game:GetItemPool() + -- Add new items to the crafting item pools, assuming Weight 1.0 + for poolNum,_ in pairs(poolToIcon) do + for i=1,EID.XMLMaxItemID do itemPool:AddRoomBlacklist(i) end + + local collID = itemPool:GetCollectible(poolNum, false, 1, 25) + while collID ~= 25 do + table.insert(CraftingItemPools[poolNum+1], {collID, 1.0}) + itemPool:AddRoomBlacklist(collID) + collID = itemPool:GetCollectible(poolNum, false, 1, 25) + end + + itemPool:ResetRoomBlacklist() + end + moddedCrafting = true + sortNeeded = true + elseif moddedCrafting then + CraftingMaxItemID = EID.XMLMaxItemID + CraftingItemPools = EID.XMLItemPools + CraftingItemQualities = EID.XMLItemQualities + moddedCrafting = false + sortNeeded = true + end +end +EID:AddCallback(ModCallbacks.MC_POST_GAME_STARTED, GameStartCrafting) + ------------------------------------------ ------------------------------------------ -----------Bag content detection --------- @@ -702,6 +772,7 @@ function EID:handleBagOfCraftingRendering() lockedRecipes = {} calcResultCache = {} randResultCache = {} + lockedResults = nil end lastSeedUsed = curSeed @@ -812,9 +883,14 @@ function EID:handleBagOfCraftingRendering() --sort by ingredient quality table.sort(itemQuery, qualitySort) - + --No Recipes Mode display - if (EID.Config["BagOfCraftingDisplayMode"] == "No Recipes") then + if EID.Config["BagOfCraftingDisplayMode"] == "Pickups Only" then + EID:appendToDescription(customDescObj, getHotkeyString()) + EID:appendToDescription(customDescObj, getFloorItemsString(false, roomItems)) + EID:printDescription(customDescObj) + return true + elseif EID.Config["BagOfCraftingDisplayMode"] == "No Recipes" then EID:appendToDescription(customDescObj, getHotkeyString()) EID:appendToDescription(customDescObj, getFloorItemsString(false, roomItems)) @@ -834,6 +910,11 @@ function EID:handleBagOfCraftingRendering() EID:printDescription(customDescObj) return true end + + if sortNeeded then + sortAllItems() + sortNeeded = false + end local queryString = table.concat(itemQuery,",") if lockedResults ~= nil then @@ -995,12 +1076,12 @@ function EID:handleBagOfCraftingRendering() --tack on the secondary recipe image to achievement-locked recipes if v[3] then customDescObj.Description = customDescObj.Description.."({{Collectible" .. v[3] .. "}})" end --color the equals sign with the item quality, so the order of the list can make sense - customDescObj.Description = customDescObj.Description.. qualities[EID.XMLItemQualities[v[2]]] .. "={{CR}}" + customDescObj.Description = customDescObj.Description.. qualities[CraftingItemQualities[v[2]]] .. "={{CR}}" --only display the item name if it's the first occurrence else if prevItem ~= v[2] then --substring the first 18 characters of the item name so it fits on one line; is there a way to get around desc line length limits? - customDescObj.Description = customDescObj.Description.."# {{Collectible"..v[2].."}} ".. qualities[EID.XMLItemQualities[v[2]]] .. + customDescObj.Description = customDescObj.Description.."# {{Collectible"..v[2].."}} ".. qualities[CraftingItemQualities[v[2]]] .. string.sub(EID:getObjectName(5, 100, v[2]),1,18).."#" else customDescObj.Description = customDescObj.Description.."#" diff --git a/eid_config.lua b/eid_config.lua index 4ccc7b68..cbf2337c 100644 --- a/eid_config.lua +++ b/eid_config.lua @@ -211,10 +211,11 @@ EID.UserConfig = { -- Default = "always" ["DisplayBagOfCrafting"] = "always", -- Display modes for the Bag of Crafting display - -- Options: "Recipe List", "Preview Only", "No Recipes" + -- Options: "Recipe List", "Preview Only", "No Recipes", "Pickups Only" -- The recipe list is a detailed calculated list of recipes based on what you have available on the floor -- Preview Only shows the description of the item you can currently craft in your bag -- No Recipes shows percentages of what item you might get from your bag / best option on the floor, for a more intended experience + -- Pickups Only just shows the room/floor pickup count -- (No Recipes is recommended if you have modded items) -- Default = "Recipe List" ["BagOfCraftingDisplayMode"] = "Recipe List", diff --git a/eid_data.lua b/eid_data.lua index 5e932172..4858a624 100644 --- a/eid_data.lua +++ b/eid_data.lua @@ -408,6 +408,6 @@ EID.GoldenTrinketData = { [159] = {goldenOnly = true, fullReplace = true, mult=1}, [160] = 1, [162] = {t={50}, mults={1.32, 2}}, [163] = {t={1},mult=2}, [164] = 1, -- Modeling Clay, Polished Bone (25, 33, 50), Hollow Heart, Kid's Drawing, Crystal Key [166] = {t={50},mult=2}, [167] = {t={25}, mults={1.32, 2}}, [168] = 1, [169] = {t={1}, goldenOnly = true, mult = 2}, [170] = {t={33}, mults={1.5,3}}, - -- Lil Clot, Swallowed M80, The Twins (default text), Cricket Leg (1/6, 2/6, 3/6), Apollyon's Best Friend, Broken Glasses - [176] = 1, [178] = {t={50},mult=2}, [183] = 0, [185] = 1, [186] = 1, [187] = {t={50,50}, mult=2}, + -- Lil Clot, Swallowed M80, The Twins (default text), Cricket Leg (17%, 1 in 6), Apollyon's Best Friend, Broken Glasses + [176] = 1, [178] = {t={50},mult=2}, [183] = 0, [185] = 17, [186] = 1, [187] = {t={50,50}, mult=2}, } diff --git a/eid_modifiers.lua b/eid_modifiers.lua index 6f5bd673..cba9ef58 100644 --- a/eid_modifiers.lua +++ b/eid_modifiers.lua @@ -232,7 +232,10 @@ local game = Game() descObj.Description = string.gsub(descObj.Description, "%d*%.?%d+", function(s) if (s == tostring(v) and count == 0) then count = count + 1 - if v == 33 and (multiplier == 1.5 or multiplier == 3) then v = (1/3)*100 end -- convert 33% to 50% or 100% + if v == 17 then + if multiplier == 2 then v = 16.5 + elseif multiplier == 3 then v = (1/6)*100 end -- convert 17% to 33% or 50% + elseif v == 33 and (multiplier == 1.5 or multiplier == 3) then v = (1/3)*100 end -- convert 33% to 50% or 100% return "{{ColorGold}}" .. string.format("%.4g",v*multiplier) .. "{{ColorText}}" end end) diff --git a/main.lua b/main.lua index 7a0abfc4..787887be 100644 --- a/main.lua +++ b/main.lua @@ -640,7 +640,7 @@ local function renderAchievementInfo() demoDescObj.Description = EID:getDescriptionEntry("OldGameVersionWarningText") or "" EID:displayPermanentText(demoDescObj) hasShownAchievementWarning = true - elseif EID.player:HasCollectible(710) and EID:DetectModdedItems() and EID.Config.DisplayBagOfCrafting ~= "never" and EID.Config.BagOfCraftingDisplayMode ~= "No Recipes" then + elseif EID.player:HasCollectible(710) and EID:DetectModdedItems() and EID.Config.DisplayBagOfCrafting ~= "never" and (EID.Config.BagOfCraftingDisplayMode == "Recipe List" or EID.Config.BagOfCraftingDisplayMode == "Preview Only") then local demoDescObj = EID:getDescriptionObj(-999, -1, 1) demoDescObj.Name = EID:getDescriptionEntry("AchievementWarningTitle") or "" demoDescObj.Description = EID:getDescriptionEntry("ModdedRecipesWarningText") or "" diff --git a/mod_config_menu.lua b/mod_config_menu.lua index bca2a1e2..67209fe1 100644 --- a/mod_config_menu.lua +++ b/mod_config_menu.lua @@ -1205,7 +1205,7 @@ if MCMLoaded then } ) -- Bag of Crafting Display Mode - local bagDisplayModes = {"Recipe List","Preview Only","No Recipes"} + local bagDisplayModes = {"Recipe List","Preview Only","No Recipes","Pickups Only"} MCM.AddSetting( "EID", "Crafting", @@ -1215,14 +1215,14 @@ if MCMLoaded then return AnIndexOf(bagDisplayModes, EID.Config["BagOfCraftingDisplayMode"]) end, Minimum = 1, - Maximum = 3, + Maximum = 4, Display = function() return "Display Mode: " .. EID.Config["BagOfCraftingDisplayMode"] end, OnChange = function(currentNum) EID.Config["BagOfCraftingDisplayMode"] = bagDisplayModes[currentNum] end, - Info = {"Toggle showing a list of calculated recipes, showing just an item preview when the bag is full, or showing percentages of what item you might get (No Recipes is recommended if using modded items)"} + Info = {"Toggle showing a list of recipes, an item preview when bag is full, what item pool/quality you might get, or only the floor pickups"} } ) -- Bag of Crafting Hide in Battle