From 68051b907bfaf3043a02364154f0a1ab83669066 Mon Sep 17 00:00:00 2001 From: Agent X <44549182+AgentXLP@users.noreply.github.com> Date: Sat, 17 May 2025 21:25:46 -0400 Subject: [PATCH] update CS [build] --- mods/character-select-coop/a-github.lua | 3 + mods/character-select-coop/a-utils.lua | 146 ++--- mods/character-select-coop/dialog.lua | 6 +- mods/character-select-coop/main.lua | 538 +++++++++++------- mods/character-select-coop/n-hud.lua | 81 ++- mods/character-select-coop/o-api.lua | 491 ++++++++++++---- .../char-select-custom-course-bottom.tex | Bin 4444 -> 4352 bytes .../char-select-custom-course-top.tex | Bin 4749 -> 4521 bytes .../char-select-custom-meter-left.tex | Bin 2031 -> 1952 bytes .../char-select-custom-meter-pie1.tex | Bin 1126 -> 1082 bytes .../char-select-custom-meter-pie2.tex | Bin 1114 -> 1101 bytes .../char-select-custom-meter-pie3.tex | Bin 1239 -> 1229 bytes .../char-select-custom-meter-pie4.tex | Bin 1306 -> 1347 bytes .../char-select-custom-meter-pie5.tex | Bin 1176 -> 1189 bytes .../char-select-custom-meter-pie6.tex | Bin 1167 -> 1152 bytes .../char-select-custom-meter-pie7.tex | Bin 1326 -> 1419 bytes .../char-select-custom-meter-pie8.tex | Bin 1320 -> 1376 bytes .../char-select-custom-meter-right.tex | Bin 2053 -> 1977 bytes .../textures/char-select-luigi-meter-left.tex | Bin 0 -> 2256 bytes .../char-select-luigi-meter-right.tex | Bin 0 -> 2134 bytes .../textures/char-select-toad-meter-left.tex | Bin 0 -> 2098 bytes .../textures/char-select-toad-meter-right.tex | Bin 0 -> 1963 bytes .../char-select-waluigi-meter-left.tex | Bin 0 -> 2432 bytes .../char-select-waluigi-meter-right.tex | Bin 0 -> 2037 bytes .../textures/char-select-wario-meter-left.tex | Bin 0 -> 2488 bytes .../char-select-wario-meter-right.tex | Bin 0 -> 2189 bytes mods/character-select-coop/z-moveset.lua | 11 +- mods/character-select-coop/z-palettes.lua | 8 - mods/character-select-coop/z-voice.lua | 8 +- 29 files changed, 888 insertions(+), 404 deletions(-) create mode 100644 mods/character-select-coop/a-github.lua create mode 100644 mods/character-select-coop/textures/char-select-luigi-meter-left.tex create mode 100644 mods/character-select-coop/textures/char-select-luigi-meter-right.tex create mode 100644 mods/character-select-coop/textures/char-select-toad-meter-left.tex create mode 100644 mods/character-select-coop/textures/char-select-toad-meter-right.tex create mode 100644 mods/character-select-coop/textures/char-select-waluigi-meter-left.tex create mode 100644 mods/character-select-coop/textures/char-select-waluigi-meter-right.tex create mode 100644 mods/character-select-coop/textures/char-select-wario-meter-left.tex create mode 100644 mods/character-select-coop/textures/char-select-wario-meter-right.tex diff --git a/mods/character-select-coop/a-github.lua b/mods/character-select-coop/a-github.lua new file mode 100644 index 000000000..86039f611 --- /dev/null +++ b/mods/character-select-coop/a-github.lua @@ -0,0 +1,3 @@ +GITHUB_COMMIT_TIME = '05/16/2025 07:27:43 PM PST' +GITHUB_COMMIT_ID = '115b65e' +GITHUB_REPO = 'Squishy6094/character-select-coop' diff --git a/mods/character-select-coop/a-utils.lua b/mods/character-select-coop/a-utils.lua index 0daacd32c..a2743c1f7 100644 --- a/mods/character-select-coop/a-utils.lua +++ b/mods/character-select-coop/a-utils.lua @@ -1,6 +1,14 @@ -- localize functions to improve performance - a-utils.lua local string_lower,string_format,table_insert,get_date_and_time = string.lower,string.format,table.insert,get_date_and_time +-- Version Data -- +MOD_VERSION_API = 1 +MOD_VERSION_MAJOR = 14 +MOD_VERSION_MINOR = 1 +MOD_VERSION_INDEV = false +MOD_VERSION_STRING = tostring(MOD_VERSION_API) .. "." .. tostring(MOD_VERSION_MAJOR) .. (MOD_VERSION_MINOR > 0 and ("." .. tostring(MOD_VERSION_MINOR)) or "") .. (MOD_VERSION_INDEV and " (In-Dev)" or "") +MOD_VERSION_DEBUG = tostring(GITHUB_REPO) .. " | " .. tostring(GITHUB_COMMIT_ID) .. " | " .. tostring(GITHUB_COMMIT_TIME) + if VERSION_NUMBER < 38 then djui_popup_create("\n\\#FFAAAA\\Character Select requires\n the latest version of CoopDX to use!\n\nYou can find CoopDX here:\n\\#6666FF\\https://sm64coopdx.com", 5) incompatibleClient = true @@ -9,6 +17,8 @@ end local dependacyFiles = { -- Required Lua File + --"a-github.lua", + "dialog.lua", "main.lua", "n-hud.lua", "o-api.lua", @@ -24,41 +34,42 @@ local legacyFiles = { "z-anims.lua", } +local fileErrorList = {} + -- Check for Missing Files -local missingDependacyFiles = false for i = 1, #dependacyFiles do if not mod_file_exists(dependacyFiles[i]) then - log_to_console("Character Select file missing: '" .. dependacyFiles[i] .. "'", CONSOLE_MESSAGE_ERROR) - missingDependacyFiles = true + log_to_console("Character Select file missing: '" .. dependacyFiles[i] .. "'", CONSOLE_MESSAGE_WARNING) + table_insert(fileErrorList, "Missing File '" .. dependacyFiles[i] .. "'") end end -if missingDependacyFiles then - djui_popup_create("\n\\#FFAAAA\\Character Select is missing\nan important file!\n\nYou can find a list of\nmissing files in the console!", 5) - incompatibleClient = true - return 0 -end - -- Check for Legacy Files -local foundLegacyFiles = false for i = 1, #legacyFiles do if mod_file_exists(legacyFiles[i]) then - log_to_console("Character Select legacy file found: '" .. legacyFiles[i] .. "'", CONSOLE_MESSAGE_ERROR) - foundLegacyFiles = true + log_to_console("Character Select legacy file found: '" .. legacyFiles[i] .. "'", CONSOLE_MESSAGE_WARNING) + table_insert(fileErrorList, "Legacy File '" .. legacyFiles[i] .. "'") end end -if foundLegacyFiles then - djui_popup_create("\n\\#FFAAAA\\Character Select is loading\nan outdated file!\n\nYou can find a list of\nold files in the console!", 5) +if #fileErrorList > 0 then incompatibleClient = true + local frameCount = 0 + hook_event(HOOK_UPDATE, function () + frameCount = frameCount + 1 + if frameCount == 5 then + local errorString = "\\#FFAAAA\\Character Select File Issues:" + djui_popup_create("\\#FFAAAA\\Character Select is having\nfile issues and cannot load!\n\nErrors have been logged in chat!", 4) + for i = 1, #fileErrorList do + errorString = errorString .. "\n" .. fileErrorList[i] + end + errorString = errorString .. "\n\nThe best way to resolve these issues is to delete your current version of Character Select and then install the latest version!" + + log_to_console(errorString) + djui_chat_message_create(errorString) + end + end) return 0 end --- Version Data -- -MOD_VERSION_API = 1 -MOD_VERSION_MAJOR = 13 -MOD_VERSION_MINOR = 1 -MOD_VERSION_INDEV = false -MOD_VERSION_STRING = tostring(MOD_VERSION_API) .. "." .. tostring(MOD_VERSION_MAJOR) .. (MOD_VERSION_MINOR > 0 and ("." .. tostring(MOD_VERSION_MINOR)) or "") .. (MOD_VERSION_INDEV and " (In-Dev)" or "") - ommActive = false for i in pairs(gActiveMods) do if gActiveMods[i].relativePath == "omm-coop" then @@ -67,49 +78,51 @@ for i in pairs(gActiveMods) do end end +E_MODEL_ARMATURE = smlua_model_util_get_id("armature_geo") + local saveableCharacters = { - ["1"] = true, - ["2"] = true, - ["3"] = true, - ["4"] = true, - ["5"] = true, - ["6"] = true, - ["7"] = true, - ["8"] = true, - ["9"] = true, - ["0"] = true, - ["a"] = true, - ["b"] = true, - ["c"] = true, - ["d"] = true, - ["e"] = true, - ["f"] = true, - ["g"] = true, - ["h"] = true, - ["i"] = true, - ["j"] = true, - ["k"] = true, - ["l"] = true, - ["m"] = true, - ["n"] = true, - ["o"] = true, - ["p"] = true, - ["q"] = true, - ["r"] = true, - ["s"] = true, - ["t"] = true, - ["u"] = true, - ["v"] = true, - ["w"] = true, - ["x"] = true, - ["y"] = true, - ["z"] = true, - ["_"] = true, - ["-"] = true, - ["."] = true, + ["1"] = 1, + ["2"] = 1, + ["3"] = 1, + ["4"] = 1, + ["5"] = 1, + ["6"] = 1, + ["7"] = 1, + ["8"] = 1, + ["9"] = 1, + ["0"] = 1, + ["a"] = 1, + ["b"] = 1, + ["c"] = 1, + ["d"] = 1, + ["e"] = 1, + ["f"] = 1, + ["g"] = 1, + ["h"] = 1, + ["i"] = 1, + ["j"] = 1, + ["k"] = 1, + ["l"] = 1, + ["m"] = 1, + ["n"] = 1, + ["o"] = 1, + ["p"] = 1, + ["q"] = 1, + ["r"] = 1, + ["s"] = 1, + ["t"] = 1, + ["u"] = 1, + ["v"] = 1, + ["w"] = 1, + ["x"] = 1, + ["y"] = 1, + ["z"] = 1, + ["_"] = 1, + ["-"] = 1, + ["."] = 1, -- Replace with Underscore - [" "] = false, + [" "] = 0, } --- @param string string @@ -126,9 +139,9 @@ function string_space_to_underscore(string) local s = '' for i = 1, #string do local c = string:sub(i,i) - if saveableCharacters[string_lower(c)] then + if saveableCharacters[string_lower(c)] == 1 then s = s .. c - elseif saveableCharacters[string_lower(c)] ~= nil then + elseif saveableCharacters[string_lower(c)] == 0 then s = s .. "_" end end @@ -137,9 +150,12 @@ end --- @param string string --- Splits a string into a table by spaces -function string_split(string) +function string_split(string, splitAt) + if splitAt == nil then + splitAt = " " + end local result = {} - for match in string:gmatch(string_format("[^%s]+", " ")) do + for match in string:gmatch(string_format("[^%s]+", splitAt)) do table_insert(result, match) end return result diff --git a/mods/character-select-coop/dialog.lua b/mods/character-select-coop/dialog.lua index b67b9e157..25c55666f 100644 --- a/mods/character-select-coop/dialog.lua +++ b/mods/character-select-coop/dialog.lua @@ -1,3 +1,5 @@ +if incompatibleClient then return 0 end + -- Original Made by EliteMasterEric along with CoopDX PR #321 to replace dialog depending on character -- -- https://github.com/coop-deluxe/sm64coopdx/pull/321 -- -- Eric's Original stuffs will be added as soon as there is some way to directly get dialog strings @@ -107,7 +109,7 @@ define_cs_dialog(DIALOG_086, 1, 3, 30, 200, ("Running around in circles\nmakes s define_cs_dialog(DIALOG_087, 1, 4, 30, 200, ("Santa Claus isn't the only\none who can go down a\nchimney! Come on in!\n/--Cabin Proprietor")) define_cs_dialog(DIALOG_088, 1, 5, 30, 200, ("Work Elevator\nFor those who get off\nhere: Grab the pole to the\nleft and slide carefully\ndown.")) define_cs_dialog(DIALOG_089, 1, 5, 95, 200, ("Both ways fraught with\ndanger! Watch your feet!\nThose who can't do the\nLong Jump, tsk, tsk. Make\nyour way to the right.\nRight: Work Elevator\n/// Cloudy Maze\nLeft: Black Hole\n///Underground Lake\n\nRed Circle: Elevator 2\n//// Underground Lake\nArrow: You are here")) -define_cs_dialog(DIALOG_090, 1, 6, 30, 200, ("Bwa ha ha ha!\nYou've stepped right into\nmy trap, just as I knew\nyou would! I warn you,\n『Friend,』 watch your\nstep!")) +define_cs_dialog(DIALOG_090, 1, 6, 30, 200, ("Bwa ha ha ha!\nYou've stepped right into\nmy trap, just as I knew\nyou would! I warn you,\n" .. ' "Friend," ' .. "watch your\nstep!")) define_cs_dialog(DIALOG_091, 2, 2, 30, 200, ("Danger!\nStrong Gusts!\nBut the wind makes a\ncomfy ride.")) define_cs_dialog(DIALOG_092, 1, 5, 30, 200, ("Pestering me again, are\nyou, Mario? Can't you see\nthat I'm having a merry\nlittle time, making\nmischief with my minions?\nNow, return those Stars!\nMy troops in the walls\nneed them! Bwa ha ha!")) define_cs_dialog(DIALOG_093, 1, 5, 30, 200, ("Mario! You again! Well\nthat's just fine--I've\nbeen looking for something\nto fry with my fire\nbreath!\nYour Star Power is\nuseless against me!\nYour friends are all\ntrapped within the\nwalls...\nAnd you'll never see the\nPrincess again!\nBwa ha ha ha!")) @@ -201,7 +203,7 @@ local function dialog_swap(charName) for i = DIALOG_000, #dialogTable do if dialogTable[i] ~= nil then local dialog = dialogTable[i] - charName = charName:gsub('"', "'") + charName = charName:gsub('"', "''") local replaced_dialog = dialog.str:gsub(DIALOG_NAME, charName) real_dialog_replace(i, dialog.unused, dialog.linesPerBox, dialog.leftOffset, dialog.width, replaced_dialog) end diff --git a/mods/character-select-coop/main.lua b/mods/character-select-coop/main.lua index d44c146cb..6cc963dae 100644 --- a/mods/character-select-coop/main.lua +++ b/mods/character-select-coop/main.lua @@ -1,10 +1,27 @@ -- name: Character Select --- description:\\#ffff33\\-- Character Select Coop v1.13.1 --\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\n\\#AAAAFF\\Updates can be found on\nCharacter Select's Github:\n\\#6666FF\\Squishy6094/character-select-coop +-- description:\\#ffff33\\-- Character Select Coop v1.14.1 --\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\n\\#AAAAFF\\Updates can be found on\nCharacter Select's Github:\n\\#6666FF\\Squishy6094/character-select-coop -- pausable: false -- category: cs if incompatibleClient then return 0 end +--- @param hookEventType LuaHookedEventType +local function create_hook_wrapper(hookEventType) + local callbacks = {} + + hook_event(hookEventType, function(...) + for _, func in pairs(callbacks) do + func(...) + end + end) + + return function(func) + table.insert(callbacks, func) + end +end + +cs_hook_mario_update = create_hook_wrapper(HOOK_MARIO_UPDATE) + -- localize functions to improve performance - main.lua local mod_storage_load,tonumber,mod_storage_save,djui_popup_create,tostring,djui_chat_message_create,is_game_paused,obj_get_first_with_behavior_id,djui_hud_is_pause_menu_created,camera_freeze,hud_hide,vec3f_copy,set_mario_action,set_mario_animation,camera_unfreeze,hud_show,type,get_id_from_behavior,obj_has_behavior_id,network_local_index_from_global,obj_has_model_extended,obj_set_model_extended,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,min,math_min,math_ceil,math_abs,math_sin,minf,djui_hud_set_rotation,table_insert,djui_hud_print_text_interpolated,math_max,play_sound,play_character_sound,string_lower = mod_storage_load,tonumber,mod_storage_save,djui_popup_create,tostring,djui_chat_message_create,is_game_paused,obj_get_first_with_behavior_id,djui_hud_is_pause_menu_created,camera_freeze,hud_hide,vec3f_copy,set_mario_action,set_mario_animation,camera_unfreeze,hud_show,type,get_id_from_behavior,obj_has_behavior_id,network_local_index_from_global,obj_has_model_extended,obj_set_model_extended,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,min,math.min,math.ceil,math.abs,math.sin,minf,djui_hud_set_rotation,table.insert,djui_hud_print_text_interpolated,math.max,play_sound,play_character_sound,string.lower @@ -14,6 +31,8 @@ options = false local credits = false local creditsAndTransition = false currChar = 1 +currCharRender = 1 +currCategory = 1 local currOption = 1 local creditScroll = 0 local prevCreditScroll = creditScroll @@ -35,6 +54,8 @@ function header_set_texture(texture) TEX_OVERRIDE_HEADER = texture end +CS_ANIM_MENU = CHAR_ANIM_MAX + 1 + local TEXT_PREF_LOAD_NAME = "Default" local TEXT_PREF_LOAD_ALT = 1 @@ -48,6 +69,8 @@ local TEXT_PREF_LOAD_ALT = 1 characterTable = { [1] = { saveName = "Default", + category = "All_CoopDX", + ogNum = 1, currAlt = 1, hasMoveset = false, locked = false, @@ -85,6 +108,12 @@ characterTable = { lifeIcon = gTextures.luigi_head, starIcon = gTextures.star, camScale = 1.0, + healthTexture = { + label = { + left = get_texture_info("char-select-luigi-meter-left"), + right = get_texture_info("char-select-luigi-meter-right"), + } + } }, [3] = { name = "Toad", @@ -102,6 +131,12 @@ characterTable = { lifeIcon = gTextures.toad_head, starIcon = gTextures.star, camScale = 0.8, + healthTexture = { + label = { + left = get_texture_info("char-select-toad-meter-left"), + right = get_texture_info("char-select-toad-meter-right"), + } + } }, [4] = { name = "Waluigi", @@ -119,6 +154,12 @@ characterTable = { lifeIcon = gTextures.waluigi_head, starIcon = gTextures.star, camScale = 1.1, + healthTexture = { + label = { + left = get_texture_info("char-select-waluigi-meter-left"), + right = get_texture_info("char-select-waluigi-meter-right"), + } + } }, [5] = { name = "Wario", @@ -137,10 +178,52 @@ characterTable = { lifeIcon = gTextures.wario_head, starIcon = gTextures.star, camScale = 1.0, + healthTexture = { + label = { + left = get_texture_info("char-select-wario-meter-left"), + right = get_texture_info("char-select-wario-meter-right"), + } + } }, }, } +characterCategories = { + "All", + "CoopDX", + "Locked", +} + +local characterTableRender = {} + +local function update_character_render_table() + local ogNum = currChar + currChar = 1 + currCharRender = 1 + local category = characterCategories[currCategory] + if category == nil then return false end + characterTableRender = {} + local listCount = 0 + for i = 1, #characterTable do + local charCategories = string_split(characterTable[i].category, "_") + for c = 1, #charCategories do + if category == charCategories[c] and not characterTable[i].locked then + table_insert(characterTableRender, characterTable[i]) + if ogNum == i then + currChar = ogNum + currCharRender = #characterTableRender + end + end + end + end + if #characterTableRender > 0 then + currChar = (characterTableRender[currCharRender] and characterTableRender[currCharRender].ogNum or characterTableRender[1].ogNum) + return true + else + return false + end +end + characterCaps = {} characterCelebrationStar = {} characterColorPresets = {} @@ -148,22 +231,27 @@ characterAnims = {} characterMovesets = {[1] = {}} characterUnlock = {} +tableRefNum = 0 +local function make_table_ref_num() + tableRefNum = tableRefNum + 1 + return tableRefNum +end + optionTableRef = { -- Menu - openInputs = 1, - notification = 2, - menuColor = 3, - anims = 4, - inputLatency = 5, - showLocked = 6, + openInputs = make_table_ref_num(), + notification = make_table_ref_num(), + menuColor = make_table_ref_num(), + anims = make_table_ref_num(), + inputLatency = make_table_ref_num(), -- Characters - localMoveset = 7, - localModels = 8, - localVoices = 9, + localMoveset = make_table_ref_num(), + localModels = make_table_ref_num(), + localVoices = make_table_ref_num(), -- CS - credits = 10, - debugInfo = 11, - resetSaveData = 12, + credits = make_table_ref_num(), + debugInfo = make_table_ref_num(), + resetSaveData = make_table_ref_num(), } optionTable = { @@ -183,7 +271,7 @@ optionTable = { toggleDefault = 1, toggleMax = 2, toggleNames = {"Off", "On", "Pop-ups Only"}, - description = {"Toggles wheather Pop-ups and", "Chat Messages display"} + description = {"Toggles whether Pop-ups and", "Chat Messages display"} }, [optionTableRef.menuColor] = { name = "Menu Color", @@ -212,14 +300,6 @@ optionTable = { toggleNames = {"Slow", "Normal", "Fast"}, description = {"Sets how fast you scroll", "throughout the Menu"} }, - [optionTableRef.showLocked] = { - name = "Show Locked Chars", - toggle = tonumber(mod_storage_load("showLocked")), - toggleSaveName = "showLocked", - toggleDefault = 1, - toggleMax = 1, - description = {"Toggles if Locked Characters", "Display In-Menu"} - }, [optionTableRef.localMoveset] = { name = "Character Moveset", toggle = tonumber(mod_storage_load("localMoveset")), @@ -329,6 +409,7 @@ local prefCharColor = {r = 255, g = 50, b = 50} local function load_preferred_char() local savedChar = mod_storage_load("PrefChar") local savedAlt = tonumber(mod_storage_load("PrefAlt")) + local savedPalette = tonumber(mod_storage_load("PrefPalette")) if savedChar == nil or savedChar == "" then mod_storage_save("PrefChar", "Default") savedChar = "Default" @@ -337,29 +418,38 @@ local function load_preferred_char() mod_storage_save("PrefAlt", "1") savedAlt = 1 end - if savedChar ~= nil and savedChar ~= "Default" then + if savedPalette == nil then + local paletteSave = savedChar ~= "Default" and 1 or 0 + mod_storage_save("PrefAlt", tostring(paletteSave)) + savedPalette = paletteSave + end + if savedChar ~= "Default" and optionTable[optionTableRef.localModels].toggle == 1 then for i = 2, #characterTable do local char = characterTable[i] if char.saveName == savedChar and not char.locked then currChar = i + currCharRender = i if savedAlt > 0 and savedAlt <= #char then char.currAlt = savedAlt end - if optionTable[optionTableRef.localModels].toggle == 1 then - if optionTable[optionTableRef.notification].toggle > 0 then - djui_popup_create('Character Select:\nYour Preferred Character\n"' .. string_underscore_to_space(char[char.currAlt].name) .. '"\nwas applied successfully!', 4) - end + local model = characterTable[currChar][savedAlt].model + if characterColorPresets[model] ~= nil then + gCSPlayers[0].presetPalette = savedPalette + characterColorPresets[model].currPalette = savedPalette + end + if optionTable[optionTableRef.notification].toggle > 0 then + djui_popup_create('Character Select:\nYour Preferred Character\n"' .. string_underscore_to_space(char[char.currAlt].name) .. '"\nwas applied successfully!', 4) end break end end end - + characterTable[1].currAlt = gNetworkPlayers[0].modelIndex + 1 local savedCharColors = mod_storage_load("PrefCharColor") if savedCharColors ~= nil and savedCharColors ~= "" then - local savedCharColorsTable = string_split(string_underscore_to_space(savedCharColors)) + local savedCharColorsTable = string_split(savedCharColors, "_") prefCharColor = { r = tonumber(savedCharColorsTable[1]), g = tonumber(savedCharColorsTable[2]), @@ -376,12 +466,14 @@ local function load_preferred_char() end TEXT_PREF_LOAD_NAME = savedChar TEXT_PREF_LOAD_ALT = savedAlt + update_character_render_table() end local function mod_storage_save_pref_char(charTable) mod_storage_save("PrefChar", charTable.saveName) mod_storage_save("PrefAlt", tostring(charTable.currAlt)) mod_storage_save("PrefCharColor", tostring(charTable[charTable.currAlt].color.r) .. "_" .. tostring(charTable[charTable.currAlt].color.g) .. "_" .. tostring(charTable[charTable.currAlt].color.b)) + mod_storage_save("PrefPalette", tostring(gCSPlayers[0].presetPalette)) TEXT_PREF_LOAD_NAME = charTable.saveName TEXT_PREF_LOAD_ALT = charTable.currAlt prefCharColor = charTable[charTable.currAlt].color @@ -467,6 +559,7 @@ local function menu_is_allowed(m) return true end +--[[ local function get_next_unlocked_char() for i = currChar, #characterTable do if not characterTable[i].locked then @@ -484,6 +577,7 @@ local function get_last_unlocked_char() end return 1 end +]] ------------------- -- Model Handler -- @@ -493,11 +587,6 @@ local stallFrame = 0 CUTSCENE_CS_MENU = 0xFA -local ignoredSurfaces = { - 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 -} - local TYPE_FUNCTION = "function" local TYPE_BOOLEAN = "boolean" local TYPE_STRING = "string" @@ -506,31 +595,6 @@ local TYPE_TABLE = "table" local MATH_PI = math.pi -local menuActBlacklist = { - -- Star Acts - [ACT_FALL_AFTER_STAR_GRAB] = true, - [ACT_STAR_DANCE_EXIT] = true, - [ACT_STAR_DANCE_NO_EXIT] = true, - [ACT_STAR_DANCE_WATER] = true, - -- Key Acts - [ACT_UNLOCKING_KEY_DOOR] = true, - [ACT_UNLOCKING_STAR_DOOR] = true, - -- Cutscene Acts - [ACT_INTRO_CUTSCENE] = true, - [ACT_CREDITS_CUTSCENE] = true, - [ACT_WARP_DOOR_SPAWN] = true, - [ACT_PULLING_DOOR] = true, - [ACT_PUSHING_DOOR] = true, - [ACT_UNLOCKING_KEY_DOOR] = true, - [ACT_UNLOCKING_STAR_DOOR] = true, - [ACT_IN_CANNON] = true, - -- Dialog Acts - [ACT_READING_NPC_DIALOG] = true, - [ACT_WAITING_FOR_DIALOG] = true, - [ACT_EXIT_LAND_SAVE_DIALOG] = true, - [ACT_READING_AUTOMATIC_DIALOG] = true, -} - local prevBaseCharFrame = gNetworkPlayers[0].modelIndex local prevAnim = 0 local animTimer = 0 @@ -565,24 +629,22 @@ local function mario_update(m) end prevBaseCharFrame = np.modelIndex - local defaultTable = characterTable[1] + if optionTable[optionTableRef.localModels].toggle == 0 then + currCategory = 1 + currChar = 1 + currCharRender = 1 + end + local charTable = characterTable[currChar] p.saveName = charTable.saveName p.currAlt = charTable.currAlt - - if optionTable[optionTableRef.localModels].toggle > 0 then - p.modelId = charTable[charTable.currAlt].model - if charTable[charTable.currAlt].forceChar ~= nil then - p.forceChar = charTable[charTable.currAlt].forceChar - end - p.modelEditOffset = charTable[charTable.currAlt].model - charTable[charTable.currAlt].ogModel - m.marioObj.hookRender = 1 - else - p.modelId = nil - p.forceChar = defaultTable.forceChar - p.modelEditOffset = 0 - currChar = 1 + + p.modelId = charTable[charTable.currAlt].model + if charTable[charTable.currAlt].forceChar ~= nil then + p.forceChar = charTable[charTable.currAlt].forceChar end + p.modelEditOffset = charTable[charTable.currAlt].model - charTable[charTable.currAlt].ogModel + m.marioObj.hookRender = 1 if menuAndTransition then --play_secondary_music(0, 0, 0.5, 0) @@ -603,7 +665,7 @@ local function mario_update(m) gLakituState.pos.x = m.pos.x + sins(faceAngle) * 500 * camScale gLakituState.pos.y = m.pos.y + 100 * camScale gLakituState.pos.z = m.pos.z + coss(faceAngle) * 500 * camScale - set_window_title("Character Select v".. MOD_VERSION_STRING .. " - " .. string_underscore_to_space(charTable[charTable.currAlt].name)) + set_window_title("Character Select v".. MOD_VERSION_STRING .. " - " .. string_underscore_to_space(charTable[charTable.currAlt].name) .. " (CoopDX)") p.inMenu = true else if p.inMenu then @@ -632,15 +694,18 @@ local function mario_update(m) if type(unlock) == TYPE_FUNCTION then if unlock() then currChar.locked = false - if stallFrame == 3 and notif then - if optionTable[optionTableRef.notification].toggle > 0 then - djui_popup_create('Character Select:\nUnlocked '..currChar.name..'\nas a Playable Character!', 3) - end - end end elseif type(unlock) == TYPE_BOOLEAN then currChar.locked = not unlock end + if not currChar.locked then -- Character was unlocked + update_character_render_table() + if stallFrame == 3 and notif then + if optionTable[optionTableRef.notification].toggle > 0 then + djui_popup_create('Character Select:\nUnlocked '..tostring(currChar[1].name)..'\nas a Playable Character!', 3) + end + end + end end end @@ -663,8 +728,10 @@ local function mario_update(m) p.movesetToggle = optionTable[optionTableRef.localMoveset].toggle ~= 0 end - if p.inMenu and m.forwardVel == 0 and m.pos.y == m.floorHeight and not ignoredSurfaces[m.floor.type] and m.health > 255 and not menuActBlacklist[m.action] then - set_mario_animation(m, MARIO_ANIM_FIRST_PERSON) + if p.inMenu and m.action & ACT_FLAG_ALLOW_FIRST_PERSON ~= 0 then + set_mario_animation(m, (characterAnims[p.modelId] and characterAnims[p.modelId][CS_ANIM_MENU]) and CS_ANIM_MENU or MARIO_ANIM_IDLE_HEAD_LEFT) + set_anim_to_frame(m, 0) + m.marioObj.header.gfx.angle.y = m.faceAngle.y end local marioGfx = m.marioObj.header.gfx @@ -674,12 +741,7 @@ local function mario_update(m) end animTimer = animTimer + 1 - - if p.forceChar ~= nil then - np.overrideModelIndex = p.forceChar - else - np.overrideModelIndex = CT_MARIO - end + np.overrideModelIndex = p.forceChar ~= nil and p.forceChar or CT_MARIO -- Character Animations if characterAnims[p.modelId] then @@ -709,12 +771,13 @@ local function on_star_or_key_grab(m, o, type) end end -local settingModel function set_model(o, model) - if settingModel then return end if optionTable[optionTableRef.localModels].toggle == 0 then return end + + -- Player Models if obj_has_behavior_id(o, id_bhvMario) ~= 0 then local i = network_local_index_from_global(o.globalPlayerIndex) + local prevModelData = obj_get_model_id_extended(o) local localModelData = nil for c = 1, #characterTable do if gCSPlayers[i].saveName == characterTable[c].saveName then @@ -725,27 +788,23 @@ function set_model(o, model) end if localModelData ~= nil then if obj_has_model_extended(o, localModelData) == 0 then - settingModel = true obj_set_model_extended(o, localModelData) - settingModel = false end else -- Original/Backup if gCSPlayers[i].modelId ~= nil and obj_has_model_extended(o, gCSPlayers[i].modelId) == 0 then - settingModel = true obj_set_model_extended(o, gCSPlayers[i].modelId) - settingModel = false end end return end + + -- Star Models if obj_has_behavior_id(o, id_bhvCelebrationStar) ~= 0 and o.parentObj ~= nil then local i = network_local_index_from_global(o.parentObj.globalPlayerIndex) local starModel = characterCelebrationStar[gCSPlayers[i].modelId] if gCSPlayers[i].modelId ~= nil and starModel ~= nil and obj_has_model_extended(o, starModel) == 0 and not BowserKey then - settingModel = true obj_set_model_extended(o, starModel) - settingModel = false end return end @@ -773,15 +832,14 @@ function set_model(o, model) capModel = capModels.metalWing end if capModel ~= E_MODEL_NONE and capModel ~= E_MODEL_ERROR_MODEL and capModel ~= nil then - settingModel = true obj_set_model_extended(o, capModel) - settingModel = false end end end end -hook_event(HOOK_MARIO_UPDATE, mario_update) +--hook_event(HOOK_MARIO_UPDATE, mario_update) +cs_hook_mario_update(mario_update) hook_event(HOOK_ON_INTERACT, on_star_or_key_grab) hook_event(HOOK_OBJECT_SET_MODEL, set_model) @@ -808,8 +866,9 @@ local yearsOfCS = get_date_and_time().year - 123 -- Zero years as of 2023 local TEXT_VERSION = "Version: " .. MOD_VERSION_STRING .. " | sm64coopdx" .. (seasonalEvent == SEASON_EVENT_BIRTHDAY and (" | " .. tostring(yearsOfCS) .. " year" .. (yearsOfCS > 1 and "s" or "") .. " of Character Select!") or "") 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_PREF_SAVE = "Preferred Char (A)" +local TEXT_PREF_PALETTE = "Toggle Palette (Y)" +local TEXT_MOVESET_INFO = "Moveset Info (Z)" local TEXT_PAUSE_Z_OPEN = "Z Button - Character Select" local TEXT_PAUSE_UNAVAILABLE = "Character Select is Unavailable" local TEXT_PAUSE_CURR_CHAR = "Current Character: " @@ -839,6 +898,8 @@ 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 TEXT_LOCAL_MODEL_ERROR = "Failed to find a Character Model" +local TEXT_LOCAL_MODEL_ERROR_FIX = "Please Verify the Integrity of the Pack!" --Credit Text local TEXT_CREDITS_HEADER = "Credits" @@ -861,22 +922,34 @@ local targetMenuColor = {r = 0 , g = 0, b = 0} menuColor = targetMenuColor local menuColorHalf = menuColor local transSpeed = 0.1 +local prevBindText = "" +local bindText = 1 +local bindTextTimerLoop = 150 +local bindTextTimer = 0 +local bindTextOpacity = -255 function update_menu_color() - if optionTable[optionTableRef.menuColor].toggle > 1 then - targetMenuColor = 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_NAME) .. ((TEXT_PREF_LOAD_ALT ~= 1 and currChar ~= 1) and " ("..TEXT_PREF_LOAD_ALT..")" or "") .. " (Pref)" - targetMenuColor = prefCharColor - elseif characterTable[currChar] ~= nil then - local char = characterTable[currChar] - targetMenuColor = char[char.currAlt].color + if optionTable[optionTableRef.menuColor].toggle == nil then return end + if optionTable[optionTableRef.localModels].toggle == 1 then + if optionTable[optionTableRef.menuColor].toggle > 1 then + targetMenuColor = 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_NAME) .. ((TEXT_PREF_LOAD_ALT ~= 1 and currChar ~= 1) and " ("..TEXT_PREF_LOAD_ALT..")" or "") .. " (Pref)" + targetMenuColor = prefCharColor + elseif characterTable[currChar] ~= nil then + local char = characterTable[currChar] + targetMenuColor = char[char.currAlt].color + end + else + targetMenuColor = menuColorTable[9] end if optionTable[optionTableRef.anims].toggle > 0 then menuColor.r = lerp(menuColor.r, targetMenuColor.r, transSpeed) menuColor.g = lerp(menuColor.g, targetMenuColor.g, transSpeed) menuColor.b = lerp(menuColor.b, targetMenuColor.b, transSpeed) else - menuColor = targetMenuColor + menuColor.r = targetMenuColor.r + menuColor.g = targetMenuColor.g + menuColor.b = targetMenuColor.b end menuColorHalf = { r = menuColor.r * 0.5 + 127, @@ -893,20 +966,24 @@ end local buttonAltAnim = 0 local menuOpacity = 245 +local menuText = {} local function on_hud_render() local FONT_USER = djui_menu_get_font() - djui_hud_set_resolution(RESOLUTION_N64) djui_hud_set_font(FONT_ALIASED) - - local width = djui_hud_get_screen_width() + 1.4 + djui_hud_set_resolution(RESOLUTION_DJUI) + local djuiWidth = djui_hud_get_screen_width() + local djuiHeight = djui_hud_get_screen_height() + djui_hud_set_resolution(RESOLUTION_N64) + local width = djuiWidth * (240/djuiHeight) -- Get accurate, unrounded width local height = 240 local widthHalf = width * 0.5 local heightHalf = height * 0.5 - local widthScale = maxf(width, 321.4) * MATH_DIVIDE_320 + local widthScale = maxf(width, 320) * MATH_DIVIDE_320 update_menu_color() if menuAndTransition then + if optionTable[optionTableRef.localModels].toggle == 0 then djui_hud_set_color(0, 0, 0, 200) djui_hud_render_rect(0, 0, width, height) @@ -915,6 +992,14 @@ local function on_hud_render() 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 + if characterTable[currChar][characterTable[currChar].currAlt].model == E_MODEL_ARMATURE 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_ERROR, widthHalf - djui_hud_measure_text(TEXT_LOCAL_MODEL_ERROR) * 0.15 * widthScale, heightHalf, 0.3 * widthScale) + djui_hud_print_text(TEXT_LOCAL_MODEL_ERROR_FIX, widthHalf - djui_hud_measure_text(TEXT_LOCAL_MODEL_ERROR_FIX) * 0.1 * widthScale, heightHalf + 10 * widthScale, 0.2 * widthScale) + end + local x = 135 * widthScale * 0.8 -- Render All Black Squares Behind Below API @@ -926,7 +1011,6 @@ local function on_hud_render() -- Header djui_hud_render_rect(2, 2, width - 4, 46) - -- API Rendering (Below Text) if #renderInMenuTable.back > 0 then for i = 1, #renderInMenuTable.back do @@ -953,16 +1037,7 @@ local function on_hud_render() 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: "..((paletteCount > 1 and "("..currPaletteTable.currPalette.."/"..paletteCount..")" or (currPaletteTable.currPalette > 0 and "On" or "Off")) or "Off") - local TEXT_PREF = "Preferred Character:" - local TEXT_PREF_LOAD_NAME = ' "' .. string_underscore_to_space(TEXT_PREF_LOAD_NAME) .. '"' .. ((TEXT_PREF_LOAD_ALT ~= 1 and TEXT_PREF_LOAD_NAME ~= "Default" and currChar ~= 1) and " ("..TEXT_PREF_LOAD_ALT..")" or "") - if djui_hud_measure_text(TEXT_PREF_LOAD_NAME) / widthScale > 110 then - TEXT_PREF = "Preferred Char:" - end - if djui_hud_measure_text(TEXT_PREF_LOAD_NAME) / widthScale > 164 then - TEXT_PREF = "Pref Char:" - end - TEXT_PREF = TEXT_PREF .. TEXT_PREF_LOAD_NAME + local TEXT_PREF_LOAD_NAME = string_underscore_to_space(TEXT_PREF_LOAD_NAME) .. ((TEXT_PREF_LOAD_ALT ~= 1 and TEXT_PREF_LOAD_NAME ~= "Default" and currChar ~= 1) and " ("..TEXT_PREF_LOAD_ALT..")" or "") local textX = x * 0.5 djui_hud_print_text(TEXT_NAME, width - textX - djui_hud_measure_text(TEXT_NAME) * 0.3, 55, 0.6) @@ -989,17 +1064,46 @@ local function on_hud_render() end end + menuText = { + TEXT_PREF_SAVE .. " - " .. TEXT_PREF_LOAD_NAME + } local modelId = gCSPlayers[0].modelId - djui_hud_print_text(TEXT_PREF, width - textX - djui_hud_measure_text(TEXT_PREF) * 0.15, height - 22, 0.3) - local text = TEXT_PREF_SAVE + local TEXT_PRESET_TOGGLE = ((currPaletteTable[currPaletteTable.currPalette] ~= nil and currPaletteTable[currPaletteTable.currPalette].name ~= nil) and (currPaletteTable[currPaletteTable.currPalette].name .. " - ") or "") .. ((paletteCount > 1 and "("..currPaletteTable.currPalette.."/"..paletteCount..")" or (currPaletteTable.currPalette > 0 and "On" or "Off")) or "Off") 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) - text = TEXT_PREF_SAVE_AND_PALETTE + table_insert(menuText, TEXT_PREF_PALETTE .. " - " .. TEXT_PRESET_TOGGLE) elseif stopPalettes then - djui_hud_print_text(TEXT_PALETTE_RESTRICTED, width - textX - djui_hud_measure_text(TEXT_PALETTE_RESTRICTED) * 0.15, height - 31, 0.3) + table_insert(menuText, TEXT_PALETTE_RESTRICTED) end - djui_hud_set_font(FONT_TINY) - djui_hud_print_text(text, width - textX - djui_hud_measure_text(TEXT_PREF_SAVE) * 0.25, height - 13, 0.5) + if #menuText > 1 then + bindTextTimer = (bindTextTimer + 1)%(bindTextTimerLoop) + end + if bindTextTimer == 0 then + bindText = bindText + 1 + bindTextOpacity = -254 + end + if bindText > #menuText or not menuText[bindText] then + bindText = 1 + end + if menuText[bindText] ~= prevBindText and bindTextOpacity == -255 then + bindTextOpacity = -254 + end + if bindTextOpacity > -255 and bindTextOpacity < 255 then + bindTextOpacity = math.min(bindTextOpacity + 25, 255) + if bindTextOpacity == 255 then + bindTextOpacity = -255 + prevBindText = menuText[bindText] + end + end + --local bindTextOpacity = clamp(math.abs(math.sin(bindTextTimer*MATH_PI/bindTextTimerLoop)), 0, 0.2) * 5 * 255 + local fadeOut = math_abs(clamp(bindTextOpacity, -255, 0)) + local fadeIn = math_abs(clamp(bindTextOpacity, 0, 255)) + local bindTextScale = math.min((x - 10)/(djui_hud_measure_text(menuText[bindText]) * 0.3), 1)*0.3 + local prevBindTextScale = math.min((x - 10)/(djui_hud_measure_text(prevBindText) * 0.3), 1)*0.3 + djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, fadeOut) + djui_hud_print_text(prevBindText, width - textX - djui_hud_measure_text(prevBindText) * prevBindTextScale*0.5, height - 15, prevBindTextScale) + djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, fadeIn) + djui_hud_print_text(menuText[bindText], width - textX - djui_hud_measure_text(menuText[bindText]) * bindTextScale*0.5, height - 15, bindTextScale) + djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) else -- Debugging Info -- local TEXT_NAME = "Name: " .. character.name @@ -1129,24 +1233,8 @@ local function on_hud_render() local charNum = -1 for i = -1, 4 do -- Hide Locked Characters based on Toggle - charNum = currChar + i - local char = characterTable[charNum] - if optionTable[optionTableRef.showLocked].toggle == 0 and char ~= nil and char.locked then - if i < 0 then - repeat - charNum = charNum - 1 - until characterTable[charNum] == nil or (not characterTable[charNum].locked) - charNum = charNum + 1 - else - repeat - charNum = charNum + 1 - until characterTable[charNum] == nil or (not characterTable[charNum].locked) - charNum = charNum - 1 - end - charNum = charNum + i - end - - local char = characterTable[charNum] + charNum = currCharRender + i + local char = characterTableRender[charNum] if char ~= nil then if not char.locked then buttonColor = char[char.currAlt].color @@ -1189,7 +1277,7 @@ local function on_hud_render() end -- Scroll Bar - local MATH_DIVIDE_CHARACTERS = 1/#characterTable + local MATH_DIVIDE_CHARACTERS = 1/#characterTableRender local MATH_7_WIDTHSCALE = 7 * widthScale djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) djui_hud_render_rect(MATH_7_WIDTHSCALE, 55, 1, 170) @@ -1197,10 +1285,11 @@ local function on_hud_render() djui_hud_render_rect(MATH_7_WIDTHSCALE + 6, 55, 1, 170) djui_hud_render_rect(MATH_7_WIDTHSCALE, 224, 7, 1) djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - 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_render_rect(MATH_7_WIDTHSCALE + 2, 57 + 166 * ((currCharRender - 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 + local TEXT_CHAR_COUNT = currCharRender .. "/" .. #characterTableRender djui_hud_print_text(TEXT_CHAR_COUNT, (11 - djui_hud_measure_text(TEXT_CHAR_COUNT) * 0.2) * widthScale, height - 12, 0.4) + djui_hud_print_text("- "..characterCategories[currCategory] .. " (L/R)", (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) @@ -1216,10 +1305,10 @@ local function on_hud_render() end djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) djui_hud_set_font(FONT_TINY) - djui_hud_print_text(TEXT_VERSION, 5, 3, 0.5) + djui_hud_print_text(optionTable[optionTableRef.debugInfo].toggle == 0 and TEXT_VERSION or MOD_VERSION_DEBUG, 5, 3, 0.5) --Unsupported Res Warning - if width < 321.2 or width > 575 then + if width < 319 or width > 575 then djui_hud_print_text(TEXT_RATIO_UNSUPPORTED, 5, 39, 0.5) end @@ -1393,7 +1482,7 @@ local function on_hud_render() local widthScaleLimited = minf(widthScale, 1.42) djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) djui_hud_render_rect(widthHalf - 50 * widthScale, height - 25 * widthScaleLimited, 100 * widthScale, 26 * widthScaleLimited) - djui_hud_set_color(0, 0, 0, menuOpacity) + djui_hud_set_color(menuColorHalf.r * 0.1, menuColorHalf.g * 0.1, menuColorHalf.b * 0.1, menuOpacity) djui_hud_render_rect(widthHalf - 50 * widthScale + 2, height - 25 * widthScaleLimited + 2, 100 * widthScale - 4, 22 * widthScaleLimited) djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) djui_hud_render_rect(widthHalf - 50 * widthScale, height - 2, 100 * widthScale, 2) @@ -1430,6 +1519,7 @@ local function on_hud_render() optionAnimTimer = optionAnimTimerCap credits = false creditsCrossFade = 0 + bindTextTimer = 0 end -- Fade in/out of menu @@ -1507,6 +1597,8 @@ local function on_hud_render() djui_hud_render_rect(0, 0, width, height) end +local prevMouseScroll = 0 +local mouseScroll = 0 local function before_mario_update(m) if m.playerIndex ~= 0 then return end local controller = m.controller @@ -1533,55 +1625,12 @@ local function before_mario_update(m) return end + mouseScroll = mouseScroll + djui_hud_get_mouse_scroll_y() + local cameraToObject = m.marioObj.header.gfx.cameraToObject if menuAndTransition and not options then if menu then - if inputStallTimerDirectional == 0 and optionTable[optionTableRef.localModels].toggle ~= 0 and not charBeingSet then - if (controller.buttonPressed & D_JPAD) ~= 0 or (controller.buttonPressed & D_CBUTTONS) ~= 0 or controller.stickY < -60 then - currChar = currChar + 1 - local character = characterTable[currChar] - if character ~= nil and character.locked then - currChar = get_next_unlocked_char() - end - if (controller.buttonPressed & D_CBUTTONS) == 0 then - inputStallTimerDirectional = inputStallToDirectional - else - inputStallTimerDirectional = 3 -- C-Scrolling - end - if currChar > #characterTable then - buttonScroll = -buttonScrollCap * #characterTable - else - buttonScroll = buttonScrollCap - end - play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) - if currChar > #characterTable then currChar = 1 end - if characterColorPresets[characterTable[currChar]] ~= nil then - characterColorPresets[characterTable[currChar]].currPalette = 0 - end - end - if (controller.buttonPressed & U_JPAD) ~= 0 or (controller.buttonPressed & U_CBUTTONS) ~= 0 or controller.stickY > 60 then - currChar = currChar - 1 - local character = characterTable[currChar] - if character ~= nil and character.locked then - currChar = get_last_unlocked_char() - end - if (controller.buttonPressed & U_CBUTTONS) == 0 then - inputStallTimerDirectional = inputStallToDirectional - else - inputStallTimerDirectional = 3 -- C-Scrolling - end - if currChar < 1 then - buttonScroll = buttonScrollCap * (#characterTable - 1) - else - buttonScroll = -buttonScrollCap - end - play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) - if currChar < 1 then currChar = #characterTable end - if characterColorPresets[characterTable[currChar]] ~= nil then - characterColorPresets[characterTable[currChar]].currPalette = 0 - end - end - + if inputStallTimerDirectional == 0 and not charBeingSet then -- Alt switcher if #characterTable[currChar] > 1 then local character = characterTable[currChar] @@ -1600,6 +1649,83 @@ local function before_mario_update(m) if character.currAlt > #character then character.currAlt = 1 end if character.currAlt < 1 then character.currAlt = #character end end + + if optionTable[optionTableRef.localModels].toggle ~= 0 then + if (controller.buttonPressed & D_JPAD) ~= 0 or (controller.buttonPressed & D_CBUTTONS) ~= 0 or controller.stickY < -60 or prevMouseScroll < mouseScroll then + currCharRender = currCharRender + 1 + --[[ + local character = characterTableRender[currCharRender] + if character ~= nil and character.locked then + currCharRender = get_next_unlocked_char() + end + ]] + if (controller.buttonPressed & D_CBUTTONS) == 0 then + inputStallTimerDirectional = inputStallToDirectional + else + inputStallTimerDirectional = 3 -- C-Scrolling + end + if currCharRender > #characterTableRender then + buttonScroll = -buttonScrollCap * #characterTableRender + else + buttonScroll = buttonScrollCap + end + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) + if currCharRender > #characterTableRender then currCharRender = 1 end + currChar = characterTableRender[currCharRender].ogNum + if characterColorPresets[characterTable[currChar]] ~= nil then + characterColorPresets[characterTable[currChar]].currPalette = 0 + end + prevMouseScroll = mouseScroll + end + if (controller.buttonPressed & U_JPAD) ~= 0 or (controller.buttonPressed & U_CBUTTONS) ~= 0 or controller.stickY > 60 or prevMouseScroll > mouseScroll then + currCharRender = currCharRender - 1 + --[[ + local character = characterTableRender[currCharRender] + if character ~= nil and character.locked then + currCharRender = get_last_unlocked_char() + end + ]] + if (controller.buttonPressed & U_CBUTTONS) == 0 then + inputStallTimerDirectional = inputStallToDirectional + else + inputStallTimerDirectional = 3 -- C-Scrolling + end + if currCharRender < 1 then + buttonScroll = buttonScrollCap * (#characterTableRender - 1) + else + buttonScroll = -buttonScrollCap + end + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) + if currCharRender < 1 then currCharRender = #characterTableRender end + currChar = characterTableRender[currCharRender].ogNum + if characterColorPresets[characterTable[currChar]] ~= nil then + characterColorPresets[characterTable[currChar]].currPalette = 0 + end + prevMouseScroll = mouseScroll + end + + -- Tab Switcher + if (controller.buttonPressed & L_TRIG) ~= 0 then + local renderEmpty = true + while renderEmpty do + currCategory = currCategory - 1 + if currCategory < 1 then currCategory = #characterCategories end + renderEmpty = not update_character_render_table() + end + inputStallTimerDirectional = inputStallToDirectional + play_sound(SOUND_MENU_CAMERA_TURN, cameraToObject) + end + if (controller.buttonPressed & R_TRIG) ~= 0 then + local renderEmpty = true + while renderEmpty do + currCategory = currCategory + 1 + if currCategory > #characterCategories then currCategory = 1 end + renderEmpty = not update_character_render_table() + end + inputStallTimerDirectional = inputStallToDirectional + play_sound(SOUND_MENU_CAMERA_TURN, cameraToObject) + end + end end if inputStallTimerButton == 0 then @@ -1611,6 +1737,10 @@ local function before_mario_update(m) else play_sound(SOUND_MENU_CAMERA_BUZZ, cameraToObject) end + + -- Set bottom right text + bindText = 1 + bindTextTimer = 1 end if (controller.buttonPressed & B_BUTTON) ~= 0 then menu = false @@ -1631,6 +1761,10 @@ local function before_mario_update(m) play_sound(SOUND_MENU_CAMERA_BUZZ, cameraToObject) inputStallTimerButton = inputStallToButton end + + -- Set bottom right text + bindText = 2 + bindTextTimer = 1 end if characterColorPresets[gCSPlayers[0].modelId] ~= nil then if paletteCount < currPaletteTable.currPalette then currPaletteTable.currPalette = 0 end @@ -1764,7 +1898,9 @@ local function chat_command(msg) local saveName = string_underscore_to_space(string_lower(characterTable[i].saveName)) for a = 1, #characterTable[i] do if msg == string_lower(characterTable[i][a].name) or msg == saveName then + currCategory = 1 currChar = i + update_character_render_table() if msg ~= saveName then characterTable[i].currAlt = a end diff --git a/mods/character-select-coop/n-hud.lua b/mods/character-select-coop/n-hud.lua index e810ebdb7..96f5dc8d2 100644 --- a/mods/character-select-coop/n-hud.lua +++ b/mods/character-select-coop/n-hud.lua @@ -5,7 +5,7 @@ if incompatibleClient then return 0 end -- localize functions to improve performance - n-hud.lua -local hud_get_value,hud_set_value,djui_hud_print_text,tostring,hud_set_flash,get_global_timer,hud_get_flash,djui_hud_get_screen_width,math_ceil,obj_get_first_with_behavior_id,get_behavior_from_id,count_objects_with_behavior,djui_hud_render_rect,djui_hud_set_resolution,djui_hud_get_screen_height,djui_hud_set_color,djui_hud_set_font,djui_hud_measure_text,djui_chat_message_create,hud_is_hidden,djui_is_playerlist_open = hud_get_value,hud_set_value,djui_hud_print_text,tostring,hud_set_flash,get_global_timer,hud_get_flash,djui_hud_get_screen_width,math.ceil,obj_get_first_with_behavior_id,get_behavior_from_id,count_objects_with_behavior,djui_hud_render_rect,djui_hud_set_resolution,djui_hud_get_screen_height,djui_hud_set_color,djui_hud_set_font,djui_hud_measure_text,djui_chat_message_create,hud_is_hidden,djui_is_playerlist_open +local og_hud_get_value,og_hud_set_value,djui_hud_print_text,tostring,hud_set_flash,get_global_timer,hud_get_flash,djui_hud_get_screen_width,math_ceil,obj_get_first_with_behavior_id,get_behavior_from_id,count_objects_with_behavior,djui_hud_render_rect,djui_hud_set_resolution,djui_hud_get_screen_height,djui_hud_set_color,djui_hud_set_font,djui_hud_measure_text,djui_chat_message_create,hud_is_hidden,djui_is_playerlist_open = hud_get_value,hud_set_value,djui_hud_print_text,tostring,hud_set_flash,get_global_timer,hud_get_flash,djui_hud_get_screen_width,math.ceil,obj_get_first_with_behavior_id,get_behavior_from_id,count_objects_with_behavior,djui_hud_render_rect,djui_hud_set_resolution,djui_hud_get_screen_height,djui_hud_set_color,djui_hud_set_font,djui_hud_measure_text,djui_chat_message_create,hud_is_hidden,djui_is_playerlist_open --[[ Some functions we need for the hud @@ -175,33 +175,66 @@ end -- Real HUD Stuffs -- --------------------- -local sHudElements = { - [HUD_DISPLAY_FLAG_LIVES] = true, - [HUD_DISPLAY_FLAG_STAR_COUNT] = true, - [HUD_DISPLAY_FLAG_CAMERA] = true -} +-- Modified Vanilla Functions -- +--[[ + These are `_G` on their own to replace vanilla functions +]] + +local sCharSelectHudDisplayFlags -- `local` because we aren't exposing this + +-- Here to make sure the flags are at the default state +hook_event(HOOK_UPDATE, function () + if not sCharSelectHudDisplayFlags or sCharSelectHudDisplayFlags == 0 then + sCharSelectHudDisplayFlags = og_hud_get_value(HUD_DISPLAY_FLAGS) | HUD_DISPLAY_DEFAULT + end +end) + +--- @param type HudDisplayValue +--- @return integer +function _G.hud_get_value(type) + if type == HUD_DISPLAY_FLAGS then + return sCharSelectHudDisplayFlags + else + return og_hud_get_value(type) + end +end + +--- @param type HudDisplayValue +--- @param value integer +--- Sets a HUD display value +function _G.hud_set_value(type, value) + if type == HUD_DISPLAY_FLAGS then + sCharSelectHudDisplayFlags = value + else + og_hud_set_value(type, value) + end +end + +-- Old CS Hud Functions -- ---Hides the specified custom hud element ---@param hudElement HUDDisplayFlag function hud_hide_element(hudElement) - if sHudElements[hudElement] == nil then return false end - sHudElements[hudElement] = false + --log_to_console("The `charSelect.hud_hide_element()` function is deprecated, please use normal vanilla functions as they have been modified to work with Character Select.", CONSOLE_MESSAGE_WARNING) + hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) & ~hudElement) return true end ---Shows the specified custom hud element ---@param hudElement HUDDisplayFlag function hud_show_element(hudElement) - if sHudElements[hudElement] == nil then return false end - sHudElements[hudElement] = true + --log_to_console("The `charSelect.hud_show_element()` function is deprecated, please use normal vanilla functions as they have been modified to work with Character Select.", CONSOLE_MESSAGE_WARNING) + hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) | hudElement) return true end ---Gets the specified custom hud element's state ---@param hudElement HUDDisplayFlag +---@return boolean function hud_get_element(hudElement) - if sHudElements[hudElement] == nil then return false end - return sHudElements[hudElement] + --log_to_console("The `charSelect.hud_get_element()` function is deprecated, please use normal vanilla functions as they have been modified to work with Character Select.", CONSOLE_MESSAGE_WARNING) + djui_chat_message_create(tostring(sCharSelectHudDisplayFlags)) + return (hud_get_value(HUD_DISPLAY_FLAGS) & hudElement) ~= 0 end local MATH_DIVIDE_16 = 1/16 @@ -299,6 +332,9 @@ function render_life_icon_from_local_index(localIndex, x, y, scale) end --- @param localIndex integer +--- @param prevX integer +--- @param prevY integer +--- @param prevScale integer --- @param x integer --- @param y integer --- @param scale integer @@ -341,6 +377,7 @@ function render_star_icon_from_local_index_interpolated(localIndex, prevX, prevY djui_hud_render_texture_interpolated(starIcon, prevX, prevY, prevScale / (starIcon.width * MATH_DIVIDE_16), prevScale / (starIcon.height * MATH_DIVIDE_16), x, y, scale / (starIcon.width * MATH_DIVIDE_16), scale / (starIcon.height * MATH_DIVIDE_16)) end +-- Health Meter -- local TEXT_DEFAULT_METER_PREFIX = "char-select-custom-meter-" local TEX_DEFAULT_METER_LEFT = get_texture_info(TEXT_DEFAULT_METER_PREFIX.."left") local TEX_DEFAULT_METER_RIGHT = get_texture_info(TEXT_DEFAULT_METER_PREFIX.."right") @@ -424,7 +461,7 @@ local pieTextureNames = { } local function render_hud_health() - if currChar == 1 then + if currChar == 1 and characterTable[1].currAlt == 1 then texture_override_reset("texture_power_meter_left_side") texture_override_reset("texture_power_meter_right_side") for i = 1, 8 do @@ -438,9 +475,9 @@ local function render_hud_health() 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 + for i = 1, 8 do + texture_override_set("texture_power_meter_" .. pieTextureNames[i], (textureTable.pie and textureTable.pie[i]) and textureTable.pie[i] or defaultMeterInfo.pie[i]) + end else -- resets the health HUD texture_override_set("texture_power_meter_left_side", defaultMeterInfo.label.left) texture_override_set("texture_power_meter_right_side", defaultMeterInfo.label.right) @@ -469,9 +506,9 @@ local function render_hud_act_select_course() end local function render_hud_mario_lives() - hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_LIVES) + og_hud_set_value(HUD_DISPLAY_FLAGS, og_hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_LIVES) - if not hud_get_element(HUD_DISPLAY_FLAG_LIVES) then return end + if (hud_get_value(HUD_DISPLAY_FLAGS) & HUD_DISPLAY_FLAG_LIVES) == 0 then return end local x = 22 local y = 15 -- SCREEN_HEIGHT - 209 - 16 @@ -481,9 +518,9 @@ local function render_hud_mario_lives() end local function render_hud_stars() - hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_STAR_COUNT) + og_hud_set_value(HUD_DISPLAY_FLAGS, og_hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_STAR_COUNT) - if not hud_get_element(HUD_DISPLAY_FLAG_STAR_COUNT) then return end + if (hud_get_value(HUD_DISPLAY_FLAGS) & HUD_DISPLAY_FLAG_STAR_COUNT) == 0 then return end if 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 @@ -513,9 +550,9 @@ end local function render_hud_camera_status() if not HUD_DISPLAY_CAMERA_STATUS then return end - hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_CAMERA) + og_hud_set_value(HUD_DISPLAY_FLAGS, og_hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_CAMERA) - if not hud_get_element(HUD_DISPLAY_FLAG_CAMERA) then return end + if (hud_get_value(HUD_DISPLAY_FLAGS) & HUD_DISPLAY_FLAG_CAMERA) == 0 then return end local x = djui_hud_get_screen_width() - 54 local y = 205 diff --git a/mods/character-select-coop/o-api.lua b/mods/character-select-coop/o-api.lua index 4e1bef1bc..b939f5447 100644 --- a/mods/character-select-coop/o-api.lua +++ b/mods/character-select-coop/o-api.lua @@ -17,7 +17,9 @@ local table_insert,djui_hud_measure_text,smlua_model_util_get_id,type,tonumber = local characterVoices = {} local saveNameTable = {} -local E_MODEL_ARMATURE = smlua_model_util_get_id("armature_geo") +-- Here for functions below api +---@ignore +local function placeholder() end ---@ignore local function split_text_into_lines(text) @@ -48,7 +50,15 @@ local TYPE_TABLE = "table" local TYPE_TEX_INFO = "userdata" local TYPE_FUNCTION = "function" +------------------------- +-- Character Functions -- +------------------------- + +---@header +---@forcedoc Character_Functions + ---@description A function that adds a Character to the Character Table +---@added 1 ---@param name string|nil `"Custom Model"` ---@param description table|string|nil `{"string"}` ---@param credit string|nil `"You!"`, Credit the creators @@ -69,11 +79,14 @@ local function character_add(name, description, credit, color, modelInfo, forceC lifeIcon = lifeIcon:sub(1,1) end local addedModel = (modelInfo and modelInfo ~= E_MODEL_ERROR_MODEL) and modelInfo or E_MODEL_ARMATURE + local charNum = #characterTable + 1 table_insert(characterTable, { saveName = type(name) == TYPE_STRING and string_space_to_underscore(name) or "Untitled", currAlt = 1, hasMoveset = false, locked = false, + category = "All", + ogNum = charNum, [1] = { name = type(name) == TYPE_STRING and name or "Untitled", description = type(description) == TYPE_TABLE and description or {"No description has been provided"}, @@ -88,12 +101,13 @@ local function character_add(name, description, credit, color, modelInfo, forceC healthTexture = nil, }, }) - saveNameTable[#characterTable] = characterTable[#characterTable].saveName - characterMovesets[#characterTable] = {} - return #characterTable + saveNameTable[charNum] = characterTable[charNum].saveName + characterMovesets[charNum] = {} + return charNum end ---@description A function that adds a Costume to an Existing Character, all inputs mimic character_edit +---@added 1.11 ---@param charNum integer The number/table position of the Character you want to add a costume to ---@param name string|nil `"Custom Model"` ---@param description table|string|nil `{"string"}` @@ -134,6 +148,7 @@ local function character_add_costume(charNum, name, description, credit, color, end ---@description A function that Edits an existing Costume +---@added 1.11 ---@param charNum integer The number/table position of the Character you want to edit the costume of ---@param charAlt integer The number/table position of the Costume you want to edit, this can be found by making a variable equal ---@param name string|nil `"Custom Model"` @@ -171,13 +186,13 @@ local function character_edit_costume(charNum, charAlt, name, description, credi healthTexture = tableCache.healthTexture, } or nil - local ccp = characterColorPresets - if modelInfo ~= nil and ccp[modelInfo] ~= nil and ccp[tableCache.model] ~= nil and ccp[modelInfo].currPalette <= ccp[tableCache.model].currPalette then - ccp[modelInfo].currPalette = ccp[tableCache.model].currPalette + if modelInfo and characterColorPresets[modelInfo] and tableCache.model and characterColorPresets[tableCache.model] and #characterColorPresets[modelInfo] == #characterColorPresets[tableCache.model] then + characterColorPresets[modelInfo].currPalette = characterColorPresets[tableCache.model].currPalette end end ---@description A function that Edits an Existing Character +---@added 1 ---@param charNum integer The number/table position of the Character you want to edit ---@param name string|nil `"Custom Model"` ---@param description table|string|nil `{"string"}` @@ -188,40 +203,44 @@ end ---@param lifeIcon TextureInfo|string|nil Use get_texture_info ---@param camScale integer|nil Zooms the camera based on a multiplier (Default `1`) local function character_edit(charNum, name, description, credit, color, modelInfo, forceChar, lifeIcon, camScale) - character_edit_costume(charNum, 1, name, description, credit, color, modelInfo, forceChar, lifeIcon, camScale) + character_edit_costume(charNum, characterTable[charNum] and characterTable[charNum].currAlt or 1, name, description, credit, color, modelInfo, forceChar, lifeIcon, camScale) end ---@description A function that adds a voice table to a character +---@added 1.5 ---@param modelInfo ModelExtendedId|integer Model Information Received from smlua_model_util_get_id ---@param clips table A Table with your Character's Sound File Names +---@note In order for sound files to function, please run config_character_sounds in your pack +---@note +---@note Table Example: ---@note ```lua ---@note local VOICETABLE_CHAR = { ----@note [CHAR_SOUND_ATTACKED] = 'NES-Hit.ogg', ----@note [CHAR_SOUND_DOH] = 'NES-Bump.ogg', ----@note [CHAR_SOUND_DROWNING] = 'NES-Die.ogg', ----@note [CHAR_SOUND_DYING] = 'NES-Die.ogg', ----@note [CHAR_SOUND_GROUND_POUND_WAH] = 'NES-Squish.ogg', ----@note [CHAR_SOUND_HAHA] = 'NES-1up.ogg', ----@note [CHAR_SOUND_HAHA_2] = 'NES-1up.ogg', ----@note [CHAR_SOUND_HERE_WE_GO] = 'NES-Flagpole.ogg', ----@note [CHAR_SOUND_HOOHOO] = 'NES-Jump.ogg', ----@note [CHAR_SOUND_MAMA_MIA] = 'NES-Warp.ogg', ----@note [CHAR_SOUND_OKEY_DOKEY] = 'NES-1up.ogg', ----@note [CHAR_SOUND_ON_FIRE] = 'NES-Enemy_Fire.ogg', ----@note [CHAR_SOUND_OOOF] = 'NES-Hit.ogg', ----@note [CHAR_SOUND_OOOF2] = 'NES-Hit.ogg', ----@note [CHAR_SOUND_PUNCH_HOO] = 'NES-Kick.ogg', ----@note [CHAR_SOUND_PUNCH_WAH] = 'NES-Thwomp.ogg', ----@note [CHAR_SOUND_PUNCH_YAH] = 'NES-Thwomp.ogg', ----@note [CHAR_SOUND_SO_LONGA_BOWSER] = 'NES-Bowser_Die.ogg', ----@note [CHAR_SOUND_TWIRL_BOUNCE] = 'NES-Item.ogg', ----@note [CHAR_SOUND_WAAAOOOW] = 'NES-Vine.ogg', ----@note [CHAR_SOUND_WAH2] = 'NES-Kick.ogg', ----@note [CHAR_SOUND_WHOA] = 'NES-Item.ogg', ----@note [CHAR_SOUND_YAHOO] = 'NES-Jump.ogg', ----@note [CHAR_SOUND_YAHOO_WAHA_YIPPEE] = 'NES-Jump.ogg', ----@note [CHAR_SOUND_YAH_WAH_HOO] = 'NES-Big_Jump.ogg', ----@note [CHAR_SOUND_YAWNING] = 'NES-Pause.ogg', +---@note [CHAR_SOUND_ATTACKED] = 'NES-Hit.ogg', +---@note [CHAR_SOUND_DOH] = 'NES-Bump.ogg', +---@note [CHAR_SOUND_DROWNING] = 'NES-Die.ogg', +---@note [CHAR_SOUND_DYING] = 'NES-Die.ogg', +---@note [CHAR_SOUND_GROUND_POUND_WAH] = 'NES-Squish.ogg', +---@note [CHAR_SOUND_HAHA] = 'NES-1up.ogg', +---@note [CHAR_SOUND_HAHA_2] = 'NES-1up.ogg', +---@note [CHAR_SOUND_HERE_WE_GO] = 'NES-Flagpole.ogg', +---@note [CHAR_SOUND_HOOHOO] = 'NES-Jump.ogg', +---@note [CHAR_SOUND_MAMA_MIA] = 'NES-Warp.ogg', +---@note [CHAR_SOUND_OKEY_DOKEY] = 'NES-1up.ogg', +---@note [CHAR_SOUND_ON_FIRE] = 'NES-Enemy_Fire.ogg', +---@note [CHAR_SOUND_OOOF] = 'NES-Hit.ogg', +---@note [CHAR_SOUND_OOOF2] = 'NES-Hit.ogg', +---@note [CHAR_SOUND_PUNCH_HOO] = 'NES-Kick.ogg', +---@note [CHAR_SOUND_PUNCH_WAH] = 'NES-Thwomp.ogg', +---@note [CHAR_SOUND_PUNCH_YAH] = 'NES-Thwomp.ogg', +---@note [CHAR_SOUND_SO_LONGA_BOWSER] = 'NES-Bowser_Die.ogg', +---@note [CHAR_SOUND_TWIRL_BOUNCE] = 'NES-Item.ogg', +---@note [CHAR_SOUND_WAAAOOOW] = 'NES-Vine.ogg', +---@note [CHAR_SOUND_WAH2] = 'NES-Kick.ogg', +---@note [CHAR_SOUND_WHOA] = 'NES-Item.ogg', +---@note [CHAR_SOUND_YAHOO] = 'NES-Jump.ogg', +---@note [CHAR_SOUND_YAHOO_WAHA_YIPPEE] = 'NES-Jump.ogg', +---@note [CHAR_SOUND_YAH_WAH_HOO] = 'NES-Big_Jump.ogg', +---@note [CHAR_SOUND_YAWNING] = 'NES-Pause.ogg', ---@note } ---@note ``` local function character_add_voice(modelInfo, clips) @@ -229,14 +248,15 @@ local function character_add_voice(modelInfo, clips) end ---@description A function that adds a caps table to a character +---@added 1.6 ---@param modelInfo ModelExtendedId|integer Model Information Received from smlua_model_util_get_id ---@param caps table Cap ---@note ```lua ---@note local CAPTABLE_CHAR = { ----@note normal = smlua_model_util_get_id("custom_model_cap_normal_geo"), ----@note wing = smlua_model_util_get_id("custom_model_cap_wing_geo"), ----@note metal = smlua_model_util_get_id("custom_model_cap_metal_geo"), ----@note metalWing = smlua_model_util_get_id("custom_model_cap_wing_geo") +---@note normal = smlua_model_util_get_id("custom_model_cap_normal_geo"), +---@note wing = smlua_model_util_get_id("custom_model_cap_wing_geo"), +---@note metal = smlua_model_util_get_id("custom_model_cap_metal_geo"), +---@note metalWing = smlua_model_util_get_id("custom_model_cap_wing_geo") ---@note } ---@note ``` local function character_add_caps(modelInfo, caps) @@ -244,13 +264,15 @@ local function character_add_caps(modelInfo, caps) end ---@description A function that gets a model's cap table +---@added 1.13 ---@param modelInfo ModelExtendedId|integer|nil Model Information Received from smlua_model_util_get_id local function character_get_caps(modelInfo) if modelInfo == nil then modelInfo = characterTable[currChar][characterTable[currChar].currAlt].model end return characterCaps[modelInfo] end ----@description A function that adds health meter textures to a character +---@description A function that adds health meter textures to a costume +---@added 1.12 ---@param charNum integer The number/table position of the Character you want to add a meter to ---@param charAlt integer The number/table position of the Costume you want to add a meter to ---@param healthTexture table|nil A Table with your Character's Health Textures (Table Shown in character_add_health_meter) @@ -261,6 +283,7 @@ local function character_add_costume_health_meter(charNum, charAlt, healthTextur end ---@description A function that adds health meter textures to a character +---@added 1.9 ---@param charNum integer The number/table position of the Character you want to add a meter to ---@param healthTexture table|nil A Table with your Character's Health Textures (Table Shown Below) ---@note ```lua @@ -281,29 +304,37 @@ end ---@note } ---@note } ---@note ``` ----@note This method is restricted to the default meter format, you can refer to the Disassembled sections in the image below for how to format your health meter (Spriters Resource Page) ----@note

local function character_add_health_meter(charNum, healthTexture) character_add_costume_health_meter(charNum, 1, healthTexture) end ----@param charNum integer ----@param charAlt integer ----@param courseTexture table|nil +---@description A function that adds course textures to a costume in the Star Select +---@added 1.12 +---@param charNum integer The number/table position of the Character you want to add a course textures to +---@param charAlt integer The number/table position of the Costume you want to add a course textures to +---@param courseTexture table|nil A Table with your Character's Health Textures (Table Shown in character_add_course) local function character_add_costume_course(charNum, charAlt, courseTexture) if type(charNum) ~= TYPE_INTEGER or charNum == nil then return end if type(charAlt) ~= TYPE_INTEGER or charAlt == nil then return end characterTable[charNum][charAlt].courseTexture = type(courseTexture) == TYPE_TABLE and courseTexture or nil end ----@description A function that adds a custom texture to the star select ----@param charNum integer The number/table position of the Character you want to add a course texture to ----@param courseTexture table|nil +---@description A function that adds course textures to a character in the Star Select +---@added 1.12 +---@param charNum integer The number/table position of the Character you want to add a course textures to +---@param courseTexture table|nil A Table with your Character's Health Textures (Table Shown Below) +---@note ```lua +---@note local COURSE_CHAR = { +---@note top = get_texture_info("char-course-top"), +---@note bottom = get_texture_info("char-course-bottom"), +---@note } +---@note ``` local function character_add_course(charNum, courseTexture) character_add_costume_course(charNum, 1, courseTexture) end ---@description A function that adds a celebration star model to a character +---@added 1.7 ---@param modelInfo ModelExtendedId|integer Model Information Received from smlua_model_util_get_id() ---@param starModel ModelExtendedId|integer Model Information Received from smlua_model_util_get_id() ---@param starIcon TextureInfo|nil Texture Information Received from get_texture_info() @@ -321,8 +352,10 @@ local function character_add_celebration_star(modelInfo, starModel, starIcon) end ---@description A function that adds a palette preset to a character +---@added 1.8 ---@param modelInfo ModelExtendedId|integer ---@param paletteTable table +---@param paletteName string|nil ---@note ```lua ---@note local PALETTE_CHAR = { ---@note [PANTS] = {r = 0x00, g = 0x00, b = 0xff}, @@ -335,8 +368,10 @@ end ---@note } ---@note ``` ---@note Strings can also be used rather than RGB tables, ex. `[PANTS] = "0000ff"` -local function character_add_palette_preset(modelInfo, paletteTable) - local paletteTableOut = {} +local function character_add_palette_preset(modelInfo, paletteTable, paletteName) + local paletteTableOut = { + name = paletteName, + } local defaultColors = characterColorPresets[E_MODEL_MARIO] for i = 0, 7 do local color = paletteTable[i] @@ -360,17 +395,23 @@ local function character_add_palette_preset(modelInfo, paletteTable) table_insert(characterColorPresets[modelInfo], paletteTableOut) end +---@description A function that adds animations to a model +---@added 1.10 ---@param modelInfo ModelExtendedId|integer ---@param animTable table local function character_add_animations(modelInfo, animTable) characterAnims[modelInfo] = type(animTable) == TYPE_TABLE and animTable or nil end +---@description A function that gets any animation table from a model +---@added 1.10 ---@param modelInfo ModelExtendedId|integer local function character_get_animations(modelInfo) return characterAnims[modelInfo] end +---@description A function that gets a character's full Character Select Table +---@added 1 ---@param tablePos integer|nil ---@param charAlt integer|nil ---@return CharacterTable @@ -380,11 +421,15 @@ local function character_get_current_table(tablePos, charAlt) return characterTable[tablePos][charAlt] end +---@description A function that gets Character Select's Entire Character Table +---@added 1.11.1 ---@return table local function character_get_full_table() return characterTable end +---@description A function that gets the current character's table position in CS +---@added 1 --- @param localIndex integer|nil --- @return integer|nil local function character_get_current_number(localIndex) @@ -400,8 +445,10 @@ local function character_get_current_number(localIndex) end end ---- @param localIndex integer|nil ---- @return integer|nil +---@description A function that gets the current costumes's table position in CS +---@added 1.12 +---@param localIndex integer|nil +---@return integer|nil local function character_get_current_costume(localIndex) if localIndex == nil or localIndex == 0 then return characterTable[currChar].currAlt @@ -415,6 +462,8 @@ local function character_get_current_costume(localIndex) end end +---@description A function that sets the current character based only table position +---@added 1.9 ---@param charNum integer|nil local function character_set_current_number(charNum) if type(charNum) ~= TYPE_INTEGER or characterTable[charNum] == nil then return end @@ -422,12 +471,16 @@ local function character_set_current_number(charNum) charBeingSet = true end +---@description A function that gets the current character's palette data +---@added 1.12 --- @return table|nil local function character_get_current_palette() local model = characterTable[currChar][characterTable[currChar].currAlt].model return characterColorPresets[model][gCSPlayers[0].presetPalette] end +---@description A function that gets the current character's palette number +---@added 1.12 --- @param localIndex integer|nil --- @return integer|nil local function character_get_current_palette_number(localIndex) @@ -435,6 +488,8 @@ local function character_get_current_palette_number(localIndex) return gCSPlayers[localIndex].presetPalette end +---@description A function that searches for a character's table posision based on name +---@added 1 ---@param name string local function character_get_number_from_string(name) if type(name) ~= TYPE_STRING then return nil end @@ -448,14 +503,88 @@ local function character_get_number_from_string(name) return nil end +---@description A function that gets the current character's voice table +---@added 1.5 ---@param m MarioState function character_get_voice(m) return characterVoices[gCSPlayers[m.playerIndex].modelId] end ----@param charNum integer|nil ----@param unlockCondition function|boolean|nil ----@param notify boolean|nil +-- Located in n-hud.lua + +---@description A function that gets a persons life icon texture / string based off of local index +---@added 1.7 +---@param localIndex integer +---@return TextureInfo|string +---@note 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)` +---@forcedoc character_get_life_icon + +---@description A function that renders a persons life icon texture / string based off of local index +---@added 1.11 +---@param localIndex integer +---@param x integer +---@param y integer +---@param scale integer +---@forcedoc character_render_life_icon + +---@description A function that acts as character_render_life_icon with support for interpolation +---@added 1.13 +---@param localIndex integer +---@param prevX integer +---@param prevY integer +---@param prevScale integer +---@param x integer +---@param y integer +---@param scale integer +---@forcedoc character_render_life_icon_interpolated + +---@description A function that gets a persons star icon texture / string based off of local index +---@added 1.8 +---@param localIndex integer +---@return TextureInfo +---@note This assumes multiple characters will not have the same model, Icons can only be seen by users who have the character avalible to them +---@forcedoc character_get_star_icon + +---@description A function that renders a persons star icon texture / string based off of local index +---@added 1.11 +---@param localIndex integer +---@param x integer +---@param y integer +---@param scale integer +---@forcedoc character_render_star_icon + +---@description A function that acts as character_render_star_icon with support for interpolation +---@added 1.13 +---@param localIndex integer +---@param prevX integer +---@param prevY integer +---@param prevScale integer +---@param x integer +---@param y integer +---@param scale integer +---@forcedoc character_render_star_icon_interpolated + +---@description A function that gets a persons health meter texture table (example of which is at character_add_health_meter) +---@added 1.12 +---@param localIndex integer +---@return table +---@note This assumes multiple characters will not have the same model, Meters can only be seen by users who have the character avalible to them +---@forcedoc character_get_health_meter + +---@description A function that renders a persons health meter texture table +---@added 1.12 +---@param localIndex integer +---@param x integer +---@param y integer +---@param scaleX integer +---@param scaleY integer +---@forcedoc character_render_health_meter + +---@description A function that locks a character under an unlock condition +---@added 1.10 +---@param charNum integer|nil The number of the Character you want to Lock +---@param unlockCondition function|boolean|nil The condition for if the character stays locked +---@param notify boolean|nil Toggles whether Character Select should notify the user when the character is unlocked local function character_set_locked(charNum, unlockCondition, notify) if charNum == nil or charNum > #characterTable or charNum < 2 then return end if unlockCondition == nil then unlockCondition = false end @@ -470,12 +599,51 @@ local function character_set_locked(charNum, unlockCondition, notify) } end ----@return string +---@description A function that sets a character under a specific category +---@added 1.14 +---@param charNum integer|nil The number of the Character you want to Lock +---@param category string The Category Name (Will create a new category if category does not exist) +local function character_set_category(charNum, category) + category = string_underscore_to_space(category) + local foundCategory = false + for i = 1, #characterCategories do + if characterCategories[i] == category then + foundCategory = true + end + end + if not foundCategory then + table_insert(characterCategories, category) + end + characterTable[charNum].category = characterTable[charNum].category .. "_" .. category +end + +---@header +---@forcedoc Menu_Functions + +---@description A function that sets the big "Character Select" texture in the Character Select Menu +---@added 1.7 +---@param texture TextureInfo|nil +---@forcedoc header_set_texture + +---@description A function that returns the version string +---@added 1 +---@return string --`"v1.2.3"` local function version_get() return MOD_VERSION_STRING end +---@description A function that returns the version in table format +---@added 1.11 ---@return table +---@note Returns the following table (Will differ based on version) +---@note ```lua +---@note { +---@note api = 1, +---@note major = 2, +---@note minor = 3, +---@note indev = true +---@note } +---@note ``` local function version_get_full() return { api = MOD_VERSION_API, @@ -485,61 +653,63 @@ local function version_get_full() } end +---@description A function that checks is the Character Select Menu is currently open +---@added 1 ---@return boolean local function is_menu_open() return menuAndTransition end +---@description A function that forces they Character Select Menu state +---@added 1.8 ---@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 +---@description A function that gets Character Select's current Menu color +---@added 1.8 ---@return table local function get_menu_color() return menuColor end ----@param func function -local function hook_allow_menu_open(func) - if type(func) ~= TYPE_FUNCTION then return end - table_insert(allowMenu, func) -end +--------------------------- +-- HUD Element Functions -- +--------------------------- ----@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 +---@header +---@forcedoc HUD_Element_Functions ----@param charNum integer|nil ----@param hookEventType LuaHookedEventType|integer ----@param func function -local function character_hook_moveset(charNum, hookEventType, func) - if charNum > #characterTable then return end - if type(func) ~= TYPE_FUNCTION then return end - characterMovesets[charNum][hookEventType] = func - characterTable[charNum].hasMoveset = true -end +---@description Hides the specified custom hud element +---@added 1.5 +---@param hudElement HUDDisplayFlag +---@forcedoc hud_hide_element ----@param charNum integer -local function character_get_moveset(charNum) - return characterMovesets[charNum] -end +---@description Shows the specified custom hud element +---@added 1.5 +---@param hudElement HUDDisplayFlag +---@forcedoc hud_show_element +---@description Gets the specified custom hud element's state +---@added 1.5 +---@param hudElement HUDDisplayFlag +---@return boolean +---@forcedoc hud_get_element + +---@description A function that checks if the options menu is open inside of the CS menu +---@added 1 ---@return boolean local function is_options_open() return options end ----@param modName string ----@param creditTo string Who did the thing ----@param creditFor string What did they do +---@description A function that adds a line of credit to the CS Options' Credit section +---@added 1.10 +---@param modName string The Name of your Character Select Mod +---@param creditTo string The person you want to Credit +---@param creditFor string What the Person helped with local function credit_add(modName, creditTo, creditFor) if #creditTable > 1 then for i = 2, #creditTable do @@ -556,18 +726,24 @@ local function credit_add(modName, creditTo, creditFor) table_insert(creditTable[i], {creditTo = creditTo, creditFor = creditFor}) end +---@description A function that sets if palettes are restricted (Default `false` unless a mod with the incompatible `gamemode` is on) +---@added 1.8 ---@param bool boolean local function restrict_palettes(bool) if bool == nil then bool = true end stopPalettes = bool end +---@description A function that sets if movesets are restricted (Default `false`) +---@added 1.10 ---@param bool boolean local function restrict_movesets(bool) if bool == nil then bool = true end stopMovesets = bool end +---@description A table that contains the local mario's controller before Character Select's menu cancels them +---@added 1 local controller = { buttonDown = 0, buttonPressed = 0, @@ -580,13 +756,15 @@ 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 +---@description A function that adds an option to the Character Select Options Menu +---@added 1.9 +---@param name string The Name of the Option +---@param toggleDefault number|nil The default number that the option toggles to (Defaults to `0`) +---@param toggleMax number|nil The max number the option can be toggled to (Defaults to `1`) +---@param toggleNames table|nil A table of strings, each entry being for a toggle's name `{"Off", "On"}` +---@param description table|nil A table of strings, each entry being a new line `{"This toggle allows your", "character to feel everything."}` +---@param save boolean|nil Toggles whether the option retains between sessions (Defaults to `true`) +---@return number --The table position of the option added local function add_option(name, toggleDefault, toggleMax, toggleNames, description, save) if save == nil then save = true end local saveName = string_space_to_underscore(name) @@ -603,22 +781,28 @@ local function add_option(name, toggleDefault, toggleMax, toggleNames, descripti return #optionTable end ----@param tableNum integer +---@description A function that gets an option's data from the Character Select Options Menu +---@added 1.9 +---@param tableNum integer The table position of the option ---@return table|nil local function get_option(tableNum) if type(tableNum) ~= TYPE_INTEGER then return nil end return optionTable[tableNum] end ----@param tableNum integer +---@description A function that gets an option's status from the Character Select Options Menu +---@added 1.9 +---@param tableNum integer The table position of the option ---@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 +---@description A function that sets an option's status from the Character Select Options Menu +---@added 1.9 +---@param tableNum integer The table position of the option +---@param toggle integer What you want to set the option to 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 @@ -626,6 +810,89 @@ local function set_options_status(tableNum, toggle) optionTable[tableNum].optionBeingSet = true end +---@header +---@forcedoc Misc + +---@description A function that sets the name to be replaced in Dialog, Default is `"Mario"` +---@added 1.10 +---@param name string +---@note This function does *NOT* change what NPCs will refer to your character as, this function is intended for Rom-Hack ports with alternate protagonists. +---@forcedoc dialog_set_replace_name + +---@description A function that sets the preset palette for a network player forcefully +---@added 1.11 +---@param np NetworkPlayer +---@forcedoc update_preset_palette + +---@header +---@forcedoc Tables & Variables + +---@description The "Reference Sheet" or IDs for all of Character Select's Options +---@added 1 +---@forcedoc optionTableRef + +---@description The info for inputs from `gMarioStates[0]` before Character Select's Menu cancels inputs +---@added 1 +---@forcedoc controller + +---@description A table containing player info from Character Select's custom networking system +---@added 1.11.1 +---@forcedoc gCSPlayers + +---@description The ID for Character Select's Menu "Cutscene" +---@added 1 +---@forcedoc CUTSCENE_CS_MENU + +---@description The ID for Character Select's Menu Animation ID, Used in combination with character_add_animations to display a specific pose in the menu. +---@added 1.14 +---@forcedoc CS_ANIM_MENU + +---@header +---@forcedoc Character_Select_Hooks + +---@description A function that allows you to add a condition for if the CS Menu can be opened +---@added 1 +---@param func function +local function hook_allow_menu_open(func) + if type(func) ~= TYPE_FUNCTION then return end + table_insert(allowMenu, func) +end + +---@description A function that allows you to render HUD Elements in the menu (Behind transistions such as Option and going in/out of menu) +---@added 1.5 +---@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 + +---@description A function that adds the necessary hooks in order for your pack to have function voicelines +---@added 1.12 +---@forcedoc config_character_sounds + +---@description A function that allows you to hook a function, much like hook_event, to a specific character number +---@added 1.10 +---@param charNum integer|nil +---@param hookEventType LuaHookedEventType|integer +---@param func function +local function character_hook_moveset(charNum, hookEventType, func) + if charNum > #characterTable then return end + if type(func) ~= TYPE_FUNCTION then return end + characterMovesets[charNum][hookEventType] = func + characterTable[charNum].hasMoveset = true +end + +---@description A function that returns the Character's moveset functions +---@added 1.14 +---@param charNum integer +local function character_get_moveset(charNum) + return characterMovesets[charNum] +end + _G.charSelectExists = true _G.charSelect = { -- Character Functions -- @@ -647,8 +914,8 @@ _G.charSelect = { character_get_current_table = character_get_current_table, character_get_full_table = character_get_full_table, character_get_current_number = character_get_current_number, - character_get_current_costume = character_get_current_costume, character_get_current_model_number = character_get_current_number, -- Outdated function name, Not recommended for use + character_get_current_costume = character_get_current_costume, character_set_current_number = character_set_current_number, character_get_current_palette = character_get_current_palette, character_get_current_palette_number = character_get_current_palette_number, @@ -663,12 +930,13 @@ _G.charSelect = { character_get_health_meter = health_meter_from_local_index, -- Function located in n-hud.lua character_render_health_meter = render_health_meter_from_local_index, -- Function located in n-hud.lua character_set_locked = character_set_locked, + character_set_category = character_set_category, character_get_moveset = character_get_moveset, -- Hud Element Functions -- - hud_hide_element = hud_hide_element, - hud_show_element = hud_show_element, - hud_get_element = hud_get_element, + hud_hide_element = hud_hide_element, -- Function located in n-hud.lua + hud_show_element = hud_show_element, -- Function located in n-hud.lua + hud_get_element = hud_get_element, -- Function located in n-hud.lua -- Menu Functions -- header_set_texture = header_set_texture, -- Function located in main.lua @@ -688,15 +956,34 @@ _G.charSelect = { -- Misc -- dialog_set_replace_name = dialog_set_replace_name, -- Function located in dialog.lua + update_preset_palette = placeholder, -- Function located in z-palettes.lua -- Tables & Variables -- optionTableRef = optionTableRef, controller = controller, gCSPlayers = gCSPlayers, CUTSCENE_CS_MENU = CUTSCENE_CS_MENU, + CS_ANIM_MENU = CS_ANIM_MENU, - -- Custom Hooks -- + -- Character Select Hooks -- hook_allow_menu_open = hook_allow_menu_open, hook_render_in_menu = hook_render_in_menu, + config_character_sounds = placeholder, -- Function located in z-voice.lua character_hook_moveset = character_hook_moveset, -} \ No newline at end of file +} + +-- Replace base functions +local obj_set_model_extended_original = obj_set_model_extended + +-- Replace obj_set_model_extended to error for mario models +---@ignore +local function obj_set_model_extended(obj, modelInfo) + for i = 0, MAX_PLAYERS - 1 do + if gMarioStates[i].marioObj == obj then + log_to_console("Character Select: Mario Object cannot be changed with 'obj_set_model_extended' while Character Select is Active, please use 'character_edit'!!", CONSOLE_MESSAGE_WARNING) + end + end + return obj_set_model_extended_original(obj, modelInfo) +end + +_G.obj_set_model_extended = obj_set_model_extended \ No newline at end of file diff --git a/mods/character-select-coop/textures/char-select-custom-course-bottom.tex b/mods/character-select-coop/textures/char-select-custom-course-bottom.tex index d0f6c8172d2db4b2239f1c32d38b56b92af656a7..05ed93274afe765c352e6ed51a4e4be4256e2411 100644 GIT binary patch literal 4352 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 i8U3Q`_fEk7_xe8gp?AvI7#l1d;U5FlX)2_ax; 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 delta 4738 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 Qpa1{>07*qoM6N<$f}(5b00000 diff --git a/mods/character-select-coop/textures/char-select-custom-meter-left.tex b/mods/character-select-coop/textures/char-select-custom-meter-left.tex index 5ea84cde3d2979fc5a88c4307c7edfd400064664..228d3d0d5950f7e6ef7c90e71be0051c4fbc62c3 100644 GIT binary patch delta 1902 zcmV-!2a)*i51FJuewDiq*H zq)bp?iEt~h*nFy9Cy#%wNm|UlD+u=DHIGWNM8-TO&q0L9HT*^*FsIl6%}oK6k~a(B zM%yMs*+(<;7$!m!4BKQ#k&5K~9)u=Z?odiTnbr3?(m>1Ec#zjcP zZ=IYA2$4q&9C!yf)DbvCxTvIx^#M-A0tYWNg-#>l_1%FCHSog}Ag>ZQPkZzd;Ue3s zgtJW(McmdAaeRLOu<wFiiJ`un034o5j?bXW`M^~j^^7QvMj}QF;CO~1 z#|P+RC2%^1N?;6?zy#o@$)ssI)n6C|B9eRGhyu2q5IpmOVQ;QLWj z20_67Nn#X^&jfy52wYpt)6j78%D7tqk)S9)VazYpNr z?p^BO7Bqjeh`l71z^>(!BgFxKYk>0ahfF%Y<_mp zbkr~b=}%EI7kIFgqEETaohDW|ivmSp>KGUFYHdk#ih($npy8e~a)Az4nF4@Jch*F3 zE)@7J9N06SIxRK3le2)|7h!Jj0JyfY;9*XrJTre0b0lIf!XODM`2w;^XFDxVib0bMP`J%-dl4X_n>PyUG_Yw@?()1L5x6MNc} L!h7584QfLq_tvAT%_q>1}IEeJ0*3`N!Uuh8AW zwpMbL5g2hb>M!61wa}_05|ASH^P&ZK5bur3lmK+4ZTBYPnj!=!<#a+^UI09zVFnvT z0falNhv4OAf7mM&JkPa3X#)0q{RI@zX;y#wEk$9C*zu_G+)D|>i;ctJU}agW$L73O z%1S}bvVEf@>kpn6 z$3pRVwKx1-y75I#39F%$JU70sw}AUQ$Bjb%3~{8ABJlj^OfKM<&Xaqmtc_f-Fu8x0 zApkmE%lmt&?OuqW6K@e0@a)huJfWlaRcZiSKXjnCb_+d0wbx41-{cBlR&haQ;H-vY@6H(r(8g3s_i4GB?loj>~DQIs46r*55j zBpO`+vqc^bKgW*ljSYTXksGE)W%_8t^qWs3TG4#Gq*fg>%MD$WHc%)OuZe$YkN{>g zove3hT&xk}*$G8UJy4lN(@}1SI2~Q0nem#AZ`leO#g8NfV6uBJsCqiWk)=mYD>gNq zAhZns#40VqSpjWdYveC>Lum@t!kKwAt{GlHc+(;=|HS$5bA#6l4KWQCz-*qgjeUfR zRqR5w6*R7vNEq22=aT&RWUPOml9>>S$iHz?!P5MIy}^z5Zm1jBS)oz4AEoKn9+Ca6 zp>?xGPTZF`zHWGpj`?U69o<_4#Dd*7vC-d-TWAN^sv|$QFOMVvT6bIMyd989X<^8V z^56}tYMVI1A$wBO{6C-@=-{aHwC}9-=m4#UJqfWxB#D`)wneN*N5o?LbjIqTU6DAv zTa*9I(_(>}gSFPv@up_*dkFogEyA7JBEq>H7JjNgWM8Yd|36cNtG#Z4t6i?9zulja o18i@-bpg%RY|Yke&1TO20}&I=^AbLaD*ylh07*qoM6N<$g8c)Fg8%>k delta 1982 zcmV;v2SNCt5AP3<9|6pfAS{0XuFf3k000MuNklZ712f@Jz={U_#UXbG?0pH6e*}ngpUumHBEoN z2leU^ep8)->J(HbAammLyzfJ#5fLZy_!&gfh}0qS@Wd1}^+TzPJA14QpK}3!-iCFrO(MdQ7jqLAoqj@n~NIHr{ zJtEsClaKXj94D5x+mKHXF|ny;D}p_QCFVf$AH(@DvCl-(&F!=MZfOFJ0+%8YNoam) zx`;apNh7j5Ou>IlX_zZ!w;BO7L-QM@do6O*26I(dm$n7D4d6ckx$R1Qb<-USp~(JP zNTneD5LCPYl_tc20Pq1HrM@)F^|%z`YYnyBm3$D4pMv=aR01o24>0ldgcNx^K$ zrQoec zXFep`ah$TH4yGLg-vHkP&jZf@FMwD8mN|a`;=OhSWNkRB2jSCBNaWGJ!ts2RX<(Qp z+2K3~-~WGvcTQYksP`ttTmjz?<|jaUcb~&xZCF+X=s5+30?WW!vw}kZ0R7nlFC6aV z>PLOtGvx6NG!9`Mq;cq+s{oPTSMlGEH<0(h8G(+!!OBXoW1t|l@os*(=R^L~ewA%E z2iOlJqp?SU>wu2hbBuufZ?btP_u##=U>M*QAZCApQhfgxf2E`4GCv;~WJffjJ+ey? zdEZHM$Kfum#|YgiUz>vfwFW#eEc~L65%a*a zzzctP{ST+P_g0P!VYo9uN^AOXaKS|D&F##>nRo0k`12NY)M05N(b{LLoo= zS`Dr%FD}QO8U-ghPN8S4ijoAV zhKArjH*O6L4Y}lpH3;N0BUqLRD1Lvna}%&!dpLGuSB1QUx4nz0hA@Q`z7o;&`4;y2AY1libTe8ke7t22Cyi9NJP0|;xQw)CsFpY4d zX&OBH?Fab#%ipBt{(Hc={o(|3hycJpyKZ?KD}yI98F!r?%8@Gu++CHzu;ZbKn8oVq z6wmB@h3&3*IqJEWwU2dZiHY9A+Q%!2YFDM$G zs9KBTTfP{VAOH~rA)kdWRM=QC6T`AFEQ4nceZ24jCP4k{D^<&^m^u~se)aH;9JU39 zsUkCIeE+jMDqtF3*t#;hK_QPDCif~s%*JE=>;9koi&(@W7O{v$EMi9d59)ixD^Z$& QWdHyG07*qoM6N<$g7D0&RsaA1 diff --git a/mods/character-select-coop/textures/char-select-custom-meter-pie1.tex b/mods/character-select-coop/textures/char-select-custom-meter-pie1.tex index cc2230bf27f045865e7ad5c0a23d4124a308ef8e..a835772fc4861f2b3de9b907b6b307ef8e9a9aa5 100644 GIT binary patch literal 1082 zcmX9+ZA?>F7`_!5htFQR5e`x|4q=1a7UXtLEbN0`+Cha>DAkM)6Y$zO#Io9!$$-Qn zpu@WO!zxS|Lj!aZWQ@&ZsTi3K z#PIKxS(9w0118>{#8=tu@0*j%CcDX+WGOeXksB$hIZvMz8nh{hqNq?^w#EQ^tZyPe zST$Y8Z@?z98L~Lhlvi;W4uO{JLK{T|Kku6&>TElPfabhhqZXXsI(F*P9UJ;2514~+U&WDgOz)7*fli>^Tis}%!Py8y^fvEJ==7uLNIL&b^G)wHv9WL`sl;Ht>ptf{>9Ev`$78$R+~fl=XC92Kf1bcHI?FT zF9mjWKYneyWV0-Dc#E^ss*{ekh)SQk-SEP$ua__X*g7(bQ=DIF$Nq3ti`)EzR|1Dl zI#i0wM}N}Zuh%>LJ3q{bo@pAco2p5?tNHYdhaL}eG*|aJ{QLa&6^Dv@r2RWS4{RNY z4pfYvt~qb@%iRzZG3Zq;|15cDu<4?0)3)nRk1;#;#rMY#JW`m0UTwH}f3BDu;P-Z2t8=APYkM|bC%Y;Rk?vVP*!o70cB z)Z8@x^HJx4<0UCpN!ziQU-*=uYH3@5WA~Ha*>v~a@DOTX^w(EDk&fLXAtGu8-+FmY d-L?AP$;YAG;9g>QYC`a3D4kZX>E}w1{156?lG^|P delta 1086 zcmV-E1i|~d2<8Zo9|1#=ARK=N0001UdV2H#0004VQb$4nuFf3k000C1Nklq5Q4vv}v=5>veGs*j zAcCewY^9)xLTNFWLVvQPXkt;ag)Lc2T4zEw%oV51Njl5=urs?evon9$Ac8OX;IcdS zoH^fj&OP_e1=jFCBd}V>GjH#!Kl0BYmR)c-`ln@?@IYvgS1nHcllcIIt600aT30Hy(a*3(mT)b-*oGlm6U8rIcs zwkPVoIClE#!oL=ag%%s!0|-F`4V&K?;AplO@!%_)KvOA zKaTZ&hL)DdP|ZUAy~8XLF94_kkOJ@}fb#(604M;S4Tk~4C=VNU6Sbyft>>>gVpY?A zUbTRDEH=1V)!t9C7GWYNhJjI&I14}kU;uvu7z~AgnwrWW%s79cX*iXWHyVuXq0P}n zA;ff50liy0?#}-?e{|QC5x#mQU_06;Km zwOhB^;_b2DuPeE0D_5Yf{)4SIZ}tTMWKb;iZH9pb5CSk@FLFtMtNbskDkg*|7XtwD z`AxEcf~INT+v$JS*&hZTXzz$JCmDcj4mL*+3>5_3=Fg}^QdTkLCN~jePA1|lkNOIj zm{kvinKxLZ>ByWn@{Dh${p#Z%~B3(>~?s9x4>N{W7x%30z^%G9xLg zfQQW;uV8X`3t+_E0lYFLGbj^bm>HkTvWHhCxefr#al3!raS+8K5knH}dp5Ymu|%eD z_AZ;307707qLjFM1J4t{mIdUI*|5TL;Da!#jHyt z3_;}Cc-FICc24^Wkb=QUH<>-4mAS-D8b)y$xKtw_asYuqVA5B>)4j28nP_>XPPQ`l z@*#7Z+J%2RnwV(0_ue~C*rzJKhRw~9k$@tebLLXHl3s8&oX0zobWBl{=j~JL;KG6X znm*PgDP39u^4j@jLa(LLOIBMNl9WE!*Ycq|hUb0Y_5SX@;e%$ zwAj^D|Ja$ynG0^S=blepxiS01gZKQB$!R+c=8b>Wm#^CJL|xrnM{E85u~a3wuK)m; zzIr`7`s(iAQdup^hSBQ2Y*Ymi0-?~@y9e)o?a0ZC=ltBN-U;;|UTJ*k)ALWpoW|Sc8Rs01Bkk*MS2zqyPW_07*qoM6N<$ Ef=*)#zyJUM diff --git a/mods/character-select-coop/textures/char-select-custom-meter-pie2.tex b/mods/character-select-coop/textures/char-select-custom-meter-pie2.tex index 3a9c0178b5305419dfb266860874fa674dc79a24..bcd8e25b5ef3b499717b4242fc1c64aa564cc8d0 100644 GIT binary patch literal 1101 zcmX9+4NQ|q82%VV4;kaA?Yznc9OBZiK%k8S%FhNL1zK=TY0DNwL$PZ{!_Sl!1IRMQ zh7%DXl^HTvMe!%WpyC424(B#V6Ou*ZeqbodhN5U7WMNA~kbQeUxIFjX`}5pA_vY@E zH?3u*)o~76h0W@Wv(`AAA6Ldz+MKrPxI=cEN+DvH7K1)Fc-zix48sKLv>GFG9Z4AqYIAEpjkS&~{<^F<}5Vhm7+ zgq&pAPL?gFR844>GUiNeetl6aAw-R_6`>x4E+W*45YKVETFon!os?w>Db+=**$5WP zjw0lPDnhprI*HIegdA{`ij9f_2{MF`7ojf@;x_WIk)@QwxCdh+LU{9;1rFvZO(w*Ys(`8z0TA$qpbIuiCX+p*lqZDBWYE_#oDV7( zfG<+I5AqNqELcK78oJ)dAc_zHVCa=ljOCP4gquq_@Cn96x$%)8kA!l)ApxxOK#HRv zNnm5FO;T93YH+hs6$1@MXbP^;?cD3TQFSn1NkKrM3C5Vo_8;b+xeHqlChJsk7N|m6 z7$C^0_t8; zYc5^m@nnSSL1;WbOsWyYK|4qKBu$hDf9JGLlWDH)dFUF97ZqUdo#p*Ao>XyIV(D&4 z-auZTNh?vb9p|D7w373`$fe?D&H27d9omIG|23J8%cH9f-whvsI9>c?#P{?}y13qS zd;R;_pS!Mc29$h96D5 n-QeF?m~&Kjbx+bi#V-RJn6(ZoeVjj*1Am6mW$QIpIZM<3G&`F+ delta 1074 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 O00002SOBu zj2&&NqauzS(>h|rK7urYk6JUuPD86U+Nq5WB@=bhW^}BPQG4A}{`vRcZ+HL4_wVh6 z&DK?~Y?K)F2EDFHqH8ubt*?{R>6`S8lKL9`JYggNyGx7nqoZa<0RW;E1#&f>h5Ufw z*vgN0x$q<~s`FXF?;|PO@M3CxL8TFZ*QfDA01ovK0ECH3i!_Vy;b2?2Oe!Wxf~F8d zV~w>~Vy#wGTZyPjzZ&HK86eVKHKiI1Vf1IAF0LoMB~lB164n zszpIJ#c@o?O*?u>vk_^Ph)JhJBEE#fN^o9!81L7jS}oKnp^||{Bce!B!62)Nu$oA_ zl~A)l$pVIkZZ~wfAVtQ@Qbm}XNe69a!l>h^s#zQh>~_>`j%Da1p%5uq$TC=g!-2BW zh{CKC?50%$wGz@av{?~Ni4qbLXbQ44@Ooj;3rR8oGxz&p&=0vFz%7#`P7Wv%*=#7} z2WmBL4N(*%2?Aq}3wqtq>w@lK=yJeeJGAvcmc^bJqo5Zk6o|ho3g9T30$dPh27V7- zk`xIYcG#|$k_6&H!0!b*Evn2-6%qtV;2y!S1LD|CrD@obBo2Xo4|EM<@mV7Ov`UfsauWvv>?TW3?%S-uwQy$K>EWiL(8)Cwg=v^PF9^C_&}_mN z#gkM^DSJz%zqh9#&m{EZ^zx{en!t8KzJp)v7{X@A$3x$9-o6qZ z`uHO(*zbKDF(Kxod(&QK^Q5qRfdG?-D~@I7IXUNtZx_DeG*UQgx}2x#?9Q8h&2!C% ze~8}{@?6cvoMk!bmy;gE0dtxLxaZ}_g$xYa-U z!rS`8?9Nd1ijl9l$hAYlq~ssRCBjGNRGnqkg?ra_9T3!w`@$oiH)J0(oQk-&gj}Fr z+*@7pQ-gTJ2X}3!d*^Tec8c`L?&5VbwqGjSYngZCrfYi!>GDHU;=j>C{&iF$Hys83v#RX(6PTJ!9<9mVPqQo9{|7=$I8Oio delta 1268 zcmVPx(u}MThR9J=W zmS1R7cNE7zopGF$ZQe{=6PeBw9AIpqV-;9;2tI8?jbj6k|te$8G}8{1HXs+ z`fjE5QwJ+XW&GW;)H)WKzZ( zb@AA?Eh~l(d^}+ND+JzuZFN)MPq+4jL%RK$u&#|p1n~>DrKB@(G7g}gw*tb^qjI^o zSI%#I@{zAjU;6Fle1n{SWv!8?I-(I{=y12;TFHp(x~;C0jJg9S!*0*phP$)fa9!7M zU01w8*$}t8+ZbwH6X}=>!&h&ixjDFBx$|C6w=8S#4nsysoH7|rS!6B6vcWEitTlE} zPMpxqhYqo7$_@r6C(SQw;nYk)BpmKq5wt$p8k5D~Clqo>rWG@Pt2hd(iUO7;j3nz3 zfK*C|MqzZ6>8@Ri-brVsPF4FXsGiu=(){!S|LtRK&)-|Ve2I|0k>lIJJepH%RrGG2 zd>+Vy=6!U%Md72$`uh!Hu{@wGTb6Hha=w*0EBxyX^VYR;zlW-S{Qb`Dcf+B35!-=8 z(k7c#0s$p!fjUBeG2YrS0|0Mc~og0$Y7( zPRZTPLq3n+m*=MX$me}5^c5n`&r(20rC`H`Tuo|?fBK%yWS0JH-m)fZDv-Q3y*m`p zhqahzhl+>;qNswS0t#9ogOJHUG+JMq_I7>PR_EpNxe5Y*BJMiH19qyU_CAUvES1uK zrYYDagv0g00gQkW47%&;5&(_V1NJ!K03wA|RpIPeAs7TBI5&8~A3`CGl+RW7fu^i2 z%*T{MQO4s+Gz=nAu~_Pj4qn>8w7|A$nv1|xKy)b-BCQ{ZfC@&y=9^v^84+Tg_S}rU z#&sqxQ{~ft6)A8WNjpe=a4mq_Du~#H&My$_v`O?EKppjLu)U(4n2>Z`0)D@L%(lJi zR!Ws#8VIU_A$EyS(PEu8qk}+o3XA(WkW34z4P$i)?0qHly*hHgxOaJ36~IBHQtI-f z*xIfn5|Bw1j%g8Gy~6H~%l(b3o;X|n|E#-UMKIWZ*MPlO{N?b4sAj5vW`1NCjPm2B zkVq5=w6)Fjl980q)oq+MP4kVq3IOa}A3Ww@q}35m1;bN9OQ|Tsn)&u3Mxkwu;y0jw zprBgT6pr*5>D`-~Kd;8Cc^e+=Xp5a6ojeD+*k4SBzlNhD4D>@Jq9q~&fD_-1B-*1*J3+3O8c=yB@`eN0j#uGO>Y#YaWU>&C%k{>4 zOFL?T*ChbZcVT?!_`c{qzdv*l3P-G(Ln-9))~%4v2uFGh_8kmdJh17-J;TW>m+ImC z?VHd!_vZ4wUtfN1>=*L`2i8{HLIS6HAryjVY!*^UVPq7NSLAYAbKs+0FFiKC?bERv zbL~IxS8=v)$C5KYUT?WDF|{RY(PBByN+9Shn|^=8)o@_Z`2LR77q`C4U#rCR*p}GiGdoR6yPAhKEP@uu|z8fkd35^XuGt+uz;r!8~_#o zBfvd?Nf3mn%!F7b3{C+W5e$GssA^LgL=CD54kOW%oaA^}o(SMUQ5(ziJj?n=(I%;1SafCO|JiocZzdF zft7S0!hjsXlA;|tnY7Sb*jAiulmu22IUvg{@J31VWwVuDJMp%!_C9;C_8LoG0k_fG zHah3`&yBWOH$>G=(f`_1ZDjs4GynMfzt;S5hwqt-`W!FK$o5QnFYVQ?&=pe)r7dH0 z>@lT}1OKxE@@{Obg-VPO$C&z=nRug*`V710(@dkIyI#m+`KEFX3rWF;b0aq^)0^&omu|JCuHA3Db=Q^I`+Mk}B&G7#H*N3zbtODJ+8t^S z+k7OjusW#;c;k{3p$8fh@4G%ZV-C6Jeq$tK)Omw8Xgca4ak8OuyQ%Tp(vF=;isncD zn5HP6xTlQ|?6*fE`zIE59EgTsp6uw+_noWz##0$#YNWagJ3|$U?MdEzm%687uvr7E z!BO7Ox~CC}m^*3ayLxFyqvpc+b2ICMJqx-J{`#G=<*hfke)UqK^}?UOl#j&lsk4D@ zPiTHeV9EQgGOxp*D7y4MTgB|U&ZyJZ75(ZDmtH^6uGibX=NryKsvkAe>gnVy(U*$c z2|PKn*fdstyF$5Fd3JTNFT;E+EdFXWPo+a$v#R10$yc)IqTPMJZMm834R)1nlB6RM z4}&gdDc7FA86HkoRC}b8TL)UDNmctq?%DJ0;gl!Km!14;9TDM~FM8v<+jkwj7<5^^ zd^yh~UekZ7v0V*OJ}CRUz9)%_hZm|!jt<&)6--S05SINl{kY-ihC^L{xE0)6o6ZP> T1wFUe&*QSQ@=RYDZB73Gs28*? delta 1136 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 diff --git a/mods/character-select-coop/textures/char-select-custom-meter-pie7.tex b/mods/character-select-coop/textures/char-select-custom-meter-pie7.tex index f2f573586643b33e85a457c4bb1287b2e2256a46..2c9e6c634bf3cbe8a223cbc6755c99303818bfa2 100644 GIT binary patch literal 1419 zcmX|94NwzD6h1`DiXul5So{GNEwVt6qcep>1bPI40~vB+Eg7xiNhL%C4Oj#$qM{&7 ze04RzSLeQ&?_zV~;#(-sQ3 z+1n+WoGm#*kwhrg6cyx4@^gxEwo3|CIZ?SYD5@qSJ;}{=o-0LBZYjxfp6CF_2F^sv zj~z4-<)q=0Sf|^4VHE_-EKJVQP}D3>$9AF)>mWrhOeD^(-K$e%p%5a3WC*e3 za~JApK}&OL7%WX-LK{m`OS8fz2`pyHFmJ$0Bj)s2T1Fd0U>1Q%1V#~PMVi+_gtJo? zOR+y@wTw<=j3U;FSZ%>vD`M1is|ZMlUZiCjX(SE|ByfNPUDH9AMSV-(9;@U?hrFjDoL>LgA8XZQL8EH-jG$O4u1GPv?4Ga$S_4TEd zMu<2FSs;u6R`m5nG^2n}3WRZ>6agnfl84neB-aXfkw!|IQ3ACU2v(r9(wGOl1@KnD zSpjPSQWIbdG~x({=8Ql|lGuQhMDY;fU@|FZqB%3brmAd~#u~ty0XI$~bym{SfB*>C z5x^5ZA($ZyD9wm~NJ_INz!9SrFe4B$MeAf5MHEf?!L2mb(vVG#3K5c}5Xt~!22u;* zBrFTjm-FP0(MSUr3t+6I1R1ueD9v_q>&8?DAxK&R*hu3#a`n6n>vu$rG_S7R7@ZP{ z$c-TQYO#^Qr}k!wo%yP`)4!7Ubg_s}Uq!v1S=&8mvki9FW_tJ(_lZ-huh>g51;lQJ zYG?`#sf5ufAdU(_mRHCU*Zlvf8QUEPyS!==SDkgJv%^FTPfS`S#e~Bk4xe?9B1wQf zbTYg-Vltm4ERj?hjY%MdhnCB`9o+7CzjQ~BeW?q)~n!Xz0!hia(&!hC(ThH43u2)yJ1Vqnuak<_hEZIh{ef(qAx{DW1)Q0cL z*!K9Ap}Km*bdTvB6?4@GN`kl=)wez?=d|~%A5$KB?a|n>yGC2=x$%FjW#yY9@;r8G+0HZ`=DCfPfkyN=v=(h>h?;jstz&ukj7 zRbJ_{_LOfv>6dYJwB=}5mrGhhke$(#C;Wb1ulGLsqQcp&Y1Yh$exEZ(N`82H|C{B| zE}I9L%g33*fBVB5V(lR}XH|5zz07lNiIT*ARN1t&VQhZl+`u=JkH^-`{#sS40k?th-aUgcYxe&pxwN+F<4TwE&n&ht8hqyr zEgSW`8-L{jwYmP`!{<9a>q{gmKgs8X3YYD=+w-3->hTYLvNwInciyg=o-K3gqy8>< zIx{QsQ?|PPU2hH58?;m3>ppO~IJuzfftc%al}Z0VnpZio`iA+!!I(=q$*Wvqz7IC^ zXGSR9^E?&)J6mtwNX`Fwcie%?wZ`_BYZkap%kYm7aP=Oc}x?l^hYHLuVE#e+;&) zt~~tA8wafagushWES|IH$e)`OMO!aI4a?9PK?tyIu!cyzybT!!B;Wu^5dFJP3VrwI z58rq7gS}t2GRiZBp5m}HGtLiE>iUg5csA*?Ca`_ z%HH=AL&+~nVN5GE5s9c<)8#d4hh(X|HYg4=6Aq6dtlNOJ_zDeTzeFdazy;4W|p zC+%d};EbJGN(n$~`y^ULkkJ3CePI~{o{4ZVLo$dN<16X$WI4e}C@ zCSBVG3SRhKzxhOjt|RZ?Jd^UK`mj87(Y9^xTcSM~O3?+ZSFu-o#ffLq%OkvAxb8?5+AO?Dowd->1Uaszl8dhlYbtCXd{o<&x zdi#5BM4KipkP}(2WV8u)B8@Vk1LfHWRBiTBfX7da=*T5a-Z+z%Okt+yE{fiH;)FS2 zjTVi-(AkR{Wo>*0mgfo5ciQpcn%l7&I&pk=9VZZw6kvav$m*DRGMd)_O%s3 z%p3xaT3-hN@M1=4V+IsA|zQlePq06IxwK0#rnzlgjzI4eoPI#cn^Y?g zz&M&Vx2S)SAOQ&?*^i8M0|H?WAj9$Ob_}j_@@;gF2S+(65Vo1bqA+*CX8YjLI4B`d z1X7D5jQ(ux6icHYIpHLeB?*Ku1~JH1etsR8AdG|u4ms5>!*N7PFS!E%uoIM(*@Gns zJh@!kFZ8Y}*q*039;E=wKxz$z#pwgcPz+4n+Yx{H(Ex<}p+e*;XAZ{9@5!4mbL7Xey0%WpTDR9U$F`J=06^UeWhJ=i0he-KTH=6w!XS47X-I%=c89 zen)@JE)Hx{q=}IG!RonKzrcL-;NbA_e5|6^apI?6N89SvZ;i22D`a`?Ox&;s`Zu|^ zo^#IcS7iSMCH*~jSliCkEd2ekzC2d2{gm_3YpDt2ni1!|acbpR4IVJ-&L(qDDGSm6J`rsVK^b xR&nc@t!o$et$!e_mo>k0-N)#ZOv#jF4= diff --git a/mods/character-select-coop/textures/char-select-custom-meter-pie8.tex b/mods/character-select-coop/textures/char-select-custom-meter-pie8.tex index 15b51f5b86259c8b2dc5a38107b6436a2e0890b1..07acd535b3254daddc9899ca443f73bd58e6bf79 100644 GIT binary patch literal 1376 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 diff --git a/mods/character-select-coop/textures/char-select-custom-meter-right.tex b/mods/character-select-coop/textures/char-select-custom-meter-right.tex index fb2e82e99dc37e0615ddef953218467fd5b63c98..94047be194c87694b34093eb287f462f787657f6 100644 GIT binary patch delta 1926 zcmV;12YL8~5V;SKAOV$;AuN9Z*~u(_00009a7bBm000XU000XU0RWnu7ytkVI!Q!9 zRCt{2n0ruEWf;a!O-(3X77$nvESySLO#@UGNd#vE#5)2B5l%3rW?leA*<}%!B~ekl zhl-$!lG>Q&Lj@@IvBkG8J$6^nT~E9CuMUyVUdt@63P0E(ez9_rBlz zedj%JTyr#sEC5tBa1Cjs|HNEl;!Z5C;UK#P_LWN(AeemEwMvq26G2th73`K?BP%&X zRdUr51aGDysb%sJ#TlOfUXatmdee<0LXmV6XwYl zsu0(|A%H;kA;8E!&E7MWHv)o6e#mr_Fa06&MON-K5kfEa0W&qqDkOhoR(i4glr>OL zFFxY}zT~V41r?wwkITE%IDlsbgQ$FR?OA4QeVHLM=K;zE0A?!5esgnJcRquVj3jdj zK+&J3yk4*ejR!FCd*4QYs*D>rJ!K0n>Qhmh+ZT7|dh@zHo9*aE!SN6^!bzwcpl%Ux zHUqep3;Z<`xHo?XcrX`uG`|`s3I&*02&7ebaQNp0GBoh z>*kFGqqTpyQ9=-35x{m@hFxQU@2M|-rsb%jzPP}ely**8A}!abM;D7mq}l}#$vGg3 z3K1zPkiPe8>xkIkPN-f+jsMLUV9$6u|5Jcp>DEX+gY&dyuTd3Bqj0Mv8YiKdBcKm(76AHr<|qPCt5kgHpC+|TDpCB2DBB6OC2>giYYkn16EcH64=Aeu zCm1~~YpL{Va|N8N0IsfzHv=fHfRAX(GPE?dG-vYha<>AwvL=BC$RGe+Uk^XU0A_zP z3kXYdrZDXrRscsAMwtOp0=-(;3?M?Po9SKS{U~h0klDe)@AKwU#pP*xnVUe7Xg1p$YkG z8qM~8BFqHrC_bTsADcSja!!rQ6`=~@qs?ErKXw{vlV=FL};G^`gY*C*pvc@pj|A1;jOUy2VY zB0%ltWaJL^<^eLp)JXAnTW+&C3x4e0KUtjhgwAGXJ9|cW%pOuUC7Q?cGeyzJ8`6P{ z-3Y*gUOnd7WzGYz2af}({KJ0{RRNgp5E} zHs!Jox9fjM&yCCh>I>9RB(Kw{LF%%py<8*yRm0|Jj^=2N=J>zGKYBg|k4d(i$p8QV M07*qoM6N<$f>I54r~m)} delta 2003 zcmV;^2Q2ux4}}nrAOYc#AuN9YuFf3k000M@Nkl8HS&8W_EYh*Nt-_ zaRS6NAiF@S3MAwRL_i3MR4P>{v?W49L?X1MAh0N+wnS9zO0>8{Tq15Nq*4`7ibGpu znkGs}($-09aMRqJ)NL+}*LIxv65H#Y^?K*y$IN)gm&94eNc`|CecFHBv$N-Y&Ue0Z zX3j!DBGS$jiHOvR$kg_Emx#32v~c1#-AJHKK!nXMM4gCKi3n{X+&NEBZRy5+{_BP| zWMdm0K17v>5EEf}Aga6|J_$fX+NFDX24~ggb}qH08}~hYn&iW$k=TBOxR(Wgq<+)} zA^;#F?NTRwf{1iWyR?7YJcx>)bImN^ybarT0}ZISh%__+Z+cg*0~!*6pEjrofEHGTy4OCE-@3esi#im)u9#EX$&)8mb zT4)wG+Pokx(jp>_`G^yD-#3X!w-=4lo*5^oStM3(6YQ)q)FPP$u*A?cg>qb z5+ss-+`9RM;?sZDearIZ2{Yf^2PmXxQv{_HvlL5y$@yB>bC&{0kVvwEGe9-ng;;w4 zocT$goXsAlIC7Y9q?MB53jjE|EX6;%tdzPTTs`$GSx54*?#Iq}g;-VyfRgmDg|03r zk3u8_ArrI)ZM=hFZH8zT?6;KKGJ2zq{M6S|zp^j@*&%N_K1sJkK}Aqa<{*n*NM zltf@z8NAR6<72txQ0CE9-}(D5<_xd_ODt?`uVH@xi%hw}nmbmJ*tC{4t1G}XAsU9V zBCx_>C@8hyA4eG$&87FQmVR{W!I8NDXaGA9QEXz@Qgj?X%Y6-d`PGYWyVHu|{I9L+%{c*dd&a)fURXfn$~B(+^D!RW_L^H0*<8Lhl%nj850V_8vIP_qVsgcrIU<2!u^Watg`i&`LLnw^j=V2+E&| z9?K$TySXV(+dTi$3I6i(+wN2Vpg^E(^>S=`3m{e+v@$nptJB zf<|`0JeZL@jm@t89c~7EnVQNa<&2~Nlk$?(vq4|Go<0A|{&iOnr86fN($^AQQHj97K7U|45hgvT( zY>#pL#5q*h1Z|8erM~(2p5$}4YVHDP4Tg~~vQ&nB|Gq#DAqRB4+l4YU+BCs5cRJ`_ zCiZl`F(2jtYWo8A%vWw)^wq?2`Zh002ovPDHLkV1f!z%`*T1 diff --git a/mods/character-select-coop/textures/char-select-luigi-meter-left.tex b/mods/character-select-coop/textures/char-select-luigi-meter-left.tex new file mode 100644 index 0000000000000000000000000000000000000000..08c1512664bf44dafc6d663ea0392c5711d1bbcc GIT binary patch literal 2256 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 literal 0 HcmV?d00001 diff --git a/mods/character-select-coop/textures/char-select-toad-meter-right.tex b/mods/character-select-coop/textures/char-select-toad-meter-right.tex new file mode 100644 index 0000000000000000000000000000000000000000..b796d4495bc125123ffd3a1e7c492516d38d4164 GIT binary patch literal 1963 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 TwX&aI00000NkvXXu0mjfmvpJg literal 0 HcmV?d00001 diff --git a/mods/character-select-coop/textures/char-select-wario-meter-left.tex b/mods/character-select-coop/textures/char-select-wario-meter-left.tex new file mode 100644 index 0000000000000000000000000000000000000000..c3624267331dbf077e83437ae34bb644acee8a5d GIT binary patch literal 2488 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 P00000NkvXXu0mjfcsmL% literal 0 HcmV?d00001 diff --git a/mods/character-select-coop/z-moveset.lua b/mods/character-select-coop/z-moveset.lua index 2c43ca53e..ea5bc9087 100644 --- a/mods/character-select-coop/z-moveset.lua +++ b/mods/character-select-coop/z-moveset.lua @@ -162,4 +162,13 @@ local function object_render(obj) if currMoveset == nil or currMoveset[hook] == nil then return end return currMoveset[hook](obj) end -hook_event(HOOK_ON_OBJECT_RENDER, object_render) \ No newline at end of file +hook_event(HOOK_ON_OBJECT_RENDER, object_render) + +local function allow_water_action(m, water) + if stopMovesets or not gCSPlayers[0].movesetToggle then return end + local hook = HOOK_ALLOW_FORCE_WATER_ACTION + local currMoveset = characterMovesets[find_character_number(0)] + if currMoveset == nil or currMoveset[hook] == nil then return end + return currMoveset[hook](m, water) +end +hook_event(HOOK_ALLOW_FORCE_WATER_ACTION, allow_water_action) \ No newline at end of file diff --git a/mods/character-select-coop/z-palettes.lua b/mods/character-select-coop/z-palettes.lua index 50a70ab2a..2300dd070 100644 --- a/mods/character-select-coop/z-palettes.lua +++ b/mods/character-select-coop/z-palettes.lua @@ -74,14 +74,6 @@ characterColorPresets = { } } -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][1] local function network_player_set_full_override_palette(networkPlayer, colorTable) diff --git a/mods/character-select-coop/z-voice.lua b/mods/character-select-coop/z-voice.lua index c71842345..8a9c353cb 100644 --- a/mods/character-select-coop/z-voice.lua +++ b/mods/character-select-coop/z-voice.lua @@ -83,7 +83,7 @@ end --- @param sound CharacterSound local function custom_character_sound(m, sound) if m.playerIndex == 0 then - if stallTimer < stallSayLine - 1 then + if stallTimer < stallSayLine then return NO_SOUND end end @@ -204,7 +204,8 @@ _G.charSelect.voice = { -- Must be ran on startup local function config_character_sounds() hook_event(HOOK_CHARACTER_SOUND, custom_character_sound) - hook_event(HOOK_MARIO_UPDATE, custom_character_snore) + --hook_event(HOOK_MARIO_UPDATE, custom_character_snore) + cs_hook_mario_update(custom_character_snore) end _G.charSelect.config_character_sounds = config_character_sounds @@ -218,4 +219,5 @@ local function mario_update(m) stallTimer = stallTimer + 1 end end -hook_event(HOOK_MARIO_UPDATE, mario_update) \ No newline at end of file +--hook_event(HOOK_MARIO_UPDATE, mario_update) +cs_hook_mario_update(mario_update) \ No newline at end of file