learned recipe + name sort + misc

This commit is contained in:
Buurazu authored and Wofsauge committed 2024-06-03 18:39:47 +02:00
1 parent 0c956054ff
commit 52ca71cc25
1 file changed
+134 -28
+134 -28
View File
@@ -200,6 +200,9 @@ local CraftingItemAllowed = {}
--These are recipes that have already been calculated, plus the contents of recipes.xml
local calculatedRecipes = {}
--These are recipes that we've learned during this run
local learnedRecipes = {}
local newRecipeLearned = false
--If the seed changes, the above two tables will be wiped
local lastSeedUsed = 0
-- Test a few specific items' availability for if we should wipe our cached recipes due to availability change
@@ -223,15 +226,15 @@ local function sortAllItems()
end
table.sort(sortedIDs, function(a, b)
if CraftingItemQualities[a] == CraftingItemQualities[b] then
if EID.Config["BagOfCraftingSortOrder"] == "Name" or CraftingItemQualities[a] == CraftingItemQualities[b] then
return (objectNames[a] < objectNames[b])
else
return (CraftingItemQualities[a] > CraftingItemQualities[b])
end
end)
end
-- delay the initial sort until needed, in case of modded items
local sortNeeded = true
-- delay the initial sort until needed, in case of modded items, or changing sorting order
EID.BoC.SortNeeded = true
local recheckPickups = false
local customRNGSeed = 0x77777770
@@ -372,6 +375,18 @@ function EID:simulateBagOfCrafting(componentsTable)
return compTotalWeight, poolString
end
-- "Learned Recipes" MODE: Save the result of the 8 items inside our bag
function EID:learnBagOfCrafting(componentsTable)
-- ingredients must be sorted by ID to store in learnedRecipes
local components = {table.unpack(componentsTable)}
table.sort(components)
local componentsAsString = table.concat(components, ",")
local recipe = REPENTOGON and EID.bagPlayer:GetBagOfCraftingOutput() or EID:calculateBagOfCrafting(componentsTable)
if (learnedRecipes[componentsAsString] ~= recipe) then newRecipeLearned = true end
learnedRecipes[componentsAsString] = recipe;
end
-- The main function that takes 8 ingredients and tells you what collectible you will get in return
-- Only pass in a table with 8 valid ingredients!!!
function EID:calculateBagOfCrafting(componentsTable)
@@ -548,7 +563,7 @@ local function GameStartCrafting()
table.insert(CraftingItemPools[poolNum+1], {collTable.itemID, collTable.weight})
end
end
sortNeeded = true
EID.BoC.SortNeeded = true
moddedCrafting = true
end
end
@@ -753,6 +768,8 @@ local function getFloorItemsString(showPreviews, roomItems)
if #bagItems >0 then
if showPreviews and #bagItems == 8 then
local recipe = REPENTOGON and EID.bagPlayer:GetBagOfCraftingOutput() or EID:calculateBagOfCrafting(bagItems)
-- when using REPENTOGON, MCM needs to think its bag is full
if EID.BoC.BagItemsOverride then recipe = EID:calculateBagOfCrafting(bagItems) end
floorString = floorString .. "{{Collectible"..recipe.."}} "
end
local bagDesc = EID:getDescriptionEntry("CraftingBagContent")
@@ -867,6 +884,59 @@ local function RecipeCrunchCoroutine()
EID.RefreshBagTextbox = true
end
-- Convert our learned recipes into a list per ID
local function LearnedRecipeList()
if not newRecipeLearned or lockedResults then return end
newRecipeLearned = false
local sortedResults = {}
for _, v in ipairs(sortedIDs) do
sortedResults[v] = {}
end
for ingreds, resultID in pairs(learnedRecipes) do
ingredTable = {}
-- split the recipe by comma
for i in string.gmatch(ingreds, "[^,]+") do table.insert(ingredTable, tonumber(i)) end
table.insert(sortedResults[resultID], {ingredTable, resultID})
end
currentRecipesList = sortedResults
numResults = 0
for _,v in ipairs(sortedIDs) do
-- keep our cursor position if we're not at the top of the list, and bag's contents don't matter for list size
if (isRefresh and bagOfCraftingOffset > 0 and v == refreshPosition and (IsTaintedCain() or #EID.BoC.BagItems == 0)) then
--jump to the item we were looking at before, so you can more easily refresh for variants of recipes
bagOfCraftingOffset = numResults
end
numResults = numResults + #currentRecipesList[v]
end
if not isRefresh then
bagOfCraftingOffset = 0
bagOfCraftingRefreshes = 0
end
isRefresh = false
EID.RefreshBagTextbox = true
end
local function MCMLearnedRecipeList()
local sortedResults = {}
for _, v in ipairs(sortedIDs) do
sortedResults[v] = {}
end
local recipe = EID:calculateBagOfCrafting({15,15,5,1,10,8,8,9})
table.insert(sortedResults[recipe], {{15,15,5,1,10,8,8,9}, recipe})
currentRecipesList = sortedResults
bagOfCraftingOffset = 0
bagOfCraftingRefreshes = 0
isRefresh = false
EID.RefreshBagTextbox = true
newRecipeLearned = true -- make the list return to normal once MCM is closed
end
function EID:BOCHandleCurseOfMaze()
-- switches tracked room contents when rooms are switched by curse of maze
if game:GetLevel():GetCurses() & LevelCurse.CURSE_OF_MAZE ~= LevelCurse.CURSE_OF_MAZE then
@@ -909,6 +979,13 @@ function EID:handleBagOfCraftingUpdating()
end
if (curSeed ~= lastSeedUsed or updatedItemAvailability) then
calculatedRecipes = {}
-- Don't reset learned recipes on item availability change
-- They'll be recalculated on bag-full if missing from calculatedRecipes
if curSeed ~= lastSeedUsed then
learnedRecipes = {}
-- for k,v in pairs(CraftingFixedRecipes) do learnedRecipes[k] = v end
newRecipeLearned = true
end
calcResultCache = {}
randResultCache = {}
EID.itemAvailableStates = {}
@@ -916,6 +993,18 @@ function EID:handleBagOfCraftingUpdating()
end
lastSeedUsed = curSeed
-- Use REPENTOGON to accurately know what's inside the bag
if REPENTOGON then
EID.BoC.BagItems = EID.bagPlayer:GetBagOfCraftingContent()
for i=1,8 do
if EID.BoC.BagItems[i] == 0 then EID.BoC.BagItems[i] = nil end
end
end
-- Save the result of the 8 items in our bag
if #EID.BoC.BagItems == 8 then
EID:learnBagOfCrafting(EID.BoC.BagItems)
end
-- watch for holding the Craft button, and pressing the ingredient shift button
EID:BoCTrackBagHolding()
EID:BoCDetectBagContentShift()
@@ -936,7 +1025,7 @@ function EID:handleBagOfCraftingUpdating()
local oldSearchInputEnabled = EID:BoCSGetSearchInputEnabled()
EID:BoCSHandleInput()
if oldSearchValue ~= EID:BoCSGetSearchValue() or oldSearchInputEnabled ~= EID:BoCSGetSearchInputEnabled() then
refreshNextTick = true
EID.RefreshBagTextbox = true
end
-- Check for Hold Tab key inputs
@@ -1036,12 +1125,6 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
return false
end
if REPENTOGON then
EID.BoC.BagItems = EID.bagPlayer:GetBagOfCraftingContent()
for i=1,8 do
if EID.BoC.BagItems[i] == 0 then EID.BoC.BagItems[i] = nil end
end
end
local bagItems = EID.BoC.BagItemsOverride or EID.BoC.BagItems
-- Display the result of the 8 items in our bag if applicable
if (EID.ShowCraftingResult or EID.Config["BagOfCraftingDisplayRecipesMode"] == "Preview Only") and #bagItems == 8 then
@@ -1050,6 +1133,8 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
return false
end
local craftingResult = REPENTOGON and EID.bagPlayer:GetBagOfCraftingOutput() or EID:calculateBagOfCrafting(bagItems)
-- when using REPENTOGON, MCM needs to think its bag is full
if EID.BoC.BagItemsOverride then craftingResult = EID:calculateBagOfCrafting(bagItems) end
local descriptionObj = EID:getDescriptionObj(5, 100, craftingResult)
-- prepend the Hide/Preview hotkeys to the description
descriptionObj.Description = getHotkeyString() .. descriptionObj.Description
@@ -1097,13 +1182,14 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
local tableToCraftingIconsFunc = EID.tableToCraftingIconsMerged
if EID.Config["BagOfCraftingDisplayIcons"] then tableToCraftingIconsFunc = EID.tableToCraftingIconsFull end
local mode = EID.Config["BagOfCraftingDisplayRecipesMode"]
-- Pickups Only / Item Probability Mode display
if EID.Config["BagOfCraftingDisplayRecipesMode"] == "Pickups Only" then
if mode == "Pickups Only" then
EID:appendToDescription(customDescObj, getHotkeyString())
EID:appendToDescription(customDescObj, getFloorItemsString(false, roomItems))
EID:addDescriptionToPrint(customDescObj)
return true
elseif EID.Config["BagOfCraftingDisplayRecipesMode"] == "Item Probability" then
elseif mode == "Item Probability" then
if not EID.RefreshBagTextbox and prevDesc ~= "" and not EID.OptionChanged then
EID:appendToDescription(customDescObj, prevDesc)
EID:addDescriptionToPrint(customDescObj)
@@ -1135,12 +1221,18 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
-- Recipe List display
displayingRecipeList = true
if sortNeeded then
if EID.BoC.SortNeeded then
sortAllItems()
sortNeeded = false
EID.BoC.SortNeeded = false
end
if lockedResults ~= nil then
if mode == "Learned Recipe List" then
if ModConfigMenu and ModConfigMenu.IsVisible then
MCMLearnedRecipeList()
else
LearnedRecipeList() --todo: do this less often
end
elseif lockedResults ~= nil then
currentRecipesList = calcResultCache[lockedResults]
elseif (calcResultCache[queryString] == nil or refreshNextTick) and EID.Coroutines["RecipeCrunch"] == nil then
isRefresh = refreshNextTick
@@ -1209,17 +1301,31 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
if (lockedResults) then
prefix = "#{{Trinket159}} "
end
local moreDesc = EID:getDescriptionEntry("CraftingMore")
-- Build the list of recipes that we will actually be displaying, dependent on bag contents (if not T.Cain) and active search
local filteredRecipesList = {}
local filteredNumResults = 0
local tcain = IsTaintedCain()
for _,id in ipairs(sortedIDs) do
filteredRecipesList[id] = {}
local IDsToCheck = { }
if EID:BoCSGetSearchEnabled() then
-- Filter out item names that don't match our search term
local itemName = EID:getDescriptionData(5, 100, id)[2];
local englishName = EID:getDescriptionDataEnglish(5, 100, id)[2];
local searchValid = not EID:BoCSGetSearchEnabled() or EID:BoCSCheckItemName(itemName, englishName)
if (searchValid) then
for _,id in ipairs(sortedIDs) do
local searchValid = #currentRecipesList[id] > 0 and (not EID:BoCSGetSearchEnabled() or EID:BoCSCheckItemName(EID:getDescriptionData(5, 100, id)[2]))
if (searchValid) then table.insert(IDsToCheck, id) end
end
-- Nothing in our recipe list passed the test; try checking English names as a backup
if #IDsToCheck == 0 then
for _,id in ipairs(sortedIDs) do
local searchValid = not EID:BoCSGetSearchEnabled() or EID:BoCSCheckItemName(EID:getDescriptionDataEnglish(5, 100, id)[2])
if (searchValid) then table.insert(IDsToCheck, id) end
end
end
else IDsToCheck = sortedIDs end
for _,id in ipairs(IDsToCheck) do
filteredRecipesList[id] = {}
-- If we aren't Tainted Cain, we should filter out recipes that don't use everything in our bag
for _, v in ipairs(currentRecipesList[id]) do
if (tcain or EID:bagContainsCount(v[1]) == #bagItems) then
@@ -1228,7 +1334,6 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
end
end
end
end
-- Keeping the offset doesn't work at all with non-Tainted-Cain bag-filtered results;
-- just reset us to 0 if we end up past the end of the list for now...
@@ -1236,11 +1341,11 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
--filteredRecipesList is a table of tables for each item, so we have to iterate over the table using sortedIDs
if (bagOfCraftingOffset > 0) then
prevDesc = prevDesc .. prefix .. "...+"..bagOfCraftingOffset.." more"
prevDesc = prevDesc .. prefix .. moreDesc:gsub("{1}", bagOfCraftingOffset)
end
local curOffset = 0
refreshPosition = -1
for _,id in ipairs(sortedIDs) do
for _,id in ipairs(IDsToCheck) do
if (curOffset + #filteredRecipesList[id] <= bagOfCraftingOffset) then curOffset = curOffset + #filteredRecipesList[id]
else
if (refreshPosition == -1) then refreshPosition = id end
@@ -1257,9 +1362,8 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
--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?
prevDesc = prevDesc .."#{{Collectible"..v[2].."}} ".. qualities[CraftingItemQualities[v[2]]] ..
string.sub(itemName,1,18).."#"
itemName.."{{NoLineBreak}}#"
else
prevDesc = prevDesc .."#"
end
@@ -1272,7 +1376,9 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
end
end
if (bagOfCraftingOffset + EID.Config["BagOfCraftingResults"] < filteredNumResults) then
prevDesc = prevDesc .. prefix .. "...+"..(filteredNumResults-EID.Config["BagOfCraftingResults"]-bagOfCraftingOffset).." more"
prevDesc = prevDesc .. prefix .. moreDesc:gsub("{1}",(filteredNumResults-EID.Config["BagOfCraftingResults"]-bagOfCraftingOffset))
elseif lockedResults then
prevDesc = prevDesc .. prefix
end
EID:appendToDescription(customDescObj, prevDesc)