mirror of
				https://github.com/coop-deluxe/sm64coopdx.git
				synced 2025-10-30 08:01:01 +00:00 
			
		
		
		
	Update Character Select to v1.9
This commit is contained in:
		
							parent
							
								
									2a6d17c4cc
								
							
						
					
					
						commit
						360fd9fb8e
					
				
					 6 changed files with 825 additions and 259 deletions
				
			
		| 
						 | 
				
			
			@ -1,5 +1,10 @@
 | 
			
		|||
MOD_VERSION = "1.7"
 | 
			
		||||
IS_COOPDX = get_coop_compatibility_enabled ~= nil
 | 
			
		||||
if VERSION_NUMBER < 37 then
 | 
			
		||||
    djui_popup_create("\n\\#FFAAAA\\Character Select requires\n CoopDX v1 or higher use!\n\nYou can find CoopDX here:\n\\#6666FF\\https://sm64coopdx.com", 5)
 | 
			
		||||
    incompatibleClient = true
 | 
			
		||||
    return 0
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
MOD_VERSION = "1.9"
 | 
			
		||||
 | 
			
		||||
ommActive = false
 | 
			
		||||
for i in pairs(gActiveMods) do
 | 
			
		||||
| 
						 | 
				
			
			@ -102,4 +107,18 @@ end
 | 
			
		|||
 | 
			
		||||
allowMenu = {}
 | 
			
		||||
 | 
			
		||||
renderInMenuTable = {}
 | 
			
		||||
renderInMenuTable = {
 | 
			
		||||
    front = {},
 | 
			
		||||
    back = {},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
queueStorageFailsafe = false
 | 
			
		||||
 | 
			
		||||
charBeingSet = false
 | 
			
		||||
 | 
			
		||||
stopPalettes = false
 | 
			
		||||
for i in pairs(gActiveMods) do
 | 
			
		||||
    if (gActiveMods[i].incompatible ~= nil and gActiveMods[i].incompatible:find("gamemode")) and not (gActiveMods[i].name:find("Personal Star Counter EX+")) then
 | 
			
		||||
        stopPalettes = true
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +1,12 @@
 | 
			
		|||
-- name: Character Select
 | 
			
		||||
-- 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
 | 
			
		||||
-- description:\\#ffff33\\---- Character Select Coop v1.9 ----\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 can be found on\nCharacter Select's Github:\n\\#6666FF\\Squishy6094/character-select-coop
 | 
			
		||||
 | 
			
		||||
if incompatibleClient then return 0 end
 | 
			
		||||
 | 
			
		||||
-- 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
 | 
			
		||||
 | 
			
		||||
local menu = false
 | 
			
		||||
menu = false
 | 
			
		||||
menuAndTransition = false
 | 
			
		||||
options = false
 | 
			
		||||
currChar = 1
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +28,7 @@ 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
 | 
			
		||||
    We highly recommend 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!
 | 
			
		||||
]]
 | 
			
		||||
