local BalatroSR = {}
BalatroSR.findPart = function(str,startPos,endCharacter) --Find certain parts of a string.
local endPos = 0
for i = startPos, #str do
local character = str:sub(i,i)
if character == endCharacter then
endPos = i
break
end
end
local foundPart = string.sub(str,startPos,endPos)
return foundPart
end
function removeParts(b,replace) --Remove certain parts of a string.
local partToRemove = {
"{C:",
"{X:",
"{s:",
"{E:",
"{V:"
}
if type(b) == "string" then
local finalStr = b
for _,part in pairs(partToRemove) do
local additionalSpace = 0
for i = 1,#finalStr do
local threeChars = string.sub(finalStr, i + additionalSpace, i + additionalSpace + 2)
if threeChars == part then
local startPos = i + additionalSpace
local foundPart = BalatroSR.findPart(finalStr,startPos,"}")
additionalSpace = additionalSpace + (#finalStr + (#foundPart - #finalStr))
finalStr = finalStr:gsub(foundPart,"")
end
end
end
finalStr = finalStr:gsub("{}","")
local startPos = 0
if replace then
for g = 1, #finalStr do
local character = finalStr:sub(g,g)
if character == "#" then
startPos = g
break
end
end
finalStr = finalStr:gsub("#"..BalatroSR.findPart(finalStr,startPos + 1,"#"),replace)
end
return finalStr
end
end
BalatroSR.firstToUpper = function(str) --Uppercase the first letter.
return (str:gsub("^%l", string.upper))
end
BalatroSR.toNormalString = function(a,replace) --Convert colored strings to normal strings.
local returnStr = nil
if a and type(a) == "table" then
returnStr = {}
for i,str in pairs(a) do
if type(str) == "string" then
local result = removeParts(str,replace)
returnStr[i] = result
end
end
elseif a and type(a) == "string" then
if type(a) == "string" then
local result = removeParts(a,replace)
returnStr = result
end
else
print("Unreadable string [function: toNormalString]")
return ""
end
return returnStr
end
function string.insert(str1, str2, pos) --...need I explain?
return str1:sub(1,pos)..str2..str1:sub(pos+1)
end
BalatroSR.trueIfNumber = function(a) --Return true if the input value is a number.
if a and (tonumber(a) or type(a) == "number") then return true end
end
BalatroSR.automaticColoring = function(a, fullModify) --spaghetti code :sob: But basically, it automatically colors certain parts of a string.
if a and type(a) == "string" then
local returnStr = a
local additionalSpace = 0 --Since we will be adding {}, {C:mult},... a lot into the string, we will need this to let the code know the string has been expanded, or vice versa.
local modifications = {
["s"] = nil, --The entire string will change its size accordingly to this.
["C"] = nil, --The entire string will change its color accordingly to this except gains, though it can be changed.
["X"] = nil, --The entire string will change its background accordingly to this. Not sure why you would want that, but it's an option.
["V"] = nil,
["E"] = nil,
["change_gains"] = true, --Allows X1.5, +30.4, etc. to change colour to their presets respective to its buff (Chips, Mult, Xchips,...)
["override_gains_modifications"] = false, --Allows gains to be changed with modifications["s"] and modifications["C"]. ignoring its preset if true. For consistency, Size is still changed accordingly regardless of whether this is enabled or not.
["force_keep_gains_size"] = false, --If enabled, gains will be the same size regardless of modifications["s"].
["override_keywords"] = false,
--All of those are presets for what gains should look like in a Joker's description which I don't really suggest changing. Though, you do you.
--Also, you can add ["s"] in here and it will also work individually for only a specific gain type.
["mult"] = {
["C"] = "mult",
},
["chips"] = {
["C"] = "chips",
},
["Xmult"] = {
["X"] = "mult",
["C"] = "white",
},
["Xchips"] = {
["X"] = "chips",
["C"] = "white",
},
["additional_keywords"] = (fullModify["additional_keywords"] or {})
--[[How to add keywords, as an example:
["additional_keywords"] = {
["Hello World!"] = {
["C"] = "white",
},
}
]]
}
--Change modifications if input (fullModify) is made.
if fullModify and type(fullModify) == "table" then
for i,v in pairs(fullModify) do
modifications[i] = v
end
end
if not modifications["change_gains"] then goto continue end --Basically, skip the entire thing.
for i = 1,#returnStr do --Check for gains.
local character = returnStr:sub(i+additionalSpace,i+additionalSpace) --Check for each character in the string.
if character == "X" or character == "+" then --This will help me choose parts which start with X and +.
local startPosForColoring = i+additionalSpace-1 --Tell the code where to start with finding the gain. (Ex: X3.5)
local endPosForColoring = i+additionalSpace --Placeholder, tell the code where to end. In the middle of startPosForColoring and endPosForColoring is where the gain is.
local color = nil --Either "chips" or "mult".
local canBeColored = false --...yeah
local ogCharacter = character --Basically telling whether it's "X" or "+", made a big oopsie down there so I made this variable.
for g = i+additionalSpace+1,#returnStr do
character = returnStr:sub(g,g)
if tonumber(character) or character == "." then
endPosForColoring = g
canBeColored = true
else
break
end
end --This loop is to help knowing the exact location of the gain.
if not canBeColored then goto inside_continue end --So that if it's just a normal +, X without numbers behind then the code will not consider it as a gain.
for g = endPosForColoring,#returnStr do
local keyword = returnStr:sub(g,g+3)
if string.lower(keyword) == "chip" then
color = "chips"
break
elseif string.lower(keyword) == "mult" then
color = "mult"
break
end
end
local coloredPart = string.sub(returnStr,startPosForColoring+1,endPosForColoring) --The gain itself.
local a = string.sub(returnStr,1,startPosForColoring)
local b = string.sub(returnStr,endPosForColoring+1,#returnStr)
--Cutting the string into two halves with the gain being the middle part. So, the whole string is technically "a..coloredPart..b".
local addon = "{"
function modify(x,y)
local returnStr = addon
if not modifications["force_keep_gains_size"] and x == "s" and modifications[x] and BalatroSR.trueIfNumber(modifications[x]) then
returnStr = returnStr..x..":"..modifications[x]..","
end
if modifications["override_gains_modifications"] then
if modifications[x] then
if x == "s" and not modifications["force_keep_gains_size"] then
returnStr = returnStr..x..":"..modifications[x]..","
else
returnStr = returnStr..x..":"..modifications[x]..","
end
end
end
if not string.find(returnStr,x..":") then
if x == "s" or x == "V" or x == "E" then
if modifications[y][x] and BalatroSR.trueIfNumber(modifications[y][x]) and ((not modifications["override_gains_modifications"]) or (modifications["override_gains_modifications"] and not modifications[x])) then
returnStr = returnStr..x..":"..modifications[y][x]..","
end
else
if modifications[y][x] and ((not modifications["override_gains_modifications"]) or (modifications["override_gains_modifications"] and not modifications[x])) then
returnStr = returnStr..x..":"..modifications[y][x]..","
end
end
end
addon = returnStr
end
if ogCharacter == "X" and color then
modify("s","X"..color) --Size handler
modify("C","X"..color) --Text color handler
modify("X","X"..color) --Background color handler
modify("V","X"..color)
modify("E","X"..color)
elseif ogCharacter == "+" and color then
modify("s",color) --Size handler
modify("C",color) --Text color handler
modify("X",color) --Background color handler
modify("V",color)
modify("E",color)
end
if color then
addon = string.sub(addon,1,#addon-1)
addon = addon.."}"
--addon is basically "{s:0.5,C:mult}".
local ending = "{}"
local newString = a..addon..coloredPart..ending..b --Fusing everything together into one string.
additionalSpace = additionalSpace + (#newString - #returnStr)
returnStr = newString
end
end
::inside_continue::
end
::continue::
if modifications["additional_keywords"] ~= {} then
for i,v in pairs(modifications["additional_keywords"]) do
local placeholderStr = returnStr
local start,ending = nil, nil
local addSpace = 0
local awaitingKeywords = {}
repeat
if string.find(placeholderStr,i,nil,true) then
start,ending = string.find(placeholderStr,i,nil,true)
local cut1 = string.sub(placeholderStr,1,start)
local cut2 = string.sub(placeholderStr,ending+1,#placeholderStr)
placeholderStr = cut1..cut2
if not awaitingKeywords[i] then
awaitingKeywords[i] = {{
["startPos"] = (start + addSpace),
["endPos"] = (ending + addSpace),
},}
else
awaitingKeywords[i][#awaitingKeywords[i]+1] = {
["startPos"] = (start + addSpace),
["endPos"] = (ending + addSpace),
}
end
addSpace = addSpace + #i - 1
end
until not string.find(placeholderStr,i,nil,true)
placeholderStr = returnStr
if awaitingKeywords ~= {} then
for key,occurrences in pairs(awaitingKeywords) do
local newSpace = 0
for _,v in pairs(occurrences) do
local toAdd = "{"
local keywordConfig = modifications["additional_keywords"][key]
for cName, cVal in pairs(keywordConfig) do
toAdd = toAdd..cName..":"..cVal..","
end
local checkVars = {"s","X","C","V","E"}
for a,b in pairs(checkVars) do
if modifications[b] and not keywordConfig[b] then
toAdd = toAdd..b..":"..modifications[b]..","
end
end
if toAdd ~= "}" then
toAdd = string.sub(toAdd,1,#toAdd - 1)
end
toAdd = toAdd.."}"
local cut1 = string.sub(placeholderStr,1,v["startPos"]-1+newSpace)
local cut2 = string.sub(placeholderStr,v["endPos"]+1+newSpace,#placeholderStr)
placeholderStr = cut1..toAdd..key.."{}"..cut2
newSpace = newSpace + #toAdd + 2 --2 means the "{}" part.
end
end
returnStr = placeholderStr
end
end
end
if modifications["s"] or modifications["C"] or modifications["X"] or modifications["V"] or modifications["E"] then --If those variables are set, it will start going through the entire string to modify parts which aren't gains as well.
additionalSpace = 0
local placed = false --Whether addon (EX: {s:0.5}) has been placed, and if it was, it will place {} next.
local halt = false --Stop the code from adding addon.
local ending = "{}"
local start = "{"
function modify(x)
local returnStr = start
if modifications[x] then
if ((x == "s" or x == "V" or x == "E") and BalatroSR.trueIfNumber(modifications[x])) or (x ~= "s") then
returnStr = returnStr..x..":"..modifications[x]..","
end
end
start = returnStr
end
modify("s")
modify("C")
modify("X")
modify("V")
modify("E")
start = string.sub(start,1,#start-1)
start = start.."}"
local f = 0
--[[I'm bad at naming variables, but here's the logic behind this:
Basically, gains should be:
...{s:0.5,C:mult}+5{}...
...and what I did is that if it finds the "{" part, then f will be set to 2, and it will only start placing addon if f is 0.
Why did I do that? You can see that there's 2 "}" within the gain.
]]
local i = 1
repeat --this is so scuffed ngl
local character = returnStr:sub(i+additionalSpace,i+additionalSpace)
local characterBefore = returnStr:sub(i+additionalSpace-1,i+additionalSpace-1)
local characterAfter = returnStr:sub(i+additionalSpace+1,i+additionalSpace+1)
if not placed then
if (character == "s" or character == "C" or character == "X" or character == "V" or character == "E") and characterAfter == ":" and not halt then --{s:0.7}...{} <-- It will have to go through 2 "}" first before continuing.
f = 2 --Hence, this variable.
halt = true
elseif character ~= "{" and character ~= "}" and characterBefore ~= "{" and characterAfter ~= "}" and not halt then
local allowed = true
if allowed then
placed = true
returnStr = string.insert(returnStr,start,i + additionalSpace - 1)
additionalSpace = additionalSpace + #start
end
elseif character == "}" and halt then
if f > 0 then
f = f - 1
end
if f <= 0 then
halt = false
end
end
elseif placed then
if character == "{" or (i + additionalSpace) == #returnStr then --It will place {} either at the correct position, or at the last character of the string where "{" isn't seen.
placed = false
if (i + additionalSpace) == #returnStr then
returnStr = string.insert(returnStr,ending,i + additionalSpace)
else
returnStr = string.insert(returnStr,ending,i + additionalSpace - 1)
end
additionalSpace = additionalSpace + #ending
end
end
i = i + 1
until (i + additionalSpace) > #returnStr
end
return returnStr
else
print("Unreadable string [function: automaticColoring]")
return ""
end
end
local keywordTest = {
["Basic Effect Efficiency"] = {
["C"] = "attention",
},
["Attack"] = {
["C"] = "inactive",
},
["ATK"] = {
["C"] = "attention",
},
["DMG Taken"] = {
["C"] = "attention",
},
["DEF Pen"] = {
["C"] = "attention"
},
["Speed"] = {
["C"] = "attention",
},
["Chosen Rank"] = {
["C"] = "attention",
},
["Chosen Suit"] = {
["C"] = "attention",
},
["Ultimate"] = {
["C"] = "attention",
["E"] = 2,
},
["Follow-up Effect"] = {
["C"] = "attention",
["E"] = 2,
},
["Wind"] = {
["C"] = "hsr_wind"
},
["Physical"] = {
["C"] = "hsr_physical"
},
["Imaginary"] = {
["C"] = "hsr_imaginary"
},
["Ice"] = {
["C"] = "hsr_ice"
},
["Fire"] = {
["C"] = "hsr_fire"
},
["Quantum"] = {
["C"] = "hsr_quantum"
},
["Lightning"] = {
["C"] = "hsr_lightning"
},
["Fire Efficiency"] = {
["C"] = "attention"
}
--[[["[Follow-up Effect]"] = {
["C"] = "inactive",
},]]
}
local textInput = "Increases ATK by 12%. After using Ultimate, increases Fire Efficiency by 12% for 1 turn"
local res = BalatroSR.automaticColoring(textInput, {["s"] = 0.7,["additional_keywords"] = keywordTest})
print(res)
To embed this project on your website, copy the following code and paste it into your website's HTML: