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

1145 lines
50 KiB
Lua
Raw Normal View History

2023-12-16 19:25:28 +01:00
-- name: Character Select
2024-03-09 20:23:25 +01:00
-- description:\\#ffff33\\---- Character Select Coop v1.7 ----\n\n\\#dcdcdc\\A Library / API made to make adding and using Custom Characters as simple as possible!\nUse\\#ffff33\\ /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\\#6666FF\\Squishy6094/character-select-coop
2023-12-16 19:25:28 +01:00
2024-03-09 20:23:25 +01:00
-- localize functions to improve performance
local mod_storage_load,tonumber,djui_popup_create,mod_storage_save,tostring,djui_chat_message_create,camera_freeze,hud_hide,vec3f_copy,set_mario_action,set_mario_animation,camera_unfreeze,hud_show,obj_has_behavior_id,network_local_index_from_global,obj_has_model_extended,obj_set_model_extended,get_id_from_behavior,nearest_player_to_object,math_random,djui_hud_set_resolution,djui_hud_set_font,djui_hud_get_screen_width,maxf,djui_hud_set_color,djui_hud_render_rect,djui_hud_measure_text,djui_hud_print_text,math_ceil,math_abs,math_sin,min,math_min,minf,djui_hud_set_rotation,djui_hud_is_pause_menu_created,is_game_paused,hud_is_hidden,obj_get_first_with_behavior_id,hud_get_value,hud_set_value,play_sound,string_lower = mod_storage_load,tonumber,djui_popup_create,mod_storage_save,tostring,djui_chat_message_create,camera_freeze,hud_hide,vec3f_copy,set_mario_action,set_mario_animation,camera_unfreeze,hud_show,obj_has_behavior_id,network_local_index_from_global,obj_has_model_extended,obj_set_model_extended,get_id_from_behavior,nearest_player_to_object,math.random,djui_hud_set_resolution,djui_hud_set_font,djui_hud_get_screen_width,maxf,djui_hud_set_color,djui_hud_render_rect,djui_hud_measure_text,djui_hud_print_text,math.ceil,math.abs,math.sin,min,math.min,minf,djui_hud_set_rotation,djui_hud_is_pause_menu_created,is_game_paused,hud_is_hidden,obj_get_first_with_behavior_id,hud_get_value,hud_set_value,play_sound,string.lower
2023-12-16 19:25:28 +01:00
2023-12-23 17:40:20 +01:00
local menu = false
menuAndTransition = false
2023-12-16 19:25:28 +01:00
options = false
currChar = 1
local currOption = 1
2024-02-20 22:10:45 +01:00
local menuCrossFade = 7
2023-12-23 17:40:20 +01:00
local menuCrossFadeCap = menuCrossFade
2024-03-09 20:23:25 +01:00
local menuCrossFadeMath = 255 / menuCrossFade
2023-12-16 19:25:28 +01:00
local TEX_HEADER = get_texture_info("char-select-text")
2024-03-09 20:23:25 +01:00
local TEX_OVERRIDE_HEADER = nil
---@param texture TextureInfo|nil
function header_set_texture(texture)
TEX_OVERRIDE_HEADER = texture
end
2023-12-16 19:25:28 +01:00
local TEXT_PREF_LOAD = "Default"
--[[
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 = {
2024-03-09 20:23:25 +01:00
[1] = {
2023-12-16 19:25:28 +01:00
name = "Default",
2024-02-20 22:10:45 +01:00
saveName = "Default",
2023-12-16 19:25:28 +01:00
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,
2024-03-09 20:23:25 +01:00
starIcon = gTextures.star,
2024-02-20 22:10:45 +01:00
camScale = 1.0
2023-12-16 19:25:28 +01:00
},
}
2024-02-20 22:10:45 +01:00
characterCaps = {}
2024-03-09 20:23:25 +01:00
characterCelebrationStar = {}
2024-02-20 22:10:45 +01:00
optionTableRef = {
2023-12-16 19:25:28 +01:00
openInputs = 1,
2024-02-20 22:10:45 +01:00
notification = 2,
menuColor = 3,
anims = 4,
inputLatency = 5,
localModels = 6,
localVoices = 7,
debugInfo = 8,
2024-03-09 20:23:25 +01:00
resetSaveData = 9
2023-12-16 19:25:28 +01: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)"},
2024-02-20 22:10:45 +01:00
description = {"Sets a Bind to Open the Menu", "rather than using the command."}
},
[optionTableRef.notification] = {
name = "Notifications",
toggle = tonumber(mod_storage_load("notifs")),
toggleSaveName = "notifs",
toggleDefault = 1,
toggleMax = 2,
toggleNames = {"Off", "On", "Pop-ups Only"},
description = {"Toggles wheather Pop-ups and", "Chat Messages display"}
2023-12-16 19:25:28 +01:00
},
[optionTableRef.menuColor] = {
name = "Menu Color",
toggle = tonumber(mod_storage_load("MenuColor")),
toggleSaveName = "MenuColor",
toggleDefault = 0,
2024-02-20 22:10:45 +01:00
toggleMax = 10,
toggleNames = {"Auto", "Saved", "Red", "Orange", "Yellow", "Green", "Blue", "Pink", "Purple", "White", "Black"},
description = {"Toggles the Menu Color"}
2023-12-16 19:25:28 +01:00
},
[optionTableRef.anims] = {
name = "Animations",
toggle = tonumber(mod_storage_load("Anims")),
toggleSaveName = "Anims",
toggleDefault = 1,
toggleMax = 1,
2024-03-09 20:23:25 +01:00
toggleNames = {"Off", "On"--[[, "On (30 fps)"]]},
2024-02-20 22:10:45 +01:00
description = {"Toggles Animations In-Menu,", "Turning these off may", "Save Performance"}
2023-12-16 19:25:28 +01:00
},
[optionTableRef.inputLatency] = {
name = "Scroll Speed",
toggle = tonumber(mod_storage_load("Latency")),
toggleSaveName = "Latency",
toggleDefault = 1,
toggleMax = 2,
toggleNames = {"Slow", "Normal", "Fast"},
2024-02-20 22:10:45 +01:00
description = {"Sets how fast you scroll", "throughout the Menu"}
2023-12-16 19:25:28 +01:00
},
[optionTableRef.localModels] = {
name = "Locally Display Models",
toggle = tonumber(mod_storage_load("localModels")),
toggleSaveName = "localModels",
toggleDefault = 1,
toggleMax = 1,
2024-02-20 22:10:45 +01:00
description = {"Toggles if Custom Models display", "on your client, practically", "disables Character Select if", "Toggled Off"}
2023-12-16 19:25:28 +01:00
},
2024-02-20 22:10:45 +01:00
[optionTableRef.localVoices] = {
name = "Custom Voices",
toggle = tonumber(mod_storage_load("localVoices")),
toggleSaveName = "localVoices",
toggleDefault = 1,
2023-12-16 19:25:28 +01:00
toggleMax = 1,
2024-02-20 22:10:45 +01:00
description = {"Toggle if Custom Voicelines play", "for Characters who support it"}
2023-12-16 19:25:28 +01:00
},
2023-12-18 23:01:33 +01:00
[optionTableRef.debugInfo] = {
name = "Debugging Info",
toggle = tonumber(mod_storage_load("debuginfo")),
toggleSaveName = "debuginfo",
toggleDefault = 0,
toggleMax = 1,
2024-02-20 22:10:45 +01:00
description = {"Replaces the Character", "Description with Character", "Debugging Information"}
},
[optionTableRef.resetSaveData] = {
name = "Reset Save Data",
toggle = 0,
toggleDefault = 0,
toggleMax = 1,
toggleNames = {"", ""},
description = {"Resets Character Select's", "Save Data"}
2023-12-18 23:01:33 +01:00
},
2023-12-16 19:25:28 +01:00
}
2024-02-20 22:10:45 +01:00
local optionTableCount = #optionTable
2023-12-16 19:25:28 +01:00
2024-02-20 22:10:45 +01:00
local latencyValueTable = {12, 6, 3}
2023-12-16 19:25:28 +01:00
2023-12-23 17:40:20 +01:00
local menuColorTable = {
2024-03-09 20:23:25 +01:00
{ 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 = 50, g = 50, 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-23 17:40:20 +01:00
}
2024-02-20 22:10:45 +01:00
-- Default Player Adjustments
local defaultNames = {
[CT_MARIO] = "Mario",
[CT_LUIGI] = "Luigi",
[CT_TOAD] = "Toad",
[CT_WALUIGI] = "Waluigi",
2024-03-09 20:23:25 +01:00
[CT_WARIO] = "Wario"
2024-02-20 22:10:45 +01:00
}
local defaultPlayerColors = {
[CT_MARIO] = menuColorTable[1],
[CT_LUIGI] = menuColorTable[4],
[CT_TOAD] = menuColorTable[5],
[CT_WALUIGI] = menuColorTable[7],
2024-03-09 20:23:25 +01:00
[CT_WARIO] = menuColorTable[3]
2024-02-20 22:10:45 +01:00
}
local defaultForceChar = {
[CT_MARIO] = "CT_MARIO",
[CT_LUIGI] = "CT_LUIGI",
[CT_TOAD] = "CT_TOAD",
[CT_WALUIGI] = "CT_WALUIGI",
2024-03-09 20:23:25 +01:00
[CT_WARIO] = "CT_WARIO"
2024-02-20 22:10:45 +01:00
}
local defaultIcons = {
[CT_MARIO] = gTextures.mario_head,
[CT_LUIGI] = gTextures.luigi_head,
[CT_TOAD] = gTextures.toad_head,
[CT_WALUIGI] = gTextures.waluigi_head,
2024-03-09 20:23:25 +01:00
[CT_WARIO] = gTextures.wario_head
2024-02-20 22:10:45 +01:00
}
local defaultCamScales = {
[CT_MARIO] = 1,
[CT_LUIGI] = 1,
[CT_TOAD] = 0.8,
[CT_WALUIGI] = 1.1,
2024-03-09 20:23:25 +01:00
[CT_WARIO] = 1
2024-02-20 22:10:45 +01:00
}
2023-12-16 19:25:28 +01:00
---@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
2024-02-20 22:10:45 +01:00
local prefCharColor = defaultPlayerColors[CT_MARIO]
2023-12-16 19:25:28 +01:00
local function load_preferred_char()
2024-02-20 22:10:45 +01:00
local savedChar = mod_storage_load("PrefChar")
2024-03-09 20:23:25 +01:00
if savedChar == nil or savedChar == "" then
mod_storage_save("PrefChar", "Default")
savedChar = "Default"
end
2024-02-20 22:10:45 +01:00
if savedChar ~= nil and savedChar ~= "Default" then
2023-12-16 19:25:28 +01:00
for i = 2, #characterTable do
2024-02-20 22:10:45 +01:00
if characterTable[i].saveName == savedChar then
2023-12-16 19:25:28 +01:00
currChar = i
2023-12-18 23:01:33 +01:00
if optionTable[optionTableRef.localModels].toggle == 1 then
2024-02-20 22:10:45 +01:00
if optionTable[optionTableRef.notification].toggle > 0 then
2024-03-09 20:23:25 +01:00
djui_popup_create('Character Select:\nYour Preferred Character\n"' .. string_underscore_to_space(characterTable[i].name) .. '"\nwas applied successfully!', 4)
2024-02-20 22:10:45 +01:00
end
2023-12-18 23:01:33 +01:00
end
2023-12-16 19:25:28 +01:00
break
end
end
2024-02-20 22:10:45 +01:00
end
local savedCharColors = mod_storage_load("PrefCharColor")
if savedCharColors ~= nil and savedCharColors ~= "" then
local savedCharColorsTable = string_split(string_underscore_to_space(savedCharColors))
prefCharColor = {
r = tonumber(savedCharColorsTable[1]),
g = tonumber(savedCharColorsTable[2]),
b = tonumber(savedCharColorsTable[3])
}
else
mod_storage_save("PrefCharColor", "255_50_50")
2023-12-16 19:25:28 +01:00
end
2024-02-20 22:10:45 +01:00
2023-12-16 19:25:28 +01:00
if #characterTable == 1 then
2024-02-20 22:10:45 +01:00
if optionTable[optionTableRef.notification].toggle > 0 then
djui_popup_create("Character Select:\nNo Characters were Found", 2)
end
2023-12-16 19:25:28 +01:00
end
2024-03-09 20:23:25 +01:00
return savedChar
2024-02-20 22:10:45 +01:00
end
local function mod_storage_save_pref_char(charTable)
mod_storage_save("PrefChar", charTable.saveName)
2024-03-09 20:23:25 +01:00
mod_storage_save("PrefCharColor", tostring(charTable.color.r) .. "_" .. tostring(charTable.color.g) .. "_" .. tostring(charTable.color.b))
2024-02-20 22:10:45 +01:00
TEXT_PREF_LOAD = charTable.saveName
prefCharColor = charTable.color
2023-12-16 19:25:28 +01:00
end
local function failsafe_options()
for i = 1, #optionTable do
2024-02-20 22:10:45 +01:00
if optionTable[i].toggle == nil or optionTable[i].toggle == "" then
2023-12-16 19:25:28 +01:00
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
2024-02-20 22:10:45 +01:00
if optionTable[optionTableRef.openInputs].toggle > 0 and ommActive then
2023-12-16 19:25:28 +01:00
djui_popup_create('Character Select:\nYour Open bind has changed to:\nD-pad Down + R\nDue to OMM Rebirth being active!', 4)
end
end
2024-02-20 22:10:45 +01:00
local promptedAreYouSure = false
local function reset_options(wasChatTriggered)
if not promptedAreYouSure then
2024-03-09 20:23:25 +01:00
djui_chat_message_create("\\#ffdcdc\\Are you sure you want to reset your Save Data for Character Select, including your Preferred Character\nand Settings?\n" .. (wasChatTriggered and "Type \\#ff3333\\/char-select reset\\#ffdcdc\\ to confirm." or "Press the \\#ff3333\\" .. optionTable[optionTableRef.resetSaveData].name .. "\\#ffdcdc\\ Option again to confirm." ))
2024-02-20 22:10:45 +01:00
promptedAreYouSure = true
else
djui_chat_message_create("\\#ff3333\\Character Select Save Data Reset!")
djui_chat_message_create("Note: If your issue has not been resolved, you may need to manually delete your save data via the directory below:\n\\#dcdcFF\\sm64ex-coop/sav/character-select-coop.sav")
for i = 1, #optionTable do
optionTable[i].toggle = optionTable[i].toggleDefault
if optionTable[i].toggleSaveName ~= nil then
mod_storage_save(optionTable[i].toggleSaveName, tostring(optionTable[i].toggle))
end
if optionTable[i].toggleNames == nil then
2024-03-09 20:23:25 +01:00
optionTable[i].toggleNames = { "Off", "On" }
2024-02-20 22:10:45 +01:00
end
end
mod_storage_save_pref_char(characterTable[1])
promptedAreYouSure = false
end
end
local function boot_note()
2023-12-23 17:40:20 +01:00
if #characterTable > 1 then
2024-03-09 20:23:25 +01:00
djui_chat_message_create("Character Select has " .. (#characterTable - 1) .. " character" .. (#characterTable > 2 and "s" or "") .. " available!\nYou can use \\#ffff33\\/char-select \\#ffffff\\to open the menu!")
2023-12-16 19:25:28 +01:00
else
2024-02-20 22:10:45 +01:00
djui_chat_message_create("Character Select is active!\nYou can use \\#ffff33\\/char-select \\#ffffff\\to open the menu!")
end
2024-03-09 20:23:25 +01:00
if not IS_COOPDX then
2024-02-20 22:10:45 +01:00
djui_chat_message_create("\\#FFAAAA\\Note: Although not required, we highly reccomend\nusing SM64CoopDX when playing Character Select!\n\\#6666FF\\https://sm64coopdx.com")
2023-12-16 19:25:28 +01:00
end
end
-------------------
-- Model Handler --
-------------------
local stallFrame = 0
local noLoop = false
2024-02-20 22:10:45 +01:00
local CUTSCENE_CS_MENU = 0xFA
2024-03-09 20:23:25 +01:00
local ignoredSurfaces = {
2023-12-16 19:25:28 +01:00
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
}
2024-02-20 22:10:45 +01:00
local menuActBlacklist = {
-- Star Acts
[ACT_FALL_AFTER_STAR_GRAB] = true,
[ACT_STAR_DANCE_EXIT] = true,
[ACT_STAR_DANCE_NO_EXIT] = true,
[ACT_STAR_DANCE_WATER] = true,
-- Key Acts
[ACT_UNLOCKING_KEY_DOOR] = true,
[ACT_UNLOCKING_STAR_DOOR] = true,
-- Cutscene Acts
[ACT_INTRO_CUTSCENE] = true,
[ACT_CREDITS_CUTSCENE] = true,
2024-03-09 20:23:25 +01:00
[ACT_WARP_DOOR_SPAWN] = true,
[ACT_PULLING_DOOR] = true,
[ACT_PUSHING_DOOR] = true,
[ACT_UNLOCKING_KEY_DOOR] = true,
[ACT_UNLOCKING_STAR_DOOR] = true,
2024-02-20 22:10:45 +01:00
-- Dialog Acts
[ACT_READING_NPC_DIALOG] = true,
[ACT_WAITING_FOR_DIALOG] = true,
[ACT_EXIT_LAND_SAVE_DIALOG] = true,
[ACT_READING_AUTOMATIC_DIALOG] = true,
}
local faceAngle = 0
2023-12-16 19:25:28 +01:00
--- @param m MarioState
local function mario_update(m)
if stallFrame == 1 then
failsafe_options()
2024-03-09 20:23:25 +01:00
TEXT_PREF_LOAD = load_preferred_char()
2024-02-20 22:10:45 +01:00
if optionTable[optionTableRef.notification].toggle == 1 then
boot_note()
end
2023-12-16 19:25:28 +01:00
end
if stallFrame < 2 then
stallFrame = stallFrame + 1
end
2024-03-09 20:23:25 +01:00
2023-12-16 19:25:28 +01:00
if m.playerIndex == 0 and stallFrame > 1 then
2023-12-19 01:17:19 +01:00
local modelIndex = gNetworkPlayers[m.playerIndex].modelIndex
characterTable[1].forceChar = modelIndex
2024-02-20 22:10:45 +01:00
characterTable[1].name = defaultNames[modelIndex]
2023-12-16 19:25:28 +01:00
if currChar == 1 then
2023-12-19 01:17:19 +01:00
characterTable[1].color = defaultPlayerColors[modelIndex]
characterTable[1].lifeIcon = defaultIcons[modelIndex]
2024-02-20 22:10:45 +01:00
characterTable[1].camScale = defaultCamScales[modelIndex]
2023-12-16 19:25:28 +01:00
end
if optionTable[optionTableRef.localModels].toggle > 0 then
2023-12-19 01:17:19 +01:00
gPlayerSyncTable[m.playerIndex].modelId = characterTable[currChar].model
2023-12-16 19:25:28 +01:00
if characterTable[currChar].forceChar ~= nil then
gNetworkPlayers[m.playerIndex].overrideModelIndex = characterTable[currChar].forceChar
end
else
2023-12-19 01:17:19 +01:00
gPlayerSyncTable[m.playerIndex].modelId = nil
2023-12-16 19:25:28 +01:00
gNetworkPlayers[m.playerIndex].overrideModelIndex = characterTable[1].forceChar
end
2023-12-23 17:40:20 +01:00
if menuAndTransition then
2023-12-16 19:25:28 +01: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
2024-02-20 22:10:45 +01:00
if m.area.camera.cutscene == 0 then
m.area.camera.cutscene = CUTSCENE_CS_MENU
end
local camScale = characterTable[currChar].camScale
2023-12-16 19:25:28 +01:00
local focusPos = {
x = m.pos.x,
2024-02-20 22:10:45 +01:00
y = m.pos.y + 120 * camScale,
2023-12-16 19:25:28 +01:00
z = m.pos.z,
}
vec3f_copy(gLakituState.focus, focusPos)
2024-02-20 22:10:45 +01:00
gLakituState.pos.x = m.pos.x + sins(faceAngle) * 500 * camScale
gLakituState.pos.y = m.pos.y + 100 * camScale
gLakituState.pos.z = m.pos.z + coss(faceAngle) * 500 * camScale
2023-12-16 19:25:28 +01:00
2024-03-09 20:23:25 +01:00
if m.forwardVel == 0 and m.pos.y == m.floorHeight and not ignoredSurfaces[m.floor.type] and m.health > 255 and not menuActBlacklist[m.action] then
2023-12-16 19:25:28 +01:00
set_mario_action(m, ACT_IDLE, 0)
2024-02-20 22:10:45 +01:00
set_mario_animation(m, MARIO_ANIM_FIRST_PERSON)
2023-12-16 19:25:28 +01:00
end
noLoop = false
elseif not noLoop then
camera_unfreeze()
hud_show()
if _G.PersonalStarCounter then
_G.PersonalStarCounter.hide_star_counters(false)
end
2024-02-20 22:10:45 +01:00
if m.area.camera.cutscene == CUTSCENE_CS_MENU then
m.area.camera.cutscene = CUTSCENE_STOP
end
2023-12-16 19:25:28 +01:00
noLoop = true
end
end
2024-02-20 22:10:45 +01:00
--Reset Save Data Check
if optionTable[optionTableRef.resetSaveData].toggle > 0 then
reset_options(false)
optionTable[optionTableRef.resetSaveData].toggle = 0
2023-12-16 19:25:28 +01:00
end
end
2024-03-09 20:23:25 +01:00
local sCapBhvs = {
[id_bhvWingCap] = true,
[id_bhvVanishCap] = true,
[id_bhvMetalCap] = true
}
--- @param o Object
--- @param model integer
2023-12-16 19:25:28 +01:00
function set_model(o, model)
if obj_has_behavior_id(o, id_bhvMario) ~= 0 then
2024-03-09 20:23:25 +01:00
local i = network_local_index_from_global(o.globalPlayerIndex)
2023-12-16 19:25:28 +01:00
if gPlayerSyncTable[i].modelId ~= nil and obj_has_model_extended(o, gPlayerSyncTable[i].modelId) == 0 then
obj_set_model_extended(o, gPlayerSyncTable[i].modelId)
2024-03-09 20:23:25 +01:00
end
return
end
if obj_has_behavior_id(o, id_bhvCelebrationStar) ~= 0 and o.parentObj ~= nil then
local i = network_local_index_from_global(o.parentObj.globalPlayerIndex)
local starModel = characterCelebrationStar[gPlayerSyncTable[i].modelId]
if gPlayerSyncTable[i].modelId ~= nil and starModel ~= nil and obj_has_model_extended(o, starModel) == 0 then
obj_set_model_extended(o, starModel)
end
return
end
if sCapBhvs[get_id_from_behavior(o.behavior)] then
o.globalPlayerIndex = nearest_player_to_object(o.parentObj).globalPlayerIndex
2023-12-16 19:25:28 +01:00
end
2024-03-09 20:23:25 +01:00
local i = network_local_index_from_global(o.globalPlayerIndex)
2024-02-20 22:10:45 +01:00
local c = gMarioStates[i].character
if model == c.capModelId or
model == c.capWingModelId or
model == c.capMetalModelId or
model == c.capMetalWingModelId then
local capModels = characterCaps[gPlayerSyncTable[i].modelId]
2023-12-16 19:25:28 +01:00
if capModels ~= nil then
2024-03-09 20:23:25 +01:00
local capModel = E_MODEL_NONE
2024-02-20 22:10:45 +01:00
if model == c.capModelId then
2023-12-16 19:25:28 +01:00
capModel = capModels.normal
2024-02-20 22:10:45 +01:00
elseif model == c.capWingModelId then
2023-12-16 19:25:28 +01:00
capModel = capModels.wing
2024-02-20 22:10:45 +01:00
elseif model == c.capMetalModelId then
2023-12-16 19:25:28 +01:00
capModel = capModels.metal
2024-02-20 22:10:45 +01:00
elseif model == c.capMetalWingModelId then
2023-12-16 19:25:28 +01:00
capModel = capModels.metalWing
end
2024-03-09 20:23:25 +01:00
if capModel ~= E_MODEL_NONE then
2023-12-16 19:25:28 +01:00
obj_set_model_extended(o, capModel)
2024-03-09 20:23:25 +01:00
end
2023-12-16 19:25:28 +01:00
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
2024-02-20 22:10:45 +01:00
local inputStallTimerButton = 0
local inputStallTimerDirectional = 0
local inputStallToDirectional = 12
local inputStallToButton = 10
2023-12-16 19:25:28 +01:00
2024-02-20 22:10:45 +01:00
-- Font Consistency between sm64ex-coop and sm64coopdx
2024-03-09 20:23:25 +01:00
local FONT_CS_NORMAL = IS_COOPDX and FONT_ALIASED or FONT_NORMAL
2023-12-18 23:01:33 +01:00
2023-12-23 17:40:20 +01:00
--Basic Menu Text
2023-12-16 19:25:28 +01:00
local TEXT_OPTIONS_HEADER = "Menu Options"
2024-03-09 20:23:25 +01:00
local TEXT_VERSION = "Version: " .. MOD_VERSION .. (IS_COOPDX and " | sm64coopdx" or " | sm64ex-coop")
2023-12-16 19:25:28 +01: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 17:40:20 +01: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 19:25:28 +01: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"
local menuColor = characterTable[currChar].color
2024-02-20 22:10:45 +01:00
local MATH_DIVIDE_THREE_HUNDRED_TWENTY = 1/320
2024-03-09 20:23:25 +01:00
local MATH_DIVIDE_THIRTY_TWO = 1/32
2024-02-20 22:10:45 +01:00
2023-12-16 19:25:28 +01:00
local function on_hud_render()
djui_hud_set_resolution(RESOLUTION_N64)
2023-12-18 23:01:33 +01:00
djui_hud_set_font(FONT_CS_NORMAL)
2023-12-16 19:25:28 +01:00
local width = djui_hud_get_screen_width() + 1.4
local height = 240
2024-03-09 20:23:25 +01:00
local widthHalf = width * 0.5
local heightHalf = height * 0.5
local widthScale = maxf(width, 321.4) * MATH_DIVIDE_THREE_HUNDRED_TWENTY
2023-12-16 19:25:28 +01:00
2023-12-23 17:40:20 +01:00
if menuAndTransition then
2024-02-20 22:10:45 +01:00
if optionTable[optionTableRef.menuColor].toggle > 1 then
menuColor = menuColorTable[optionTable[optionTableRef.menuColor].toggle - 1]
elseif optionTable[optionTableRef.menuColor].toggle == 1 then
2024-03-09 20:23:25 +01:00
optionTable[optionTableRef.menuColor].toggleNames[2] = string_underscore_to_space(TEXT_PREF_LOAD) .. " (Pref)"
2024-02-20 22:10:45 +01:00
menuColor = prefCharColor
2023-12-16 19:25:28 +01:00
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)
2024-03-09 20:23:25 +01:00
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)
2023-12-16 19:25:28 +01:00
end
2024-03-09 20:23:25 +01:00
2023-12-16 19:25:28 +01:00
local x = 135 * widthScale * 0.8
--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 23:01:33 +01:00
djui_hud_set_font(FONT_CS_NORMAL)
2023-12-23 17:40:20 +01:00
local character = characterTable[currChar]
if optionTable[optionTableRef.debugInfo].toggle == 0 then -- Actual Description
local TEXT_NAME = string_underscore_to_space(character.name)
2024-03-09 20:23:25 +01:00
local TEXT_CREDIT = "Credit: " .. character.credit
2023-12-23 17:40:20 +01:00
local TEXT_DESCRIPTION_TABLE = character.description
2024-02-20 22:10:45 +01:00
local TEXT_PREF = "Preferred Character:"
2024-03-09 20:23:25 +01:00
local TEXT_PREF_LOAD = string_underscore_to_space(TEXT_PREF_LOAD)
if djui_hud_measure_text(TEXT_PREF_LOAD) / widthScale > 110 then
2024-02-20 22:10:45 +01:00
TEXT_PREF = "Preferred Char:"
end
2024-03-09 20:23:25 +01:00
if djui_hud_measure_text(TEXT_PREF_LOAD) / widthScale > 164 then
2024-02-20 22:10:45 +01:00
TEXT_PREF = "Pref Char:"
end
2024-03-09 20:23:25 +01:00
TEXT_PREF = TEXT_PREF .. ' "' .. TEXT_PREF_LOAD .. '"'
2023-12-16 19:25:28 +01:00
2023-12-18 23:01:33 +01:00
local textX = x * 0.5
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_NAME, width - textX - djui_hud_measure_text(TEXT_NAME) * 0.3, 55, 0.6)
2023-12-18 23:01:33 +01:00
djui_hud_set_font(FONT_TINY)
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_CREDIT, width - textX - djui_hud_measure_text(TEXT_CREDIT) * 0.3, 74, 0.6)
2023-12-18 23:01:33 +01:00
djui_hud_set_font(FONT_CS_NORMAL)
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_DESCRIPTION, width - textX - djui_hud_measure_text(TEXT_DESCRIPTION) * 0.2, 85, 0.4)
2023-12-23 17:40:20 +01:00
if widthScale < 1.65 then
for i = 1, #TEXT_DESCRIPTION_TABLE do
2024-03-09 20:23:25 +01:00
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)
2023-12-23 17:40:20 +01:00
end
else
for i = 1, math_ceil(#TEXT_DESCRIPTION_TABLE*0.5) do
2024-03-09 20:23:25 +01:00
local tablePos = (i * 2) - 1
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)
2023-12-23 17:40:20 +01:00
end
end
2023-12-18 23:01:33 +01:00
end
2023-12-23 17:40:20 +01:00
2024-03-09 20:23:25 +01: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)
2023-12-23 17:40:20 +01:00
else -- Debugging Info
2024-03-09 20:23:25 +01:00
local TEXT_NAME = "Name: " .. character.name
local TEXT_SAVE_NAME = "Save Name: " .. character.saveName
local TEXT_CREDIT = "Credit: " .. character.credit
2023-12-23 17:40:20 +01:00
local TEXT_DESCRIPTION_TABLE = character.description
2024-03-09 20:23:25 +01:00
local TEXT_COLOR = "Color: R-" .. character.color.r ..", G-" ..character.color.g ..", B-"..character.color.b
2023-12-23 17:40:20 +01:00
local TEX_ICON = character.lifeIcon
2024-02-20 22:10:45 +01:00
local TEXT_ICON_DEFAULT = "?"
2024-03-09 20:23:25 +01:00
local TEXT_SCALE = "Camera Scale: " .. character.camScale
local TEXT_PREF = "Preferred: " .. TEXT_PREF_LOAD
local TEXT_PREF_COLOR = "Pref Color: R-" .. prefCharColor.r .. ", G-" .. prefCharColor.g .. ", B-" .. prefCharColor.b
2023-12-18 23:01:33 +01:00
local textX = x * 0.5
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_DEBUGGING, width - textX - djui_hud_measure_text(TEXT_DEBUGGING) * 0.3, 55, 0.6)
2023-12-18 23:01:33 +01:00
djui_hud_set_font(FONT_TINY)
djui_hud_print_text(TEXT_NAME, width - x + 8, 72, 0.6)
2024-02-20 22:10:45 +01:00
djui_hud_print_text(TEXT_SAVE_NAME, width - x + 8, 81, 0.6)
djui_hud_print_text(TEXT_CREDIT, width - x + 8, 90, 0.6)
djui_hud_print_text(TEXT_DESCRIPTION_SHORT, width - x + 8, 99, 0.6)
2023-12-23 17:40:20 +01:00
local removeLine = 0
2023-12-18 23:01:33 +01:00
for i = 1, #TEXT_DESCRIPTION_TABLE do
2023-12-23 17:40:20 +01:00
if TEXT_DESCRIPTION_TABLE[i] ~= "" then
2024-02-20 22:10:45 +01:00
djui_hud_set_font(FONT_CS_NORMAL)
local TEXT_DESCRIPTION_LINE = TEXT_DESCRIPTION_TABLE[i]
2024-03-09 20:23:25 +01:00
if (djui_hud_measure_text(TEXT_DESCRIPTION_TABLE[i]) * 0.3 > 100) then
TEXT_DESCRIPTION_LINE = "(!) " .. TEXT_DESCRIPTION_LINE
2024-02-20 22:10:45 +01:00
else
2024-03-09 20:23:25 +01:00
TEXT_DESCRIPTION_LINE = " " .. TEXT_DESCRIPTION_LINE
2024-02-20 22:10:45 +01:00
end
djui_hud_set_font(FONT_TINY)
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_DESCRIPTION_LINE, width - x + 5, 101 + (i-removeLine) * 7, 0.5)
2023-12-23 17:40:20 +01:00
else
removeLine = removeLine + 1
end
2023-12-18 23:01:33 +01:00
end
2023-12-23 17:40:20 +01:00
local descriptionOffset = (#TEXT_DESCRIPTION_TABLE - removeLine) * 7
2024-02-20 22:10:45 +01:00
djui_hud_print_text(TEXT_COLOR, width - x + 8, 109 + descriptionOffset, 0.6)
if TEX_ICON ~= nil then
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_LIFE_ICON .. " (" .. TEX_ICON.width .. "x" .. TEX_ICON.height .. ")", width - x + 8, 118 + descriptionOffset, 0.6)
2024-02-20 22:10:45 +01:00
djui_hud_set_color(255, 255, 255, 255)
2024-03-09 20:23:25 +01:00
djui_hud_render_texture(TEX_ICON, width - x + 38, 119 + descriptionOffset, 0.5 / (TEX_ICON.width / 16), 0.5 / (TEX_ICON.height / 16))
2024-02-20 22:10:45 +01:00
else
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_LIFE_ICON .. " (?x?)", width - x + 8, 118 + descriptionOffset, 0.6)
2024-02-20 22:10:45 +01:00
djui_hud_set_font(FONT_HUD)
djui_hud_set_color(255, 255, 255, 255)
djui_hud_print_text(TEXT_ICON_DEFAULT, width - x + 38, 119 + descriptionOffset, 0.5)
djui_hud_set_font(FONT_TINY)
end
2023-12-23 17:40:20 +01:00
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_FORCED_CHAR .. defaultForceChar[character.forceChar], width - x + 8, 127 + descriptionOffset, 0.6)
djui_hud_print_text(TEXT_TABLE_POS .. currChar, width - x + 8, 136 + descriptionOffset, 0.6)
2024-02-20 22:10:45 +01:00
djui_hud_print_text(TEXT_SCALE, width - x + 8, 145 + descriptionOffset, 0.6)
djui_hud_print_text(TEXT_PREF, width - x + 8, height - 27, 0.6)
djui_hud_print_text(TEXT_PREF_COLOR, width - x + 8, height - 18, 0.6)
end
--Character Buttons
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 math_abs(buttonScroll) > 0.1 then
2024-03-09 20:23:25 +01:00
buttonScroll = buttonScroll * 0.03 * inputStallToDirectional
2024-02-20 22:10:45 +01:00
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 i == 0 then
if optionTable[optionTableRef.anims].toggle > 0 then
2024-03-09 20:23:25 +01:00
buttonX = buttonX + math_sin(buttonAnimTimer * 0.05) * 2.5 + 5
2024-02-20 22:10:45 +01:00
else
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
2023-12-16 19:25:28 +01:00
end
2024-02-20 22:10:45 +01:00
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)
djui_hud_render_rect(7 * widthScale, 55, 7, 170)
djui_hud_set_color(0, 0, 0, 255)
djui_hud_render_rect(7 * widthScale + 1, 56, 5, 168)
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2024-03-09 20:23:25 +01:00
djui_hud_render_rect(7 * widthScale + 2, 57 + 166 * ((currChar - 1) / #characterTable) - (buttonScroll * 0.03333333333) * (166 / #characterTable), 3, 166 / #characterTable)
2024-02-20 22:10:45 +01:00
djui_hud_set_font(FONT_TINY)
2024-03-09 20:23:25 +01:00
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 19:25:28 +01:00
--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)
2024-03-09 20:23:25 +01:00
if TEX_OVERRIDE_HEADER then -- Render Override Header
djui_hud_render_texture(TEX_OVERRIDE_HEADER, widthHalf - 128, 10, 1/(TEX_OVERRIDE_HEADER.height*MATH_DIVIDE_THIRTY_TWO), 1/(TEX_OVERRIDE_HEADER.height*MATH_DIVIDE_THIRTY_TWO))
else
djui_hud_render_texture(TEX_HEADER, widthHalf - 128, 10, 1, 1)
end
2023-12-16 19:25:28 +01:00
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_set_font(FONT_TINY)
2023-12-18 23:01:33 +01:00
djui_hud_print_text(TEXT_VERSION, 5, 3, 0.5)
2024-03-09 20:23:25 +01:00
2023-12-16 19:25:28 +01:00
--Unsupported Res Warning
if width < 321.2 or width > 575 then
djui_hud_print_text(TEXT_RATIO_UNSUPPORTED, 5, 39, 0.5)
end
2024-03-09 20:23:25 +01:00
-- API Rendering
if #renderInMenuTable > 0 then
for i = 1, #renderInMenuTable do
renderInMenuTable[i]()
end
end
2023-12-16 19:25:28 +01:00
--Options display
if options or optionAnimTimer > optionAnimTimerCap then
2024-03-09 20:23:25 +01:00
djui_hud_set_color(menuColor.r * 0.25, menuColor.g * 0.25, menuColor.b * 0.25, 205 + maxf(-200, optionAnimTimer))
2023-12-16 19:25:28 +01:00
djui_hud_render_rect(0, 0, width, height)
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2024-03-09 20:23:25 +01:00
djui_hud_render_rect(width * 0.5 - 50 * widthScale, minf(55 - optionAnimTimer, height - 25 * widthScale), 100 * widthScale, 200)
2023-12-16 19:25:28 +01:00
djui_hud_set_color(0, 0, 0, 255)
2024-03-09 20:23:25 +01:00
djui_hud_render_rect(width * 0.5 - 50 * widthScale + 2, minf(55 - optionAnimTimer + 2, height - 25 * widthScale + 2), 100 * widthScale - 4, 196)
2023-12-18 23:01:33 +01:00
djui_hud_set_font(FONT_CS_NORMAL)
2023-12-16 19:25:28 +01:00
djui_hud_set_color(menuColor.r * 0.5 + 127, menuColor.g * 0.5 + 127, menuColor.b * 0.5 + 127, 255)
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_OPTIONS_HEADER, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_HEADER) * 0.3 * minf(widthScale, 1.5), 65 + optionAnimTimer * -1, 0.6 * minf(widthScale, 1.5))
2023-12-16 19:25:28 +01:00
2024-03-09 20:23:25 +01:00
local widthScaleLimited = minf(widthScale, 1.5)
2024-02-20 22:10:45 +01:00
-- Up Arrow
if currOption > 3 then
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_set_rotation(0x2000, 0.5, 0.5)
djui_hud_render_rect(widthHalf - 3 * widthScaleLimited, 95 - optionAnimTimer, 5 * widthScaleLimited, 5 * widthScaleLimited)
djui_hud_set_color(0, 0, 0, 255)
djui_hud_set_rotation(0x0000, 0.5, 0.5)
djui_hud_render_rect(widthHalf - 4 * widthScaleLimited, 95 - optionAnimTimer + 2 * widthScaleLimited, 8 * widthScaleLimited, 10)
end
-- Down Arrow
if currOption < optionTableCount - 2 then
local yOffset = 90 - optionAnimTimer + 45 * widthScaleLimited
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
djui_hud_set_rotation(0x2000, 0.5, 0.5)
djui_hud_render_rect(widthHalf - 3 * widthScaleLimited, yOffset + 10, 5 * widthScaleLimited, 5 * widthScaleLimited)
djui_hud_set_color(0, 0, 0, 255)
djui_hud_set_rotation(0x0000, 0.5, 0.5)
djui_hud_render_rect(widthHalf - 4 * widthScaleLimited, yOffset + 10 - 2 * widthScaleLimited, 8 * widthScaleLimited, 5 * widthScaleLimited)
end
-- Options
for i = currOption - 2, currOption + 2 do
2024-03-09 20:23:25 +01:00
if not (i < 1 or i > optionTableCount) then
2024-02-20 22:10:45 +01:00
local toggleName = optionTable[i].name
local scale = 0.5
local yOffset = 100 - optionAnimTimer + (i - currOption + 2) * 9 * widthScaleLimited
if i == currOption then
djui_hud_set_font(FONT_CS_NORMAL)
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
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2023-12-16 19:25:28 +01:00
else
2024-02-20 22:10:45 +01:00
djui_hud_set_font(FONT_TINY)
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 150)
2023-12-16 19:25:28 +01:00
end
2024-02-20 22:10:45 +01:00
scale = scale * widthScaleLimited
2024-03-09 20:23:25 +01:00
djui_hud_print_text(toggleName, widthHalf - djui_hud_measure_text(toggleName) * scale * 0.5, yOffset, scale)
2023-12-16 19:25:28 +01:00
end
end
2024-02-20 22:10:45 +01:00
-- Description
if optionTable[currOption].description ~= nil then
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
for i = 1, #optionTable[currOption].description do
djui_hud_set_font(FONT_CS_NORMAL)
local line = optionTable[currOption].description[i]
2024-03-09 20:23:25 +01:00
djui_hud_print_text(line, widthHalf - djui_hud_measure_text(line) * 0.15, 180 - optionAnimTimer + 15 * widthScaleLimited + 8 * i - 8 * #optionTable[currOption].description, 0.3)
2024-02-20 22:10:45 +01:00
end
end
-- Footer
2023-12-16 19:25:28 +01:00
djui_hud_set_font(FONT_TINY)
2024-02-20 22:10:45 +01:00
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_OPTIONS_SELECT, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_SELECT) * 0.3, height - 20 - optionAnimTimer, 0.6)
2024-02-20 22:10:45 +01:00
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2024-03-09 20:23:25 +01:00
djui_hud_render_rect(width * 0.5 - 50 * widthScale, height - 2, 100 * widthScale, 2)
2023-12-16 19:25:28 +01:00
else
-- How to open options display
2024-03-09 20:23:25 +01:00
local widthScaleLimited = minf(widthScale, 1.42)
2023-12-16 19:25:28 +01:00
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2024-02-20 22:10:45 +01:00
djui_hud_render_rect(widthHalf - 50 * widthScale, height - 25 * widthScaleLimited, 100 * widthScale, 26 * widthScaleLimited)
2023-12-16 19:25:28 +01:00
djui_hud_set_color(0, 0, 0, 255)
2024-02-20 22:10:45 +01:00
djui_hud_render_rect(widthHalf - 50 * widthScale + 2, height - 25 * widthScaleLimited + 2, 100 * widthScale - 4, 22 * widthScaleLimited)
2023-12-16 19:25:28 +01:00
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
2024-02-20 22:10:45 +01:00
djui_hud_render_rect(widthHalf - 50 * widthScale, height - 2, 100 * widthScale, 2)
2023-12-18 23:01:33 +01:00
djui_hud_set_font(FONT_CS_NORMAL)
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_OPTIONS_OPEN, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_OPEN) * 0.175 * widthScaleLimited, height - 23 * widthScaleLimited + optionAnimTimer + 202, 0.35 * widthScaleLimited)
2023-12-16 19:25:28 +01:00
djui_hud_set_font(FONT_TINY)
2024-03-09 20:23:25 +01:00
djui_hud_print_text(TEXT_MENU_CLOSE, widthHalf - djui_hud_measure_text(TEXT_MENU_CLOSE) * 0.25 * widthScaleLimited, height - 13 * widthScaleLimited + optionAnimTimer + 202, 0.5 * widthScaleLimited)
2023-12-16 19:25:28 +01:00
end
2024-03-09 20:23:25 +01:00
2023-12-16 19:25:28 +01:00
-- Anim logic
if options then
if optionTable[optionTableRef.anims].toggle > 0 then
if optionAnimTimer < -1 then
2024-03-09 20:23:25 +01:00
optionAnimTimer = optionAnimTimer / 1.1
2023-12-16 19:25:28 +01:00
end
else
optionAnimTimer = -1
end
else
if optionTable[optionTableRef.anims].toggle > 0 then
if optionAnimTimer > optionAnimTimerCap then
2024-03-09 20:23:25 +01:00
optionAnimTimer = optionAnimTimer * 1.3
2023-12-16 19:25:28 +01:00
end
else
optionAnimTimer = optionAnimTimerCap
end
end
2024-03-09 20:23:25 +01:00
optionAnimTimer = maxf(optionAnimTimer, -200)
2023-12-16 19:25:28 +01:00
else
options = false
optionAnimTimer = optionAnimTimerCap
end
2023-12-23 17:40:20 +01: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 19:25:28 +01: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 17:40:20 +01:00
djui_hud_set_font(FONT_NORMAL)
2023-12-16 19:25:28 +01:00
if optionTable[optionTableRef.openInputs].toggle == 2 then
currCharY = 27
2024-03-09 20:23:25 +01:00
width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_PAUSE_Z_OPEN)
if not IS_COOPDX then -- Done to match DX not having dropshadow on the "R Button - Options" thingy
2023-12-18 23:01:33 +01:00
djui_hud_set_color(0, 0, 0, 255)
djui_hud_print_text(TEXT_PAUSE_Z_OPEN, width - 19, 17, 1)
end
2023-12-16 19:25:28 +01: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)
2024-03-09 20:23:25 +01:00
local TEXT_PAUSE_CURR_CHAR_WITH_NAME = TEXT_PAUSE_CURR_CHAR .. charName
width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_PAUSE_CURR_CHAR_WITH_NAME)
2023-12-16 19:25:28 +01:00
local charColor = characterTable[currChar].color
2024-03-09 20:23:25 +01:00
if not IS_COOPDX then
2023-12-18 23:01:33 +01:00
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 19:25:28 +01: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
2024-03-09 20:23:25 +01:00
width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF)
if not IS_COOPDX then
2023-12-18 23:01:33 +01:00
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 19:25:28 +01: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
local function before_mario_update(m)
if m.playerIndex ~= 0 then return end
2024-02-20 22:10:45 +01:00
if inputStallTimerButton > 0 then inputStallTimerButton = inputStallTimerButton - 1 end
if inputStallTimerDirectional > 0 then inputStallTimerDirectional = inputStallTimerDirectional - 1 end
2024-03-09 20:23:25 +01:00
2024-02-20 22:10:45 +01:00
if menu and inputStallToDirectional ~= latencyValueTable[optionTable[optionTableRef.inputLatency].toggle + 1] then
inputStallToDirectional = latencyValueTable[optionTable[optionTableRef.inputLatency].toggle + 1]
2023-12-16 19:25:28 +01:00
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
2024-02-20 22:10:45 +01:00
inputStallTimerDirectional = inputStallToDirectional
2023-12-16 19:25:28 +01:00
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
2024-02-20 22:10:45 +01:00
if gNetworkPlayers[0].currActNum == 99 then menu = false end
if m.action == ACT_INTRO_CUTSCENE then menu = false end
2023-12-16 19:25:28 +01:00
2023-12-23 17:40:20 +01:00
if menuAndTransition and not options then
2024-02-20 22:10:45 +01:00
if menu then
if inputStallTimerDirectional == 0 then
if (m.controller.buttonPressed & D_JPAD) ~= 0 or (m.controller.buttonPressed & D_CBUTTONS) ~= 0 or m.controller.stickY < -60 then
currChar = currChar + 1
if (m.controller.buttonPressed & D_CBUTTONS) == 0 then
inputStallTimerDirectional = inputStallToDirectional
else
inputStallTimerDirectional = 3 -- C-Scrolling
end
buttonScroll = buttonScrollCap
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if (m.controller.buttonPressed & U_JPAD) ~= 0 or (m.controller.buttonPressed & U_CBUTTONS) ~= 0 or m.controller.stickY > 60 then
currChar = currChar - 1
if (m.controller.buttonPressed & U_CBUTTONS) == 0 then
inputStallTimerDirectional = inputStallToDirectional
else
inputStallTimerDirectional = 3 -- C-Scrolling
end
buttonScroll = -buttonScrollCap
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
2023-12-16 19:25:28 +01:00
end
end
2024-02-20 22:10:45 +01:00
if inputStallTimerButton == 0 then
if (m.controller.buttonPressed & A_BUTTON) ~= 0 then
if characterTable[currChar] ~= nil then
mod_storage_save_pref_char(characterTable[currChar])
inputStallTimerButton = inputStallToButton
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
2023-12-16 19:25:28 +01:00
end
end
2024-02-20 22:10:45 +01:00
-- Wraping Menu
2023-12-16 19:25:28 +01:00
if currChar > #characterTable then currChar = 1 end
if currChar < 1 then currChar = #characterTable end
2024-02-20 22:10:45 +01:00
-- Handles Camera Posistioning
faceAngle = m.faceAngle.y
if m.controller.buttonPressed & R_CBUTTONS ~= 0 then faceAngle = faceAngle + 0x1000 end
if m.controller.buttonPressed & L_CBUTTONS ~= 0 then faceAngle = faceAngle - 0x1000 end
2023-12-16 19:25:28 +01:00
nullify_inputs(m)
if is_game_paused() then
m.controller.buttonPressed = START_BUTTON
end
end
if options then
2024-02-20 22:10:45 +01:00
if inputStallTimerDirectional == 0 then
2023-12-16 19:25:28 +01:00
if (m.controller.buttonPressed & D_JPAD) ~= 0 then
currOption = currOption + 1
2024-02-20 22:10:45 +01:00
inputStallTimerDirectional = inputStallToDirectional
2023-12-16 19:25:28 +01:00
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if (m.controller.buttonPressed & U_JPAD) ~= 0 then
currOption = currOption - 1
2024-02-20 22:10:45 +01:00
inputStallTimerDirectional = inputStallToDirectional
2023-12-16 19:25:28 +01:00
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if m.controller.stickY < -60 then
currOption = currOption + 1
2024-02-20 22:10:45 +01:00
inputStallTimerDirectional = inputStallToDirectional
2023-12-16 19:25:28 +01:00
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
if m.controller.stickY > 60 then
currOption = currOption - 1
2024-02-20 22:10:45 +01:00
inputStallTimerDirectional = inputStallToDirectional
2023-12-16 19:25:28 +01:00
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
end
2024-02-20 22:10:45 +01:00
end
if inputStallTimerButton == 0 then
2023-12-16 19:25:28 +01:00
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
2024-02-20 22:10:45 +01:00
inputStallTimerButton = inputStallToButton
2023-12-16 19:25:28 +01:00
play_sound(SOUND_MENU_CHANGE_SELECT, cameraToObject)
end
if (m.controller.buttonPressed & B_BUTTON) ~= 0 then
options = false
2024-02-20 22:10:45 +01:00
inputStallTimerButton = inputStallToButton
2023-12-16 19:25:28 +01:00
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)
--------------
-- Commands --
--------------
2024-03-09 20:23:25 +01:00
promptedAreYouSure = false
2024-02-20 22:10:45 +01:00
2023-12-16 19:25:28 +01:00
local function chat_command(msg)
2024-02-20 22:10:45 +01:00
msg = string_lower(msg)
-- Open Menu Check
if msg == "" or msg == "menu" then
2023-12-16 19:25:28 +01:00
menu = not menu
return true
end
2024-02-20 22:10:45 +01:00
-- Help Prompt Check
if msg == "?" or msg == "help" then
2024-03-09 20:23:25 +01:00
djui_chat_message_create("Character Select's Avalible Commands:" ..
"\n\\#ffff33\\/char-select help\\#ffffff\\ - Returns Avalible Commands" ..
"\n\\#ffff33\\/char-select menu\\#ffffff\\ - Opens the Menu" ..
"\n\\#ffff33\\/char-select [name/num]\\#ffffff\\ - Switches to Character" ..
2024-02-20 22:10:45 +01:00
"\n\\#ff3333\\/char-select reset\\#ffffff\\ - Resets your Save Data")
return true
end
-- Reset Save Data Check
if msg == "reset" or (msg == "confirm" and promptedAreYouSure) then
reset_options(true)
return true
end
-- Name Check
for i = 1, #characterTable do
if msg == string_lower(characterTable[i].name) or msg == string_underscore_to_space(string_lower(characterTable[i].saveName)) then
currChar = i
2024-03-09 20:23:25 +01:00
djui_chat_message_create('Character set to "' .. characterTable[i].name .. '" Successfully!')
2024-02-20 22:10:45 +01:00
return true
end
end
2024-03-09 20:23:25 +01:00
2024-02-20 22:10:45 +01:00
-- Number Check
if tonumber(msg) then
2024-03-09 20:23:25 +01:00
msg = tonumber(msg)
2024-02-20 22:10:45 +01:00
if msg > 0 and msg <= #characterTable then
currChar = msg
2024-03-09 20:23:25 +01:00
djui_chat_message_create('Character set to "' .. characterTable[msg].name .. '" Successfully!')
2024-02-20 22:10:45 +01:00
return true
end
end
djui_chat_message_create("Character Not Found")
return true
2023-12-16 19:25:28 +01:00
end
hook_chat_command("char-select", "- Opens the Character Select Menu", chat_command)