| 
						 | 
				
			
			@ -34,11 +36,12 @@ characterTable = {
 | 
			
		|||
    [1] = {
 | 
			
		||||
        name = "Default",
 | 
			
		||||
        saveName = "Default",
 | 
			
		||||
        description = {"The vanilla cast for sm64ex-coop!", "", "These Characters are swappable", "via the default Options Menu"},
 | 
			
		||||
        description = {"The vanilla cast for sm64coopdx!", "", "These Characters are swappable", "via the default Options Menu"},
 | 
			
		||||
        credit = "Nintendo / Coop Team",
 | 
			
		||||
        color = {r = 255, g = 50, b = 50},
 | 
			
		||||
        model = nil,
 | 
			
		||||
        forceChar = nil,
 | 
			
		||||
        offset = 0,
 | 
			
		||||
        forceChar = nil, -- Legacy Functionality
 | 
			
		||||
        lifeIcon = gTextures.mario_head,
 | 
			
		||||
        starIcon = gTextures.star,
 | 
			
		||||
        camScale = 1.0
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +50,7 @@ characterTable = {
 | 
			
		|||
 | 
			
		||||
characterCaps = {}
 | 
			
		||||
characterCelebrationStar = {}
 | 
			
		||||
characterColorPresets = {}
 | 
			
		||||
 | 
			
		||||
optionTableRef = {
 | 
			
		||||
    openInputs = 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -54,10 +58,11 @@ optionTableRef = {
 | 
			
		|||
    menuColor = 3,
 | 
			
		||||
    anims = 4,
 | 
			
		||||
    inputLatency = 5,
 | 
			
		||||
    localModels = 6,
 | 
			
		||||
    localVoices = 7,
 | 
			
		||||
    debugInfo = 8,
 | 
			
		||||
    resetSaveData = 9
 | 
			
		||||
    autoPalette = 6,
 | 
			
		||||
    localModels = 7,
 | 
			
		||||
    localVoices = 8,
 | 
			
		||||
    debugInfo = 9,
 | 
			
		||||
    resetSaveData = 10
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
optionTable = {
 | 
			
		||||
| 
						 | 
				
			
			@ -65,9 +70,9 @@ optionTable = {
 | 
			
		|||
        name = "Open Binds",
 | 
			
		||||
        toggle = tonumber(mod_storage_load("MenuInput")),
 | 
			
		||||
        toggleSaveName = "MenuInput",
 | 
			
		||||
        toggleDefault = 0,
 | 
			
		||||
        toggleDefault = 1,
 | 
			
		||||
        toggleMax = 2,
 | 
			
		||||
        toggleNames = {"None", ommActive and "D-pad Down + R" or "D-pad Down", "Z (Pause Menu)"},
 | 
			
		||||
        toggleNames = {"None", "Z (Pause Menu)", ommActive and "D-pad Down + R" or "D-pad Down"},
 | 
			
		||||
        description = {"Sets a Bind to Open the Menu", "rather than using the command."}
 | 
			
		||||
    },
 | 
			
		||||
    [optionTableRef.notification] = {
 | 
			
		||||
| 
						 | 
				
			
			@ -106,6 +111,14 @@ optionTable = {
 | 
			
		|||
        toggleNames = {"Slow", "Normal", "Fast"},
 | 
			
		||||
        description = {"Sets how fast you scroll", "throughout the Menu"}
 | 
			
		||||
    },
 | 
			
		||||
    [optionTableRef.autoPalette] = {
 | 
			
		||||
        name = "Auto-Apply Palette",
 | 
			
		||||
        toggle = tonumber(mod_storage_load("autoPalette")),
 | 
			
		||||
        toggleSaveName = "autoPalette",
 | 
			
		||||
        toggleDefault = 1,
 | 
			
		||||
        toggleMax = 1,
 | 
			
		||||
        description = {"If On, Automatically", "sets your palette to the", "Character's Preset if avalible"}
 | 
			
		||||
    },
 | 
			
		||||
    [optionTableRef.localModels] = {
 | 
			
		||||
        name = "Locally Display Models",
 | 
			
		||||
        toggle = tonumber(mod_storage_load("localModels")),
 | 
			
		||||
| 
						 | 
				
			
			@ -140,7 +153,7 @@ optionTable = {
 | 
			
		|||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local optionTableCount = #optionTable
 | 
			
		||||
local defaultOptionCount = #optionTable
 | 
			
		||||
 | 
			
		||||
local latencyValueTable = {12, 6, 3}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +177,7 @@ local defaultNames = {
 | 
			
		|||
    [CT_WALUIGI] = "Waluigi",
 | 
			
		||||
    [CT_WARIO] = "Wario"
 | 
			
		||||
}
 | 
			
		||||
local defaultPlayerColors = {
 | 
			
		||||
local defaultMenuColors = {
 | 
			
		||||
    [CT_MARIO] = menuColorTable[1],
 | 
			
		||||
    [CT_LUIGI] = menuColorTable[4],
 | 
			
		||||
    [CT_TOAD] =  menuColorTable[5],
 | 
			
		||||
| 
						 | 
				
			
			@ -192,6 +205,13 @@ local defaultCamScales = {
 | 
			
		|||
    [CT_WALUIGI] = 1.1,
 | 
			
		||||
    [CT_WARIO] = 1
 | 
			
		||||
}
 | 
			
		||||
local defaultModels = {
 | 
			
		||||
    [CT_MARIO] = E_MODEL_MARIO,
 | 
			
		||||
    [CT_LUIGI] = E_MODEL_LUIGI,
 | 
			
		||||
    [CT_TOAD] = E_MODEL_TOAD_PLAYER,
 | 
			
		||||
    [CT_WALUIGI] = E_MODEL_WALUIGI,
 | 
			
		||||
    [CT_WARIO] = E_MODEL_WARIO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
---@param m MarioState
 | 
			
		||||
local function nullify_inputs(m)
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +238,7 @@ local function nullify_inputs(m)
 | 
			
		|||
    c.stickY = 0
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local prefCharColor = defaultPlayerColors[CT_MARIO]
 | 
			
		||||
local prefCharColor = defaultMenuColors[CT_MARIO]
 | 
			
		||||
 | 
			
		||||
local function load_preferred_char()
 | 
			
		||||
    local savedChar = mod_storage_load("PrefChar")
 | 
			
		||||
| 
						 | 
				
			
			@ -267,10 +287,14 @@ local function mod_storage_save_pref_char(charTable)
 | 
			
		|||
    prefCharColor = charTable.color
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function failsafe_options()
 | 
			
		||||
function failsafe_options()
 | 
			
		||||
    for i = 1, #optionTable do
 | 
			
		||||
        if optionTable[i].toggle == nil or optionTable[i].toggle == "" then
 | 
			
		||||
            optionTable[i].toggle = optionTable[i].toggleDefault
 | 
			
		||||
            local load = optionTable[i].toggleSaveName and mod_storage_load(optionTable[i].toggleSaveName) or nil
 | 
			
		||||
            if load == "" then
 | 
			
		||||
                load = nil
 | 
			
		||||
            end
 | 
			
		||||
            optionTable[i].toggle = load and tonumber(load) or optionTable[i].toggleDefault
 | 
			
		||||
            if optionTable[i].toggleSaveName ~= nil then
 | 
			
		||||
                mod_storage_save(optionTable[i].toggleSaveName, tostring(optionTable[i].toggle))
 | 
			
		||||
            end
 | 
			
		||||
| 
						 | 
				
			
			@ -279,7 +303,7 @@ local function failsafe_options()
 | 
			
		|||
            optionTable[i].toggleNames = {"Off", "On"}
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    if optionTable[optionTableRef.openInputs].toggle > 0 and ommActive then
 | 
			
		||||
    if optionTable[optionTableRef.openInputs].toggle == 2 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
 | 
			
		||||
| 
						 | 
				
			
			@ -313,10 +337,15 @@ local function boot_note()
 | 
			
		|||
    else
 | 
			
		||||
        djui_chat_message_create("Character Select is active!\nYou can use \\#ffff33\\/char-select \\#ffffff\\to open the menu!")
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
    if not IS_COOPDX then
 | 
			
		||||
        djui_chat_message_create("\\#FFAAAA\\Note: Although not required, we highly reccomend\nusing SM64CoopDX when playing Character Select!\n\\#6666FF\\https://sm64coopdx.com")
 | 
			
		||||
local function menu_is_allowed()
 | 
			
		||||
    for _, func in pairs(allowMenu) do
 | 
			
		||||
        if not func() then
 | 
			
		||||
            return false
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    return true
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -361,12 +390,15 @@ local faceAngle = 0
 | 
			
		|||
 | 
			
		||||
--- @param m MarioState
 | 
			
		||||
local function mario_update(m)
 | 
			
		||||
    if stallFrame == 1 then
 | 
			
		||||
    if stallFrame == 1 or queueStorageFailsafe then
 | 
			
		||||
        failsafe_options()
 | 
			
		||||
        TEXT_PREF_LOAD = load_preferred_char()
 | 
			
		||||
        if optionTable[optionTableRef.notification].toggle == 1 then
 | 
			
		||||
            boot_note()
 | 
			
		||||
        if not queueStorageFailsafe then
 | 
			
		||||
            TEXT_PREF_LOAD = load_preferred_char()
 | 
			
		||||
            if optionTable[optionTableRef.notification].toggle == 1 then
 | 
			
		||||
                boot_note()
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        queueStorageFailsafe = false
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if stallFrame < 2 then
 | 
			
		||||
| 
						 | 
				
			
			@ -374,31 +406,30 @@ local function mario_update(m)
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    if m.playerIndex == 0 and stallFrame > 1 then
 | 
			
		||||
        local modelIndex = gNetworkPlayers[m.playerIndex].modelIndex
 | 
			
		||||
        local modelIndex = gNetworkPlayers[0].modelIndex
 | 
			
		||||
        characterTable[1].forceChar = modelIndex
 | 
			
		||||
        characterTable[1].name = defaultNames[modelIndex]
 | 
			
		||||
        characterTable[1].color = defaultMenuColors[modelIndex]
 | 
			
		||||
        if currChar == 1 then
 | 
			
		||||
            characterTable[1].color = defaultPlayerColors[modelIndex]
 | 
			
		||||
            characterTable[1].lifeIcon = defaultIcons[modelIndex]
 | 
			
		||||
            characterTable[1].camScale = defaultCamScales[modelIndex]
 | 
			
		||||
            gNetworkPlayers[0].overrideModelIndex = modelIndex
 | 
			
		||||
        else
 | 
			
		||||
            gNetworkPlayers[0].overrideModelIndex = CT_MARIO
 | 
			
		||||
        end
 | 
			
		||||
        if optionTable[optionTableRef.localModels].toggle > 0 then
 | 
			
		||||
            gPlayerSyncTable[m.playerIndex].modelId = characterTable[currChar].model
 | 
			
		||||
            gPlayerSyncTable[0].modelId = characterTable[currChar].model
 | 
			
		||||
            if characterTable[currChar].forceChar ~= nil then
 | 
			
		||||
                gNetworkPlayers[m.playerIndex].overrideModelIndex = characterTable[currChar].forceChar
 | 
			
		||||
                gNetworkPlayers[0].overrideModelIndex = characterTable[currChar].forceChar
 | 
			
		||||
            end
 | 
			
		||||
            m.marioObj.hookRender = 1
 | 
			
		||||
        else
 | 
			
		||||
            gPlayerSyncTable[m.playerIndex].modelId = nil
 | 
			
		||||
            gNetworkPlayers[m.playerIndex].overrideModelIndex = characterTable[1].forceChar
 | 
			
		||||
            gPlayerSyncTable[0].modelId = nil
 | 
			
		||||
            gNetworkPlayers[0].overrideModelIndex = characterTable[1].forceChar
 | 
			
		||||
            currChar = 1
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if menuAndTransition then
 | 
			
		||||
            for _, func in pairs(allowMenu) do
 | 
			
		||||
                if not func() then
 | 
			
		||||
                    menu = false
 | 
			
		||||
                    return
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
            camera_freeze()
 | 
			
		||||
            hud_hide()
 | 
			
		||||
            if _G.PersonalStarCounter then
 | 
			
		||||
| 
						 | 
				
			
			@ -434,12 +465,41 @@ local function mario_update(m)
 | 
			
		|||
            end
 | 
			
		||||
            noLoop = true
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    --Reset Save Data Check
 | 
			
		||||
    if optionTable[optionTableRef.resetSaveData].toggle > 0 then
 | 
			
		||||
        reset_options(false)
 | 
			
		||||
        optionTable[optionTableRef.resetSaveData].toggle = 0
 | 
			
		||||
        --Reset Save Data Check
 | 
			
		||||
        if optionTable[optionTableRef.resetSaveData].toggle > 0 then
 | 
			
		||||
            reset_options(false)
 | 
			
		||||
            optionTable[optionTableRef.resetSaveData].toggle = 0
 | 
			
		||||
        end
 | 
			
		||||
        charBeingSet = false
 | 
			
		||||
        for i = 1, #optionTable do
 | 
			
		||||
            optionTable[i].optionBeingSet = false
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local altOffsetActs = {
 | 
			
		||||
    [ACT_CROUCH_SLIDE] = true,
 | 
			
		||||
    [ACT_READING_AUTOMATIC_DIALOG] = true,
 | 
			
		||||
    [ACT_DEATH_EXIT_LAND] = true,
 | 
			
		||||
    [ACT_SLIDE_KICK] = false,
 | 
			
		||||
    [ACT_SLIDE_KICK_SLIDE] = false,
 | 
			
		||||
    [ACT_GROUND_POUND] = true,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
-- Vertical Offsets
 | 
			
		||||
local function on_object_render(obj)
 | 
			
		||||
    if get_id_from_behavior(obj.behavior) ~= id_bhvMario then
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    for i=0, MAX_PLAYERS-1 do
 | 
			
		||||
        local m = gMarioStates[i]
 | 
			
		||||
        if characterTable[currChar].offset ~= 0 then
 | 
			
		||||
            if altOffsetActs[m.action] ~= false then
 | 
			
		||||
                m.marioObj.header.gfx.pos.y = (altOffsetActs[m.action] and m.pos.y or m.marioObj.header.gfx.pos.y) + characterTable[currChar].offset
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -452,6 +512,7 @@ local sCapBhvs = {
 | 
			
		|||
--- @param o Object
 | 
			
		||||
--- @param model integer
 | 
			
		||||
function set_model(o, model)
 | 
			
		||||
    if optionTable[optionTableRef.localModels].toggle == 0 then return end
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			@ -490,7 +551,7 @@ function set_model(o, model)
 | 
			
		|||
            elseif model == c.capMetalWingModelId then
 | 
			
		||||
                capModel = capModels.metalWing
 | 
			
		||||
            end
 | 
			
		||||
            if capModel ~= E_MODEL_NONE then
 | 
			
		||||
            if capModel ~= E_MODEL_NONE and capModel ~= E_MODEL_ERROR_MODEL and capModel ~= nil then
 | 
			
		||||
                obj_set_model_extended(o, capModel)
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
| 
						 | 
				
			
			@ -499,6 +560,7 @@ end
 | 
			
		|||
 | 
			
		||||
hook_event(HOOK_MARIO_UPDATE, mario_update)
 | 
			
		||||
hook_event(HOOK_OBJECT_SET_MODEL, set_model)
 | 
			
		||||
hook_event(HOOK_ON_OBJECT_RENDER, on_object_render)
 | 
			
		||||
 | 
			
		||||
------------------
 | 
			
		||||
-- Menu Handler --
 | 
			
		||||
| 
						 | 
				
			
			@ -516,19 +578,20 @@ local inputStallTimerDirectional = 0
 | 
			
		|||
local inputStallToDirectional = 12
 | 
			
		||||
local inputStallToButton = 10
 | 
			
		||||
 | 
			
		||||
-- Font Consistency between sm64ex-coop and sm64coopdx
 | 
			
		||||
local FONT_CS_NORMAL = IS_COOPDX and FONT_ALIASED or FONT_NORMAL
 | 
			
		||||
 | 
			
		||||
--Basic Menu Text
 | 
			
		||||
local TEXT_OPTIONS_HEADER = "Menu Options"
 | 
			
		||||
local TEXT_VERSION = "Version: " .. MOD_VERSION .. (IS_COOPDX and " | sm64coopdx" or " | sm64ex-coop")
 | 
			
		||||
local TEXT_OPTIONS_HEADER_API = "API Options"
 | 
			
		||||
local TEXT_VERSION = "Version: " .. MOD_VERSION .. " | sm64coopdx"
 | 
			
		||||
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_PREF_SAVE_AND_PALETTE = "A - Set Preference | Y - Toggle Palette"
 | 
			
		||||
local TEXT_PAUSE_Z_OPEN = "Z Button - Character Select"
 | 
			
		||||
local TEXT_PAUSE_UNAVALIBLE = "Character Select is Unavalible"
 | 
			
		||||
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
 | 
			
		||||
if math_random(100) == 64 then
 | 
			
		||||
    -- Easter Egg if you get lucky loading the mod Referencing the original sm64ex DynOS options by PeachyPeach >v<
 | 
			
		||||
    TEXT_PAUSE_Z_OPEN = "Z - DynOS"
 | 
			
		||||
    TEXT_PAUSE_CURR_CHAR = "Model: "
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -536,8 +599,11 @@ end
 | 
			
		|||
local TEXT_DEBUGGING = "Character Debug"
 | 
			
		||||
local TEXT_DESCRIPTION_SHORT = "Description:"
 | 
			
		||||
local TEXT_LIFE_ICON = "Life Icon:"
 | 
			
		||||
local TEXT_STAR_ICON = "Star Icon:"
 | 
			
		||||
local TEXT_FORCED_CHAR = "Forced: "
 | 
			
		||||
local TEXT_OFFSET = "Offset: "
 | 
			
		||||
local TEXT_TABLE_POS = "Table Position: "
 | 
			
		||||
local TEXT_PALETTE = "Palette: "
 | 
			
		||||
 | 
			
		||||
--Options Text
 | 
			
		||||
local TEXT_OPTIONS_OPEN = "Press START to open Options"
 | 
			
		||||
| 
						 | 
				
			
			@ -546,30 +612,38 @@ 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
 | 
			
		||||
menuColor = characterTable[currChar].color
 | 
			
		||||
 | 
			
		||||
local MATH_DIVIDE_THREE_HUNDRED_TWENTY = 1/320
 | 
			
		||||
local MATH_DIVIDE_THIRTY_TWO = 1/32
 | 
			
		||||
local MATH_DIVIDE_320 = 1/320
 | 
			
		||||
local MATH_DIVIDE_32 = 1/32
 | 
			
		||||
local MATH_DIVIDE_30 = 1/30
 | 
			
		||||
local MATH_DIVIDE_16 = 1/16
 | 
			
		||||
 | 
			
		||||
function update_menu_color()
 | 
			
		||||
    if optionTable[optionTableRef.menuColor].toggle > 1 then
 | 
			
		||||
        menuColor = menuColorTable[optionTable[optionTableRef.menuColor].toggle - 1]
 | 
			
		||||
    elseif optionTable[optionTableRef.menuColor].toggle == 1 then
 | 
			
		||||
        optionTable[optionTableRef.menuColor].toggleNames[2] = string_underscore_to_space(TEXT_PREF_LOAD) .. " (Pref)"
 | 
			
		||||
        menuColor = prefCharColor
 | 
			
		||||
    else
 | 
			
		||||
        menuColor = characterTable[currChar].color
 | 
			
		||||
    end
 | 
			
		||||
    return menuColor
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function on_hud_render()
 | 
			
		||||
    local FONT_USER = djui_menu_get_font()
 | 
			
		||||
    djui_hud_set_resolution(RESOLUTION_N64)
 | 
			
		||||
    djui_hud_set_font(FONT_CS_NORMAL)
 | 
			
		||||
    djui_hud_set_font(FONT_ALIASED)
 | 
			
		||||
 | 
			
		||||
    local width = djui_hud_get_screen_width() + 1.4
 | 
			
		||||
    local height = 240
 | 
			
		||||
    local widthHalf = width * 0.5
 | 
			
		||||
    local heightHalf = height * 0.5
 | 
			
		||||
    local widthScale = maxf(width, 321.4) * MATH_DIVIDE_THREE_HUNDRED_TWENTY
 | 
			
		||||
    local widthScale = maxf(width, 321.4) * MATH_DIVIDE_320
 | 
			
		||||
 | 
			
		||||
    if menuAndTransition then
 | 
			
		||||
        if optionTable[optionTableRef.menuColor].toggle > 1 then
 | 
			
		||||
            menuColor = menuColorTable[optionTable[optionTableRef.menuColor].toggle - 1]
 | 
			
		||||
        elseif optionTable[optionTableRef.menuColor].toggle == 1 then
 | 
			
		||||
            optionTable[optionTableRef.menuColor].toggleNames[2] = string_underscore_to_space(TEXT_PREF_LOAD) .. " (Pref)"
 | 
			
		||||
            menuColor = prefCharColor
 | 
			
		||||
        else
 | 
			
		||||
            menuColor = characterTable[currChar].color
 | 
			
		||||
        end
 | 
			
		||||
        update_menu_color()
 | 
			
		||||
 | 
			
		||||
        if optionTable[optionTableRef.localModels].toggle == 0 then
 | 
			
		||||
            djui_hud_set_color(0, 0, 0, 200)
 | 
			
		||||
| 
						 | 
				
			
			@ -581,18 +655,37 @@ local function on_hud_render()
 | 
			
		|||
 | 
			
		||||
        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)
 | 
			
		||||
        -- Render All Black Squares Behind Below API
 | 
			
		||||
        -- Description
 | 
			
		||||
        djui_hud_set_color(0, 0, 0, 255)
 | 
			
		||||
        djui_hud_render_rect(width - x + 2, 2, x - 4, height - 4)
 | 
			
		||||
        -- Buttons
 | 
			
		||||
        djui_hud_set_color(0, 0, 0, 255)
 | 
			
		||||
        djui_hud_render_rect(2, 2, x - 4, height - 4)
 | 
			
		||||
        -- Header
 | 
			
		||||
        djui_hud_set_color(0, 0, 0, 255)
 | 
			
		||||
        djui_hud_render_rect(2, 2, width - 4, 46)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        -- API Rendering (Below Text)
 | 
			
		||||
        if #renderInMenuTable.back > 0 then
 | 
			
		||||
            for i = 1, #renderInMenuTable.back do
 | 
			
		||||
                renderInMenuTable.back[i]()
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        --Character Description
 | 
			
		||||
        djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
 | 
			
		||||
        djui_hud_set_font(FONT_CS_NORMAL)
 | 
			
		||||
        djui_hud_render_rect(width - x, 50, 2, height - 50)
 | 
			
		||||
        djui_hud_render_rect(width - x, height - 2, x, 2)
 | 
			
		||||
        djui_hud_render_rect(width - 2, 50, 2, height - 50)
 | 
			
		||||
        djui_hud_set_font(FONT_ALIASED)
 | 
			
		||||
        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
 | 
			
		||||
            local TEXT_PRESET = "Preset Character Palette: "..(gPlayerSyncTable[0].presetPalette and "On" or "Off")
 | 
			
		||||
            local TEXT_PREF = "Preferred Character:"
 | 
			
		||||
            local TEXT_PREF_LOAD = string_underscore_to_space(TEXT_PREF_LOAD)
 | 
			
		||||
            if djui_hud_measure_text(TEXT_PREF_LOAD) / widthScale > 110 then
 | 
			
		||||
| 
						 | 
				
			
			@ -606,8 +699,10 @@ local function on_hud_render()
 | 
			
		|||
            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, 74, 0.6)
 | 
			
		||||
            djui_hud_set_font(FONT_CS_NORMAL)
 | 
			
		||||
            local creditScale = 0.6 
 | 
			
		||||
            creditScale = math.min(creditScale, 100/djui_hud_measure_text(TEXT_CREDIT))
 | 
			
		||||
            djui_hud_print_text(TEXT_CREDIT, width - textX - djui_hud_measure_text(TEXT_CREDIT) * creditScale *0.5, 74, creditScale)
 | 
			
		||||
            djui_hud_set_font(FONT_ALIASED)
 | 
			
		||||
            djui_hud_print_text(TEXT_DESCRIPTION, width - textX - djui_hud_measure_text(TEXT_DESCRIPTION) * 0.2, 85, 0.4)
 | 
			
		||||
            if widthScale < 1.65 then
 | 
			
		||||
                for i = 1, #TEXT_DESCRIPTION_TABLE do
 | 
			
		||||
| 
						 | 
				
			
			@ -626,72 +721,117 @@ local function on_hud_render()
 | 
			
		|||
                end
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            local modelId = gPlayerSyncTable[0].modelId and gPlayerSyncTable[0].modelId or defaultModels[gMarioStates[0].character.type]
 | 
			
		||||
            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)
 | 
			
		||||
            if characterColorPresets[modelId] and not stopPalettes then
 | 
			
		||||
                djui_hud_print_text(TEXT_PRESET, width - textX - djui_hud_measure_text(TEXT_PRESET) * 0.15, height - 31, 0.3)
 | 
			
		||||
                djui_hud_set_font(FONT_TINY)
 | 
			
		||||
                djui_hud_print_text(TEXT_PREF_SAVE_AND_PALETTE, width - textX - djui_hud_measure_text(TEXT_PREF_SAVE_AND_PALETTE) * 0.25, height - 13, 0.5)
 | 
			
		||||
            else
 | 
			
		||||
                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)
 | 
			
		||||
            end
 | 
			
		||||
        else -- Debugging Info
 | 
			
		||||
            local TEXT_NAME = "Name: " .. character.name
 | 
			
		||||
            local TEXT_SAVE_NAME = "Save Name: " .. character.saveName
 | 
			
		||||
            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 TEX_LIFE_ICON = character.lifeIcon
 | 
			
		||||
            local TEX_STAR_ICON = character.starIcon
 | 
			
		||||
            local TEXT_ICON_DEFAULT = "?"
 | 
			
		||||
            local TEXT_SCALE = "Camera Scale: " .. character.camScale
 | 
			
		||||
            local TEXT_PRESET = "Preset Palette: "..(gPlayerSyncTable[0].presetPalette and "On" or "Off")
 | 
			
		||||
            local TEXT_PREF = "Preferred: " .. TEXT_PREF_LOAD
 | 
			
		||||
            local TEXT_PREF_COLOR = "Pref Color: R-" .. prefCharColor.r .. ", G-" .. prefCharColor.g .. ", B-" .. prefCharColor.b
 | 
			
		||||
 | 
			
		||||
            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)
 | 
			
		||||
            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)
 | 
			
		||||
            local removeLine = 0
 | 
			
		||||
            for i = 1, #TEXT_DESCRIPTION_TABLE do
 | 
			
		||||
                if TEXT_DESCRIPTION_TABLE[i] ~= "" then
 | 
			
		||||
                    djui_hud_set_font(FONT_CS_NORMAL)
 | 
			
		||||
                    local TEXT_DESCRIPTION_LINE = TEXT_DESCRIPTION_TABLE[i]
 | 
			
		||||
                    if (djui_hud_measure_text(TEXT_DESCRIPTION_TABLE[i]) * 0.3 > 100) then
 | 
			
		||||
                        TEXT_DESCRIPTION_LINE = "(!) " .. TEXT_DESCRIPTION_LINE
 | 
			
		||||
            local y = 72
 | 
			
		||||
            djui_hud_print_text(TEXT_NAME, width - x + 8, y, 0.5)
 | 
			
		||||
            y = y + 7
 | 
			
		||||
            djui_hud_print_text(TEXT_SAVE_NAME, width - x + 8, y, 0.5)
 | 
			
		||||
            y = y + 7
 | 
			
		||||
            djui_hud_print_text(TEXT_CREDIT, width - x + 8, y, 0.5)
 | 
			
		||||
            y = y + 7
 | 
			
		||||
            if TEXT_DESCRIPTION_TABLE[1] ~= "No description has been provided" then
 | 
			
		||||
                djui_hud_print_text(TEXT_DESCRIPTION_SHORT, width - x + 8, y, 0.5)
 | 
			
		||||
                y = y + 2
 | 
			
		||||
                local removeLine = 0
 | 
			
		||||
                for i = 1, #TEXT_DESCRIPTION_TABLE do
 | 
			
		||||
                    if TEXT_DESCRIPTION_TABLE[i] ~= "" then
 | 
			
		||||
                        djui_hud_set_font(FONT_ALIASED)
 | 
			
		||||
                        local TEXT_DESCRIPTION_LINE = TEXT_DESCRIPTION_TABLE[i]
 | 
			
		||||
                        if (djui_hud_measure_text(TEXT_DESCRIPTION_TABLE[i]) * 0.3 > 100) then
 | 
			
		||||
                            TEXT_DESCRIPTION_LINE = "(!) " .. TEXT_DESCRIPTION_LINE
 | 
			
		||||
                        else
 | 
			
		||||
                            TEXT_DESCRIPTION_LINE = "    " .. TEXT_DESCRIPTION_LINE
 | 
			
		||||
                        end
 | 
			
		||||
                        djui_hud_set_font(FONT_TINY)
 | 
			
		||||
                        djui_hud_print_text(TEXT_DESCRIPTION_LINE, width - x + 5, y + (i-removeLine) * 5, 0.4)
 | 
			
		||||
                    else
 | 
			
		||||
                        TEXT_DESCRIPTION_LINE = "    " .. TEXT_DESCRIPTION_LINE
 | 
			
		||||
                        removeLine = removeLine + 1
 | 
			
		||||
                    end
 | 
			
		||||
                    djui_hud_set_font(FONT_TINY)
 | 
			
		||||
                    djui_hud_print_text(TEXT_DESCRIPTION_LINE, width - x + 5, 101 + (i-removeLine) * 7, 0.5)
 | 
			
		||||
                else
 | 
			
		||||
                    removeLine = removeLine + 1
 | 
			
		||||
                end
 | 
			
		||||
                local descriptionOffset = (#TEXT_DESCRIPTION_TABLE - removeLine) * 5
 | 
			
		||||
                y = y + 5 + descriptionOffset
 | 
			
		||||
            end
 | 
			
		||||
            local descriptionOffset = (#TEXT_DESCRIPTION_TABLE - removeLine) * 7
 | 
			
		||||
            djui_hud_print_text(TEXT_COLOR, width - x + 8, 109 + descriptionOffset, 0.6)
 | 
			
		||||
            if TEX_ICON ~= nil then
 | 
			
		||||
                djui_hud_print_text(TEXT_LIFE_ICON .. "    (" .. TEX_ICON.width .. "x" .. TEX_ICON.height .. ")", width - x + 8, 118 + descriptionOffset, 0.6)
 | 
			
		||||
            djui_hud_set_color(character.color.r, character.color.g, character.color.b, 255)
 | 
			
		||||
            djui_hud_print_text(TEXT_COLOR, width - x + 8, y, 0.5)
 | 
			
		||||
            djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
 | 
			
		||||
            y = y + 7
 | 
			
		||||
            if TEX_LIFE_ICON ~= nil then
 | 
			
		||||
                djui_hud_print_text(TEXT_LIFE_ICON .. "    (" .. TEX_LIFE_ICON.width .. "x" .. TEX_LIFE_ICON.height .. ")", width - x + 8, y, 0.5)
 | 
			
		||||
                djui_hud_set_color(255, 255, 255, 255)
 | 
			
		||||
                djui_hud_render_texture(TEX_ICON, width - x + 38, 119 + descriptionOffset, 0.5 / (TEX_ICON.width / 16), 0.5 / (TEX_ICON.height / 16))
 | 
			
		||||
                djui_hud_render_texture(TEX_LIFE_ICON, width - x + 33, y + 1, 0.4 / (TEX_LIFE_ICON.width * MATH_DIVIDE_16), 0.4 / (TEX_LIFE_ICON.height * MATH_DIVIDE_16))
 | 
			
		||||
            else
 | 
			
		||||
                djui_hud_print_text(TEXT_LIFE_ICON .. "    (?x?)", width - x + 8, 118 + descriptionOffset, 0.6)
 | 
			
		||||
                djui_hud_print_text(TEXT_LIFE_ICON .. "    (?x?)", width - x + 8, y, 0.5)
 | 
			
		||||
                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_print_text(TEXT_ICON_DEFAULT, width - x + 33, y + 1, 0.5)
 | 
			
		||||
                djui_hud_set_font(FONT_TINY)
 | 
			
		||||
            end
 | 
			
		||||
            y = y + 7
 | 
			
		||||
            djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
 | 
			
		||||
            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)
 | 
			
		||||
            djui_hud_print_text(TEXT_SCALE, width - x + 8, 145 + descriptionOffset, 0.6)
 | 
			
		||||
            djui_hud_print_text(TEXT_STAR_ICON .. "    (" .. TEX_STAR_ICON.width .. "x" .. TEX_STAR_ICON.height .. ")", width - x + 8, y, 0.5)
 | 
			
		||||
            djui_hud_set_color(255, 255, 255, 255)
 | 
			
		||||
            djui_hud_render_texture(TEX_STAR_ICON, width - x + 35, y + 1, 0.4 / (TEX_STAR_ICON.width * MATH_DIVIDE_16), 0.4 / (TEX_STAR_ICON.height * MATH_DIVIDE_16))
 | 
			
		||||
            y = y + 7
 | 
			
		||||
            djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
 | 
			
		||||
            djui_hud_print_text(TEXT_FORCED_CHAR .. defaultForceChar[character.forceChar], width - x + 8, y, 0.5)
 | 
			
		||||
            y = y + 7
 | 
			
		||||
            djui_hud_print_text(TEXT_OFFSET .. character.offset, width - x + 8, y, 0.5)
 | 
			
		||||
            y = y + 7
 | 
			
		||||
            djui_hud_print_text(TEXT_TABLE_POS .. currChar, width - x + 8, y, 0.5)
 | 
			
		||||
            y = y + 7
 | 
			
		||||
            djui_hud_print_text(TEXT_SCALE, width - x + 8, y, 0.5)
 | 
			
		||||
            local modelId = gPlayerSyncTable[0].modelId and gPlayerSyncTable[0].modelId or defaultModels[gMarioStates[0].character.type]
 | 
			
		||||
            if characterColorPresets[modelId] ~= nil then
 | 
			
		||||
                y = y + 7
 | 
			
		||||
                djui_hud_print_text(TEXT_PALETTE, width - x + 8, y, 0.5)
 | 
			
		||||
                local x = x - djui_hud_measure_text(TEXT_PALETTE)*0.5
 | 
			
		||||
                for i = 0, #characterColorPresets[modelId] do
 | 
			
		||||
                    djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
 | 
			
		||||
                    djui_hud_render_rect(width - x + 6.5 + (6.5 * i), y + 1.5, 6, 6)
 | 
			
		||||
                    djui_hud_set_color(characterColorPresets[modelId][i].r, characterColorPresets[modelId][i].g, characterColorPresets[modelId][i].g, 255)
 | 
			
		||||
                    djui_hud_render_rect(width - x + 7 + (6.5 * i), y + 2, 5, 5)
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            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)
 | 
			
		||||
            djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
 | 
			
		||||
            djui_hud_print_text(TEXT_PRESET, width - x + 8, height - 29, 0.5)
 | 
			
		||||
            djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
 | 
			
		||||
            djui_hud_print_text(TEXT_PREF, width - x + 8, height - 22, 0.5)
 | 
			
		||||
            djui_hud_set_color(prefCharColor.r, prefCharColor.g, prefCharColor.b, 255)
 | 
			
		||||
            djui_hud_print_text(TEXT_PREF_COLOR, width - x + 8, height - 15, 0.5)
 | 
			
		||||
        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)
 | 
			
		||||
        djui_hud_render_rect(0, 50, 2, height - 50)
 | 
			
		||||
        djui_hud_render_rect(x - 2, 50, 2, height - 50)
 | 
			
		||||
        djui_hud_render_rect(0, height - 2, x, 2)
 | 
			
		||||
 | 
			
		||||
        if optionTable[optionTableRef.anims].toggle > 0 then
 | 
			
		||||
            buttonAnimTimer = buttonAnimTimer + 1
 | 
			
		||||
| 
						 | 
				
			
			@ -699,53 +839,59 @@ local function on_hud_render()
 | 
			
		|||
        if optionTable[optionTableRef.anims].toggle == 0 then
 | 
			
		||||
            buttonScroll = 0
 | 
			
		||||
        elseif math_abs(buttonScroll) > 0.1 then
 | 
			
		||||
            buttonScroll = buttonScroll * 0.03 * inputStallToDirectional
 | 
			
		||||
            buttonScroll = buttonScroll * 0.05 * inputStallToDirectional
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        local buttonColor = {}
 | 
			
		||||
        local buttonX = 20 * widthScale
 | 
			
		||||
        local buttonAnimX = buttonX + math_sin(buttonAnimTimer * 0.05) * 2.5 + 5
 | 
			
		||||
        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
 | 
			
		||||
                local x = buttonX
 | 
			
		||||
                if i == 0 then
 | 
			
		||||
                    if optionTable[optionTableRef.anims].toggle > 0 then
 | 
			
		||||
                        buttonX = buttonX + math_sin(buttonAnimTimer * 0.05) * 2.5 + 5
 | 
			
		||||
                        x = buttonAnimX
 | 
			
		||||
                    else
 | 
			
		||||
                        buttonX = buttonX + 10
 | 
			
		||||
                        x = 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_render_rect(x, y, 1, 20)
 | 
			
		||||
                djui_hud_render_rect(x, y, 70, 1)
 | 
			
		||||
                djui_hud_render_rect(x + 69, y, 1, 20)
 | 
			
		||||
                djui_hud_render_rect(x, y + 19, 70, 1)
 | 
			
		||||
                djui_hud_set_color(0, 0, 0, 200)
 | 
			
		||||
                djui_hud_render_rect(x + 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)
 | 
			
		||||
                djui_hud_print_text(characterTable[currChar + i].name, x + 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
 | 
			
		||||
        local MATH_DIVIDE_CHARACTERS = 1/#characterTable
 | 
			
		||||
        local MATH_7_WIDTHSCALE = 7 * widthScale
 | 
			
		||||
        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)
 | 
			
		||||
        djui_hud_render_rect(7 * widthScale + 2, 57 + 166 * ((currChar - 1) / #characterTable) - (buttonScroll * 0.03333333333) * (166 / #characterTable), 3, 166 / #characterTable)
 | 
			
		||||
        djui_hud_render_rect(MATH_7_WIDTHSCALE, 55, 1, 170)
 | 
			
		||||
        djui_hud_render_rect(MATH_7_WIDTHSCALE, 55, 7, 1)
 | 
			
		||||
        djui_hud_render_rect(MATH_7_WIDTHSCALE + 6, 55, 1, 170)
 | 
			
		||||
        djui_hud_render_rect(MATH_7_WIDTHSCALE, 224, 7, 1)
 | 
			
		||||
        djui_hud_render_rect(MATH_7_WIDTHSCALE + 2, 57 + 166 * ((currChar - 1) * MATH_DIVIDE_CHARACTERS) - (buttonScroll * MATH_DIVIDE_30) * (166 * MATH_DIVIDE_CHARACTERS), 3, 166 * MATH_DIVIDE_CHARACTERS)
 | 
			
		||||
        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)
 | 
			
		||||
 | 
			
		||||
        --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_render_rect(0, 0, width, 2)
 | 
			
		||||
        djui_hud_render_rect(0, 0, 2, 50)
 | 
			
		||||
        djui_hud_render_rect(0, 48, width, 2)
 | 
			
		||||
        djui_hud_render_rect(width - 2, 0, 2, 50)
 | 
			
		||||
        djui_hud_set_color(menuColor.r * 0.5 + 127, menuColor.g * 0.5 + 127, menuColor.b * 0.5 + 127, 255)
 | 
			
		||||
        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))
 | 
			
		||||
            djui_hud_render_texture(TEX_OVERRIDE_HEADER, widthHalf - 128, 10, 1 / (TEX_OVERRIDE_HEADER.height*MATH_DIVIDE_32), 1 / (TEX_OVERRIDE_HEADER.height*MATH_DIVIDE_32))
 | 
			
		||||
        else
 | 
			
		||||
            djui_hud_render_texture(TEX_HEADER, widthHalf - 128, 10, 1, 1)
 | 
			
		||||
        end
 | 
			
		||||
| 
						 | 
				
			
			@ -758,14 +904,15 @@ local function on_hud_render()
 | 
			
		|||
            djui_hud_print_text(TEXT_RATIO_UNSUPPORTED, 5, 39, 0.5)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        -- API Rendering
 | 
			
		||||
        if #renderInMenuTable > 0 then
 | 
			
		||||
            for i = 1, #renderInMenuTable do
 | 
			
		||||
                renderInMenuTable[i]()
 | 
			
		||||
        -- API Rendering (Above Text)
 | 
			
		||||
        if #renderInMenuTable.front > 0 then
 | 
			
		||||
            for i = 1, #renderInMenuTable.front do
 | 
			
		||||
                renderInMenuTable.front[i]()
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        --Options display
 | 
			
		||||
        local optionTableCount = #optionTable
 | 
			
		||||
        if options or optionAnimTimer > optionAnimTimerCap then
 | 
			
		||||
            djui_hud_set_color(menuColor.r * 0.25, menuColor.g * 0.25, menuColor.b * 0.25, 205 + maxf(-200, optionAnimTimer))
 | 
			
		||||
            djui_hud_render_rect(0, 0, width, height)
 | 
			
		||||
| 
						 | 
				
			
			@ -773,9 +920,13 @@ local function on_hud_render()
 | 
			
		|||
            djui_hud_render_rect(width * 0.5 - 50 * widthScale, minf(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, minf(55 - optionAnimTimer + 2, height - 25 * widthScale + 2), 100 * widthScale - 4, 196)
 | 
			
		||||
            djui_hud_set_font(FONT_CS_NORMAL)
 | 
			
		||||
            djui_hud_set_font(FONT_ALIASED)
 | 
			
		||||
            djui_hud_set_color(menuColor.r * 0.5 + 127, menuColor.g * 0.5 + 127, menuColor.b * 0.5 + 127, 255)
 | 
			
		||||
            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))
 | 
			
		||||
            local text = TEXT_OPTIONS_HEADER
 | 
			
		||||
            if currOption > defaultOptionCount then
 | 
			
		||||
                text = TEXT_OPTIONS_HEADER_API
 | 
			
		||||
            end
 | 
			
		||||
            djui_hud_print_text(text, widthHalf - djui_hud_measure_text(text) * 0.3 * minf(widthScale, 1.5), 65 + optionAnimTimer * -1, 0.6 * minf(widthScale, 1.5))
 | 
			
		||||
 | 
			
		||||
            local widthScaleLimited = minf(widthScale, 1.5)
 | 
			
		||||
            -- Up Arrow
 | 
			
		||||
| 
						 | 
				
			
			@ -806,11 +957,13 @@ local function on_hud_render()
 | 
			
		|||
                    local scale = 0.5
 | 
			
		||||
                    local yOffset = 100 - optionAnimTimer + (i - currOption + 2) * 9 * widthScaleLimited
 | 
			
		||||
                    if i == currOption then
 | 
			
		||||
                        djui_hud_set_font(FONT_CS_NORMAL)
 | 
			
		||||
                        djui_hud_set_font(FONT_ALIASED)
 | 
			
		||||
                        scale = 0.3
 | 
			
		||||
                        yOffset = yOffset - 1
 | 
			
		||||
                        if optionTable[i].toggleNames[optionTable[i].toggle + 1] ~= "" then
 | 
			
		||||
                            toggleName = toggleName .. " - " .. optionTable[i].toggleNames[optionTable[i].toggle + 1]
 | 
			
		||||
                        local currToggleName = optionTable[i].toggleNames[optionTable[i].toggle + 1]
 | 
			
		||||
                        currToggleName = currToggleName and currToggleName or "???"
 | 
			
		||||
                        if currToggleName ~= "" then
 | 
			
		||||
                            toggleName = toggleName .. " - " .. currToggleName
 | 
			
		||||
                        else
 | 
			
		||||
                            toggleName = toggleName
 | 
			
		||||
                        end
 | 
			
		||||
| 
						 | 
				
			
			@ -828,7 +981,7 @@ local function on_hud_render()
 | 
			
		|||
            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)
 | 
			
		||||
                    djui_hud_set_font(FONT_ALIASED)
 | 
			
		||||
                    local line = optionTable[currOption].description[i]
 | 
			
		||||
                    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)
 | 
			
		||||
                end
 | 
			
		||||
| 
						 | 
				
			
			@ -848,7 +1001,7 @@ local function on_hud_render()
 | 
			
		|||
            djui_hud_render_rect(widthHalf - 50 * widthScale + 2, height - 25 * widthScaleLimited + 2, 100 * widthScale - 4, 22 * widthScaleLimited)
 | 
			
		||||
            djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
 | 
			
		||||
            djui_hud_render_rect(widthHalf - 50 * widthScale, height - 2, 100 * widthScale, 2)
 | 
			
		||||
            djui_hud_set_font(FONT_CS_NORMAL)
 | 
			
		||||
            djui_hud_set_font(FONT_ALIASED)
 | 
			
		||||
            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)
 | 
			
		||||
            djui_hud_set_font(FONT_TINY)
 | 
			
		||||
            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)
 | 
			
		||||
| 
						 | 
				
			
			@ -859,7 +1012,7 @@ local function on_hud_render()
 | 
			
		|||
        if options then
 | 
			
		||||
            if optionTable[optionTableRef.anims].toggle > 0 then
 | 
			
		||||
                if optionAnimTimer < -1 then
 | 
			
		||||
                    optionAnimTimer = optionAnimTimer / 1.1
 | 
			
		||||
                    optionAnimTimer = optionAnimTimer * 0.9
 | 
			
		||||
                end
 | 
			
		||||
            else
 | 
			
		||||
                optionAnimTimer = -1
 | 
			
		||||
| 
						 | 
				
			
			@ -910,16 +1063,13 @@ local function on_hud_render()
 | 
			
		|||
    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)
 | 
			
		||||
        djui_hud_set_font(FONT_NORMAL)
 | 
			
		||||
        if optionTable[optionTableRef.openInputs].toggle == 2 then
 | 
			
		||||
        djui_hud_set_font(FONT_USER)
 | 
			
		||||
        if optionTable[optionTableRef.openInputs].toggle == 1 then
 | 
			
		||||
            currCharY = 27
 | 
			
		||||
            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
 | 
			
		||||
                djui_hud_set_color(0, 0, 0, 255)
 | 
			
		||||
                djui_hud_print_text(TEXT_PAUSE_Z_OPEN, width - 19, 17, 1)
 | 
			
		||||
            end
 | 
			
		||||
            local text = menu_is_allowed() and TEXT_PAUSE_Z_OPEN or TEXT_PAUSE_UNAVALIBLE
 | 
			
		||||
            width = djui_hud_get_screen_width() - djui_hud_measure_text(text)
 | 
			
		||||
            djui_hud_set_color(255, 255, 255, 255)
 | 
			
		||||
            djui_hud_print_text(TEXT_PAUSE_Z_OPEN, width - 20, 16, 1)
 | 
			
		||||
            djui_hud_print_text(text, width - 20, 16, 1)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if optionTable[optionTableRef.localModels].toggle == 1 then
 | 
			
		||||
