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