From de7668bcba6c0f0b2683b6294d85a25b4d4f6e87 Mon Sep 17 00:00:00 2001 From: Wofsauge Date: Tue, 23 Apr 2024 22:25:28 +0200 Subject: [PATCH] ItemReminder: Added player selection feature and description entry limit --- descriptions/ab+/en_us.lua | 1 + eid_api.lua | 7 ++ eid_config.lua | 12 +++- eid_holdmapdesc.lua | 135 +++++++++++++++++++++++-------------- eid_mcm.lua | 6 ++ main.lua | 5 +- 6 files changed, 114 insertions(+), 52 deletions(-) diff --git a/descriptions/ab+/en_us.lua b/descriptions/ab+/en_us.lua index 730811e6..ae52d270 100644 --- a/descriptions/ab+/en_us.lua +++ b/descriptions/ab+/en_us.lua @@ -918,6 +918,7 @@ EID.descriptions[languageCode].MCM = { -- the ItemReminder description will predict the abilities of items with a header like "Item Name Result" EID.descriptions[languageCode].ItemReminder = { ResultHeader = " Result", + InventoryEmpty = "(Player has no items)", CategoryNames = { Overview = "Inventory Overview", Special = "Special", diff --git a/eid_api.lua b/eid_api.lua index 2b2663c2..3f910ebb 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -1971,4 +1971,11 @@ function EID:GetIconStringByDescriptionObject(descObj) end end return "{{Blank}}" +end + +-- returns the markup for a given player ID or type. If no icon was found, returns the customTransformation icon markup +function EID:GetPlayerIcon(playerID, altFallback) + local fallback = altFallback or "{{CustomTransformation}}" + + return EID:getIcon("Player" .. playerID) ~= EID.InlineIcons["ERROR"] and "{{Player" .. playerID .. "}}" or fallback end \ No newline at end of file diff --git a/eid_config.lua b/eid_config.lua index cfad24c5..57abeb7f 100644 --- a/eid_config.lua +++ b/eid_config.lua @@ -336,7 +336,15 @@ EID.UserConfig = { -- Look into the AB+ or Repentance documentation for the key names here: https://wofsauge.github.io/IsaacDocs/rep/enums/ButtonAction.html -- Default = ButtonAction.ACTION_SHOOTLEFT ["ItemReminderNavigateRightButton"] = ButtonAction.ACTION_SHOOTRIGHT, - -- + -- Set the keybinding that is used to scroll thru the players in the left direction + -- Look into the AB+ or Repentance documentation for the key names here: https://wofsauge.github.io/IsaacDocs/rep/enums/ButtonAction.html + -- Default = ButtonAction.ACTION_SHOOTDOWN + ["ItemReminderNavigateDownButton"] = ButtonAction.ACTION_SHOOTDOWN, + -- Number of entries to display per category of the item description. + -- Set the keybinding that is used to scroll thru the players in the right direction + -- Look into the AB+ or Repentance documentation for the key names here: https://wofsauge.github.io/IsaacDocs/rep/enums/ButtonAction.html + -- Default = ButtonAction.ACTION_SHOOTUP + ["ItemReminderNavigateUpButton"] = ButtonAction.ACTION_SHOOTUP, -- Default = 3 ["ItemReminderMaxEntriesCount"] = 3, -- Show recently acquired item descriptions in the Item Reminder (good for Curse of the Blind!) @@ -607,6 +615,8 @@ EID.DefaultConfig = { ["BagOfCraftingToggleKey"] = ButtonAction.ACTION_MAP, ["ItemReminderNavigateLeftButton"] = ButtonAction.ACTION_SHOOTLEFT, ["ItemReminderNavigateRightButton"] = ButtonAction.ACTION_SHOOTRIGHT, + ["ItemReminderNavigateDownButton"] = ButtonAction.ACTION_SHOOTDOWN, + ["ItemReminderNavigateUpButton"] = ButtonAction.ACTION_SHOOTUP, ["ItemReminderMaxEntriesCount"] = 5, ["ItemReminderShowRecentItem"] = 1, ["ItemReminderShowActiveDesc"] = 1, diff --git a/eid_holdmapdesc.lua b/eid_holdmapdesc.lua index cf10e902..328be874 100644 --- a/eid_holdmapdesc.lua +++ b/eid_holdmapdesc.lua @@ -3,10 +3,13 @@ local GLITCH_ITEM_FLAG = 4294967296 local currentBlacklist local lastInputTime = 0 local lastScrollDirection = 1 -- used for automatic scroll feature, if no description is visible for a category +local lastAutoScrollPosition = -1 -- Stores last category before the automatic category skip. This prevents infinite loops, when the player has no items +local numAvailableDescriptionSlots = 0 EID.ItemReminderBlacklist = { ["5.100.714"] = true, ["5.100.715"] = true } -- Dont display these in the Item reminder view EID.ItemReminderTempDescriptions = {} -- Temporary stores descriptions that will be displayed after everythng got evaluated EID.ItemReminderSelectedCategory = 0 -- Currently selected category +EID.ItemReminderSelectedPlayer = 0 -- Currently selected player EID.InsideItemReminder = false -- Disable some modifiers, when building the Item Reminder description -- TODO: @@ -251,8 +254,16 @@ EID.ItemReminderDescriptionModifier = { -- Simple function to help with adding properly formatted sections to the reminder description +-- returns false, when no further descriptions should be added function EID:ItemReminderAddTempDescriptionEntry(icon, title, newDesc) table.insert(EID.ItemReminderTempDescriptions, { icon or "{{Blank}}", title, newDesc }) + numAvailableDescriptionSlots = numAvailableDescriptionSlots - 1 + return EID:ItemReminderCanAddMoreToView() +end + +-- returns true, if its possible for the currently evaluated view to have more descriptions added to it +function EID:ItemReminderCanAddMoreToView() + return numAvailableDescriptionSlots > 0 end -- Adds a formatted "Result" text to the item name @@ -269,7 +280,7 @@ end -- Add item description for a given entity to the reminder. Also tries to apply special modifiers if present function EID:ItemReminderAddDescription(player, entityType, variant, subType, extraIcon) local objectID = entityType .. "." .. variant .. "." .. subType - if currentBlacklist[objectID] then return end + if currentBlacklist[objectID] then return true end local descObj = EID:getDescriptionObj(entityType, variant, subType) @@ -285,21 +296,18 @@ function EID:ItemReminderAddDescription(player, entityType, variant, subType, ex currentBlacklist[objectID] = true local iconString = extraIcon or EID:GetIconStringByDescriptionObject(descObj) - EID:ItemReminderAddTempDescriptionEntry(iconString, descObj.Name, descObj.Description) + return EID:ItemReminderAddTempDescriptionEntry(iconString, descObj.Name, descObj.Description) end -- Recently Acquired Item Descriptions function EID:ItemReminderHandleRecentItems(player) - 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] % GLITCH_ITEM_FLAG - EID:ItemReminderAddDescription(player, 5, 100, recentID) - end + local playerNum = EID:getPlayerID(player) + if EID.RecentlyTouchedItems[playerNum] then + for i = #EID.RecentlyTouchedItems[playerNum], 1, -1 do + if not EID:ItemReminderCanAddMoreToView() then return end + + local recentID = EID.RecentlyTouchedItems[playerNum][i] % GLITCH_ITEM_FLAG + EID:ItemReminderAddDescription(player, 5, 100, recentID) end end end @@ -307,7 +315,8 @@ end -- Active Item Descriptions function EID:ItemReminderHandleActiveItems(player) -- limit number of active item descriptions to 2, since Slot 3 and 4 are handled seperately - for i = 0, math.min(EID.Config["ItemReminderShowActiveDesc"], 2) - 1 do + for i = 0, 1 do + if not EID:ItemReminderCanAddMoreToView() then return end -- the modulo is to convert negative IDs (glitched items) to positive IDs local heldActive = player:GetActiveItem(i) % GLITCH_ITEM_FLAG if heldActive > 0 then @@ -318,8 +327,7 @@ end -- pocket active function EID:ItemReminderHandlePocketActive(player) - if not EID.isRepentance then return end - + if not EID.isRepentance or not EID:ItemReminderCanAddMoreToView() then return end local pocketActive = player:GetActiveItem(2) or 0 if pocketActive > 0 then EID:ItemReminderAddDescription(player, 5, 100, pocketActive) @@ -328,7 +336,7 @@ end -- dice bag function EID:ItemReminderHandleDiceBag(player) - if not EID.isRepentance then return end + if not EID.isRepentance or not EID:ItemReminderCanAddMoreToView() then return end local diceBag = player:GetActiveItem(3) or 0 if diceBag > 0 then @@ -338,7 +346,8 @@ end -- Pocket Item Descriptions function EID:ItemReminderHandlePocketItems(player) - for i = 0, EID.Config["ItemReminderShowPocketDesc"] - 1 do + for i = 0, 2 do + if not EID:ItemReminderCanAddMoreToView() then return end local heldCard = player:GetCard(i) local heldPill = player:GetPill(i) if heldCard > 0 then @@ -358,7 +367,8 @@ end -- Trinket Descriptions function EID:ItemReminderHandleTrinkets(player) - for t = 0, EID.Config["ItemReminderShowTrinketDesc"] - 1 do + for t = 0, 1 do + if not EID:ItemReminderCanAddMoreToView() then return end -- account for Golden Trinket IDs local heldTrinketTrue = player:GetTrinket(t) local heldTrinket = heldTrinketTrue @@ -372,16 +382,16 @@ end -- Gulped/unslotted Modeling Clay -- (Hidden information, because Modeling Clay does not visually show its item when gulped) function EID:ItemReminderHandleGulpedModelingClay(player) - if EID.isRepentance and EID.Config["ItemReminderShowHiddenInfo"] and player:GetModelingClayEffect() > 0 then + if EID.isRepentance and EID.Config["ItemReminderShowHiddenInfo"] and player:GetModelingClayEffect() > 0 and EID:ItemReminderCanAddMoreToView() then EID:ItemReminderAddDescription(player, 5, 350, 166) end end -- Tainted ??? Poop Descriptions function EID:ItemReminderHandlePoopSpells(player) - if EID.isRepentance and EID.Config["ItemReminderShowPoopDesc"] > 0 and player:GetPlayerType() == 25 then + if EID.isRepentance and player:GetPlayerType() == 25 and EID:ItemReminderCanAddMoreToView() then local poopInfo = EID:getDescriptionEntry("poopSpells") - for i = 0, EID.Config["ItemReminderShowPoopDesc"] - 1 do + for i = 0, 3 do local nextPoop = player:GetPoopSpell(i) EID:ItemReminderAddTempDescriptionEntry("{{PoopSpell" .. nextPoop .. "}}", poopInfo[nextPoop][1], poopInfo[nextPoop][2]) @@ -410,6 +420,16 @@ function EID:ItemReminderHandleInputs() EID.ForceRefreshCache = true lastInputTime = Isaac.GetTime() lastScrollDirection = 1 + elseif Input.IsActionTriggered(EID.Config["ItemReminderNavigateDownButton"], EID.holdTabPlayer.ControllerIndex) and Isaac.GetTime() - lastInputTime > 50 then + EID.ItemReminderSelectedPlayer = (EID.ItemReminderSelectedPlayer - 1) % #EID.coopAllPlayers + + EID.ForceRefreshCache = true + lastInputTime = Isaac.GetTime() + elseif Input.IsActionTriggered(EID.Config["ItemReminderNavigateUpButton"], EID.holdTabPlayer.ControllerIndex) and Isaac.GetTime() - lastInputTime > 50 then + EID.ItemReminderSelectedPlayer = (EID.ItemReminderSelectedPlayer + 1) % #EID.coopAllPlayers + + EID.ForceRefreshCache = true + lastInputTime = Isaac.GetTime() end end end @@ -421,68 +441,83 @@ function EID:ItemReminderGetTitle() local translatedTitleEnglish = EID:getDescriptionEntryEnglish("ItemReminder", "CategoryNames") local title = translatedTitle and translatedTitle[category.id] or translatedTitleEnglish and translatedTitleEnglish[category.id] or category.id - return "{{ButtonDLeft}}{{ColorText}} " .. title .. " {{CR}}{{ButtonDRight}}" + + local combinedText = EID.ButtonToIconMap[EID.Config["ItemReminderNavigateLeftButton"]] .. + "{{ColorText}} " .. title .. " {{CR}}" .. EID.ButtonToIconMap[EID.Config["ItemReminderNavigateRightButton"]] + + -- add player toggle when more than 1 player is present + if #EID.coopAllPlayers > 1 then + local currentPlayer = EID.coopAllPlayers[EID.ItemReminderSelectedPlayer + 1] + local playerIcon = EID:GetPlayerIcon(currentPlayer:GetPlayerType()) + combinedText = EID.ButtonToIconMap[EID.Config["ItemReminderNavigateDownButton"]] .. " " .. + playerIcon .. " " .. EID.ButtonToIconMap[EID.Config["ItemReminderNavigateUpButton"]] .. " " .. combinedText + end + + return combinedText end -function EID:ItemReminderGetDescription(player, checkingTwin) +function EID:ItemReminderGetDescription() EID.InsideItemReminder = true EID.ItemReminderTempDescriptions = {} -- empty blacklist and fill with default values currentBlacklist = {} for key, _ in pairs(EID.ItemReminderBlacklist) do currentBlacklist[key] = true end + + local player = EID.coopMainPlayers[EID.ItemReminderSelectedPlayer + 1] + if EID.Config["ItemReminderShowOverview"] and EID.ItemReminderSelectedCategory == 0 then -- execute all functions defined per category for _, category in ipairs(EID.ItemReminderCategories) do + numAvailableDescriptionSlots = 1 -- limit to one description per category in overview mode for _, func in ipairs(category.entryGenerators) do func(player) end end else local category = EID.ItemReminderCategories[EID.ItemReminderSelectedCategory + 1] + numAvailableDescriptionSlots = EID.Config["ItemReminderMaxEntriesCount"] for _, func in ipairs(category.entryGenerators) do func(player) end end -- Skip category if nothing is in it - if #EID.ItemReminderTempDescriptions == 0 and EID.ItemReminderSelectedCategory <= #EID.ItemReminderCategories then + if #EID.ItemReminderTempDescriptions == 0 then + if lastAutoScrollPosition == -1 then + -- auto scroll was started. store last valid category. skip overview if its disabled + if not EID.Config["ItemReminderShowOverview"] and EID.ItemReminderSelectedCategory == 0 then + lastAutoScrollPosition = lastScrollDirection % #EID.ItemReminderCategories + else + lastAutoScrollPosition = EID.ItemReminderSelectedCategory + end + end + EID.ItemReminderSelectedCategory = (EID.ItemReminderSelectedCategory + lastScrollDirection) % #EID.ItemReminderCategories if not EID.Config["ItemReminderShowOverview"] and EID.ItemReminderSelectedCategory == 0 then - EID.ItemReminderSelectedCategory = lastScrollDirection % #EID.ItemReminderCategories + EID.ItemReminderSelectedCategory = #EID.ItemReminderCategories end - return EID:ItemReminderGetDescription(player, checkingTwin) + + if lastAutoScrollPosition ~= EID.ItemReminderSelectedCategory then + -- new category found. try to display text + local newCategoryText = EID:ItemReminderGetDescription() + if newCategoryText ~= "" then + return newCategoryText + end + end + -- auto scroll was stopped. reset scroll value + lastAutoScrollPosition = -1 + + return "{{Blank}}#{{Blank}} " .. EID:getDescriptionEntry("ItemReminder", "InventoryEmpty") end + lastAutoScrollPosition = -1 + -- put descriptions into one long description local finalHoldMapDesc = "" for _, entry in ipairs(EID.ItemReminderTempDescriptions) do finalHoldMapDesc = finalHoldMapDesc .. entry[1] .. " {{ColorEIDObjName}}" .. entry[2] .. "#" .. entry[3] .. "#" 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 EID.isRepentance and not checkingTwin then - local twin = player:GetOtherTwin() - local mainTwinDesc = finalHoldMapDesc - local otherTwinDesc = "" - if twin then otherTwinDesc = EID:ItemReminderGetDescription(twin, true) end - if otherTwinDesc ~= "" then - -- Only the other twin had a desc - if mainTwinDesc == "" then - finalHoldMapDesc = otherTwinDesc - else - -- Both twins had a desc; merge them with player icon headers - finalHoldMapDesc = (EID:getIcon("Player" .. player:GetPlayerType()) ~= EID.InlineIcons["ERROR"] and "{{Player" .. player:GetPlayerType() .. "}}" or "{{CustomTransformation}}") .. - " {{ColorGray}}" .. player:GetName() .. "#" .. mainTwinDesc .. "#" - finalHoldMapDesc = finalHoldMapDesc .. - (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 - finalHoldMapDesc = mainTwinDesc - end - end finalHoldMapDesc = "{{Blank}}#" .. finalHoldMapDesc EID.InsideItemReminder = false diff --git a/eid_mcm.lua b/eid_mcm.lua index 0e37ad4b..a87e9813 100644 --- a/eid_mcm.lua +++ b/eid_mcm.lua @@ -598,6 +598,12 @@ if MCMLoaded then EID:AddNumberSetting("Reminder", "ItemReminderNavigateRightButton", "Navigate Right", 0, 13, {displayTable = actionToName, infoText = {"Keybinding that is used to scroll thru the categories in the left direction"}}) + EID:AddNumberSetting("Reminder", "ItemReminderNavigateDownButton", "Navigate Down", 0, 13, {displayTable = actionToName, + infoText = {"Keybinding that is used to scroll thru the players in the left direction"}}) + + EID:AddNumberSetting("Reminder", "ItemReminderNavigateUpButton", "Navigate Up", 0, 13, {displayTable = actionToName, + infoText = {"Keybinding that is used to scroll thru the players in the right direction"}}) + MCM.AddSpace("EID", "Reminder") MCM.AddText("EID", "Reminder", "Item Descriptions") -- should these be organized in the order they're shown in the map desc code? diff --git a/main.lua b/main.lua index 5de9476d..a71e8ee2 100644 --- a/main.lua +++ b/main.lua @@ -1285,6 +1285,9 @@ function EID:OnRender() local tabHeld, playerNumHoldingTab = EID:PlayersActionPressed(EID.Config["BagOfCraftingToggleKey"]) if tabHeld then EID.holdTabPlayer = EID.coopMainPlayers[playerNumHoldingTab] + if EID.holdTabCounter == 0 then -- update item reminder player selection + EID.ItemReminderSelectedPlayer = playerNumHoldingTab - 1 + end EID.holdTabCounter = EID.holdTabCounter + 1 else EID.holdTabPlayer = nil @@ -1580,7 +1583,7 @@ function EID:OnRender() local demoDescObj = EID:getDescriptionObj(-999, -1, 1) demoDescObj.PermanentTextEnglish = EID:getDescriptionEntryEnglish("ItemReminder", "Title") -- check for scrolling being enabled here and append scroll controls to the title? - demoDescObj.Description = EID:ItemReminderGetDescription(EID.holdTabPlayer) + demoDescObj.Description = EID:ItemReminderGetDescription() demoDescObj.Name = EID:ItemReminderGetTitle() if (demoDescObj.Description ~= "") then EID:addDescriptionToPrint(demoDescObj, 1) end end