| 
						 | 
				
			
			@ -927,20 +1077,12 @@ local function on_hud_render()
 | 
			
		|||
            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)
 | 
			
		||||
            local charColor = characterTable[currChar].color
 | 
			
		||||
            if not IS_COOPDX 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
 | 
			
		||||
            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
 | 
			
		||||
            width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF)
 | 
			
		||||
            if not IS_COOPDX then
 | 
			
		||||
                djui_hud_set_color(0, 0, 0, 255)
 | 
			
		||||
                djui_hud_print_text(TEXT_LOCAL_MODEL_OFF, width - 19, 17 + currCharY, 1)
 | 
			
		||||
            end
 | 
			
		||||
            djui_hud_set_color(255, 255, 255, 255)
 | 
			
		||||
            djui_hud_print_text(TEXT_LOCAL_MODEL_OFF, width - 20, 16 + currCharY, 1)
 | 
			
		||||
        end
 | 
			
		||||
| 
						 | 
				
			
			@ -957,18 +1099,19 @@ local function before_mario_update(m)
 | 
			
		|||
    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
 | 
			
		||||
    if is_game_paused() and m.action ~= ACT_EXIT_LAND_SAVE_DIALOG and (m.controller.buttonPressed & Z_TRIG) ~= 0 and optionTable[optionTableRef.openInputs].toggle == 1 then
 | 
			
		||||
        menu = true
 | 
			
		||||
    end
 | 
			
		||||
    if not menu and (m.controller.buttonDown & D_JPAD) ~= 0 and m.action ~= ACT_EXIT_LAND_SAVE_DIALOG and optionTable[optionTableRef.openInputs].toggle == 2 then
 | 
			
		||||
        if (m.controller.buttonDown & R_TRIG) ~= 0 or not ommActive then
 | 
			
		||||
            menu = true
 | 
			
		||||
        end
 | 
			
		||||
        inputStallTimerDirectional = inputStallToDirectional
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
    if not menu_is_allowed() then
 | 
			
		||||
        menu = false
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local cameraToObject = gMarioStates[0].marioObj.header.gfx.cameraToObject
 | 
			
		||||
