BoC: Added basic search function
This commit is contained in:
1 parent
78052f2e5c
commit
de1d96a103
2 files changed
+305
-5
No files matched your search
+37
-5
@@ -1,5 +1,7 @@
|
|||||||
local game = Game()
|
local game = Game()
|
||||||
|
|
||||||
|
require("eid_bagofcrafting_search")
|
||||||
|
|
||||||
--these aren't local so that they can be saved and reloaded, or cleared in the Mod Config Menu
|
--these aren't local so that they can be saved and reloaded, or cleared in the Mod Config Menu
|
||||||
EID.BoC = {}
|
EID.BoC = {}
|
||||||
EID.BoC.CurrentPickupCount = -1
|
EID.BoC.CurrentPickupCount = -1
|
||||||
@@ -235,6 +237,9 @@ local recheckPickups = false
|
|||||||
local customRNGSeed = 0x77777770
|
local customRNGSeed = 0x77777770
|
||||||
local customRNGShift = {0,0,0}
|
local customRNGShift = {0,0,0}
|
||||||
|
|
||||||
|
local lastSearchValue = "";
|
||||||
|
local lastSearchInputEnabled = false;
|
||||||
|
|
||||||
-- Use local RNG functions to possibly reduce processing time a little bit
|
-- Use local RNG functions to possibly reduce processing time a little bit
|
||||||
local function RNGNext()
|
local function RNGNext()
|
||||||
local num = customRNGSeed
|
local num = customRNGSeed
|
||||||
@@ -930,6 +935,15 @@ function EID:handleBagOfCraftingUpdating()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local currentSearchValue = EID:BoCSGetSearchValue()
|
||||||
|
local currentSearchInputEnabled = EID:BoCSGetSearchInputEnabled()
|
||||||
|
EID:BoCSHandleInput()
|
||||||
|
if currentSearchValue ~= lastSearchValue or currentSearchInputEnabled ~= lastSearchInputEnabled then
|
||||||
|
refreshNextTick = true
|
||||||
|
end
|
||||||
|
lastSearchValue = currentSearchValue
|
||||||
|
lastSearchInputEnabled = currentSearchInputEnabled
|
||||||
|
|
||||||
-- Check for Hold Tab key inputs
|
-- Check for Hold Tab key inputs
|
||||||
if displayingRecipeList and Input.IsActionPressed(EID.Config["BagOfCraftingToggleKey"], EID.bagPlayer.ControllerIndex) then
|
if displayingRecipeList and Input.IsActionPressed(EID.Config["BagOfCraftingToggleKey"], EID.bagPlayer.ControllerIndex) then
|
||||||
EID.TabDescThisFrame = true
|
EID.TabDescThisFrame = true
|
||||||
@@ -1176,6 +1190,11 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
|
|||||||
prevDesc = ""
|
prevDesc = ""
|
||||||
EID.RefreshBagTextbox = false
|
EID.RefreshBagTextbox = false
|
||||||
|
|
||||||
|
local searchLine = EID:BoCSGetSearchLine()
|
||||||
|
if searchLine ~= nil then
|
||||||
|
prevDesc = prevDesc .. searchLine
|
||||||
|
end
|
||||||
|
|
||||||
prevDesc = prevDesc .. getHotkeyString()
|
prevDesc = prevDesc .. getHotkeyString()
|
||||||
prevDesc = prevDesc .. getFloorItemsString(true, roomItems)
|
prevDesc = prevDesc .. getFloorItemsString(true, roomItems)
|
||||||
if (EID.Config["BagOfCraftingShowControls"]) then
|
if (EID.Config["BagOfCraftingShowControls"]) then
|
||||||
@@ -1191,7 +1210,6 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
|
|||||||
prefix = "#{{Trinket159}} "
|
prefix = "#{{Trinket159}} "
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local filteredRecipesList = {}
|
local filteredRecipesList = {}
|
||||||
local filteredNumResults = 0
|
local filteredNumResults = 0
|
||||||
-- If we aren't Tainted Cain, we should filter out recipes that don't use everything in our bag
|
-- If we aren't Tainted Cain, we should filter out recipes that don't use everything in our bag
|
||||||
@@ -1199,15 +1217,28 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
|
|||||||
for _,id in ipairs(sortedIDs) do
|
for _,id in ipairs(sortedIDs) do
|
||||||
filteredRecipesList[id] = {}
|
filteredRecipesList[id] = {}
|
||||||
for _, v in ipairs(currentRecipesList[id]) do
|
for _, v in ipairs(currentRecipesList[id]) do
|
||||||
if (EID:bagContainsCount(v[1]) == #bagItems) then
|
local itemName = EID:getObjectName(5, 100, v[2]);
|
||||||
|
local searchValid = not EID:BoCSGetSearchEnabled() or EID:BoCSCheckItemName(itemName)
|
||||||
|
|
||||||
|
if (searchValid and EID:bagContainsCount(v[1]) == #bagItems) then
|
||||||
table.insert(filteredRecipesList[id], v)
|
table.insert(filteredRecipesList[id], v)
|
||||||
filteredNumResults = filteredNumResults + 1
|
filteredNumResults = filteredNumResults + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
filteredRecipesList = currentRecipesList
|
for _,id in ipairs(sortedIDs) do
|
||||||
filteredNumResults = numResults
|
filteredRecipesList[id] = {}
|
||||||
|
for _, v in ipairs(currentRecipesList[id]) do
|
||||||
|
local itemName = EID:getObjectName(5, 100, v[2]);
|
||||||
|
local searchValid = not EID:BoCSGetSearchEnabled() or EID:BoCSCheckItemName(itemName)
|
||||||
|
|
||||||
|
if (searchValid) then
|
||||||
|
table.insert(filteredRecipesList[id], v)
|
||||||
|
filteredNumResults = filteredNumResults + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Keeping the offset doesn't work at all with non-Tainted-Cain bag-filtered results;
|
-- Keeping the offset doesn't work at all with non-Tainted-Cain bag-filtered results;
|
||||||
@@ -1229,6 +1260,7 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
|
|||||||
if (curOffset > bagOfCraftingOffset+EID.Config["BagOfCraftingResults"]) then break end
|
if (curOffset > bagOfCraftingOffset+EID.Config["BagOfCraftingResults"]) then break end
|
||||||
if not v then break end
|
if not v then break end
|
||||||
if (curOffset > bagOfCraftingOffset) then
|
if (curOffset > bagOfCraftingOffset) then
|
||||||
|
local itemName = EID:getObjectName(5, 100, v[2]);
|
||||||
if not EID.Config["BagOfCraftingDisplayNames"] then
|
if not EID.Config["BagOfCraftingDisplayNames"] then
|
||||||
prevDesc = prevDesc .."#{{Collectible"..v[2].."}} "
|
prevDesc = prevDesc .."#{{Collectible"..v[2].."}} "
|
||||||
--color the equals sign with the item quality, so the order of the list can make sense
|
--color the equals sign with the item quality, so the order of the list can make sense
|
||||||
@@ -1238,7 +1270,7 @@ function EID:handleBagOfCraftingRendering(ignoreRefreshRate)
|
|||||||
if prevItem ~= v[2] then
|
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?
|
--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]]] ..
|
prevDesc = prevDesc .."#{{Collectible"..v[2].."}} ".. qualities[CraftingItemQualities[v[2]]] ..
|
||||||
string.sub(EID:getObjectName(5, 100, v[2]),1,18).."#"
|
string.sub(itemName,1,18).."#"
|
||||||
else
|
else
|
||||||
prevDesc = prevDesc .."#"
|
prevDesc = prevDesc .."#"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,268 @@
|
|||||||
|
local indexCharMapping = " ??????'????,-./0123456789?;?????abcdefghijklmnopqrstuvwxyz"
|
||||||
|
local searchValue = ""
|
||||||
|
local searchInputEnabled = false
|
||||||
|
local lastBackspaceTrigger = 0
|
||||||
|
local backspaceStep = 0
|
||||||
|
|
||||||
|
--- Returns the current search query
|
||||||
|
-- @return string
|
||||||
|
function EID:BoCSGetSearchValue()
|
||||||
|
return searchValue
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Enables or disables the search input respectively
|
||||||
|
-- @param newState boolean
|
||||||
|
function EID:BoCSSetSearchInputEnabled(newState)
|
||||||
|
searchInputEnabled = newState
|
||||||
|
|
||||||
|
if newState then
|
||||||
|
EID:AddCallback(ModCallbacks.MC_INPUT_ACTION, EID.BoCSBlockInputAction)
|
||||||
|
else
|
||||||
|
EID:RemoveCallback(ModCallbacks.MC_INPUT_ACTION, EID.BoCSBlockInputAction)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns if the search input is enabled
|
||||||
|
-- @returns boolean
|
||||||
|
function EID:BoCSGetSearchInputEnabled()
|
||||||
|
return searchInputEnabled
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets if the filtering is currently enabled
|
||||||
|
function EID:BoCSGetSearchEnabled()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns true if the item name is matched
|
||||||
|
-- @returns boolean
|
||||||
|
function EID:BoCSCheckItemName(itemName)
|
||||||
|
if searchValue == "" then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return string.find(string.lower(itemName), string.lower(searchValue))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Handles any input done related to Bag of Crafting search
|
||||||
|
function EID:BoCSHandleInput()
|
||||||
|
if Game():IsPaused() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if EID.bagPlayer == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if Input.IsButtonTriggered(Keyboard.KEY_ENTER, EID.bagPlayer.ControllerIndex, true) then
|
||||||
|
EID:BoCSSetSearchInputEnabled(not searchInputEnabled)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if searchInputEnabled then
|
||||||
|
local newValue = searchValue
|
||||||
|
local index = 0
|
||||||
|
local hasLetterInput = false
|
||||||
|
|
||||||
|
-- Keep in mind that this only works because the respective
|
||||||
|
-- enum values are integers
|
||||||
|
for i=Keyboard.KEY_SPACE,Keyboard.KEY_Z do
|
||||||
|
index = index + 1
|
||||||
|
if Input.IsButtonTriggered(i, EID.bagPlayer.ControllerIndex, true) then
|
||||||
|
local toAppend = string.upper(indexCharMapping:sub(index, index))
|
||||||
|
|
||||||
|
newValue = newValue .. toAppend
|
||||||
|
hasLetterInput = true
|
||||||
|
|
||||||
|
-- We only handle one input at a time
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
if hasLetterInput then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if Input.IsButtonTriggered(Keyboard.KEY_BACKSPACE, EID.bagPlayer.ControllerIndex, true) then
|
||||||
|
lastBackspaceTrigger = 0
|
||||||
|
backspaceStep = 0
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local currentFrame = Game():GetFrameCount()
|
||||||
|
-- 30 Frames = 1 second
|
||||||
|
-- 15 = 500ms
|
||||||
|
if Input.IsButtonPressed(Keyboard.KEY_BACKSPACE, EID.bagPlayer.ControllerIndex, true) and (
|
||||||
|
backspaceStep == 0
|
||||||
|
or
|
||||||
|
(backspaceStep == 1 and currentFrame - lastBackspaceTrigger > 15) -- we delay the second deletion a little bit more
|
||||||
|
or
|
||||||
|
(backspaceStep >= 2 and currentFrame - lastBackspaceTrigger > 3)
|
||||||
|
) then
|
||||||
|
local isControlPressed = (
|
||||||
|
Input.IsButtonPressed(Keyboard.KEY_LEFT_CONTROL, EID.bagPlayer.ControllerIndex, true)
|
||||||
|
or
|
||||||
|
Input.IsButtonPressed(Keyboard.KEY_RIGHT_CONTROL, EID.bagPlayer.ControllerIndex, true)
|
||||||
|
)
|
||||||
|
|
||||||
|
if isControlPressed then
|
||||||
|
newValue = ""
|
||||||
|
else
|
||||||
|
newValue = searchValue:sub(1, -2)
|
||||||
|
end
|
||||||
|
|
||||||
|
lastBackspaceTrigger = currentFrame
|
||||||
|
backspaceStep = backspaceStep + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
searchValue = newValue
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the line that should be displayed inside of the menu
|
||||||
|
function EID:BoCSGetSearchLine()
|
||||||
|
if not searchInputEnabled and (searchValue == nil or searchValue == "") then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = ""
|
||||||
|
|
||||||
|
if searchInputEnabled then
|
||||||
|
result = "{{ColorGreen}}"
|
||||||
|
end
|
||||||
|
|
||||||
|
result = result .. "Search: " .. searchValue .. "#"
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- This is a workaround to block every single Input call that could potentially be
|
||||||
|
-- used from another mod.
|
||||||
|
-- We override the Input functions with our own stubs to prevent other mods from
|
||||||
|
-- doing actions while the user is performing a search.
|
||||||
|
-- This does NOT block the main game from performing actions like toggling fullscreen
|
||||||
|
-- or toggling the pause!--
|
||||||
|
-- Since this could be useful for multiple reasons, this should probably be put
|
||||||
|
-- inside the main.lua instead of leaving this here
|
||||||
|
-- Hooking multiple times WILL impact the performance!--
|
||||||
|
-- I've also added a third parameter called "force"
|
||||||
|
-- This way, we are still able to force the real function to be called instead
|
||||||
|
-- of our modified code--
|
||||||
|
-- This code should not impact the performance in a huge way
|
||||||
|
-- since the first thing we do is check if the searchInput is enabled anyway
|
||||||
|
-- We can allow losing a bit of performance when searching
|
||||||
|
function EID:BoCSHookInput()
|
||||||
|
local oldInputIsButtonTriggered = Input.IsButtonTriggered
|
||||||
|
local oldInputIsButtonPressed = Input.IsButtonPressed
|
||||||
|
local oldInputIsActionTriggered = Input.IsActionTriggered
|
||||||
|
local oldInputIsActionPressed = Input.IsActionPressed
|
||||||
|
|
||||||
|
Input.IsButtonTriggered = function(key, controller, force)
|
||||||
|
if force or not searchInputEnabled then
|
||||||
|
return oldInputIsButtonTriggered(key, controller)
|
||||||
|
end
|
||||||
|
|
||||||
|
local bagPlayer = nil
|
||||||
|
if EID.isRepentance then
|
||||||
|
local hasBag, player = EID:PlayersHaveCollectible(710)
|
||||||
|
if hasBag then
|
||||||
|
bagPlayer = player
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if bagPlayer == nil or controller ~= bagPlayer.ControllerIndex then
|
||||||
|
return oldInputIsButtonTriggered(key, controller)
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
Input.IsButtonPressed = function(key, controller, force)
|
||||||
|
if force or not searchInputEnabled then
|
||||||
|
return oldInputIsButtonPressed(key, controller)
|
||||||
|
end
|
||||||
|
|
||||||
|
local bagPlayer = nil
|
||||||
|
if EID.isRepentance then
|
||||||
|
local hasBag, player = EID:PlayersHaveCollectible(710)
|
||||||
|
if hasBag then
|
||||||
|
bagPlayer = player
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if bagPlayer == nil or controller ~= bagPlayer.ControllerIndex then
|
||||||
|
return oldInputIsButtonPressed(key, controller)
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
Input.IsActionTriggered = function(key, controller, force)
|
||||||
|
if force or not searchInputEnabled then
|
||||||
|
return oldInputIsActionTriggered(key, controller)
|
||||||
|
end
|
||||||
|
|
||||||
|
local bagPlayer = nil
|
||||||
|
if EID.isRepentance then
|
||||||
|
local hasBag, player = EID:PlayersHaveCollectible(710)
|
||||||
|
if hasBag then
|
||||||
|
bagPlayer = player
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if bagPlayer == nil or controller ~= bagPlayer.ControllerIndex then
|
||||||
|
return oldInputIsActionTriggered(key, controller)
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
Input.IsActionPressed = function(key, controller, force)
|
||||||
|
if force or not searchInputEnabled then
|
||||||
|
return oldInputIsActionPressed(key, controller)
|
||||||
|
end
|
||||||
|
|
||||||
|
local bagPlayer = nil
|
||||||
|
if EID.isRepentance then
|
||||||
|
local hasBag, player = EID:PlayersHaveCollectible(710)
|
||||||
|
if hasBag then
|
||||||
|
bagPlayer = player
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if bagPlayer == nil or controller ~= bagPlayer.ControllerIndex then
|
||||||
|
return oldInputIsActionPressed(key, controller)
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
Isaac.DebugString("Hooked Input")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Blocks all input actions triggered by the games bindings itself
|
||||||
|
function EID:BoCSBlockInputAction(entity, inputHook, buttonAction)
|
||||||
|
local bagPlayer = nil
|
||||||
|
if EID.isRepentance then
|
||||||
|
local hasBag, player = EID:PlayersHaveCollectible(710)
|
||||||
|
if hasBag then
|
||||||
|
bagPlayer = player
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if bagPlayer == nil then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if inputHook == InputHook.GET_ACTION_VALUE then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if inputHook == InputHook.IS_ACTION_PRESSED or inputHook == InputHook.IS_ACTION_TRIGGERED then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
EID:BoCSHookInput()
|
||||||
Reference in new issue
Block a user