sm64coopdx/mods/character-select-coop/main.lua

920 lines
39 KiB
Lua
Raw Normal View History

2023-12-16 18:25:28 +00:00
-- name: Character Select
2023-12-23 16:40:20 +00:00
-- description: \\#ffff00\\ ----- Character Select Coop ----- \n\n\\#dcdcdc\\A Library / API made to make adding and using Custom Characters as simple as possible!\nUse\\#ffff00\\ /char-select\\#dcdcdc\\ to get started!\n\nCreated by:\\#008800\\ Squishy6094\n\\#dcdcdc\\Concepts by:\\#4496f5\\ AngelicMiracles\n\n\\#AAAAFF\\Updates and Packs can be found on\nCharacter Select's Github:\n\\#4444FF\\Squishy6094/character-select-coop
2023-12-16 18:25:28 +00:00
2023-12-23 16:40:20 +00:00
local menu = false
menuAndTransition = false
2023-12-16 18:25:28 +00:00
options = false
currChar = 1
local currOption = 1
2023-12-23 16:40:20 +00:00
local menuCrossFade = 10
local menuCrossFadeCap = menuCrossFade
local menuCrossFadeMath = 255/menuCrossFade
2023-12-16 18:25:28 +00:00
local TEX_HEADER = get_texture_info("char-select-text")
local TEXT_PREF_LOAD = "Default"
local ommActive = _G.OmmApi ~= nil
--[[
Note: Do NOT add characters via the characterTable below,
We highly reccomend you create your own mod and use the
API to add characters, this ensures your pack is easy
to use for anyone and low on file space!
]]
characterTable = {
[1] = {
name = "Default",
description = {"The vanilla cast for sm64ex-coop!", "", "These Characters are swappable", "via the default Options Menu"},
credit = "Nintendo / Coop Team",
color = {r = 255, g = 50, b = 50},
model = nil,
forceChar = nil,
lifeIcon = gTextures.mario_head,
},
}
local optionTableRef = {
openInputs = 1,
menuColor = 2,
anims = 3,
inputLatency = 4,
localModels = 5,
prefToDefault = 6,
2023-12-23 16:40:20 +00:00
debugInfo = 7
2023-12-16 18:25:28 +00:00
}
optionTable = {
[optionTableRef.openInputs] = {
name = "Open Binds",
toggle = tonumber(mod_storage_load("MenuInput")),
toggleSaveName = "MenuInput",
toggleDefault = 0,
toggleMax = 2,
toggleNames = {"None", ommActive and "D-pad Down + R" or "D-pad Down", "Z (Pause Menu)"},
},
[optionTableRef.menuColor] = {
name = "Menu Color",
toggle = tonumber(mod_storage_load("MenuColor")),
toggleSaveName = "MenuColor",
toggleDefault = 0,
toggleMax = 9,
toggleNames = {"Auto", "Red", "Orange", "Yellow", "Green", "Blue", "Pink", "Purple", "White", "Black"},
},
[optionTableRef.anims] = {
name = "Animations",
toggle = tonumber(mod_storage_load("Anims")),
toggleSaveName = "Anims",
toggleDefault = 1,
toggleMax = 1,
},
[optionTableRef.inputLatency] = {
name = "Scroll Speed",
toggle = tonumber(mod_storage_load("Latency")),
toggleSaveName = "Latency",
toggleDefault = 1,
toggleMax = 2,
toggleNames = {"Slow", "Normal", "Fast"},
},
[optionTableRef.localModels] = {
name = "Locally Display Models",
toggle = tonumber(mod_storage_load("localModels")),
toggleSaveName = "localModels",
toggleDefault = 1,
toggleMax = 1,
},
[optionTableRef.prefToDefault] = {
name = "Set Preference to Default",
toggle = 0,
toggleDefault = 0,
toggleMax = 1,
toggleNames = {"", ""},
},
2023-12-18 22:01:33 +00:00
[optionTableRef.debugInfo] = {
name = "Debugging Info",
toggle = tonumber(mod_storage_load("debuginfo")),
toggleSaveName = "debuginfo",
toggleDefault = 0,
toggleMax = 1,
},
2023-12-16 18:25:28 +00:00
}
local defaultPlayerColors = {
[CT_MARIO] = {r = 255, g = 50, b = 50},
[CT_LUIGI] = {r = 50, g = 255, b = 50},
[CT_TOAD] = {r = 100, g = 100, b = 255},
[CT_WALUIGI] = {r = 130, g = 25, b = 130},
[CT_WARIO] = {r = 255, g = 255, b = 50},
}
local defaultIcons = {
[CT_MARIO] = gTextures.mario_head,
[CT_LUIGI] = gTextures.luigi_head,
[CT_TOAD] = gTextures.toad_head,
[CT_WALUIGI] = gTextures.waluigi_head,
[CT_WARIO] = gTextures.wario_head,
}
local latencyValueTable = {15, 10, 5}
2023-12-23 16:40:20 +00:00
local menuColorTable = {
{r = 255, g = 50, b = 50 },
{r = 255, g = 100, b = 50 },
{r = 255, g = 255, b = 50 },
{r = 50, g = 255, b = 50 },
{r = 100, g = 100, b = 255},
{r = 251, g = 148, b = 220},
{r = 130, g = 25, b = 130},
{r = 255, g = 255, b = 255},
{r = 50, g = 50, b = 50 },
}
2023-12-16 18:25:28 +00:00
local camera_freeze = camera_freeze
local camera_unfreeze = camera_unfreeze
local network_local_index_from_global = network_local_index_from_global
local obj_set_model_extended = obj_set_model_extended
local hud_hide = hud_hide
local hud_show = hud_show
local djui_chat_message_create = djui_chat_message_create
local djui_hud_set_resolution = djui_hud_set_resolution
local djui_hud_set_font = djui_hud_set_font
local djui_hud_set_color = djui_hud_set_color
local djui_hud_get_screen_width = djui_hud_get_screen_width
local djui_hud_render_rect = djui_hud_render_rect
local djui_hud_print_text = djui_hud_print_text
local djui_hud_render_texture = djui_hud_render_texture
local math_max = math.max
local math_min = math.min
local math_sin = math.sin
local math_random = math.random
2023-12-23 16:40:20 +00:00
local math_abs = math.abs
local math_ceil = math.ceil
2023-12-16 18:25:28 +00:00
local play_sound = play_sound
local mod_storage_save = mod_storage_save
local mod_storage_load = mod_storage_load
local string_lower = string.lower
---@param m MarioState
local function nullify_inputs(m)
local c = m.controller
_G.charSelect.controller = {
buttonDown = c.buttonDown,
buttonPressed = c.buttonPressed & ~_G.charSelect.controller.buttonDown,
extStickX = c.extStickX,
extStickY = c.extStickY,
rawStickX = c.rawStickX,
rawStickY = c.rawStickY,
stickMag = c.stickMag,
stickX = c.stickX,
stickY = c.stickY
}
c.buttonDown = 0
c.buttonPressed = 0
c.extStickX = 0
c.extStickY = 0
c.rawStickX = 0
c.rawStickY = 0
c.stickMag = 0
c.stickX = 0
c.stickY = 0
end
local function load_preferred_char()
if mod_storage_load("PrefChar") ~= nil and mod_storage_load("PrefChar") ~= "Default" then
for i = 2, #characterTable do
if characterTable[i].name == mod_storage_load("PrefChar") then
currChar = i
2023-12-18 22:01:33 +00:00
if optionTable[optionTableRef.localModels].toggle == 1 then
djui_popup_create('Character Select:\nYour Preferred Character\n"'..string_underscore_to_space(characterTable[i].name)..'"\nwas applied successfully!', 4)
end
2023-12-16 18:25:28 +00:00
break
end
end
elseif mod_storage_load("PrefChar") == nil then
mod_storage_save("PrefChar", "Default")
end
if #characterTable == 1 then
djui_popup_create("Character Select:\nNo Characters were Found", 2)
end
TEXT_PREF_LOAD = mod_storage_load("PrefChar")
end
local function failsafe_options()
for i = 1, #optionTable do
if optionTable[i].toggle == nil then
optionTable[i].toggle = optionTable[i].toggleDefault
if optionTable[i].toggleSaveName ~= nil then
mod_storage_save(optionTable[i].toggleSaveName, tostring(optionTable[i].toggle))
end
end
if optionTable[i].toggleNames == nil then
optionTable[i].toggleNames = {"Off", "On"}
end
end
if optionTable[optionTableRef.openInputs].toggle == 1 and ommActive then
djui_popup_create('Character Select:\nYour Open bind has changed to:\nD-pad Down + R\nDue to OMM Rebirth being active!', 4)
end
end
local function idiot_proof_note()
2023-12-23 16:40:20 +00:00
if #characterTable > 1 then
djui_chat_message_create("Character Select is active and has "..(#characterTable - 1).." characters available!\nYou can use \\#ffff00\\/char-select \\#ffffff\\to open the menu!")
2023-12-16 18:25:28 +00:00
else
2023-12-23 16:40:20 +00:00
djui_chat_message_create("Character Select is active!\nYou can use \\#ffff00\\/char-select \\#ffffff\\to open the menu!")
2023-12-16 18:25:28 +00:00
end
end
-------------------
-- Model Handler --
-------------------
local stallFrame = 0
local noLoop = false
-- Respecfully, GO FUCK YOURSELVES. I hate EVERY SINGLE ONE OF YOU. Your lives are NOTHING. You serve ZERO PURPOSE. You should kill yourselves, NOW!
local ignored_surfaces = {
SURFACE_BURNING, SURFACE_QUICKSAND, SURFACE_INSTANT_QUICKSAND, SURFACE_INSTANT_MOVING_QUICKSAND, SURFACE_DEEP_MOVING_QUICKSAND, SURFACE_INSTANT_QUICKSAND, SURFACE_DEEP_QUICKSAND, SURFACE_SHALLOW_MOVING_QUICKSAND,
SURFACE_SHALLOW_QUICKSAND, SURFACE_WARP, SURFACE_LOOK_UP_WARP, SURFACE_WOBBLING_WARP, SURFACE_INSTANT_WARP_1B, SURFACE_INSTANT_WARP_1C, SURFACE_INSTANT_WARP_1D, SURFACE_INSTANT_WARP_1E
}
-- Yes, floral gave me permission to use this table full of USELESS PIECES OF SHITS
--- @param m MarioState
local function mario_update(m)
if stallFrame == 1 then
load_preferred_char()
failsafe_options()
idiot_proof_note()
end
if stallFrame < 2 then
stallFrame = stallFrame + 1
end
if m.playerIndex == 0 and stallFrame > 1 then
2023-12-19 00:17:19 +00:00
local modelIndex = gNetworkPlayers[m.playerIndex].modelIndex
characterTable[1].forceChar = modelIndex
2023-12-16 18:25:28 +00:00
if currChar == 1 then
2023-12-19 00:17:19 +00:00
characterTable[1].color = defaultPlayerColors[modelIndex]
characterTable[1].lifeIcon = defaultIcons[modelIndex]
2023-12-16 18:25:28 +00:00
end
if optionTable[optionTableRef.localModels].toggle > 0 then
2023-12-19 00:17:19 +00:00
gPlayerSyncTable[m.playerIndex].modelId = characterTable[currChar].model
gPlayerSyncTable[m.playerIndex].capModels = characterTable[currChar].capModels
2023-12-16 18:25:28 +00:00
if characterTable[currChar].forceChar ~= nil then
gNetworkPlayers[m.playerIndex].overrideModelIndex = characterTable[currChar].forceChar
end
else
2023-12-19 00:17:19 +00:00
gPlayerSyncTable[m.playerIndex].modelId = nil
gPlayerSyncTable[m.playerIndex].capModels = nil
2023-12-16 18:25:28 +00:00
gNetworkPlayers[m.playerIndex].overrideModelIndex = characterTable[1].forceChar
end
2023-12-23 16:40:20 +00:00
if menuAndTransition then
2023-12-16 18:25:28 +00:00
for _, func in pairs(allowMenu) do
if not func() then
menu = false
return
end
end
camera_freeze()
hud_hide()
if _G.PersonalStarCounter then
_G.PersonalStarCounter.hide_star_counters(true)
end
local focusPos = {
x = m.pos.x,
y = m.pos.y + 120,
z = m.pos.z,
}
vec3f_copy(gLakituState.focus, focusPos)
gLakituState.pos.x = m.pos.x + sins(m.faceAngle.y) * 500
gLakituState.pos.y = m.pos.y + 100
gLakituState.pos.z = m.pos.z + coss(m.faceAngle.y) * 500
if m.forwardVel == 0 and m.pos.y == m.floorHeight and not ignored_surfaces[m.floor.type] and m.health > 255 then
set_mario_action(m, ACT_IDLE, 0)
set_mario_animation(m, MARIO_ANIM_STAR_DANCE)
end
noLoop = false
elseif not noLoop then
camera_unfreeze()
hud_show()
if _G.PersonalStarCounter then
_G.PersonalStarCounter.hide_star_counters(false)
end
noLoop = true
end
end
--Set Pref to Default Check
if optionTable[optionTableRef.prefToDefault].toggle > 0 then
mod_storage_save("PrefChar", "Default")
TEXT_PREF_LOAD = "Default"
optionTable[optionTableRef.prefToDefault].toggle = 0
end
end
function set_model(o, model)
if obj_has_behavior_id(o, id_bhvMario) ~= 0 then
local i = network_local_index_from_global(o.globalPlayerIndex)
if gPlayerSyncTable[i].modelId ~= nil and obj_has_model_extended(o, gPlayerSyncTable[i].modelId) == 0 then
obj_set_model_extended(o, gPlayerSyncTable[i].modelId)
return
end
end
if get_object_list_from_behavior(o.behavior) == OBJ_LIST_LEVEL then
local i = network_local_index_from_global(o.globalPlayerIndex)
local capModels = gPlayerSyncTable[i].capModels
local capModel = nil
if capModels ~= nil then
if model == gMarioStates[i].character.capModelId then
capModel = capModels.normal
elseif model == gMarioStates[i].character.capWingModelId then
capModel = capModels.wing
elseif model == gMarioStates[i].character.capMetalModelId then
capModel = capModels.metal
elseif model == gMarioStates[i].character.capMetalWingModelId then
capModel = capModels.metalWing
end
if capModel ~= nil and obj_has_model_extended(o, capModel) == 0 then
obj_set_model_extended(o, capModel)
return
end
end
end
end
hook_event(HOOK_MARIO_UPDATE, mario_update)
hook_event(HOOK_OBJECT_SET_MODEL, set_model)
------------------
-- Menu Handler --
------------------
local buttonAnimTimer = 0
local buttonScroll = 0
local buttonScrollCap = 30
local optionAnimTimer = -200
local optionAnimTimerCap = optionAnimTimer
local inputStallTimer = 0
local inputStallTo = 15
2023-12-18 22:01:33 +00:00
local FONT_CS_NORMAL = FONT_NORMAL
if version_coop_dx() then
FONT_CS_NORMAL = FONT_ALIASED
end
2023-12-23 16:40:20 +00:00
--Basic Menu Text
2023-12-16 18:25:28 +00:00
local TEXT_OPTIONS_HEADER = "Menu Options"
2023-12-18 22:01:33 +00:00
local TEXT_VERSION = "Version: "..modVersion
if version_coop_dx() then
TEXT_VERSION = TEXT_VERSION.." | CoopDX Detected"
end
2023-12-16 18:25:28 +00:00
local TEXT_RATIO_UNSUPPORTED = "Your Current Aspect-Ratio isn't Supported!"
local TEXT_DESCRIPTION = "Character Description:"
local TEXT_PREF_SAVE = "Press A to Set as Preferred Character"
local TEXT_PAUSE_Z_OPEN = "Z Button - Character Select"
local TEXT_PAUSE_CURR_CHAR = "Current Character: "
if math_random(100) == 64 then -- Easter Egg if you get lucky loading the mod >v<
TEXT_PAUSE_Z_OPEN = "Z - DynOS" -- Referencing the original sm64ex DynOS options
TEXT_PAUSE_CURR_CHAR = "Model: "
end
2023-12-23 16:40:20 +00:00
--Debug Text
local TEXT_DEBUGGING = "Character Debug"
local TEXT_DESCRIPTION_SHORT = "Description:"
local TEXT_LIFE_ICON = "Life Icon:"
local TEXT_FORCED_CHAR = "Forced: "
local TEXT_TABLE_POS = "Table Position: "
--Options Text
2023-12-16 18:25:28 +00:00
local TEXT_OPTIONS_OPEN = "Press START to open Options"
local TEXT_MENU_CLOSE = "Press B to Exit Menu"
local TEXT_OPTIONS_SELECT = "A - Select | B - Exit "
local TEXT_LOCAL_MODEL_OFF = "Locally Display Models is Off"
local TEXT_LOCAL_MODEL_OFF_OPTIONS = "You can turn it back on in the Options Menu"
2023-12-23 16:40:20 +00:00
local forceCharTable = {
[CT_MARIO] = "CT_MARIO",
[CT_LUIGI] = "CT_LUIGI",
[CT_TOAD] = "CT_TOAD",
[CT_WARIO] = "CT_WARIO",
[CT_WALUIGI] = "CT_WALUIGI",
}
2023-12-16 18:25:28 +00:00
local menuColor = characterTable[currChar].color
local function on_hud_render()
djui_hud_set_resolution(RESOLUTION_N64)
2023-12-18 22:01:33 +00:00
djui_hud_set_font(FONT_CS_NORMAL)
2023-12-16 18:25:28 +00:00
local width = djui_hud_get_screen_width() + 1.4
local height = 240
local widthHalf = width*0.5
local heightHalf = height*0.5
local widthScale = math_max(width, 321.4)*0.00311332503
2023-12-23 16:40:20 +00:00
if menuAndTransition then
2023-12-16 18:25:28 +00:00
if optionTable[optionTableRef.menuColor].toggle ~= 0 then
menuColor = menuColorTable[optionTable[optionTableRef.menuColor].toggle]
else
menuColor = characterTable[currChar].color
end
if optionTable[optionTableRef.localModels].toggle == 0 then
djui_hud_set_color(0, 0, 0, 200)
djui_hud_render_rect(0, 0, width, height)
djui_hud_set_color(255, 255, 255, 255)
djui_hud_print_text(TEXT_LOCAL_MODEL_OFF, widthHalf - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF)*0.15*widthScale, heightHalf, 0.3 * widthScale)
djui_hud_print_text(TEXT_LOCAL_MODEL_OFF_OPTIONS, widthHalf - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF_OPTIONS)*0.1*widthScale, heightHalf + 10*widthScale, 0.2*widthScale)
end
--Character Buttons
local x = 135 * widthScale * 0.8
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_render_rect(0, 0, x, height)
djui_hud_set_color(0, 0, 0, 255)
djui_hud_render_rect(2, 2, x - 4, height - 4)
if optionTable[optionTableRef.anims].toggle > 0 then
buttonAnimTimer = buttonAnimTimer + 1
end
if optionTable[optionTableRef.anims].toggle == 0 then
buttonScroll = 0
elseif buttonScroll > 0.1 or buttonScroll < -0.1 then
buttonScroll = buttonScroll*0.03*inputStallTo
end
local buttonColor = {}
for i = -1, 4 do
if characterTable[i + currChar] ~= nil then
buttonColor = characterTable[i + currChar].color
djui_hud_set_color(buttonColor.r, buttonColor.g, buttonColor.b, 255)
local buttonX = 20 * widthScale
if optionTable[optionTableRef.anims].toggle > 0 then
if i == 0 then buttonX = buttonX + math_sin(buttonAnimTimer*0.05)*2.5 + 5 end
else
if i == 0 then buttonX = buttonX + 10 end
end
local y = (i + 3) * 30 + buttonScroll
djui_hud_render_rect(buttonX, y, 70, 20)
djui_hud_set_color(0, 0, 0, 255)
djui_hud_render_rect(buttonX + 1, y + 1, 68, 18)
djui_hud_set_font(FONT_TINY)
djui_hud_set_color(buttonColor.r, buttonColor.g, buttonColor.b, 255)
djui_hud_print_text(string_underscore_to_space(characterTable[currChar + i].name), buttonX + 5, y + 5, 0.6)
end
end
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_render_rect(0, height-2, x, 2)
-- Scroll Bar
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2023-12-23 16:40:20 +00:00
djui_hud_render_rect(7 * widthScale, 55, 7, 170)
2023-12-16 18:25:28 +00:00
djui_hud_set_color(0, 0, 0, 255)
2023-12-23 16:40:20 +00:00
djui_hud_render_rect(7 * widthScale + 1, 56, 5, 168)
2023-12-16 18:25:28 +00:00
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2023-12-23 16:40:20 +00:00
djui_hud_render_rect(7 * widthScale + 2, 57 + 166 * ((currChar - 1) / #characterTable) - (buttonScroll*0.03333333333)*(166/#characterTable), 3, 166/#characterTable)
djui_hud_set_font(FONT_TINY)
local TEXT_CHAR_COUNT = currChar.."/"..#characterTable
djui_hud_print_text(TEXT_CHAR_COUNT, (11 - djui_hud_measure_text(TEXT_CHAR_COUNT)*0.2) * widthScale, height - 12, 0.4)
2023-12-16 18:25:28 +00:00
--Character Description
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_render_rect(width - x, 0, x, height)
djui_hud_set_color(0, 0, 0, 255)
djui_hud_render_rect(width - x + 2, 2, x - 4, height - 4)
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2023-12-18 22:01:33 +00:00
djui_hud_set_font(FONT_CS_NORMAL)
2023-12-23 16:40:20 +00:00
local character = characterTable[currChar]
if optionTable[optionTableRef.debugInfo].toggle == 0 then -- Actual Description
local TEXT_NAME = string_underscore_to_space(character.name)
local TEXT_CREDIT = "Credit: "..character.credit
local TEXT_DESCRIPTION_TABLE = character.description
2023-12-18 22:01:33 +00:00
local TEXT_PREF = 'Preferred Character: "'..string_underscore_to_space(TEXT_PREF_LOAD)..'"'
2023-12-16 18:25:28 +00:00
2023-12-18 22:01:33 +00:00
local textX = x * 0.5
djui_hud_print_text(TEXT_NAME, width - textX - djui_hud_measure_text(TEXT_NAME)*0.3, 55, 0.6)
djui_hud_set_font(FONT_TINY)
djui_hud_print_text(TEXT_CREDIT, width - textX - djui_hud_measure_text(TEXT_CREDIT)*0.3, 72, 0.6)
djui_hud_set_font(FONT_CS_NORMAL)
djui_hud_print_text(TEXT_DESCRIPTION, width - textX - djui_hud_measure_text(TEXT_DESCRIPTION)*0.2, 85, 0.4)
2023-12-23 16:40:20 +00:00
if widthScale < 1.65 then
for i = 1, #TEXT_DESCRIPTION_TABLE do
djui_hud_print_text(TEXT_DESCRIPTION_TABLE[i], width - textX - djui_hud_measure_text(TEXT_DESCRIPTION_TABLE[i])*0.15, 90 + i*9, 0.3)
end
else
for i = 1, math_ceil(#TEXT_DESCRIPTION_TABLE*0.5) do
local TablePos = (i * 2) - 1
local TEXT_STRING = ""
if TEXT_DESCRIPTION_TABLE[TablePos] and TEXT_DESCRIPTION_TABLE[TablePos + 1] then
local TEXT_STRING = TEXT_DESCRIPTION_TABLE[TablePos].." "..TEXT_DESCRIPTION_TABLE[TablePos + 1]
djui_hud_print_text(TEXT_STRING, width - textX - djui_hud_measure_text(TEXT_STRING)*0.15, 90 + i*9, 0.3)
elseif TEXT_DESCRIPTION_TABLE[TablePos] then
local TEXT_STRING = TEXT_DESCRIPTION_TABLE[TablePos]
djui_hud_print_text(TEXT_STRING, width - textX - djui_hud_measure_text(TEXT_STRING)*0.15, 90 + i*9, 0.3)
end
end
2023-12-18 22:01:33 +00:00
end
2023-12-23 16:40:20 +00:00
djui_hud_print_text(TEXT_PREF, width - textX - djui_hud_measure_text(TEXT_PREF)*0.15, height - 22, 0.3)
djui_hud_set_font(FONT_TINY)
djui_hud_print_text(TEXT_PREF_SAVE, width - textX - djui_hud_measure_text(TEXT_PREF_SAVE)*0.25, height - 13, 0.5)
else -- Debugging Info
local TEXT_NAME = "Name: "..character.name
local TEXT_CREDIT = "Credit: "..character.credit
local TEXT_DESCRIPTION_TABLE = character.description
local TEXT_COLOR = "Color: R-"..character.color.r..", G-"..character.color.g..", B-"..character.color.b
local TEX_ICON = character.lifeIcon
local TEXT_PREF = "Preferred: "..TEXT_PREF_LOAD
2023-12-18 22:01:33 +00:00
local textX = x * 0.5
djui_hud_print_text(TEXT_DEBUGGING, width - textX - djui_hud_measure_text(TEXT_DEBUGGING)*0.3, 55, 0.6)
djui_hud_set_font(FONT_TINY)
djui_hud_print_text(TEXT_NAME, width - x + 8, 72, 0.6)
2023-12-23 16:40:20 +00:00
djui_hud_print_text(TEXT_CREDIT, width - x + 8, 81, 0.6)
djui_hud_print_text(TEXT_DESCRIPTION_SHORT, width - x + 8, 90, 0.6)
local removeLine = 0
2023-12-18 22:01:33 +00:00
for i = 1, #TEXT_DESCRIPTION_TABLE do
2023-12-23 16:40:20 +00:00
if TEXT_DESCRIPTION_TABLE[i] ~= "" then
djui_hud_print_text(TEXT_DESCRIPTION_TABLE[i], width - x + 12, 92 + (i-removeLine)*7, 0.5)
else
removeLine = removeLine + 1
end
2023-12-18 22:01:33 +00:00
end
2023-12-23 16:40:20 +00:00
local descriptionOffset = (#TEXT_DESCRIPTION_TABLE - removeLine) * 7
djui_hud_print_text(TEXT_COLOR, width - x + 8, 100 + descriptionOffset, 0.6)
djui_hud_print_text(TEXT_LIFE_ICON.." ("..TEX_ICON.width.."x"..TEX_ICON.height..")", width - x + 8, 109 + descriptionOffset, 0.6)
djui_hud_set_color(255, 255, 255, 255)
djui_hud_render_texture(TEX_ICON, width - x + 38, 110 + descriptionOffset, 0.5/(TEX_ICON.width/16), 0.5/(TEX_ICON.height/16))
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_print_text(TEXT_FORCED_CHAR..forceCharTable[character.forceChar], width - x + 8, 118 + descriptionOffset, 0.6)
djui_hud_print_text(TEXT_TABLE_POS..currChar, width - x + 8, 127 + descriptionOffset, 0.6)
djui_hud_print_text(TEXT_PREF, width - x + 8, height - 18, 0.6)
2023-12-16 18:25:28 +00:00
end
--Character Select Header
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_render_rect(0, 0, width, 50)
djui_hud_set_color(0, 0, 0, 255)
djui_hud_render_rect(2, 2, width - 4, 46)
djui_hud_set_color(menuColor.r * 0.5 + 127, menuColor.g * 0.5 + 127, menuColor.b * 0.5 + 127, 255)
djui_hud_render_texture(TEX_HEADER, widthHalf - 128, 10, 1, 1)
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_set_font(FONT_TINY)
2023-12-18 22:01:33 +00:00
djui_hud_print_text(TEXT_VERSION, 5, 3, 0.5)
2023-12-16 18:25:28 +00:00
--Unsupported Res Warning
if width < 321.2 or width > 575 then
djui_hud_print_text(TEXT_RATIO_UNSUPPORTED, 5, 39, 0.5)
end
--Options display
if options or optionAnimTimer > optionAnimTimerCap then
djui_hud_set_color(menuColor.r * 0.25, menuColor.g * 0.25, menuColor.b * 0.25, 205 + math_max(-200, optionAnimTimer))
djui_hud_render_rect(0, 0, width, height)
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_render_rect(width*0.5 - 50 * widthScale, math.min(55 - optionAnimTimer, height - 25 * widthScale), 100 * widthScale, 200)
djui_hud_set_color(0, 0, 0, 255)
djui_hud_render_rect(width*0.5 - 50 * widthScale + 2, math.min(55 - optionAnimTimer + 2, height - 25 * widthScale + 2), 100 * widthScale - 4, 196)
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_render_rect(width*0.5 - 50 * widthScale, height - 2, 100 * widthScale, 2)
2023-12-18 22:01:33 +00:00
djui_hud_set_font(FONT_CS_NORMAL)
2023-12-16 18:25:28 +00:00
djui_hud_set_color(menuColor.r * 0.5 + 127, menuColor.g * 0.5 + 127, menuColor.b * 0.5 + 127, 255)
2023-12-23 16:40:20 +00:00
djui_hud_print_text(TEXT_OPTIONS_HEADER, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_HEADER)*0.3*math_min(widthScale, 1.5), 65 + optionAnimTimer * -1, 0.6*math_min(widthScale, 1.5))
2023-12-16 18:25:28 +00:00
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2023-12-23 16:40:20 +00:00
local widthScale = math_min(widthScale, 1.5)
2023-12-16 18:25:28 +00:00
for i = 1, #optionTable do
local toggleName = optionTable[i].name
local scale = 0.5
2023-12-23 16:40:20 +00:00
local yOffset = 70 + 10 * widthScale + i * 9 * widthScale - optionAnimTimer
2023-12-16 18:25:28 +00:00
if i == currOption then
2023-12-18 22:01:33 +00:00
djui_hud_set_font(FONT_CS_NORMAL)
2023-12-16 18:25:28 +00:00
scale = 0.3
yOffset = yOffset - 1
if optionTable[i].toggleNames[optionTable[i].toggle + 1] ~= "" then
toggleName = "> " .. toggleName .. " - " .. optionTable[i].toggleNames[optionTable[i].toggle + 1]
else
toggleName = "> " .. toggleName
end
else
djui_hud_set_font(FONT_TINY)
end
2023-12-23 16:40:20 +00:00
scale = scale * widthScale
2023-12-16 18:25:28 +00:00
djui_hud_print_text(toggleName, widthHalf - djui_hud_measure_text(toggleName)*scale*0.5, yOffset, scale)
end
djui_hud_set_font(FONT_TINY)
djui_hud_print_text(TEXT_OPTIONS_SELECT, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_SELECT)*0.3, height - 20 - optionAnimTimer, 0.6)
else
-- How to open options display
local widthScaleUnlimited = widthScale
local widthScale = math_min(widthScale, 1.42)
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_render_rect(widthHalf - 50 * widthScaleUnlimited, height - 25 * widthScale, 100 * widthScaleUnlimited, 26 * widthScale)
djui_hud_set_color(0, 0, 0, 255)
djui_hud_render_rect(widthHalf - 50 * widthScaleUnlimited + 2, height - 25 * widthScale + 2, 100 * widthScaleUnlimited - 4, 22 * widthScale)
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_render_rect(widthHalf - 50 * widthScaleUnlimited, height - 2, 100 * widthScaleUnlimited, 2)
2023-12-18 22:01:33 +00:00
djui_hud_set_font(FONT_CS_NORMAL)
2023-12-16 18:25:28 +00:00
djui_hud_print_text(TEXT_OPTIONS_OPEN, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_OPEN)*0.175 * widthScale, height - 23 * widthScale + optionAnimTimer + 202, 0.35 * widthScale)
djui_hud_set_font(FONT_TINY)
djui_hud_print_text(TEXT_MENU_CLOSE, widthHalf - djui_hud_measure_text(TEXT_MENU_CLOSE)*0.25 * widthScale, height - 13 * widthScale + optionAnimTimer + 202, 0.5 * widthScale)
end
-- Anim logic
if options then
if optionTable[optionTableRef.anims].toggle > 0 then
if optionAnimTimer < -1 then
optionAnimTimer = optionAnimTimer/1.1
end
else
optionAnimTimer = -1
end
else
if optionTable[optionTableRef.anims].toggle > 0 then
if optionAnimTimer > optionAnimTimerCap then
optionAnimTimer = optionAnimTimer*1.2
end
else
optionAnimTimer = optionAnimTimerCap
end
end
optionAnimTimer = math_max(optionAnimTimer, -200)
else
options = false
optionAnimTimer = optionAnimTimerCap
end
2023-12-23 16:40:20 +00:00
-- Cross fade
if optionTable[optionTableRef.anims].toggle == 1 then
if menu and menuCrossFade > -menuCrossFadeCap then
menuCrossFade = menuCrossFade - 1
if menuCrossFade == 0 then menuCrossFade = menuCrossFade - 1 end
end
if not menu and menuCrossFade < menuCrossFadeCap then
menuCrossFade = menuCrossFade + 1
if menuCrossFade == 0 then menuCrossFade = menuCrossFade + 1 end
end
if menuCrossFade < 0 then
menuAndTransition = true
else
menuAndTransition = false
end
else
if menu then
menuCrossFade = -menuCrossFadeCap
else
menuCrossFade = menuCrossFadeCap
end
menuAndTransition = menu
end
djui_hud_set_resolution(RESOLUTION_N64)
djui_hud_set_color(0, 0, 0, (math_abs(menuCrossFade)) * -menuCrossFadeMath)
djui_hud_render_rect(0, 0, width, height)
2023-12-16 18:25:28 +00:00
-- Info / Z Open Bind on Pause Menu
if is_game_paused() and not djui_hud_is_pause_menu_created() and gMarioStates[0].action ~= ACT_EXIT_LAND_SAVE_DIALOG then
local currCharY = 0
djui_hud_set_resolution(RESOLUTION_DJUI)
2023-12-23 16:40:20 +00:00
djui_hud_set_font(FONT_NORMAL)
2023-12-16 18:25:28 +00:00
if optionTable[optionTableRef.openInputs].toggle == 2 then
currCharY = 27
local width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_PAUSE_Z_OPEN)
2023-12-18 22:01:33 +00:00
if not version_coop_dx() then -- Done to match DX not having dropshadow on the "R Button - Options" thingy
djui_hud_set_color(0, 0, 0, 255)
djui_hud_print_text(TEXT_PAUSE_Z_OPEN, width - 19, 17, 1)
end
2023-12-16 18:25:28 +00:00
djui_hud_set_color(255, 255, 255, 255)
djui_hud_print_text(TEXT_PAUSE_Z_OPEN, width - 20, 16, 1)
end
if optionTable[optionTableRef.localModels].toggle == 1 then
local charName = string_underscore_to_space(characterTable[currChar].name)
local TEXT_PAUSE_CURR_CHAR_WITH_NAME = TEXT_PAUSE_CURR_CHAR..charName
local width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_PAUSE_CURR_CHAR_WITH_NAME)
local charColor = characterTable[currChar].color
2023-12-18 22:01:33 +00:00
if not version_coop_dx() then
djui_hud_set_color(0, 0, 0, 255)
djui_hud_print_text(TEXT_PAUSE_CURR_CHAR_WITH_NAME, width - 19, 17 + currCharY, 1)
end
2023-12-16 18:25:28 +00:00
djui_hud_set_color(255, 255, 255, 255)
djui_hud_print_text(TEXT_PAUSE_CURR_CHAR, width - 20, 16 + currCharY, 1)
djui_hud_set_color(charColor.r, charColor.g, charColor.b, 255)
djui_hud_print_text(charName, djui_hud_get_screen_width() - djui_hud_measure_text(charName) - 20, 16 + currCharY, 1)
else
local width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF)
2023-12-18 22:01:33 +00:00
if not version_coop_dx() then
djui_hud_set_color(0, 0, 0, 255)
djui_hud_print_text(TEXT_LOCAL_MODEL_OFF, width - 19, 17 + currCharY, 1)
end
2023-12-16 18:25:28 +00:00
djui_hud_set_color(255, 255, 255, 255)
djui_hud_print_text(TEXT_LOCAL_MODEL_OFF, width - 20, 16 + currCharY, 1)
end
end
end
-- Custom life icon rendering (Thanks LuigiGamer)
function on_life_counter_render()
if obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then return end
djui_hud_set_font(FONT_HUD)
djui_hud_set_resolution(RESOLUTION_N64)
djui_hud_set_color(255, 255, 255, 255);
local x = 22
local y = 15
if gNetworkPlayers[0].currActNum == 99 then return end
if not hud_is_hidden() then
local icon = characterTable[currChar].lifeIcon
djui_hud_render_texture(icon, x, y, 1/(icon.width/16), 1/(icon.height/16))
djui_hud_print_text("@", x + 16, y, 1)
djui_hud_print_text(tostring(gMarioStates[0].numLives), x + 32, y, 1)
hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) &~ HUD_DISPLAY_FLAG_LIVES) -- Hides the lives counter
else
hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) | HUD_DISPLAY_FLAG_LIVES) -- Shows the lives counter, use this when you're no longer using a custom character
end
end
local function before_mario_update(m)
if m.playerIndex ~= 0 then return end
if inputStallTimer > 0 then inputStallTimer = inputStallTimer - 1 end
if menu and inputStallTo ~= latencyValueTable[optionTable[optionTableRef.inputLatency].toggle + 1] then
inputStallTo = latencyValueTable[optionTable[optionTableRef.inputLatency].toggle + 1]
end
-- Menu Inputs
if not menu and (m.controller.buttonDown & D_JPAD) ~= 0 and m.action ~= ACT_EXIT_LAND_SAVE_DIALOG and optionTable[optionTableRef.openInputs].toggle == 1 then
if ommActive then
if (m.controller.buttonDown & R_TRIG) ~= 0 then
menu = true
end
else
menu = true
end
inputStallTimer = inputStallTo
end
if is_game_paused() and m.action ~= ACT_EXIT_LAND_SAVE_DIALOG and (m.controller.buttonPressed & Z_TRIG) ~= 0 and optionTable[optionTableRef.openInputs].toggle == 2 then
menu = true
end
local cameraToObject = gMarioStates[0].marioObj.header.gfx.cameraToObject
-- C-up Failsafe (Camera Softlocks)
if m.action == ACT_FIRST_PERSON or (m.prevAction == ACT_FIRST_PERSON and is_game_paused()) then
menu = false
elseif m.prevAction == ACT_FIRST_PERSON and not is_game_paused() then
m.prevAction = ACT_WALKING
end
if gNetworkPlayers[0].currActNum == 99 then
menu = false
end
2023-12-23 16:40:20 +00:00
if menuAndTransition and not options then
if inputStallTimer == 0 and menu then
2023-12-16 18:25:28 +00:00
if (m.controller.buttonPressed & D_JPAD) ~= 0 then
currChar = currChar + 1
inputStallTimer = inputStallTo
buttonScroll = buttonScrollCap
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if (m.controller.buttonPressed & U_JPAD) ~= 0 then
currChar = currChar - 1
inputStallTimer = inputStallTo
buttonScroll = -buttonScrollCap
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if (m.controller.buttonPressed & D_CBUTTONS) ~= 0 then
currChar = currChar + 1
inputStallTimer = inputStallTo*0.6
buttonScroll = buttonScrollCap
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if (m.controller.buttonPressed & U_CBUTTONS) ~= 0 then
currChar = currChar - 1
inputStallTimer = inputStallTo*0.6
buttonScroll = -buttonScrollCap
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if m.controller.stickY < -60 then
currChar = currChar + 1
inputStallTimer = inputStallTo
buttonScroll = buttonScrollCap
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if m.controller.stickY > 60 then
currChar = currChar - 1
inputStallTimer = inputStallTo
buttonScroll = -buttonScrollCap
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if (m.controller.buttonPressed & A_BUTTON) ~= 0 then
if characterTable[currChar] ~= nil then
TEXT_PREF_LOAD = characterTable[currChar].name
mod_storage_save("PrefChar", TEXT_PREF_LOAD)
inputStallTimer = inputStallTo
play_sound(SOUND_MENU_CLICK_FILE_SELECT, cameraToObject)
else
play_sound(SOUND_MENU_CAMERA_BUZZ, cameraToObject)
end
end
if (m.controller.buttonPressed & B_BUTTON) ~= 0 then
menu = false
end
if (m.controller.buttonPressed & START_BUTTON) ~= 0 then
options = true
end
end
if currChar > #characterTable then currChar = 1 end
if currChar < 1 then currChar = #characterTable end
nullify_inputs(m)
if is_game_paused() then
m.controller.buttonPressed = START_BUTTON
end
end
if options then
if inputStallTimer == 0 then
if (m.controller.buttonPressed & D_JPAD) ~= 0 then
currOption = currOption + 1
inputStallTimer = inputStallTo
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if (m.controller.buttonPressed & U_JPAD) ~= 0 then
currOption = currOption - 1
inputStallTimer = inputStallTo
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if m.controller.stickY < -60 then
currOption = currOption + 1
inputStallTimer = inputStallTo
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if m.controller.stickY > 60 then
currOption = currOption - 1
inputStallTimer = inputStallTo
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if (m.controller.buttonPressed & A_BUTTON) ~= 0 then
optionTable[currOption].toggle = optionTable[currOption].toggle + 1
if optionTable[currOption].toggle > optionTable[currOption].toggleMax then optionTable[currOption].toggle = 0 end
if optionTable[currOption].toggleSaveName ~= nil then
mod_storage_save(optionTable[currOption].toggleSaveName, tostring(optionTable[currOption].toggle))
end
inputStallTimer = inputStallTo
play_sound(SOUND_MENU_CHANGE_SELECT, cameraToObject)
end
if (m.controller.buttonPressed & B_BUTTON) ~= 0 then
options = false
inputStallTimer = inputStallTo
end
end
if currOption > #optionTable then currOption = 1 end
if currOption < 1 then currOption = #optionTable end
nullify_inputs(m)
end
end
hook_event(HOOK_BEFORE_MARIO_UPDATE, before_mario_update)
hook_event(HOOK_ON_HUD_RENDER, on_hud_render)
hook_event(HOOK_ON_HUD_RENDER_BEHIND, on_life_counter_render)
--------------
-- Commands --
--------------
local function chat_command(msg)
2023-12-23 16:40:20 +00:00
if msg ~= "" and msg ~= "menu" then
-- Name Check
2023-12-16 18:25:28 +00:00
msg = string_lower(msg)
for i = 1, #characterTable do
2023-12-23 16:40:20 +00:00
if msg == string_underscore_to_space(string_lower(characterTable[i].name)) or msg == string_lower(characterTable[i].name) then
2023-12-16 18:25:28 +00:00
currChar = i
2023-12-23 16:40:20 +00:00
djui_chat_message_create('Character set to "'..characterTable[i].name..'" Successfully!')
return true
end
end
-- Number Check
if tonumber(msg) then
msg = tonumber(msg)
if msg > 0 and msg <= #characterTable then
currChar = msg
djui_chat_message_create('Character set to "'..characterTable[msg].name..'" Successfully!')
2023-12-16 18:25:28 +00:00
return true
end
end
djui_chat_message_create("Character Not Found")
return true
else
menu = not menu
return true
end
end
hook_chat_command("char-select", "- Opens the Character Select Menu", chat_command)