| 
						 | 
				
			
			@ -985,7 +1128,7 @@ local function before_mario_update(m)
 | 
			
		|||
 | 
			
		||||
    if menuAndTransition and not options then
 | 
			
		||||
        if menu then
 | 
			
		||||
            if inputStallTimerDirectional == 0 then
 | 
			
		||||
            if inputStallTimerDirectional == 0 and optionTable[optionTableRef.localModels].toggle ~= 0 and not charBeingSet 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
 | 
			
		||||
| 
						 | 
				
			
			@ -993,8 +1136,13 @@ local function before_mario_update(m)
 | 
			
		|||
                    else
 | 
			
		||||
                        inputStallTimerDirectional = 3 -- C-Scrolling
 | 
			
		||||
                    end
 | 
			
		||||
                    buttonScroll = buttonScrollCap
 | 
			
		||||
                    if currChar > #characterTable then
 | 
			
		||||
                        buttonScroll = -buttonScrollCap * #characterTable
 | 
			
		||||
                    else
 | 
			
		||||
                        buttonScroll = buttonScrollCap
 | 
			
		||||
                    end
 | 
			
		||||
                    play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
 | 
			
		||||
                    gPlayerSyncTable[0].presetPalette = false
 | 
			
		||||
                end
 | 
			
		||||
                if (m.controller.buttonPressed & U_JPAD) ~= 0 or (m.controller.buttonPressed & U_CBUTTONS) ~= 0 or m.controller.stickY > 60 then
 | 
			
		||||
                    currChar = currChar - 1
 | 
			
		||||
