sm64coopdx/mods/character-select-coop/o-api.lua

366 lines
14 KiB
Lua

if incompatibleClient then return 0 end
--- @class CharacterTable
--- @field public name string
--- @field public saveName string
--- @field public description table
--- @field public credit string
--- @field public color Color
--- @field public model ModelExtendedId|integer
--- @field public forceChar CharacterType
--- @field public lifeIcon TextureInfo
--- @field public camScale integer
--- @field public offset integer
-- localize functions to improve performance
local smlua_model_util_get_id,table_insert,type,djui_hud_measure_text,tonumber = smlua_model_util_get_id,table.insert,type,djui_hud_measure_text,tonumber
local characterVoices = {}
local saveNameTable = {}
local E_MODEL_ARMATURE = smlua_model_util_get_id("armature_geo")
---------
-- API --
---------
local function split_text_into_lines(text)
local words = {}
for word in text:gmatch("%S+") do
table.insert(words, word)
end
local lines = {}
local currentLine = ""
for i, word in ipairs(words) do
local measuredWidth = djui_hud_measure_text(currentLine .. " " .. word)*0.3
if measuredWidth <= 100 then
currentLine = currentLine .. " " .. word
else
table.insert(lines, currentLine)
currentLine = word
end
end
table.insert(lines, currentLine) -- add the last line
return lines
end
local TYPE_INTEGER = "number"
local TYPE_STRING = "string"
local TYPE_TABLE = "table"
local TYPE_FUNCTION = "function"
---@param name string|nil Underscores turn into Spaces
---@param description table|string|nil {"string"}
---@param credit string|nil
---@param color Color|string|nil {r, g, b}
---@param modelInfo ModelExtendedId|integer|nil Use smlua_model_util_get_id()
---@param forceChar CharacterType|nil CT_MARIO, CT_LUIGI, CT_TOAD, CT_WALUIGI, CT_WARIO
---@param lifeIcon TextureInfo|nil Use get_texture_info()
---@param camScale integer|nil Zooms the camera based on a multiplier (Default 1.0)
---@param offset integer|nil Visually offsets the character
---@return integer
local function character_add(name, description, credit, color, modelInfo, forceChar, lifeIcon, camScale, offset)
if type(description) == TYPE_STRING then
description = split_text_into_lines(description)
end
if type(color) == TYPE_STRING then
color = {r = tonumber(color:sub(1,2), 16), g = tonumber(color:sub(3,4), 16), b = tonumber(color:sub(5,6), 16) }
end
if type(offset) ~= TYPE_INTEGER then
offset = (forceChar == CT_WALUIGI and 25 or 0)
end
table_insert(characterTable, {
name = type(name) == TYPE_STRING and name or "Untitled",
saveName = type(name) == TYPE_STRING and string_space_to_underscore(name) or "Untitled",
description = type(description) == TYPE_TABLE and description or {"No description has been provided"},
credit = type(credit) == TYPE_STRING and credit or "Unknown",
color = type(color) == TYPE_TABLE and color or {r = 255, g = 255, b = 255},
model = (modelInfo and modelInfo ~= E_MODEL_ERROR_MODEL) and modelInfo or E_MODEL_ARMATURE,
forceChar = forceChar and forceChar or CT_MARIO,
offset = offset and offset or 0,
lifeIcon = type(lifeIcon) == TYPE_TABLE and lifeIcon or nil,
starIcon = gTextures.star,
camScale = type(camScale) == TYPE_INTEGER and camScale or 1,
healthTexture = nil,
})
saveNameTable[#characterTable] = characterTable[#characterTable].saveName
return #characterTable
end
---@param charNum integer Use _G.charSelect.character_get_number_from_string() or _G.charSelect.character_add()'s return value
---@param name string|nil Underscores turn into Spaces
---@param description table|string|nil {"string"}
---@param credit string|nil
---@param color Color|nil {r, g, b}
---@param modelInfo ModelExtendedId|integer|nil Use smlua_model_util_get_id()
---@param forceChar integer|CharacterType|nil CT_MARIO, CT_LUIGI, CT_TOAD, CT_WALUIGI, CT_WARIO
---@param lifeIcon TextureInfo|nil Use get_texture_info()
---@param camScale integer|nil Zooms the camera based on a multiplier (Default 1.0)
---@param offset integer|nil Visually offsets the character
local function character_edit(charNum, name, description, credit, color, modelInfo, forceChar, lifeIcon, camScale, offset)
if tonumber(charNum) == nil or charNum > #characterTable or charNum < 0 then return end
if type(description) == TYPE_STRING then
description = split_text_into_lines(description)
end
if type(color) == TYPE_STRING then
color = {r = tonumber(color:sub(1,2), 16), g = tonumber(color:sub(3,4), 16), b = tonumber(color:sub(5,6), 16) }
end
if type(offset) ~= TYPE_INTEGER then
offset = (forceChar == CT_WALUIGI and 25 or 0)
end
local tableCache = characterTable[charNum]
characterTable[charNum] = characterTable[charNum] and {
name = type(name) == TYPE_STRING and name or tableCache.name,
saveName = saveNameTable[charNum],
description = type(description) == TYPE_TABLE and description or tableCache.description,
credit = type(credit) == TYPE_STRING and credit or tableCache.credit,
color = type(color) == TYPE_TABLE and color or tableCache.color,
model = (modelInfo and modelInfo ~= E_MODEL_ERROR_MODEL) and modelInfo or tableCache.model,
forceChar = type(forceChar) == TYPE_INTEGER and forceChar or tableCache.forceChar,
offset = type(offset) == TYPE_INTEGER and offset or tableCache.offset,
lifeIcon = type(lifeIcon) == TYPE_TABLE and lifeIcon or tableCache.lifeIcon,
starIcon = tableCache.starIcon, -- Done to prevent it getting lost in the sauce
camScale = type(camScale) == TYPE_INTEGER and camScale or tableCache.camScale,
healthTexture = tableCache.healthTexture,
} or nil
end
---@param modelInfo ModelExtendedId|integer
---@param clips table
local function character_add_voice(modelInfo, clips)
characterVoices[modelInfo] = type(clips) == TYPE_TABLE and clips or nil
end
---@param modelInfo ModelExtendedId|integer
---@param caps table
local function character_add_caps(modelInfo, caps)
characterCaps[modelInfo] = type(caps) == TYPE_TABLE and caps or nil
end
---@param charNum integer
---@param healthTexture table|nil
local function character_add_health_meter(charNum, healthTexture)
if type(charNum) ~= TYPE_INTEGER or charNum == nil then return end
characterTable[charNum].healthTexture = type(healthTexture) == TYPE_TABLE and healthTexture or nil
return false
end
---@param modelInfo ModelExtendedId|integer
---@param starModel ModelExtendedId|integer
---@param starIcon TextureInfo|nil Use get_texture_info()
local function character_add_celebration_star(modelInfo, starModel, starIcon)
characterCelebrationStar[modelInfo] = starModel
for i = 2, #characterTable do
if characterTable[i].model == modelInfo then
characterTable[i].starIcon = type(starIcon) == TYPE_TABLE and starIcon or gTextures.star
return
end
end
return false
end
---@param modelInfo ModelExtendedId|integer
---@param paletteTable table
local function character_add_palette_preset(modelInfo, paletteTable)
local paletteTableOut = {}
local defaultColors = characterColorPresets[E_MODEL_MARIO]
for i = 0, 7 do
local color = paletteTable[i]
paletteTableOut[i] = {r = 0, g = 0, b = 0}
if type(color) == TYPE_STRING then
paletteTableOut[i].r = tonumber(color:sub(1,2), 16) and tonumber(color:sub(1,2), 16) or defaultColors[i].r
paletteTableOut[i].g = tonumber(color:sub(3,4), 16) and tonumber(color:sub(3,4), 16) or defaultColors[i].g
paletteTableOut[i].b = tonumber(color:sub(5,6), 16) and tonumber(color:sub(5,6), 16) or defaultColors[i].b
end
if type(color) == TYPE_TABLE then
paletteTableOut[i].r = (type(color) == TYPE_TABLE and color.r ~= nil) and color.r or defaultColors[i].r
paletteTableOut[i].g = (type(color) == TYPE_TABLE and color.g ~= nil) and color.g or defaultColors[i].g
paletteTableOut[i].b = (type(color) == TYPE_TABLE and color.b ~= nil) and color.b or defaultColors[i].b
end
end
characterColorPresets[modelInfo] = paletteTableOut
end
---@param tablePos integer|nil
---@return CharacterTable
local function character_get_current_table(tablePos)
tablePos = tablePos and tablePos or currChar
return characterTable[tablePos]
end
local function character_get_current_number()
return currChar
end
---@param charNum integer|nil
local function character_set_current_number(charNum)
if type(charNum) ~= TYPE_INTEGER or characterTable[charNum] == nil then return end
currChar = charNum
charBeingSet = true
end
---@param name string
local function character_get_number_from_string(name)
if type(name) ~= TYPE_STRING then return nil end
for i = 2, #characterTable do
if characterTable[i].name == name or characterTable[i].name == string_space_to_underscore(name) then
return i
end
end
return nil
end
---@param m MarioState
function character_get_voice(m)
return characterVoices[gPlayerSyncTable[m.playerIndex].modelId]
end
---@return string
local function version_get()
return MOD_VERSION
end
---@return boolean
local function is_menu_open()
return menuAndTransition
end
---@param bool boolean|nil Sets if the menu is open
local function set_menu_open(bool)
if bool == nil then bool = true end
menu = bool
end
---@return table
local function get_menu_color()
return update_menu_color()
end
---@param func function
local function hook_allow_menu_open(func)
if type(func) ~= TYPE_FUNCTION then return end
table_insert(allowMenu, func)
end
---@param func function
local function hook_render_in_menu(func, underText)
if type(func) ~= TYPE_FUNCTION then return end
if underText then
table_insert(renderInMenuTable.back, func)
else
table_insert(renderInMenuTable.front, func)
end
end
---@return boolean
local function is_options_open()
return options
end
---@param bool boolean
local function restrict_palettes(bool)
if bool == nil then bool = true end
stopPalettes = bool
end
local controller = {
buttonDown = 0,
buttonPressed = 0,
extStickX = 0,
extStickY = 0,
rawStickX = 0,
rawStickY = 0,
stickMag = 0,
stickX = 0,
stickY = 0
}
---@param name string
---@param toggleDefault number|nil Defaults to 0
---@param toggleMax number|nil Defaults to 1
---@param toggleNames table|nil Table of Strings {"Off", "On"}
---@param description table|nil Table of Strings {"This toggle allows your", "character to feel everything."}
---@param save boolean|nil Defaults to true
---@return number
local function add_option(name, toggleDefault, toggleMax, toggleNames, description, save)
if save == nil then save = true end
local saveName = string_space_to_underscore(name)
table_insert(optionTable, {
name = type(name) == TYPE_STRING and name or "Unknown Toggle",
toggle = nil, -- Set as nil for Failsafe to Catch
toggleSaveName = save and saveName or nil,
toggleDefault = type(toggleDefault) == TYPE_INTEGER and toggleDefault or 0,
toggleMax = type(toggleMax) == TYPE_INTEGER and toggleMax or 1,
toggleNames = type(toggleNames) == TYPE_TABLE and toggleNames or {"Off", "On"},
description = type(description) == TYPE_TABLE and description or {""},
})
queueStorageFailsafe = true -- Used variable trigger to not save/load in the external mod
return #optionTable
end
---@param tableNum integer
---@return table|nil
local function get_option(tableNum)
if type(tableNum) ~= TYPE_INTEGER then return nil end
return optionTable[tableNum]
end
---@param tableNum integer
---@return number|nil
local function get_options_status(tableNum)
if type(tableNum) ~= TYPE_INTEGER then return nil end
return optionTable[tableNum].toggle
end
---@param tableNum integer
---@param toggle integer
local function set_options_status(tableNum, toggle)
local currOption = optionTable[tableNum]
if currOption == nil or type(toggle) ~= TYPE_INTEGER or toggle > currOption.toggleMax or toggle < 1 then return end
optionTable[tableNum].toggle = toggle
optionTable[tableNum].optionBeingSet = true
end
_G.charSelectExists = true
_G.charSelect = {
-- Character Functions --
character_add = character_add,
character_edit = character_edit,
character_add_voice = character_add_voice,
character_add_caps = character_add_caps,
character_add_celebration_star = character_add_celebration_star,
character_add_health_meter = character_add_health_meter,
character_add_palette_preset = character_add_palette_preset,
character_get_current_table = character_get_current_table,
character_get_current_number = character_get_current_number,
character_get_current_model_number = character_get_current_number, -- Outdated function name, Not recommended for use
character_set_current_number = character_set_current_number,
character_get_number_from_string = character_get_number_from_string,
character_get_voice = character_get_voice,
character_get_life_icon = life_icon_from_local_index, -- Function located in n-hud.lua
character_get_star_icon = star_icon_from_local_index, -- Function located in n-hud.lua
-- Menu Functions --
header_set_texture = header_set_texture, -- Function located in main.lua
version_get = version_get,
is_menu_open = is_menu_open,
set_menu_open = set_menu_open,
is_options_open = is_options_open,
get_menu_color = get_menu_color,
add_option = add_option,
get_option = get_option,
get_options_status = get_options_status,
set_options_status = set_options_status,
restrict_palettes = restrict_palettes,
-- Tables --
optionTableRef = optionTableRef,
controller = controller,
-- Custom Hooks --
hook_allow_menu_open = hook_allow_menu_open,
hook_render_in_menu = hook_render_in_menu,
}