From 75461bedfe9b97d6b6ee5165a7016d29ee21b69f Mon Sep 17 00:00:00 2001 From: Wofsauge Date: Thu, 5 Jun 2025 23:54:03 +0200 Subject: [PATCH] Refactored grid entity handling to allow for custom grid entity descriptions relates to #866 --- features/eid_api.lua | 18 +--- features/eid_conditionals_funcs.lua | 2 +- features/eid_data.lua | 15 --- features/eid_grid_descriptions.lua | 150 ++++++++++++++++++++++++++++ features/eid_holdmapdesc.lua | 8 +- features/eid_modifiers.lua | 15 --- main.lua | 18 +--- 7 files changed, 161 insertions(+), 65 deletions(-) create mode 100644 features/eid_grid_descriptions.lua diff --git a/features/eid_api.lua b/features/eid_api.lua index e0bcf372..442a1f8f 100644 --- a/features/eid_api.lua +++ b/features/eid_api.lua @@ -60,7 +60,6 @@ local dynamicSpriteCache = {} -- used to store sprite objects of collectible ico ---| "pills" @ "5.70" ---| "horsepills" @ "5.70" ---| "horsepill" @ "5.70" ----| "sacrifice" @ "-999.-1" ---| "dice" @ "1000.76" ---| "entity" @ Indicates that a full entity identifier is used @@ -519,7 +518,6 @@ function EID:getIDVariantString(typeName) elseif typeName == "trinket" or typeName == "trinkets" then return "5.350" elseif typeName == "card" or typeName == "cards" then return "5.300" elseif typeName == "pill" or typeName == "pills" or typeName == "horsepills" or typeName == "horsepill" then return "5.70" - elseif typeName == "sacrifice" then return "-999.-1" elseif typeName == "dice" then return "1000.76" end return nil @@ -541,7 +539,6 @@ function EID:getTableName(Type, Variant, SubType) else return "horsepills" end - elseif idString == "-999.-1" then return "sacrifice" elseif idString == "1000.76" then return "dice" elseif idString == "1.0" then return "players" else return "custom" @@ -832,8 +829,6 @@ function EID:getAdjustedSubtype(Type, Variant, SubType) if EID.isRepentance then return (SubType & TrinketType.TRINKET_ID_MASK) end - elseif tableName == "sacrifice" then - return math.min(#EID.descriptions["en"].sacrifice, SubType) elseif tableName == "pills" or tableName == "horsepills" then -- The effect of a pill varies depending on what player is looking at it in co-op -- EID.pillPlayer is a way to recheck a pill for what different players will turn it into @@ -937,8 +932,6 @@ function EID:getObjectName(Type, Variant, SubType) elseif tableName == "pills" or tableName == "horsepills" then local adjustedSubtype = EID:getAdjustedSubtype(Type, Variant, SubType) return EID:getPillName(adjustedSubtype, tableName == "horsepills") - elseif tableName == "sacrifice" then - return EID:getDescriptionEntry("sacrificeHeader").." ("..SubType.."/"..#EID.descriptions["en"].sacrifice..")" elseif tableName == "dice" then return EID:getDescriptionEntry("diceHeader").." ("..SubType..")" elseif tableName == "players" then @@ -1019,14 +1012,7 @@ function EID:hasDescription(entity) if not EID:EntitySanityCheck(entity) then return false end if EID:IsGridEntity(entity) then - if EID.GridEntityWhitelist[entity:GetType()] then - for _, func in ipairs(EID.GridEntityWhitelist[entity:GetType()]) do - if func(entity) then - return true - end - end - end - return false + return EID:CheckGridEntityHasDescription(entity) end local isAllowed = false local entityString = entity.Type .. "." .. entity.Variant .. "." .. entity.SubType @@ -1445,7 +1431,7 @@ function EID:replaceAllMarkupWithSpaces(text, checkBulletpoint) end end -- iconsFound is used to make the next space after a markup icon be immune to line breaks, but only if it's just one icon with no other text - local iconsFound = 0; if text:gsub(" ", ""):gsub("{{.-}}","") ~= "" then iconsFound = -999 end + local iconsFound = 0; if text:gsub(" ", ""):gsub("{{.-}}","") ~= "" then iconsFound = math.mininteger end for word in string.gmatch(text, "{{.-}}") do local lookup = EID:getIcon(word) diff --git a/features/eid_conditionals_funcs.lua b/features/eid_conditionals_funcs.lua index 1cec323c..f9a60f5b 100644 --- a/features/eid_conditionals_funcs.lua +++ b/features/eid_conditionals_funcs.lua @@ -551,7 +551,7 @@ function EID:applyConditionals(descObj) local adjustedSubtype = EID:getAdjustedSubtype(descObj.ObjType, descObj.ObjVariant, descObj.ObjSubType) local typeVar = descObj.ObjType.."."..descObj.ObjVariant -- for general conditions (Tarot Cloth, Book of Virtues) local typeVarSub = descObj.ObjType.."."..descObj.ObjVariant.."."..adjustedSubtype -- for specific conditions - local highestLayer = -999 + local highestLayer = math.mininteger local printedDescs = {} -- Combine specific+generic conditions into one table (in that order) diff --git a/features/eid_data.lua b/features/eid_data.lua index 094a4662..5dde6cd0 100644 --- a/features/eid_data.lua +++ b/features/eid_data.lua @@ -32,21 +32,6 @@ EID.effectList = { ["161"] = true, } --- Grid entity types to be detected by EID --- Add functions to the list to further filter the entries -EID.GridEntityWhitelist = { - [GridEntityType.GRID_SPIKES] = { - function(gridEntity) - return Game():GetRoom():GetType() == RoomType.ROOM_SACRIFICE and - EID.Config["DisplaySacrificeInfo"] - end, - function(gridEntity) - return EID.isRepentance and gridEntity:GetVariant() >= 100 and - EID.Config["DisplaySanguineInfo"] - end, - }, -} - --maps the Player transformation from the enum PlayerForm to the internal transformation table -- Possible usages: EID.TRANSFORMATION[ PlayerForm.PLAYERFORM_MUSHROOM ] -- EID.TRANSFORMATION.MUSHROOM diff --git a/features/eid_grid_descriptions.lua b/features/eid_grid_descriptions.lua new file mode 100644 index 00000000..a1b90657 --- /dev/null +++ b/features/eid_grid_descriptions.lua @@ -0,0 +1,150 @@ +--------------- Grid entity description modifiers --------------- + +-- Table containing grid entity description handlers +-- Use EID:addGridEntity() or EID:addGridEntityConditional() to add new entries to this table. +-- Keys in this table are integers or type GridEntityType +-- Each value is a list of tables with the keys "condition" and "callback", which act like modifiers +-- and define when a description should be shown and how it should be modified. +EID.GridEntityDescriptions = { +} + +--- @deprecated Use EID:addGridEntity() instead +EID.GridEntityWhitelist = setmetatable({}, { + __newindex = function(_, _, _) + EID:WriteErrorMsg("GridEntityWhitelist is deprecated, use EID:addGridEntity() instead.") + end +}) + +--- Adds a new grid entity description entry. +---@param type GridEntityType +---@param variant integer +---@param name string +---@param description string +---@param language? EID_LanguageCode @Default: "en" +function EID:addGridEntity(type, variant, name, description, language) + variant = variant or 0 + language = language or "en" + + EID:CreateDescriptionTableIfMissing("custom", language) + EID.descriptions[language].custom["-999." .. type .. "." .. variant] = { + variant, + name, + description + } + -- Add a new grid entity description entry + if variant == -1 then + -- Apply to all variants of the grid entity type + EID:addGridEntityConditional(type, + function(_) + return true + end, + function(descObj) + if descObj.ObjSubType == -1 then + return descObj + else + return EID:getDescriptionObj(-999, type, -1, descObj.Entity, true) + end + end) + else + -- Only apply to the specific variant of the grid entity type + EID:addGridEntityConditional(type, + function(entity) + return entity:GetVariant() == variant + end, + function(descObj) return descObj end) + end +end + +--- Adds a conditional description handler for a specific grid entity type. +--- This function allows you to specify a grid entity type, a condition function to determine +--- when the description should be shown, and a callback function to modify the description further. +--- @param type GridEntityType +--- @param conditionalFunction function +--- @param callbackFunction function +function EID:addGridEntityConditional(type, conditionalFunction, callbackFunction) + if not EID.GridEntityDescriptions[type] then + EID.GridEntityDescriptions[type] = {} + end + table.insert(EID.GridEntityDescriptions[type], { + condition = conditionalFunction, + callback = callbackFunction + }) +end + +--- Checks if the given grid entity has a description available +--- @param entity GridEntity: The grid entity to check for a description. +--- @return boolean: Returns true if a description exists for the entity, false otherwise. +function EID:CheckGridEntityHasDescription(entity) + -- Check if the grid entity has a description + if EID.GridEntityDescriptions[entity:GetType()] then + for _, func in ipairs(EID.GridEntityDescriptions[entity:GetType()]) do + if func.condition and func.condition(entity) then + return true + end + end + end + return false +end + +---------------------------------------------------- +-- Handle Sacrifice room payout +---------------------------------------------------- +local function SacrificeRoomCondition(_) + return Game():GetRoom():GetType() == RoomType.ROOM_SACRIFICE and EID.Config["DisplaySacrificeInfo"] +end + +local function SacrificeRoomCallback(descObj) + descObj.ObjSubType = math.min(#EID.descriptions["en"].sacrifice, descObj.Entity.VarData + 1) + -- Get sacrifice name by subtype + descObj.Name = EID:getDescriptionEntry("sacrificeHeader") .. + " (" .. descObj.ObjSubType .. "/" .. #EID.descriptions["en"].sacrifice .. ")" + + descObj.Description = EID:getDescriptionEntry("sacrifice", descObj.ObjSubType)[3] + local curCounter = descObj.ObjSubType or 1 + if curCounter <= 2 then + --Remove B1 Bomb drop info when not on B1 + if game:GetLevel():GetAbsoluteStage() > 1 then + local splitPoint = string.find(descObj.Description, '#', 1) + descObj.Description = descObj.Description:sub(1,splitPoint-1) + end + end + return descObj +end +EID:addGridEntityConditional(GridEntityType.GRID_SPIKES, SacrificeRoomCondition, SacrificeRoomCallback) + +---------------------------------------------------- +-- Handle Sanguine bond payout preview +---------------------------------------------------- +local function SanguineSpikeCondition(gridEntity) + return EID.isRepentance and gridEntity:GetVariant() >= 100 and + EID.Config["DisplaySanguineInfo"] +end + +local function SanguineSpikeCallback(descObj) + descObj = EID:getDescriptionObj(5, 100, 692, descObj.Entity, false) + local desc = EID:trimSanguineDesc(descObj.Entity, descObj) + if desc ~= "" then + descObj.Description = desc + end + return descObj +end +EID:addGridEntityConditional(GridEntityType.GRID_SPIKES, SanguineSpikeCondition, SanguineSpikeCallback) + + +---------------------------------------------------- +-- Define GridEntity Conditional handler +---------------------------------------------------- +local function EIDGridConditions(descObj) + -- Only run if the grid entity is valid + if descObj.ObjType ~= -999 or not EID.GridEntityDescriptions[descObj.ObjVariant] or not descObj.Entity then return false end + + local callbacks = {} + for _, entry in ipairs(EID.GridEntityDescriptions[descObj.ObjVariant]) do + if entry.condition and entry.condition(descObj.Entity) then + table.insert(callbacks, entry.callback) + end + end + return callbacks +end + +EID:addDescriptionModifier("EID Grid Descriptions", EIDGridConditions, nil, 1) \ No newline at end of file diff --git a/features/eid_holdmapdesc.lua b/features/eid_holdmapdesc.lua index 7a5884fd..e0db0a2f 100644 --- a/features/eid_holdmapdesc.lua +++ b/features/eid_holdmapdesc.lua @@ -3,7 +3,7 @@ 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 autoScrollTriesLeft = -999 -- Stores how many tries the automatic category skip has left to do. This prevents infinite loops, when the player has no items +local autoScrollTriesLeft = math.mininteger -- Stores how many tries the automatic category skip has left to do. 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 @@ -886,7 +886,7 @@ function EID:ItemReminderGetDescription() -- Skip category if nothing is in it if #EID.ItemReminderTempDescriptions == 0 then - if autoScrollTriesLeft == -999 then + if autoScrollTriesLeft == math.mininteger then -- auto scroll was started autoScrollTriesLeft = #EID.ItemReminderCategories - 1 end @@ -908,11 +908,11 @@ function EID:ItemReminderGetDescription() end end -- auto scroll was stopped. reset scroll value - autoScrollTriesLeft = -999 + autoScrollTriesLeft = math.mininteger EID.InsideItemReminder = false return "{{Blank}}#{{Blank}} " .. EID:getDescriptionEntry("ItemReminder", "InventoryEmpty") end - autoScrollTriesLeft = -999 + autoScrollTriesLeft = math.mininteger local finalHoldMapDesc = "" EID.ItemReminderDisplayingScrollbar = false diff --git a/features/eid_modifiers.lua b/features/eid_modifiers.lua index a1b96b2d..70d743d2 100644 --- a/features/eid_modifiers.lua +++ b/features/eid_modifiers.lua @@ -211,19 +211,6 @@ local function ItemCollectionPageCallback(descObj) return descObj end --- Handle Sacrifice room payout -local function SacrificeRoomCallback(descObj) - local curCounter = descObj.ObjSubType or 1 - if curCounter <= 2 then - --Remove B1 Bomb drop info when not on B1 - if game:GetLevel():GetAbsoluteStage() > 1 then - local splitPoint = string.find(descObj.Description, '#', 1) - descObj.Description = descObj.Description:sub(1,splitPoint-1) - end - end - return descObj -end - -- Handle Black Feather dynamic damage up text local function BlackFeatherCallback(descObj) for i = 1,#EID.coopAllPlayers do @@ -1266,8 +1253,6 @@ end -- AFTERBIRTH+ OR REPENTANCE MODIFIERS local function EIDConditionsAB(descObj) - -- handle Sacrifice room - if descObj.ObjType == -999 and descObj.ObjVariant == -1 then return {SacrificeRoomCallback} end -- currently, only pickup descriptions have modifiers if descObj.ObjType ~= 5 then return false end diff --git a/main.lua b/main.lua index a7bfc75d..d4e710fe 100644 --- a/main.lua +++ b/main.lua @@ -102,6 +102,7 @@ end require("features.eid_api") +require("features.eid_grid_descriptions") require("features.eid_language_manager") EID:InitializeLanguagePacks() @@ -821,7 +822,7 @@ function EID:renderUnidentifiedPill(entity) local descriptionObj = EID:getDescriptionObj(entity.Type, entity.Variant, entity.SubType, entity, false) descriptionObj.Description = "" descriptionObj.ShowWhenUnidentified = false - descriptionObj = EID:applyDescriptionModifier(descriptionObj, -999) + descriptionObj = EID:applyDescriptionModifier(descriptionObj, math.mininteger) if EID.Config["ShowItemIcon"] and descriptionObj.Icon then offsetX = offsetX + 14 @@ -1590,19 +1591,8 @@ function EID:OnRender() end end else -- Grid entities - local room = game:GetRoom() - if closest:GetType() == GridEntityType.GRID_SPIKES then - if EID.isRepentance and closest:GetVariant() >= 100 and EID.Config["DisplaySanguineInfo"] then - local desc = EID:getDescriptionObj(5, 100, 692, closest, false) - desc.Description = EID:trimSanguineDesc(closest, desc) - if desc.Description ~= "" then - EID:addDescriptionToPrint(desc) - end - elseif room:GetType() == RoomType.ROOM_SACRIFICE and EID.Config["DisplaySacrificeInfo"] then - local desc = EID:getDescriptionObj(-999, -1, closest.VarData + 1, closest) - EID:addDescriptionToPrint(desc) - end - end + local desc = EID:getDescriptionObj(-999, closest:GetType(), closest:GetVariant(), closest) + EID:addDescriptionToPrint(desc) end end end