| 
						 | 
				
			
			@ -1003,8 +1151,13 @@ local function before_mario_update(m)
 | 
			
		|||
                    else
 | 
			
		||||
                        inputStallTimerDirectional = 3 -- C-Scrolling
 | 
			
		||||
                    end
 | 
			
		||||
                    buttonScroll = -buttonScrollCap
 | 
			
		||||
                    if currChar < 1 then
 | 
			
		||||
                        buttonScroll = buttonScrollCap * (#characterTable - 1)
 | 
			
		||||
                    else
 | 
			
		||||
                        buttonScroll = -buttonScrollCap
 | 
			
		||||
                    end
 | 
			
		||||
                    play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
 | 
			
		||||
                    gPlayerSyncTable[0].presetPalette = false
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1024,6 +1177,17 @@ local function before_mario_update(m)
 | 
			
		|||
                if (m.controller.buttonPressed & START_BUTTON) ~= 0 then
 | 
			
		||||
                    options = true
 | 
			
		||||
                end
 | 
			
		||||
                local modelId = gPlayerSyncTable[0].modelId and gPlayerSyncTable[0].modelId or defaultModels[m.character.type]
 | 
			
		||||
                if (m.controller.buttonPressed & Y_BUTTON) ~= 0 then
 | 
			
		||||
                    if characterColorPresets[modelId] and optionTable[optionTableRef.localModels].toggle > 0 and not stopPalettes then
 | 
			
		||||
                        play_sound(SOUND_MENU_CLICK_FILE_SELECT, cameraToObject)
 | 
			
		||||
                        gPlayerSyncTable[0].presetPalette = not gPlayerSyncTable[0].presetPalette
 | 
			
		||||
                        inputStallTimerButton = inputStallToButton
 | 
			
		||||
                    else
 | 
			
		||||
                        play_sound(SOUND_MENU_CAMERA_BUZZ, cameraToObject)
 | 
			
		||||
                        inputStallTimerButton = inputStallToButton
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        -- Wraping Menu
 | 
			
		||||
| 
						 | 
				
			
			@ -1066,7 +1230,7 @@ local function before_mario_update(m)
 | 
			
		|||
        end
 | 
			
		||||
 | 
			
		||||
        if inputStallTimerButton == 0 then
 | 
			
		||||
            if (m.controller.buttonPressed & A_BUTTON) ~= 0 then
 | 
			
		||||
            if (m.controller.buttonPressed & A_BUTTON) ~= 0 and not optionTable[currOption].optionBeingSet 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
 | 
			
		||||
| 
						 | 
				
			
			@ -1120,6 +1284,12 @@ local function chat_command(msg)
 | 
			
		|||
        return true
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Stop Character checks if API disallows it 
 | 
			
		||||
    if not menu_is_allowed() or charBeingSet then
 | 
			
		||||
        djui_chat_message_create("Character Cannot be Changed")
 | 
			
		||||
        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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,17 +2,83 @@
 | 
			
		|||
-- Custom HUD Rendering by Agent X and xLuigiGamerx --
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
if incompatibleClient then return 0 end
 | 
			
		||||
 | 
			
		||||
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 MATH_DIVIDE_16 = 1/16
 | 
			
		||||
 | 
			
		||||
-- Localize Functions to improve performence
 | 
			
		||||
local texture_override_set,texture_override_reset,djui_hud_print_text,djui_hud_render_texture,tostring,hud_set_value,hud_get_value,hud_get_flash,djui_hud_get_screen_width,djui_hud_render_rect,math_ceil = texture_override_set,texture_override_reset,djui_hud_print_text,djui_hud_render_texture,tostring,hud_set_value,hud_get_value,hud_get_flash,djui_hud_get_screen_width,djui_hud_render_rect,math.ceil
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--- @param localIndex integer
 | 
			
		||||
--- @return TextureInfo|nil
 | 
			
		||||
--- This assumes multiple characters will not have the same model
 | 
			
		||||
--- This assumes multiple characters will not have the same model,
 | 
			
		||||
--- Icons can only be seen by users who have the character avalible to them.
 | 
			
		||||
--- This function can return nil. if this is the case, render `djui_hud_print_text("?", x, y, 1)`
 | 
			
		||||
function life_icon_from_local_index(localIndex)
 | 
			
		||||
    for i = 1, #characterTable do
 | 
			
		||||
        if i == 1 and characterTable[i].model == gPlayerSyncTable[localIndex].modelId then
 | 
			
		||||
            return defaultIcons[gMarioStates[localIndex].character.type]
 | 
			
		||||
        end
 | 
			
		||||
        if characterTable[i].model == gPlayerSyncTable[localIndex].modelId then
 | 
			
		||||
            return characterTable[i].lifeIcon
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- @param localIndex integer
 | 
			
		||||
--- @return TextureInfo
 | 
			
		||||
--- This assumes multiple characters will not have the same model,
 | 
			
		||||
--- Icons can only be seen by users who have the character avalible to them
 | 
			
		||||
function star_icon_from_local_index(localIndex)
 | 
			
		||||
    for i = 1, #characterTable do
 | 
			
		||||
        if characterTable[i].model == gPlayerSyncTable[localIndex].modelId then
 | 
			
		||||
            return characterTable[i].starIcon
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    return gTextures.star
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local pieTextureNames = {
 | 
			
		||||
    "one_segments",
 | 
			
		||||
    "two_segments",
 | 
			
		||||
    "three_segments",
 | 
			
		||||
    "four_segments",
 | 
			
		||||
    "five_segments",
 | 
			
		||||
    "six_segments",
 | 
			
		||||
    "seven_segments",
 | 
			
		||||
    "full",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local function render_hud_health()
 | 
			
		||||
	local textureTable = characterTable[currChar].healthTexture
 | 
			
		||||
	if textureTable then -- sets health HUD to custom textures
 | 
			
		||||
		if textureTable.label.left and textureTable.label.right then -- if left and right label textures exist. BOTH have to exist to be set!
 | 
			
		||||
			texture_override_set("texture_power_meter_left_side", textureTable.label.left)
 | 
			
		||||
			texture_override_set("texture_power_meter_right_side", textureTable.label.right)
 | 
			
		||||
		end
 | 
			
		||||
		
 | 
			
		||||
		for i = 1, 8 do
 | 
			
		||||
			texture_override_set("texture_power_meter_" .. pieTextureNames[i], textureTable.pie[i])
 | 
			
		||||
		end
 | 
			
		||||
	else -- resets the health HUD
 | 
			
		||||
		texture_override_reset("texture_power_meter_left_side")
 | 
			
		||||
		texture_override_reset("texture_power_meter_right_side")
 | 
			
		||||
		
 | 
			
		||||
		for i = 1, 8 do
 | 
			
		||||
			texture_override_reset("texture_power_meter_" .. pieTextureNames[i])
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function render_hud_mario_lives()
 | 
			
		||||
    hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_LIVES)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +89,7 @@ local function render_hud_mario_lives()
 | 
			
		|||
    if lifeIcon == nil then
 | 
			
		||||
        djui_hud_print_text("?", x, y, 1)
 | 
			
		||||
    else
 | 
			
		||||
        djui_hud_render_texture(lifeIcon, x, y, 1 / (lifeIcon.width * 0.0625), 1 / (lifeIcon.height * 0.0625)) -- 0.0625 is 1/16
 | 
			
		||||
        djui_hud_render_texture(lifeIcon, x, y, 1 / (lifeIcon.width * MATH_DIVIDE_16), 1 / (lifeIcon.height * MATH_DIVIDE_16))
 | 
			
		||||
    end
 | 
			
		||||
    djui_hud_print_text("@", x + 16, y, 1)
 | 
			
		||||
    djui_hud_print_text(tostring(hud_get_value(HUD_DISPLAY_LIVES)):gsub("-", "M"), x + 32, y, 1)
 | 
			
		||||
| 
						 | 
				
			
			@ -32,10 +98,7 @@ end
 | 
			
		|||
local function render_hud_stars()
 | 
			
		||||
    hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_STAR_COUNT)
 | 
			
		||||
 | 
			
		||||
    -- the flashing when you exit a painting, uses sm64coopdx exclusive functionality
 | 
			
		||||
    -- v0.1.5
 | 
			
		||||
    --[[
 | 
			
		||||
    if IS_COOPDX then
 | 
			
		||||
    if IS_COOPDX and hud_get_flash ~= nil then
 | 
			
		||||
        -- prevent star count from flashing outside of castle
 | 
			
		||||
        if gNetworkPlayers[0].currCourseNum ~= COURSE_NONE then hud_set_flash(0) end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -43,17 +106,19 @@ local function render_hud_stars()
 | 
			
		|||
            return
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    ]]
 | 
			
		||||
 | 
			
		||||
    local x = djui_hud_get_screen_width() - 78
 | 
			
		||||
    local y = 15 -- SCREEN_HEIGHT - 209 - 16
 | 
			
		||||
    local x = math_ceil(djui_hud_get_screen_width() - 76)
 | 
			
		||||
    if x % 2 ~= 0 then
 | 
			
		||||
        x = x - 1
 | 
			
		||||
    end
 | 
			
		||||
    local y = math_ceil(240 - 209 - 16)
 | 
			
		||||
    local starIcon = characterTable[currChar].starIcon and characterTable[currChar].starIcon or gTextures.star
 | 
			
		||||
 | 
			
		||||
    local showX = 0
 | 
			
		||||
    local hudDisplayStars = hud_get_value(HUD_DISPLAY_STARS)
 | 
			
		||||
    if hudDisplayStars < 100 then showX = 1 end
 | 
			
		||||
 | 
			
		||||
    djui_hud_render_texture(starIcon, x, y, 1 / (starIcon.width * 0.0625), 1 / (starIcon.height * 0.0625)) -- 0.0625 is 1/16
 | 
			
		||||
    djui_hud_render_texture(starIcon, x, y, 1 / (starIcon.width*MATH_DIVIDE_16), 1 / (starIcon.height*MATH_DIVIDE_16))
 | 
			
		||||
    if showX == 1 then
 | 
			
		||||
        djui_hud_print_text("@", x + 16, y, 1)
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +144,7 @@ local function render_hud_camera_status()
 | 
			
		|||
            if lifeIcon == nil then
 | 
			
		||||
                djui_hud_print_text("?", x + 16, y, 1)
 | 
			
		||||
            else
 | 
			
		||||
                djui_hud_render_texture(lifeIcon, x + 16, y, 1 / (lifeIcon.width * 0.0625), 1 / (lifeIcon.height * 0.0625)) -- 0.0625 is 1/16
 | 
			
		||||
                djui_hud_render_texture(lifeIcon, x + 16, y, 1 / (lifeIcon.width * MATH_DIVIDE_16), 1 / (lifeIcon.height * MATH_DIVIDE_16))
 | 
			
		||||
            end
 | 
			
		||||
        end,
 | 
			
		||||
        [CAM_STATUS_LAKITU] = function()
 | 
			
		||||
