Open BadPig03 opened 3 months ago
Need to either figure out a good place to hook minimap render to change the loaded anm2, or reimplement curse rendering
Need to either figure out a good place to hook minimap render to change the loaded anm2, or reimplement curse rendering
I wrote some scripts about curse icon rendering
-- Curse HUD Tool
-- Curse text localization
local showStickyStreak = false
function ddad:ShowCurseText(title, subtitle, isSticky, isCurseDisplay)
if Options.Language ~= "en" and isCurseDisplay then
for key, value in pairs(self.text.en.curse) do
if subtitle and subtitle == value.TEXT then
self.game:GetHUD():ShowItemText(title, self:T("curse." .. key .. ".TEXT"), true)
if isSticky then
showStickyStreak = true
end
return false
end
end
end
if not (isSticky) then
showStickyStreak = false
end
end
ddad:AddCallback(ModCallbacks.MC_PRE_ITEM_TEXT_DISPLAY, ddad.ShowCurseText)
function ddad:ShowStreakText()
if showStickyStreak then
local sprite = self.game:GetHUD():GetStreakSprite()
if Input.IsActionPressed(ButtonAction.ACTION_MAP, 0) then
if sprite:IsPlaying("Text") then
sprite:Play("TextIn")
elseif sprite:IsFinished("TextIn") then
sprite:Play("TextStay")
end
else
sprite:Play("TextOut")
showStickyStreak = false
end
end
end
ddad:AddCallback(ModCallbacks.MC_POST_HUD_RENDER, ddad.ShowStreakText)
-- Curse icon rendering
local modCurseIcon = ddad.LoadNewSprite("gfx/ui/hud_minimap_ddadcurse.anm2") -- my mod's curse icon
if not (MinimapAPI) then
local curseIcon = Minimap.GetItemIconsSprite() -- in game curse icon
local curseAlpha = { 1.0, 0 }
-- get which curse icon should be render
local function GetCurseList(curse, canSee)
curse = curse or ddad.game:GetLevel():GetCurses()
canSee = canSee or false
local i = 1
local list = {}
-- item icon always render first
if PlayerManager.AnyoneHasCollectible(CollectibleType.COLLECTIBLE_MIND) then -- mind would over write other 3
table.insert(list, -6)
else
if PlayerManager.AnyoneHasCollectible(CollectibleType.COLLECTIBLE_COMPASS) then
table.insert(list, -1)
end
if PlayerManager.AnyoneHasCollectible(CollectibleType.COLLECTIBLE_BLUE_MAP) then
table.insert(list, -2)
end
if PlayerManager.AnyoneHasCollectible(CollectibleType.COLLECTIBLE_TREASURE_MAP) then
table.insert(list, -3)
end
end
if PlayerManager.AnyoneHasCollectible(CollectibleType.COLLECTIBLE_RESTOCK) then
table.insert(list, -5)
end
-- in original game, the max count that curse could be render is 7
-- if the total number exceeds 7, rendering will be stopped directly
-- the curse icon will be rendered after the item icon, in order of number from smallest to largest
while curse > 0 and (#list < 7 or not (canSee)) do
if curse % 2 == 1 then
table.insert(list, i)
end
curse = math.floor(curse * .5)
i = i + 1
end
return list
end
-- check if mod curse had be mentioned (if not, just do not change render)
local function IsModCurse(curseID)
for _, curse in pairs(ddad.curse) do
if curse.id == curseID then
return curse.frame
end
end
return -1
end
-- I don't know why I named like this
-- while open the map, the pos and alpha will change
-- and more important, in some frame, curse would be render twice
local function RenderCurseIcons(sprite, basepos)
local hight = { 47, Minimap.GetDisplayedSize().Y }
-- can't make sure exactly as same as the original game
if Minimap.GetState() == MinimapState.NORMAL then
curseAlpha[1] = math.min(curseAlpha[1] + .125, 1)
curseAlpha[2] = math.max(curseAlpha[2] - .125, 0)
elseif Minimap.GetState() == MinimapState.EXPANDED then
curseAlpha[1] = math.max(curseAlpha[1] - .125, 0)
curseAlpha[2] = math.min(curseAlpha[2] + .100, .8)
else
curseAlpha[1] = math.max(curseAlpha[1] - .125, 0)
curseAlpha[2] = math.min(curseAlpha[2] + .125, 1)
end
if curseAlpha[1] > 0 or hight[2] == hight[1] then
sprite.Color = Color(1, 1, 1, curseAlpha[1])
sprite:Render(basepos + Vector(0, hight[1]))
end
if hight[2] ~= hight[1] and curseAlpha[2] > 0 then
sprite.Color = Color(1, 1, 1, curseAlpha[2])
sprite:Render(basepos + Vector(0, hight[2]))
end
end
-- main function
function ddad:RenderCurseIcon()
-- get icons that should be render
local curseList = GetCurseList(nil, true)
local hasModCurse = false
local sholdRenderDefalt = false
for _, curse in ipairs(curseList) do
if IsModCurse(curse) >= 0 then
hasModCurse = true
break
end
end
-- reset curse icon offset
--[[
why?
here is a bug!
when game trying to render the first mod curse, would unanticipately render Curse of the Giant!
so when curse 9 will appear, set its offset to -9999 so that it won't be on the screen
for other mod curse icon, would render blank
]]
curseIcon.Offset = Vector(0, 0)
if hasModCurse then
-- base pos (top right)
local pos = Vector(Isaac.GetScreenWidth(), 0) + Options.HUDOffset * Vector(-24, 14) + Vector(-11, 10) + Minimap.GetShakeOffset()
-- the gap between icons varies depending on the number of icons
local offset = 16 - math.max(#curseList - 3, 0)
-- would have that bug
sholdRenderDefalt = self.FindItemInA(curseList, 9)
if sholdRenderDefalt then
for index, curse in ipairs(curseList) do
-- original game icon
if curse <= 8 then
-- negative values correspond to item icon
if curse < 0 then
curseIcon:Play("icons")
-- positive values correspond to curse icon
else
curseIcon:Play("curses")
end
curseIcon:SetFrame(math.abs(curse) - 1)
RenderCurseIcons(curseIcon, pos + Vector(-offset, 0) * (index - 1))
end
end
curseIcon.Offset = Vector(0, -9999)
end
-- mod curse icon
for index, curse in ipairs(curseList) do
local frame = IsModCurse(curse)
if frame >= 0 then
modCurseIcon:SetFrame(frame)
RenderCurseIcons(modCurseIcon, pos + Vector(-offset, 0) * (index - 1))
end
end
end
end
ddad:AddCallback(ModCallbacks.MC_HUD_RENDER, ddad.RenderCurseIcon)
else
-- has MinimapAPI mod
for key, value in pairs(ddad.curse) do
MinimapAPI:AddMapFlag(
"ddad_curse_" .. key,
function() return ddad.game:GetLevel():GetCurses() & value.levelCurse ~= 0 end,
modCurseIcon, "Idle", value.frame
)
end
end
I am not good at programming and English, please forgive me if there is any problem
It is known that all curses active on the floor, alongside any active mapping effects are shown below the map and represented by their respective icons. However, custom curses can only be rendered using callbacks; they cannot be directly rendered by game. Is is possible to add custom icons in curses.xml and render them without using callbacks?