| 
						 | 
				
			
			@ -103,20 +168,21 @@ end
 | 
			
		|||
local function render_act_select_hud()
 | 
			
		||||
    local course = gNetworkPlayers[0].currCourseNum
 | 
			
		||||
    if gServerSettings.enablePlayersInLevelDisplay == 0 or course == 0 or obj_get_first_with_behavior_id(id_bhvActSelector) == nil then return end
 | 
			
		||||
 | 
			
		||||
    local stars = save_file_get_star_flags(get_current_save_file_num() - 1, course - 1)
 | 
			
		||||
    local maxStar = 0
 | 
			
		||||
    local wasLastActBeat = true -- True by default to account for 0 stars collected not needing an offset
 | 
			
		||||
 | 
			
		||||
    for i = 5, 0, -1 do
 | 
			
		||||
        if stars & 2 ^ i ~= 0 then
 | 
			
		||||
            maxStar = i
 | 
			
		||||
            wasLastActBeat = stars & 2^(i-1) ~= 0
 | 
			
		||||
            break
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    for a = 1, maxStar + 1 do
 | 
			
		||||
        local x = (38 - maxStar * 17 + a * 34) + djui_hud_get_screen_width() * 0.5 - 75
 | 
			
		||||
        for j = 0, MAX_PLAYERS - 1 do
 | 
			
		||||
        local x = (139 - (maxStar - (wasLastActBeat and 1 or 0) - (maxStar < 5 and 0 or 1) - (maxStar < 1 and 1 or 0)) * 17 + (a - (wasLastActBeat and 1 or 0)) * 34) + (djui_hud_get_screen_width()/2) - 176
 | 
			
		||||
        for j = 1, MAX_PLAYERS - 1 do -- 0 is not needed due to the due to the fact that you are never supposed to see yourself in the act
 | 
			
		||||
            local np = gNetworkPlayers[j]
 | 
			
		||||
            if np and np.connected and np.currCourseNum == course and np.currActNum == a then
 | 
			
		||||
                djui_hud_render_rect(x - 4, 17, 16, 16)
 | 
			
		||||
| 
						 | 
				
			
			@ -124,8 +190,9 @@ local function render_act_select_hud()
 | 
			
		|||
                if displayHead == nil then
 | 
			
		||||
                    djui_hud_print_text("?", x - 4, 17, 1)
 | 
			
		||||
                else
 | 
			
		||||
                    djui_hud_render_texture(displayHead, x - 4, 17, 1 / (displayHead.width * 0.0625), 1 / (displayHead.height * 0.0625)) -- 0.0625 is 1/16
 | 
			
		||||
                    djui_hud_render_texture(displayHead, x - 4, 17, 1 / (displayHead.width/16), 1 / (displayHead.height * MATH_DIVIDE_16))
 | 
			
		||||
                end
 | 
			
		||||
                break
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			@ -136,17 +203,26 @@ local function on_hud_render_behind()
 | 
			
		|||
    djui_hud_set_font(FONT_HUD)
 | 
			
		||||
    djui_hud_set_color(255, 255, 255, 255)
 | 
			
		||||
 | 
			
		||||
    if obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then
 | 
			
		||||
        render_act_select_hud()
 | 
			
		||||
        return
 | 
			
		||||
    elseif gNetworkPlayers[0].currActNum == 99 or gMarioStates[0].action == ACT_INTRO_CUTSCENE or hud_is_hidden() then
 | 
			
		||||
    if gNetworkPlayers[0].currActNum == 99 or gMarioStates[0].action == ACT_INTRO_CUTSCENE or hud_is_hidden() or obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    render_hud_mario_lives()
 | 
			
		||||
    render_hud_stars()
 | 
			
		||||
    render_hud_camera_status()
 | 
			
		||||
    render_hud_health()
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function on_hud_render()
 | 
			
		||||
    djui_hud_set_resolution(RESOLUTION_N64)
 | 
			
		||||
    djui_hud_set_font(FONT_HUD)
 | 
			
		||||
    djui_hud_set_color(255, 255, 255, 255)
 | 
			
		||||
 | 
			
		||||
    if obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then
 | 
			
		||||
        render_act_select_hud()
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
hook_event(HOOK_ON_HUD_RENDER_BEHIND, on_hud_render_behind)
 | 
			
		||||
hook_event(HOOK_ON_HUD_RENDER_BEHIND, on_hud_render_behind)
 | 
			
		||||
hook_event(HOOK_ON_HUD_RENDER, on_hud_render)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,6 @@
 | 
			
		|||
 | 
			
		||||
if incompatibleClient then return 0 end
 | 
			
		||||
 | 
			
		||||
--- @class CharacterTable
 | 
			
		||||
--- @field public name string
 | 
			
		||||
--- @field public saveName string
 | 
			
		||||
| 
						 | 
				
			
			@ -8,15 +11,20 @@
 | 
			
		|||
--- @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,djui_hud_measure_text,type = smlua_model_util_get_id,table.insert,djui_hud_measure_text,type
 | 
			
		||||
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
 | 
			
		||||
| 
						 | 
				
			
			@ -39,33 +47,44 @@ local function split_text_into_lines(text)
 | 
			
		|||
    return lines
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
---------
 | 
			
		||||
-- API --
 | 
			
		||||
---------
 | 
			
		||||
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|nil {r, g, b}
 | 
			
		||||
---@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)
 | 
			
		||||
    if type(description) == "string" then
 | 
			
		||||
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 = name and name or "Untitled",
 | 
			
		||||
        saveName = name and string_space_to_underscore(name) or "Untitled",
 | 
			
		||||
        description = description and description or {"No description has been provided"},
 | 
			
		||||
        credit = credit and credit or "Unknown",
 | 
			
		||||
        color = color and color or {r = 255, g = 255, b = 255},
 | 
			
		||||
        model = modelInfo and modelInfo or E_MODEL_ARMATURE,
 | 
			
		||||
        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,
 | 
			
		||||
        lifeIcon = lifeIcon and lifeIcon or nil,
 | 
			
		||||
        camScale = camScale and camScale or 1
 | 
			
		||||
        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
 | 
			
		||||
| 
						 | 
				
			
			@ -77,36 +96,56 @@ end
 | 
			
		|||
---@param credit string|nil
 | 
			
		||||
---@param color Color|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 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)
 | 
			
		||||
local function character_edit(charNum, name, description, credit, color, modelInfo, forceChar, lifeIcon, camScale)
 | 
			
		||||
    if type(description) == "string" then
 | 
			
		||||
---@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 = name and name or characterTable[charNum].name,
 | 
			
		||||
        name = type(name) == TYPE_STRING and name or tableCache.name,
 | 
			
		||||
        saveName = saveNameTable[charNum],
 | 
			
		||||
        description = description and description or characterTable[charNum].description,
 | 
			
		||||
        credit = credit and credit or characterTable[charNum].credit,
 | 
			
		||||
        color = color and color or characterTable[charNum].color,
 | 
			
		||||
        model = modelInfo and modelInfo or characterTable[charNum].model,
 | 
			
		||||
        forceChar = forceChar and forceChar or characterTable[charNum].forceChar,
 | 
			
		||||
        lifeIcon = lifeIcon and lifeIcon or characterTable[charNum].lifeIcon,
 | 
			
		||||
        camScale = camScale and camScale or 1
 | 
			
		||||
        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] = 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] = 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
 | 
			
		||||
| 
						 | 
				
			
			@ -116,24 +155,56 @@ 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 = starIcon and starIcon or gTextures.star
 | 
			
		||||
            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()
 | 
			
		||||
    return characterTable[currChar]
 | 
			
		||||
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
 | 
			
		||||
| 
						 | 
				
			
			@ -147,26 +218,54 @@ local 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
 | 
			
		||||
 | 
			
		||||
local function hook_render_in_menu(func)
 | 
			
		||||
    table_insert(renderInMenuTable, func)
 | 
			
		||||
---@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,
 | 
			
		||||
| 
						 | 
				
			
			@ -179,31 +278,89 @@ local controller = {
 | 
			
		|||
    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
 | 
			
		||||
local function get_status(tableNum)
 | 
			
		||||
---@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 --[[Depreiciated Function Name, Not recommended for use]] = 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,
 | 
			
		||||
    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_status = get_status,
 | 
			
		||||
    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,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										138
									
								
								mods/character-select-coop/palettes.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								mods/character-select-coop/palettes.lua
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,138 @@
 | 
			
		|||
 | 
			
		||||
if incompatibleClient then return 0 end
 | 
			
		||||
 | 
			
		||||
characterColorPresets = {
 | 
			
		||||
    [E_MODEL_MARIO] = {
 | 
			
		||||
        [PANTS]  = {r = 0x00, g = 0x00, b = 0xff},
 | 
			
		||||
        [SHIRT]  = {r = 0xff, g = 0x00, b = 0x00},
 | 
			
		||||
        [GLOVES] = {r = 0xff, g = 0xff, b = 0xff},
 | 
			
		||||
        [SHOES]  = {r = 0x72, g = 0x1c, b = 0x0e},
 | 
			
		||||
        [HAIR]   = {r = 0x73, g = 0x06, b = 0x00},
 | 
			
		||||
        [SKIN]   = {r = 0xfe, g = 0xc1, b = 0x79},
 | 
			
		||||
        [CAP]    = {r = 0xff, g = 0x00, b = 0x00},
 | 
			
		||||
        [EMBLEM] = {r = 0xff, g = 0x00, b = 0x00},
 | 
			
		||||
    },
 | 
			
		||||
    [E_MODEL_LUIGI] = {
 | 
			
		||||
        [PANTS]  = {r = 0x00, g = 0x00, b = 0xff},
 | 
			
		||||
        [SHIRT]  = {r = 0x00, g = 0xff, b = 0x00},
 | 
			
		||||
        [GLOVES] = {r = 0xff, g = 0xff, b = 0xff},
 | 
			
		||||
        [SHOES]  = {r = 0x72, g = 0x1c, b = 0x0e},
 | 
			
		||||
        [HAIR]   = {r = 0x73, g = 0x06, b = 0x00},
 | 
			
		||||
        [SKIN]   = {r = 0xfe, g = 0xc1, b = 0x79},
 | 
			
		||||
        [CAP]    = {r = 0x00, g = 0xff, b = 0x00},
 | 
			
		||||
        [EMBLEM] = {r = 0x00, g = 0xff, b = 0x00},
 | 
			
		||||
    },
 | 
			
		||||
    [E_MODEL_TOAD_PLAYER] = {
 | 
			
		||||
        [PANTS]  = {r = 0xff, g = 0xff, b = 0xff},
 | 
			
		||||
        [SHIRT]  = {r = 0x4c, g = 0x2c, b = 0xd3},
 | 
			
		||||
        [GLOVES] = {r = 0xff, g = 0xff, b = 0xff},
 | 
			
		||||
        [SHOES]  = {r = 0x68, g = 0x40, b = 0x1b},
 | 
			
		||||
        [HAIR]   = {r = 0x73, g = 0x06, b = 0x00},
 | 
			
		||||
        [SKIN]   = {r = 0xfe, g = 0xd5, b = 0xa1},
 | 
			
		||||
        [CAP]    = {r = 0xff, g = 0x00, b = 0x00},
 | 
			
		||||
        [EMBLEM] = {r = 0xff, g = 0x00, b = 0x00},
 | 
			
		||||
    },
 | 
			
		||||
    [E_MODEL_WALUIGI] = {
 | 
			
		||||
        [PANTS]  = {r = 0x16, g = 0x16, b = 0x27},
 | 
			
		||||
        [SHIRT]  = {r = 0x61, g = 0x26, b = 0xb0},
 | 
			
		||||
        [GLOVES] = {r = 0xff, g = 0xff, b = 0xff},
 | 
			
		||||
        [SHOES]  = {r = 0xfe, g = 0x76, b = 0x00},
 | 
			
		||||
        [HAIR]   = {r = 0x73, g = 0x53, b = 0x00},
 | 
			
		||||
        [SKIN]   = {r = 0xfe, g = 0xc1, b = 0x79},
 | 
			
		||||
        [CAP]    = {r = 0x61, g = 0x26, b = 0xb0},
 | 
			
		||||
        [EMBLEM]  = {r = 0x4c, g = 0x2c, b = 0xd3},
 | 
			
		||||
    },
 | 
			
		||||
    [E_MODEL_WARIO] = {
 | 
			
		||||
        [PANTS]  = {r = 0x7f, g = 0x20, b = 0x7a},
 | 
			
		||||
        [SHIRT]  = {r = 0xe3, g = 0xa9, b = 0x01},
 | 
			
		||||
        [GLOVES] = {r = 0xff, g = 0xff, b = 0xff},
 | 
			
		||||
        [SHOES]  = {r = 0x0e, g = 0x72, b = 0x1c},
 | 
			
		||||
        [HAIR]   = {r = 0x73, g = 0x53, b = 0x00},
 | 
			
		||||
        [SKIN]   = {r = 0xfe, g = 0xc1, b = 0x79},
 | 
			
		||||
        [CAP]    = {r = 0xe3, g = 0xa9, b = 0x01},
 | 
			
		||||
        [EMBLEM]  = {r = 0x61, g = 0x26, b = 0xb0},
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local defaultModels = {
 | 
			
		||||
    [CT_MARIO] = E_MODEL_MARIO,
 | 
			
		||||
    [CT_LUIGI] = E_MODEL_LUIGI,
 | 
			
		||||
    [CT_TOAD] = E_MODEL_TOAD_PLAYER,
 | 
			
		||||
    [CT_WALUIGI] = E_MODEL_WALUIGI,
 | 
			
		||||
    [CT_WARIO] = E_MODEL_WARIO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local paletteLoop = #characterColorPresets[E_MODEL_MARIO]
 | 
			
		||||
 | 
			
		||||
local network_player_set_override_palette_color = network_player_set_override_palette_color
 | 
			
		||||
 | 
			
		||||
local function network_player_set_full_override_palette(networkPlayer, colorTable)
 | 
			
		||||
    for i = 0, paletteLoop do
 | 
			
		||||
        network_player_set_override_palette_color(networkPlayer, i, colorTable[i])
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local prevChar = currChar
 | 
			
		||||
local stallTimer = 5
 | 
			
		||||
 | 
			
		||||
local prevPresetPalette = {}
 | 
			
		||||
local prevModel = {}
 | 
			
		||||
 | 
			
		||||
local function mario_update(m)
 | 
			
		||||
    local np = gNetworkPlayers[m.playerIndex]
 | 
			
		||||
    local p = gPlayerSyncTable[m.playerIndex]
 | 
			
		||||
    
 | 
			
		||||
    if m.playerIndex == 0 and not p.isUpdating then
 | 
			
		||||
        p.isUpdating = true
 | 
			
		||||
        for i = 1, MAX_PLAYERS - 1 do
 | 
			
		||||
            prevPresetPalette[i] = gPlayerSyncTable[i].presetPalette
 | 
			
		||||
            prevModel[i] = gPlayerSyncTable[i].modelId and gPlayerSyncTable[i].modelId or defaultModels[gMarioStates[i].character.type]
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if np.connected then
 | 
			
		||||
        local modelId = p.modelId and p.modelId or defaultModels[m.character.type]
 | 
			
		||||
        if p.presetPalette == nil or characterColorPresets[modelId] == nil then
 | 
			
		||||
            if p.presetPalette == nil then
 | 
			
		||||
                prevPresetPalette[m.playerIndex] = false
 | 
			
		||||
            end
 | 
			
		||||
            p.presetPalette = false
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if (prevPresetPalette[m.playerIndex] ~= p.presetPalette or prevModel[m.playerIndex] ~= modelId) then
 | 
			
		||||
            if not p.presetPalette or not characterColorPresets[modelId] then
 | 
			
		||||
                network_player_reset_override_palette(np)
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        prevPresetPalette[m.playerIndex] = p.presetPalette
 | 
			
		||||
        prevModel[m.playerIndex] = modelId
 | 
			
		||||
 | 
			
		||||
        if p.presetPalette and characterColorPresets[modelId] and not stopPalettes then
 | 
			
		||||
            network_player_set_full_override_palette(np, characterColorPresets[modelId])
 | 
			
		||||
        end
 | 
			
		||||
    else
 | 
			
		||||
        if p.isUpdating then
 | 
			
		||||
            p.isUpdating = false
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    if m.playerIndex == 0 then
 | 
			
		||||
        if (menuAndTransition or prevChar ~= currChar) and stallTimer == 0 then
 | 
			
		||||
            local modelId = p.modelId and p.modelId or defaultModels[m.character.type]
 | 
			
		||||
            if optionTable[optionTableRef.autoPalette].toggle > 0 and optionTable[optionTableRef.localModels].toggle > 0 and (currChar ~= 1 and prevChar ~= currChar and not p.presetPalette) and characterColorPresets[modelId] and not stopPalettes then
 | 
			
		||||
                p.presetPalette = true
 | 
			
		||||
            end
 | 
			
		||||
            if optionTable[optionTableRef.localModels].toggle == 0 then
 | 
			
		||||
                p.presetPalette = false
 | 
			
		||||
            end
 | 
			
		||||
            prevChar = currChar
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if stallTimer > 0 then
 | 
			
		||||
            stallTimer = stallTimer - 1
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
hook_event(HOOK_MARIO_UPDATE, mario_update)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,13 +1,11 @@
 | 
			
		|||
for i = 0, MAX_PLAYERS -1, 1 do
 | 
			
		||||
    gPlayerSyncTable[i].customVoice = 0
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local voicecount = 0
 | 
			
		||||
if incompatibleClient then return 0 end
 | 
			
		||||
 | 
			
		||||
local voiceTimeout = false
 | 
			
		||||
 | 
			
		||||
local SLEEP_TALK_SNORES = 8
 | 
			
		||||
 | 
			
		||||
gCustomVoiceSamples = {}
 | 
			
		||||
gCustomVoiceSamplesBackup = {}
 | 
			
		||||
gCustomVoiceStream = nil
 | 
			
		||||
 | 
			
		||||
-- localize functions to improve performance
 | 
			
		||||
| 
						 | 
				
			
			@ -16,19 +14,8 @@ local audio_sample_stop,audio_sample_destroy,type,math_random,audio_stream_stop,
 | 
			
		|||
--- @param m MarioState
 | 
			
		||||
function stop_custom_character_sound(m, sound)
 | 
			
		||||
    local voice_sample = gCustomVoiceSamples[m.playerIndex]
 | 
			
		||||
    if voice_sample == false and gCustomVoiceSamplesBackup[m.playerIndex].loaded then
 | 
			
		||||
        audio_sample_stop(gCustomVoiceSamplesBackup[m.playerIndex])
 | 
			
		||||
        audio_sample_destroy(gCustomVoiceSamplesBackup[m.playerIndex])
 | 
			
		||||
        voicecount = voicecount - 1
 | 
			
		||||
        gCustomVoiceSamplesBackup[m.playerIndex] = nil
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
    if voice_sample == nil or type(voice_sample) == "boolean" then
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
    if not voice_sample.loaded then
 | 
			
		||||
        gCustomVoiceSamplesBackup[m.playerIndex] = true
 | 
			
		||||
        return
 | 
			
		||||
    if voice_sample == nil or not voice_sample.loaded or voice_sample.isStream then
 | 
			
		||||
        return nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    audio_sample_stop(voice_sample)
 | 
			
		||||
| 
						 | 
				
			
			@ -36,14 +23,17 @@ function stop_custom_character_sound(m, sound)
 | 
			
		|||
        return voice_sample
 | 
			
		||||
    end
 | 
			
		||||
    audio_sample_destroy(voice_sample)
 | 
			
		||||
    voicecount = voicecount - 1
 | 
			
		||||
    gCustomVoiceSamples[m.playerIndex] = nil -- prevent this from pointing to another sample or possibly garbage data
 | 
			
		||||
 | 
			
		||||
    return nil
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- @param m MarioState
 | 
			
		||||
function play_custom_character_sound(m, voice)
 | 
			
		||||
    if voiceTimeout then return 0 end
 | 
			
		||||
    local sound
 | 
			
		||||
    if type(voice) == "table" then
 | 
			
		||||
        sound = voice[math.random(#voice)]
 | 
			
		||||
        sound = voice[math_random(#voice)]
 | 
			
		||||
    else
 | 
			
		||||
        sound = voice
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			@ -66,23 +56,29 @@ function play_custom_character_sound(m, voice)
 | 
			
		|||
    else
 | 
			
		||||
        if voice_sample == nil then
 | 
			
		||||
            voice_sample = audio_sample_load(sound)
 | 
			
		||||
			while not voice_sample.loaded do end
 | 
			
		||||
            voicecount = voicecount + 1
 | 
			
		||||
            local lagTimer = 0
 | 
			
		||||
            repeat
 | 
			
		||||
                lagTimer = lagTimer + 1
 | 
			
		||||
                if lagTimer > 500 then
 | 
			
		||||
                    voiceTimeout = true
 | 
			
		||||
                    if optionTable[optionTableRef.notification].toggle == 1 then
 | 
			
		||||
                        djui_chat_message_create("\\#FFAAAA\\Note: Custom Character Voices are unavalible due to\ninability to load audio, This is most likely because\nyour client does not support custom audio functionality.")
 | 
			
		||||
                    elseif optionTable[optionTableRef.notification].toggle == 2 then
 | 
			
		||||
                        djui_popup_create('Character Select:\nCustom Character Voices\nare unavalible due to\ninability to load audio!', 4)
 | 
			
		||||
                    end
 | 
			
		||||
                    break
 | 
			
		||||
                end
 | 
			
		||||
            until voice_sample.loaded
 | 
			
		||||
        end
 | 
			
		||||
        audio_sample_play(voice_sample, m.pos, 1)
 | 
			
		||||
 | 
			
		||||
        if gCustomVoiceSamplesBackup[m.playerIndex] ~= nil and not(gCustomVoiceSamples[m.playerIndex] == false) then
 | 
			
		||||
            gCustomVoiceSamplesBackup[m.playerIndex] = voice_sample
 | 
			
		||||
        else
 | 
			
		||||
            gCustomVoiceSamples[m.playerIndex] = voice_sample
 | 
			
		||||
        end
 | 
			
		||||
        gCustomVoiceSamples[m.playerIndex] = voice_sample
 | 
			
		||||
    end
 | 
			
		||||
    return 0
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- @param m MarioState
 | 
			
		||||
local function custom_character_sound(m, characterSound)
 | 
			
		||||
    if is_game_paused() or optionTable[optionTableRef.localVoices].toggle == 0 then return end
 | 
			
		||||
    if is_game_paused() or voiceTimeout or optionTable[optionTableRef.localVoices].toggle == 0 then return 0 end
 | 
			
		||||
    if characterSound == CHAR_SOUND_SNORING3 then return 0 end
 | 
			
		||||
    if characterSound == CHAR_SOUND_HAHA and m.hurtCounter > 0 then return 0 end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,16 +95,10 @@ local SLEEP_TALK_END = SLEEP_TALK_START + SLEEP_TALK_SNORES
 | 
			
		|||
 | 
			
		||||
--- @param m MarioState
 | 
			
		||||
local function custom_character_snore(m)
 | 
			
		||||
    if is_game_paused() or optionTable[optionTableRef.localVoices].toggle == 0 then return end
 | 
			
		||||
    if gCustomVoiceSamplesBackup[m.playerIndex] ~= nil and not (gCustomVoiceSamples[m.playerIndex] == false) then
 | 
			
		||||
        if gCustomVoiceSamples[m.playerIndex].loaded then
 | 
			
		||||
            audio_sample_destroy(gCustomVoiceSamples[m.playerIndex])
 | 
			
		||||
            voicecount = voicecount - 1
 | 
			
		||||
            gCustomVoiceSamples[m.playerIndex] = false
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    if is_game_paused() or voiceTimeout or optionTable[optionTableRef.localVoices].toggle == 0 then return end
 | 
			
		||||
 | 
			
		||||
    local SNORE3_TABLE = _G.charSelect.character_get_voice(m)[CHAR_SOUND_SNORING3]
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    if m.action ~= ACT_SLEEPING then
 | 
			
		||||
        if m.isSnoring > 0 then
 | 
			
		||||
            stop_custom_character_sound(m)
 | 
			
		||||
| 
						 | 
				
			
			@ -147,8 +137,24 @@ local function custom_character_snore(m)
 | 
			
		|||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function stop_all_character_sounds()
 | 
			
		||||
    if gCustomVoiceStream then
 | 
			
		||||
        audio_stream_stop(gCustomVoiceStream)
 | 
			
		||||
        audio_stream_destroy(gCustomVoiceStream)
 | 
			
		||||
        gCustomVoiceStream = nil
 | 
			
		||||
    end
 | 
			
		||||
    for i = 0, MAX_PLAYERS-1 do
 | 
			
		||||
        stop_custom_character_sound(gMarioStates[i])
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
hook_event(HOOK_ON_WARP, stop_all_character_sounds)
 | 
			
		||||
hook_event(HOOK_UPDATE, function ()
 | 
			
		||||
    if is_game_paused() then
 | 
			
		||||
        stop_all_character_sounds()
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
_G.charSelect.voice = {
 | 
			
		||||
    sound = custom_character_sound,
 | 
			
		||||
    snore = custom_character_snore,
 | 
			
		||||
}
 | 
			
		||||
gPlayerSyncTable[0].customVoice = true
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue