diff --git a/mods/character-select-coop/a-font-handler.lua b/mods/character-select-coop/a-font-handler.lua new file mode 100644 index 000000000..e5e7f2f48 --- /dev/null +++ b/mods/character-select-coop/a-font-handler.lua @@ -0,0 +1,353 @@ +--[[ + Custom Font Handler v1 - By Squishy6094 + + This file adds custom font functionality, and does not need to be edited + Ensure this file is loaded before anything else (make the file name start with a or !) + Use djui_hud_add_font() to add fonts as shown in main.lua +]] + +FONT_HANDLER_VERSION_MAJOR = 1 +FONT_HANDLER_VERSION_MINOR = 0 +FONT_HANDLER_VERSION = "v"..FONT_HANDLER_VERSION_MAJOR.."."..FONT_HANDLER_VERSION_MINOR + +local djui_classic_hud_set_font = djui_hud_set_font +local djui_classic_hud_print_text = djui_hud_print_text +local djui_classic_hud_print_text_interpolated = djui_hud_print_text_interpolated +local djui_classic_hud_measure_text = djui_hud_measure_text + +local customFont = false + +local fontTable = {} + +CUSTOM_FONT_COUNT = FONT_COUNT +local customFontType = FONT_NORMAL + +local latinChars = { + [32] = " ", [33] = "!", [34] = "\"", [35] = "#", [36] = "$", [37] = "%", [38] = "&", [39] = "'", + [40] = "(", [41] = ")", [42] = "*", [43] = "+", [44] = ",", [45] = "-", [46] = ".", [47] = "/", + [48] = "0", [49] = "1", [50] = "2", [51] = "3", [52] = "4", [53] = "5", [54] = "6", [55] = "7", + [56] = "8", [57] = "9", [58] = ":", [59] = ";", [60] = "<", [61] = "=", [62] = ">", [63] = "?", + [64] = "@", [65] = "A", [66] = "B", [67] = "C", [68] = "D", [69] = "E", [70] = "F", [71] = "G", + [72] = "H", [73] = "I", [74] = "J", [75] = "K", [76] = "L", [77] = "M", [78] = "N", [79] = "O", + [80] = "P", [81] = "Q", [82] = "R", [83] = "S", [84] = "T", [85] = "U", [86] = "V", [87] = "W", + [88] = "X", [89] = "Y", [90] = "Z", [91] = "[", [92] = "\\", [93] = "]", [94] = "^", [95] = "_", + [96] = "`", [97] = "a", [98] = "b", [99] = "c", [100] = "d", [101] = "e", [102] = "f", [103] = "g", + [104] = "h", [105] = "i", [106] = "j", [107] = "k", [108] = "l", [109] = "m", [110] = "n", [111] = "o", + [112] = "p", [113] = "q", [114] = "r", [115] = "s", [116] = "t", [117] = "u", [118] = "v", [119] = "w", + [120] = "x", [121] = "y", [122] = "z", [123] = "{", [124] = "|", [125] = "}", [126] = "~", + -- Latin-1 Supplement + [160] = " ", [161] = "¡", [162] = "¢", [163] = "£", [164] = "¤", [165] = "¥", [166] = "¦", [167] = "§", + [168] = "¨", [169] = "©", [170] = "ª", [171] = "«", [172] = "¬", [173] = "­", [174] = "®", [175] = "¯", + [176] = "°", [177] = "±", [178] = "²", [179] = "³", [180] = "´", [181] = "µ", [182] = "¶", [183] = "·", + [184] = "¸", [185] = "¹", [186] = "º", [187] = "»", [188] = "¼", [189] = "½", [190] = "¾", [191] = "¿", + [192] = "À", [193] = "Á", [194] = "Â", [195] = "Ã", [196] = "Ä", [197] = "Å", [198] = "Æ", [199] = "Ç", + [200] = "È", [201] = "É", [202] = "Ê", [203] = "Ë", [204] = "Ì", [205] = "Í", [206] = "Î", [207] = "Ï", + [208] = "Ð", [209] = "Ñ", [210] = "Ò", [211] = "Ó", [212] = "Ô", [213] = "Õ", [214] = "Ö", [215] = "×", + [216] = "Ø", [217] = "Ù", [218] = "Ú", [219] = "Û", [220] = "Ü", [221] = "Ý", [222] = "Þ", [223] = "ß", + [224] = "à", [225] = "á", [226] = "â", [227] = "ã", [228] = "ä", [229] = "å", [230] = "æ", [231] = "ç", + [232] = "è", [233] = "é", [234] = "ê", [235] = "ë", [236] = "ì", [237] = "í", [238] = "î", [239] = "ï", + [240] = "ð", [241] = "ñ", [242] = "ò", [243] = "ó", [244] = "ô", [245] = "õ", [246] = "ö", [247] = "÷", + [248] = "ø", [249] = "ù", [250] = "ú", [251] = "û", [252] = "ü", [253] = "ý", [254] = "þ", [255] = "ÿ" +} + +local HudAnimTimer = 0 + +local function convert_unicode_table_to_string_table(input) + local output = {} + for i = 1, #input do + local letter = input[i] + if letter ~= nil and latinChars[letter.id] ~= nil then + output[latinChars[letter.id]] = letter + end + end + return output +end + +local function string_to_table(str) + local charArray = {}; + local iStart = 0; + local strLen = str:len(); + local function bit(b) + return 2 ^ (b - 1); + end + local function hasbit(w, b) + return w % (b + b) >= b + end + local checkMultiByte = function(i) + if (iStart ~= 0) then + charArray[#charArray + 1] = str:sub(iStart, i - 1) + iStart = 0 + end + end + for i = 1, strLen do + local b = str:byte(i) + local multiStart = hasbit(b, bit(7)) and hasbit(b, bit(8)) + local multiTrail = not hasbit(b, bit(7)) and hasbit(b, bit(8)) + if (multiStart) then + checkMultiByte(i) + iStart = i + elseif (not multiTrail) then + checkMultiByte(i) + charArray[#charArray + 1] = str:sub(i, i) + end + end + return charArray +end + +---@param texture TextureInfo +---@param info table +---@param spacing integer +---@param offset integer +---@param backup string +---@param scale integer +---@return DjuiFontType +function djui_hud_add_font(texture, info, spacing, offset, backup, scale) + if texture == nil then return FONT_NORMAL end + if info == nil then return FONT_NORMAL end + if spacing == nil then spacing = 1 end + if offset == nil then offset = 0 end + if backup == nil then backup = "x" end + if scale == nil then scale = 1 end + if info[1] ~= nil and info[1].id ~= nil then + info = convert_unicode_table_to_string_table(info) + end + CUSTOM_FONT_COUNT = CUSTOM_FONT_COUNT + 1 + fontTable[CUSTOM_FONT_COUNT] = { + spritesheet = texture, + spacing = spacing, + offset = offset, + info = info, + backup = backup, + scale = scale, + } + return CUSTOM_FONT_COUNT +end + +---@param fontType DjuiFontType +---@return nil +function djui_hud_set_font(fontType) + if fontType > FONT_COUNT then + customFont = true + customFontType = fontType + else + customFont = false + djui_classic_hud_set_font(fontType) + end +end + +local textShake = 0 +function djui_hud_effect_shake(intensity) + textShake = math.ceil(intensity*100)*0.01 +end + +local textWaveX = 0 +local textWaveY = 0 +local textWaveSpeed = 0 +function djui_hud_effect_wave(x, y, speed) + textWaveX = x + textWaveY = y + textWaveSpeed = speed +end + +---@param message string +---@param x number +---@param y number +---@param scale number +---@return nil +function djui_hud_print_text(message, x, y, scale) + if customFont then + if message == nil or message == "" then return end + local message = string_to_table(message) + local currFont = fontTable[customFontType] + y = y + currFont.offset + scale = scale*currFont.scale + for i = 1, #message do + local letter = message[i] + if letter and letter ~= " " then + if currFont.info[letter] == nil then + letter = currFont.backup + end + local scaleWidth = scale*(currFont.info[letter].height/currFont.info[letter].width) + djui_hud_render_texture_tile(currFont.spritesheet, + x + ((currFont.info[letter].xoffset or 0)*scale) + math.random(-textShake*100, textShake*100)*0.01 + math.sin((HudAnimTimer+i*2)*textWaveSpeed*0.1)*textWaveX, + y + ((currFont.info[letter].yoffset or 0)*scale) + math.random(-textShake*100, textShake*100)*0.01 + math.cos((HudAnimTimer+i*2)*textWaveSpeed*0.1)*textWaveY, + scaleWidth, scale, + currFont.info[letter].x, + currFont.info[letter].y, + currFont.info[letter].width, + currFont.info[letter].height) + else + letter = currFont.backup + end + x = x + (currFont.info[letter].width + currFont.spacing)*scale + end + else + djui_classic_hud_print_text(message, x, y, scale) + end +end + +---@param message string +---@param prevX number +---@param prevY number +---@param prevScale number +---@param x number +---@param y number +---@param scale number +---@return nil +-- Custom Fonts do not currently support Interpolation due to lack of RESOLUTION_N64 support +function djui_hud_print_text_interpolated(message, prevX, prevY, prevScale, x, y, scale) + if customFont then + if message == nil or message == "" then return end + local message = string_to_table(message) + local currFont = fontTable[customFontType] + prevY = prevY + currFont.offset + y = y + currFont.offset + scale = scale*currFont.scale + for i = 1, #message do + local letter = message[i] + if letter and letter ~= " " then + if currFont.info[letter] == nil then + letter = currFont.backup + end + local prevScaleWidth = prevScale*(currFont.info[letter].height/currFont.info[letter].width) + local scaleWidth = scale*(currFont.info[letter].height/currFont.info[letter].width) + local xOffset = ((currFont.info[letter].xoffset or 0)*scale) + math.random(-textShake*100, textShake*100)*0.01 + math.sin((HudAnimTimer+i*2)*textWaveSpeed*0.1)*textWaveX + local yOffset = ((currFont.info[letter].yoffset or 0)*scale) + math.random(-textShake*100, textShake*100)*0.01 + math.cos((HudAnimTimer+i*2)*textWaveSpeed*0.1)*textWaveY + djui_hud_render_texture_tile_interpolated(currFont.spritesheet, + prevX + xOffset, + prevY + yOffset, + prevScaleWidth, prevScale, + x + xOffset, + y + yOffset, + scaleWidth, scale, + currFont.info[letter].x, + currFont.info[letter].y, + currFont.info[letter].width, + currFont.info[letter].height) + else + letter = currFont.backup + end + x = x + (currFont.info[letter].width + currFont.spacing)*scale + prevX = prevX + (currFont.info[letter].width + currFont.spacing)*prevScale + end + else + djui_classic_hud_print_text_interpolated(message, prevX, prevY, prevScale, x, y, scale) + end +end + +---@param message string +---@return number +function djui_hud_measure_text(message) + if customFont then + if message == nil or message == "" then return end + local message = string_to_table(message) + local currFont = fontTable[customFontType] + local scale = 1 + local x = 0 + for i = 1, #message do + local letter = message[i] + if letter and letter ~= " " then + if currFont.info[letter] == nil then + letter = currFont.backup + end + else + letter = currFont.backup + end + x = x + (currFont.info[letter].width + currFont.spacing)*scale + end + return x + else + return djui_classic_hud_measure_text(message) + end +end + +local function hud_update() + -- Reset Values Every Frame + textShake = 0 + textWaveX = 0 + textWaveY = 0 + textWaveSpeed = 0 + + -- Update Basic Anim Timer + HudAnimTimer = HudAnimTimer + 1 +end + +hook_event(HOOK_ON_HUD_RENDER_BEHIND, hud_update) + +-- Adding custom fonts here to prevent main clutter +fontdataCharacteristic = { + ["A"] = {x = 0, y = 0, width = 26, height = 32}, + ["B"] = {x = 32, y = 0, width = 25, height = 32}, + ["C"] = {x = 32*2, y = 0, width = 25, height = 32}, + ["D"] = {x = 32*3, y = 0, width = 23, height = 32}, + ["E"] = {x = 32*4, y = 0, width = 24, height = 32}, + ["F"] = {x = 32*5, y = 0, width = 24, height = 32}, + ["G"] = {x = 32*6, y = 0, width = 26, height = 32}, + ["H"] = {x = 32*7, y = 0, width = 25, height = 32}, + + ["I"] = {x = 0, y = 32, width = 15, height = 32}, + ["J"] = {x = 32, y = 32, width = 21, height = 32}, + ["K"] = {x = 32*2, y = 32, width = 25, height = 32}, + ["L"] = {x = 32*3, y = 32, width = 22, height = 32}, + ["M"] = {x = 32*4, y = 32, width = 29, height = 32}, + ["N"] = {x = 32*5, y = 32, width = 27, height = 32}, + ["Ñ"] = {x = 32*6, y = 32, width = 27, height = 32}, + ["O"] = {x = 32*7, y = 32, width = 26, height = 32}, + + ["P"] = {x = 0, y = 32*2, width = 25, height = 32}, + ["Q"] = {x = 32, y = 32*2, width = 27, height = 32}, + ["R"] = {x = 32*2, y = 32*2, width = 25, height = 32}, + ["S"] = {x = 32*3, y = 32*2, width = 24, height = 32}, + ["T"] = {x = 32*4, y = 32*2, width = 28, height = 32}, + ["U"] = {x = 32*5, y = 32*2, width = 26, height = 32}, + ["V"] = {x = 32*6, y = 32*2, width = 27, height = 32}, + ["W"] = {x = 32*7, y = 32*2, width = 30, height = 32}, + + ["X"] = {x = 0, y = 32*3, width = 28, height = 32}, + ["Y"] = {x = 32, y = 32*3, width = 27, height = 32}, + ["Z"] = {x = 32*2, y = 32*3, width = 27, height = 32}, + ["!"] = {x = 32*3, y = 32*3, width = 30, height = 32}, + ["?"] = {x = 32*4, y = 32*3, width = 27, height = 32}, + ["@"] = {x = 32*5, y = 32*3, width = 29, height = 32}, + ["#"] = {x = 32*6, y = 32*3, width = 29, height = 32}, + ["$"] = {x = 32*7, y = 32*3, width = 23, height = 32}, + + ["%"] = {x = 0, y = 32*4, width = 27, height = 32}, + ["^"] = {x = 32, y = 32*4, width = 24, height = 32}, + ["&"] = {x = 32*2, y = 32*4, width = 29, height = 32}, + ["*"] = {x = 32*3, y = 32*4, width = 18, height = 32}, + ["("] = {x = 32*4, y = 32*4, width = 17, height = 32}, + [")"] = {x = 32*5, y = 32*4, width = 17, height = 32}, + ["_"] = {x = 32*6, y = 32*4, width = 31, height = 32}, + ["-"] = {x = 32*7, y = 32*4, width = 23, height = 32}, + + ["+"] = {x = 0, y = 32*5, width = 24, height = 32}, + ["="] = {x = 32, y = 32*5, width = 27, height = 32}, + ["<"] = {x = 32*2, y = 32*5, width = 23, height = 32}, + [">"] = {x = 32*3, y = 32*5, width = 23, height = 32}, + ["."] = {x = 32*4, y = 32*5, width = 11, height = 32}, + [","] = {x = 32*5, y = 32*5, width = 11, height = 32}, + [":"] = {x = 32*6, y = 32*5, width = 11, height = 32}, + [";"] = {x = 32*7, y = 32*5, width = 11, height = 32}, + + ["/"] = {x = 0, y = 32*6, width = 28, height = 32}, + ["\\"] = {x = 32, y = 32*6, width = 28, height = 32}, + ['"'] = {x = 32*2, y = 32*6, width = 14, height = 32}, + ["'"] = {x = 32*3, y = 32*6, width = 9, height = 32}, + ["|"] = {x = 32*4, y = 32*6, width = 10, height = 32}, + ["~"] = {x = 32*5, y = 32*6, width = 23, height = 32}, + ["1"] = {x = 32*6, y = 32*6, width = 23, height = 32}, + ["2"] = {x = 32*7, y = 32*6, width = 26, height = 32}, + + ["3"] = {x = 0, y = 32*7, width = 24, height = 32}, + ["4"] = {x = 32, y = 32*7, width = 24, height = 32}, + ["5"] = {x = 32*2, y = 32*7, width = 26, height = 32}, + ["6"] = {x = 32*3, y = 32*7, width = 26, height = 32}, + ["7"] = {x = 32*4, y = 32*7, width = 30, height = 32}, + ["8"] = {x = 32*5, y = 32*7, width = 22, height = 32}, + ["9"] = {x = 32*6, y = 32*7, width = 24, height = 32}, + ["0"] = {x = 32*7, y = 32*7, width = 24, height = 32}, + +} + +FONT_CHARACTERISTIC = djui_hud_add_font(get_texture_info("char_select_font_characteristic"), fontdataCharacteristic, -5, 0, "X", 1) \ No newline at end of file diff --git a/mods/character-select-coop/a-github.lua b/mods/character-select-coop/a-github.lua deleted file mode 100644 index 86039f611..000000000 --- a/mods/character-select-coop/a-github.lua +++ /dev/null @@ -1,3 +0,0 @@ -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-supporters.lua b/mods/character-select-coop/a-supporters.lua new file mode 100644 index 000000000..f3547551b --- /dev/null +++ b/mods/character-select-coop/a-supporters.lua @@ -0,0 +1,15 @@ +CREDIT_SUPPORTERS = { + "Saul", + "Ellie", + "Lyrae", + "Sophia", + "maemae", + "charity", + "FunkyLion", + "VioletArts", + "Nope208", + "Jack Black", + "GRAND DAD", + "Key's Artworks", + "Kale!", +} \ No newline at end of file diff --git a/mods/character-select-coop/a-utils.lua b/mods/character-select-coop/a-utils.lua index a2743c1f7..ef06fd13c 100644 --- a/mods/character-select-coop/a-utils.lua +++ b/mods/character-select-coop/a-utils.lua @@ -1,68 +1,22 @@ --- 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_MAJOR = 16 +MOD_VERSION_MINOR = 0 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 - return 0 -end - -local dependacyFiles = { - -- Required Lua File - --"a-github.lua", - "dialog.lua", - "main.lua", - "n-hud.lua", - "o-api.lua", - "z-moveset.lua", - "z-palettes.lua", - "z-voice.lua", - -- Required Actors - "actors/armature_geo.bin", -} -local legacyFiles = { - "voice.lua", - "palettes.lua", - "z-anims.lua", -} - -local fileErrorList = {} - --- Check for Missing Files -for i = 1, #dependacyFiles do - if not mod_file_exists(dependacyFiles[i]) then - log_to_console("Character Select file missing: '" .. dependacyFiles[i] .. "'", CONSOLE_MESSAGE_WARNING) - table_insert(fileErrorList, "Missing File '" .. dependacyFiles[i] .. "'") - end -end --- Check for Legacy Files -for i = 1, #legacyFiles do - if mod_file_exists(legacyFiles[i]) then - log_to_console("Character Select legacy file found: '" .. legacyFiles[i] .. "'", CONSOLE_MESSAGE_WARNING) - table_insert(fileErrorList, "Legacy File '" .. legacyFiles[i] .. "'") - end -end -if #fileErrorList > 0 then +-- Check CoopDX Version +VERSION_REQUIRED = 41 +if VERSION_NUMBER < VERSION_REQUIRED 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!" + djui_popup_create("\n\\#FFAAAA\\Character Select requires\n the latest version of CoopDX to use!\n\nYou can find CoopDX here:\n\\#AAAAFF\\https://sm64coopdx.com", 5) + djui_chat_message_create("\\#FFAAAA\\Character Select Version Issue:\nVersion " .. tostring(VERSION_NUMBER) .. " < " .. tostring(VERSION_REQUIRED)) + local errorString = "\\#FFAAAA\\The best way to resolve this issue is to reinstall SM64CoopDX from the Offical Site or Github Repo!\n\\#AAAAFF\\https://sm64coopdx.com/\nhttps://github.com/coop-deluxe/sm64coopdx/" log_to_console(errorString) djui_chat_message_create(errorString) end @@ -70,6 +24,132 @@ if #fileErrorList > 0 then return 0 end +log_to_console("Character Select "..MOD_VERSION_STRING) + +local dependacyFiles = { + --- Required Lua Files + "a-font-handler.lua", + "anims.lua", + "dialog.lua", + "hud.lua", + "main.lua", + "moveset.lua", + "palettes.lua", + "voice.lua", + "z-api.lua", + + -- Required Texture Files + "textures/char_select_album_back.tex", + "textures/char_select_album_front.tex", + "textures/char_select_album_overlay.tex", + "textures/char_select_category.tex", + "textures/char_select_caution_tape.tex", + "textures/char_select_cd_layer1.tex", + "textures/char_select_cd_layer2.tex", + "textures/char_select_cd_layer3.tex", + "textures/char_select_cd_layer4.tex", + "textures/char_select_custom_course_bottom.tex", + "textures/char_select_custom_course_top.tex", + "textures/char_select_custom_meter_left.tex", + "textures/char_select_custom_meter_pie1.tex", + "textures/char_select_custom_meter_pie2.tex", + "textures/char_select_custom_meter_pie3.tex", + "textures/char_select_custom_meter_pie4.tex", + "textures/char_select_custom_meter_pie5.tex", + "textures/char_select_custom_meter_pie6.tex", + "textures/char_select_custom_meter_pie7.tex", + "textures/char_select_custom_meter_pie8.tex", + "textures/char_select_custom_meter_right.tex", + "textures/char_select_font_brick.tex", + "textures/char_select_font_characteristic.tex", + "textures/char_select_gear.tex", + "textures/char_select_graffiti_default.tex", + "textures/char_select_graffiti_luigi.tex", + "textures/char_select_graffiti_mario.tex", + "textures/char_select_graffiti_toad.tex", + "textures/char_select_graffiti_waluigi.tex", + "textures/char_select_graffiti_wario.tex", + "textures/char_select_icon_signs.tex", + "textures/char_select_list_button.tex", + "textures/char_select_logo.tex", + "textures/char_select_luigi_meter_left.tex", + "textures/char_select_luigi_meter_right.tex", + "textures/char_select_nameplate.tex", + "textures/char_select_options_tv.tex", + "textures/char_select_palette_bucket.tex", + "textures/char_select_record.tex", + "textures/char_select_toad_meter_left.tex", + "textures/char_select_toad_meter_right.tex", + "textures/char_select_wall_left.tex", + "textures/char_select_wall_right.tex", + "textures/char_select_waluigi_meter_left.tex", + "textures/char_select_waluigi_meter_right.tex", + "textures/char_select_wario_meter_left.tex", + "textures/char_select_wario_meter_right.tex", +} +local legacyFiles = { + "z-anims.lua", + "n-hud.lua", + "o-api.lua", + "z-moveset.lua", + "z-palettes.lua", + "z-voice.lua", +} + +local fileErrorList = {} + +if network_is_server() then + -- Check for Missing Files + for i = 1, #dependacyFiles do + if not mod_file_exists(dependacyFiles[i]) then + log_to_console("Character Select file missing: '" .. dependacyFiles[i] .. "'", CONSOLE_MESSAGE_WARNING) + table.insert(fileErrorList, "Missing File '" .. dependacyFiles[i] .. "'") + end + end + -- Check for Legacy Files + for i = 1, #legacyFiles do + if mod_file_exists(legacyFiles[i]) then + log_to_console("Character Select legacy file found: '" .. legacyFiles[i] .. "'", CONSOLE_MESSAGE_WARNING) + table.insert(fileErrorList, "Legacy File '" .. legacyFiles[i] .. "'") + end + end + 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 + log_to_console(errorString) + djui_chat_message_create(errorString) + + errorString = "\\#FFAAAA\\The best way to resolve these issues is to delete your current version of Character Select and then install the latest version from the Github Repo!\n\\#AAAAFF\\https://github.com/Squishy6094/character-select-coop/\\#FFAAAA\\" + log_to_console(errorString) + djui_chat_message_create(errorString) + end + end) + return 0 + end +end + +-- Failsafe printing nil text +local djui_hud_print_text_original = djui_hud_print_text +function djui_hud_print_text(string, x, y, scale) + djui_hud_print_text_original(tostring(string), x, y, scale) +end + +local string_sub = string.sub +function djui_hud_print_monospace_text(string, x, y, scale, space) + space = space or 16 + for i = 1, #string do + djui_hud_print_text(string_sub(string, i, i), x + space*(i - 1)*scale, y, scale) + end +end + ommActive = false for i in pairs(gActiveMods) do if gActiveMods[i].relativePath == "omm-coop" then @@ -78,8 +158,6 @@ for i in pairs(gActiveMods) do end end -E_MODEL_ARMATURE = smlua_model_util_get_id("armature_geo") - local saveableCharacters = { ["1"] = 1, ["2"] = 1, @@ -125,44 +203,44 @@ local saveableCharacters = { [" "] = 0, } ---- @param string string +---@param string string --- Replaces underscores in the string with spaces function string_underscore_to_space(string) if string == nil then return "" end return string:gsub("_", " ") end ---- @param string string +---@param string string --- Constructs a new string but only with characters from `saveableCharacters` --- * Spaces are the notable character that gets turned into an underscore function string_space_to_underscore(string) local s = '' for i = 1, #string do local c = string:sub(i,i) - if saveableCharacters[string_lower(c)] == 1 then + if saveableCharacters[string.lower(c)] == 1 then s = s .. c - elseif saveableCharacters[string_lower(c)] == 0 then + elseif saveableCharacters[string.lower(c)] == 0 then s = s .. "_" end end return s end ---- @param string string +---@param string string --- Splits a string into a table by spaces function string_split(string, splitAt) if splitAt == nil then splitAt = " " end local result = {} - for match in string:gmatch(string_format("[^%s]+", splitAt)) do - table_insert(result, match) + for match in string:gmatch(string.format("[^%s]+", splitAt)) do + table.insert(result, match) end return result end ---- @param param number ---- @param caseTable table +---@param param number +---@param caseTable table --- Switch statement function function switch(param, caseTable) local case = caseTable[param] @@ -171,17 +249,52 @@ function switch(param, caseTable) return def and def() or nil end -function clamp(num, min, max) - return math.max(math.min(num, max), min) +---@param s string +---@param v any +--- Defines a global variable by name `s` with the value `v` and indexes it if it already exists +function define_valid_global(s, v) + local name = s + local index = 1 + + while _G[name] ~= nil do + name = s .. "_" .. index + index = index + 1 + end + + _G[name] = v +end + +---@param n integer +---@return boolean +function num_power_of_two(n) + return n ~= 0 and (n & (n - 1)) == 0 +end + +function angle_from_2d_points(x1, y1, x2, y2) + return atan2s(y2 - y1, x2 - x1) - 0x4000 +end + +function hash(word) + local result = 5381 + for i = 1, #word do + result = (result << 5) + result + word:byte(i) + end + return result end function lerp(a, b, t) return a * (1 - t) + b * t end +function num_wrap(num, min, max) + if num > max then num = min end + if num < min then num = max end + return num +end + allowMenu = {} -renderInMenuTable = { +hookTableRenderInMenu = { front = {}, back = {}, } @@ -190,18 +303,13 @@ queueStorageFailsafe = false charBeingSet = false -stopPalettes = false -for i in pairs(gActiveMods) do - if (gActiveMods[i].incompatible ~= nil and gActiveMods[i].incompatible:find("gamemode")) and not (gActiveMods[i].name:find("Personal Star Counter")) then - stopPalettes = true - end -end - -stopMovesets = false +gGlobalSyncTable.charSelectRestrictPalettes = 0 +gGlobalSyncTable.charSelectRestrictMovesets = 0 seasonalEvent = 0 SEASON_EVENT_BIRTHDAY = 1 SEASON_EVENT_CHRISTMAS = 2 +SEASON_EVENT_FOOLS = 2 -- December if get_date_and_time().month == 11 then if get_date_and_time().day == 3 then @@ -211,6 +319,8 @@ if get_date_and_time().month == 11 then -- Christmas seasonalEvent = SEASON_EVENT_CHRISTMAS end +elseif get_date_and_time().month == 4 and get_date_and_time().month == 1 then + seasonalEvent = SEASON_EVENT_FOOLS end -- Dedicated Networking Table for Character Select @@ -222,8 +332,9 @@ for i = 0, MAX_PLAYERS - 1 do currAlt = 1, presetPalette = 0, offset = 0, - forceChar = 0, + baseChar = 0, modelId = E_MODEL_MARIO, + prevModelId = E_MODEL_MARIO, isUpdating = false, movesetToggle = true, modelEditOffset = 0, @@ -231,9 +342,24 @@ for i = 0, MAX_PLAYERS - 1 do } end +local stallFrame = 0 +local stallComplete = 3 +function startup_init_stall(framesBefore) + framesBefore = framesBefore or 0 + return stallFrame == (stallComplete - framesBefore) +end + local stallPacket = 0 -local function update() - stallPacket = (stallPacket+1)%3 -- refresh rate (to reduce stress) +local function network_update(m) + if m.playerIndex ~= 0 then return end + + -- Initialization Update + if stallFrame < stallComplete then + stallFrame = stallFrame + 1 + end + + -- Packet Refresh Rate + stallPacket = (stallPacket+1)%3 if stallPacket == 0 then network_send(false, gCSPlayers[0]) end @@ -245,4 +371,353 @@ local function on_packet_recieve(data) end hook_event(HOOK_ON_PACKET_RECEIVE, on_packet_recieve) -hook_event(HOOK_UPDATE, update) \ No newline at end of file +hook_event(HOOK_MARIO_UPDATE, network_update) + +-- Default Actions Check +local defaultActions = { + [ACT_UNINITIALIZED] = ACT_UNINITIALIZED, + [ACT_IDLE] = ACT_IDLE, + [ACT_START_SLEEPING] = ACT_START_SLEEPING, + [ACT_SLEEPING] = ACT_SLEEPING, + [ACT_WAKING_UP] = ACT_WAKING_UP, + [ACT_PANTING] = ACT_PANTING, + [ACT_HOLD_PANTING_UNUSED] = ACT_HOLD_PANTING_UNUSED, + [ACT_HOLD_IDLE] = ACT_HOLD_IDLE, + [ACT_HOLD_HEAVY_IDLE] = ACT_HOLD_HEAVY_IDLE, + [ACT_STANDING_AGAINST_WALL] = ACT_STANDING_AGAINST_WALL, + [ACT_COUGHING] = ACT_COUGHING, + [ACT_SHIVERING] = ACT_SHIVERING, + [ACT_IN_QUICKSAND] = ACT_IN_QUICKSAND, + [ACT_UNKNOWN_0002020E] = ACT_UNKNOWN_0002020E, + [ACT_CROUCHING] = ACT_CROUCHING, + [ACT_START_CROUCHING] = ACT_START_CROUCHING, + [ACT_STOP_CROUCHING] = ACT_STOP_CROUCHING, + [ACT_START_CRAWLING] = ACT_START_CRAWLING, + [ACT_STOP_CRAWLING] = ACT_STOP_CRAWLING, + [ACT_SLIDE_KICK_SLIDE_STOP] = ACT_SLIDE_KICK_SLIDE_STOP, + [ACT_SHOCKWAVE_BOUNCE] = ACT_SHOCKWAVE_BOUNCE, + [ACT_FIRST_PERSON] = ACT_FIRST_PERSON, + [ACT_BACKFLIP_LAND_STOP] = ACT_BACKFLIP_LAND_STOP, + [ACT_JUMP_LAND_STOP] = ACT_JUMP_LAND_STOP, + [ACT_DOUBLE_JUMP_LAND_STOP] = ACT_DOUBLE_JUMP_LAND_STOP, + [ACT_FREEFALL_LAND_STOP] = ACT_FREEFALL_LAND_STOP, + [ACT_SIDE_FLIP_LAND_STOP] = ACT_SIDE_FLIP_LAND_STOP, + [ACT_HOLD_JUMP_LAND_STOP] = ACT_HOLD_JUMP_LAND_STOP, + [ACT_HOLD_FREEFALL_LAND_STOP] = ACT_HOLD_FREEFALL_LAND_STOP, + [ACT_AIR_THROW_LAND] = ACT_AIR_THROW_LAND, + [ACT_TWIRL_LAND] = ACT_TWIRL_LAND, + [ACT_LAVA_BOOST_LAND] = ACT_LAVA_BOOST_LAND, + [ACT_TRIPLE_JUMP_LAND_STOP] = ACT_TRIPLE_JUMP_LAND_STOP, + [ACT_LONG_JUMP_LAND_STOP] = ACT_LONG_JUMP_LAND_STOP, + [ACT_GROUND_POUND_LAND] = ACT_GROUND_POUND_LAND, + [ACT_BRAKING_STOP] = ACT_BRAKING_STOP, + [ACT_BUTT_SLIDE_STOP] = ACT_BUTT_SLIDE_STOP, + [ACT_HOLD_BUTT_SLIDE_STOP] = ACT_HOLD_BUTT_SLIDE_STOP, + [ACT_WALKING] = ACT_WALKING, + [ACT_HOLD_WALKING] = ACT_HOLD_WALKING, + [ACT_TURNING_AROUND] = ACT_TURNING_AROUND, + [ACT_FINISH_TURNING_AROUND] = ACT_FINISH_TURNING_AROUND, + [ACT_BRAKING] = ACT_BRAKING, + [ACT_RIDING_SHELL_GROUND] = ACT_RIDING_SHELL_GROUND, + [ACT_HOLD_HEAVY_WALKING] = ACT_HOLD_HEAVY_WALKING, + [ACT_CRAWLING] = ACT_CRAWLING, + [ACT_BURNING_GROUND] = ACT_BURNING_GROUND, + [ACT_DECELERATING] = ACT_DECELERATING, + [ACT_HOLD_DECELERATING] = ACT_HOLD_DECELERATING, + [ACT_BEGIN_SLIDING] = ACT_BEGIN_SLIDING, + [ACT_HOLD_BEGIN_SLIDING] = ACT_HOLD_BEGIN_SLIDING, + [ACT_BUTT_SLIDE] = ACT_BUTT_SLIDE, + [ACT_STOMACH_SLIDE] = ACT_STOMACH_SLIDE, + [ACT_HOLD_BUTT_SLIDE] = ACT_HOLD_BUTT_SLIDE, + [ACT_HOLD_STOMACH_SLIDE] = ACT_HOLD_STOMACH_SLIDE, + [ACT_DIVE_SLIDE] = ACT_DIVE_SLIDE, + [ACT_MOVE_PUNCHING] = ACT_MOVE_PUNCHING, + [ACT_CROUCH_SLIDE] = ACT_CROUCH_SLIDE, + [ACT_SLIDE_KICK_SLIDE] = ACT_SLIDE_KICK_SLIDE, + [ACT_HARD_BACKWARD_GROUND_KB] = ACT_HARD_BACKWARD_GROUND_KB, + [ACT_HARD_FORWARD_GROUND_KB] = ACT_HARD_FORWARD_GROUND_KB, + [ACT_BACKWARD_GROUND_KB] = ACT_BACKWARD_GROUND_KB, + [ACT_FORWARD_GROUND_KB] = ACT_FORWARD_GROUND_KB, + [ACT_SOFT_BACKWARD_GROUND_KB] = ACT_SOFT_BACKWARD_GROUND_KB, + [ACT_SOFT_FORWARD_GROUND_KB] = ACT_SOFT_FORWARD_GROUND_KB, + [ACT_GROUND_BONK] = ACT_GROUND_BONK, + [ACT_DEATH_EXIT_LAND] = ACT_DEATH_EXIT_LAND, + [ACT_JUMP_LAND] = ACT_JUMP_LAND, + [ACT_FREEFALL_LAND] = ACT_FREEFALL_LAND, + [ACT_DOUBLE_JUMP_LAND] = ACT_DOUBLE_JUMP_LAND, + [ACT_SIDE_FLIP_LAND] = ACT_SIDE_FLIP_LAND, + [ACT_HOLD_JUMP_LAND] = ACT_HOLD_JUMP_LAND, + [ACT_HOLD_FREEFALL_LAND] = ACT_HOLD_FREEFALL_LAND, + [ACT_QUICKSAND_JUMP_LAND] = ACT_QUICKSAND_JUMP_LAND, + [ACT_HOLD_QUICKSAND_JUMP_LAND] = ACT_HOLD_QUICKSAND_JUMP_LAND, + [ACT_TRIPLE_JUMP_LAND] = ACT_TRIPLE_JUMP_LAND, + [ACT_LONG_JUMP_LAND] = ACT_LONG_JUMP_LAND, + [ACT_BACKFLIP_LAND] = ACT_BACKFLIP_LAND, + [ACT_JUMP] = ACT_JUMP, + [ACT_DOUBLE_JUMP] = ACT_DOUBLE_JUMP, + [ACT_TRIPLE_JUMP] = ACT_TRIPLE_JUMP, + [ACT_BACKFLIP] = ACT_BACKFLIP, + [ACT_STEEP_JUMP] = ACT_STEEP_JUMP, + [ACT_WALL_KICK_AIR] = ACT_WALL_KICK_AIR, + [ACT_SIDE_FLIP] = ACT_SIDE_FLIP, + [ACT_LONG_JUMP] = ACT_LONG_JUMP, + [ACT_WATER_JUMP] = ACT_WATER_JUMP, + [ACT_DIVE] = ACT_DIVE, + [ACT_FREEFALL] = ACT_FREEFALL, + [ACT_TOP_OF_POLE_JUMP] = ACT_TOP_OF_POLE_JUMP, + [ACT_BUTT_SLIDE_AIR] = ACT_BUTT_SLIDE_AIR, + [ACT_FLYING_TRIPLE_JUMP] = ACT_FLYING_TRIPLE_JUMP, + [ACT_SHOT_FROM_CANNON] = ACT_SHOT_FROM_CANNON, + [ACT_FLYING] = ACT_FLYING, + [ACT_RIDING_SHELL_JUMP] = ACT_RIDING_SHELL_JUMP, + [ACT_RIDING_SHELL_FALL] = ACT_RIDING_SHELL_FALL, + [ACT_VERTICAL_WIND] = ACT_VERTICAL_WIND, + [ACT_HOLD_JUMP] = ACT_HOLD_JUMP, + [ACT_HOLD_FREEFALL] = ACT_HOLD_FREEFALL, + [ACT_HOLD_BUTT_SLIDE_AIR] = ACT_HOLD_BUTT_SLIDE_AIR, + [ACT_HOLD_WATER_JUMP] = ACT_HOLD_WATER_JUMP, + [ACT_TWIRLING] = ACT_TWIRLING, + [ACT_FORWARD_ROLLOUT] = ACT_FORWARD_ROLLOUT, + [ACT_AIR_HIT_WALL] = ACT_AIR_HIT_WALL, + [ACT_RIDING_HOOT] = ACT_RIDING_HOOT, + [ACT_GROUND_POUND] = ACT_GROUND_POUND, + [ACT_SLIDE_KICK] = ACT_SLIDE_KICK, + [ACT_AIR_THROW] = ACT_AIR_THROW, + [ACT_JUMP_KICK] = ACT_JUMP_KICK, + [ACT_BACKWARD_ROLLOUT] = ACT_BACKWARD_ROLLOUT, + [ACT_CRAZY_BOX_BOUNCE] = ACT_CRAZY_BOX_BOUNCE, + [ACT_SPECIAL_TRIPLE_JUMP] = ACT_SPECIAL_TRIPLE_JUMP, + [ACT_BACKWARD_AIR_KB] = ACT_BACKWARD_AIR_KB, + [ACT_FORWARD_AIR_KB] = ACT_FORWARD_AIR_KB, + [ACT_HARD_FORWARD_AIR_KB] = ACT_HARD_FORWARD_AIR_KB, + [ACT_HARD_BACKWARD_AIR_KB] = ACT_HARD_BACKWARD_AIR_KB, + [ACT_BURNING_JUMP] = ACT_BURNING_JUMP, + [ACT_BURNING_FALL] = ACT_BURNING_FALL, + [ACT_SOFT_BONK] = ACT_SOFT_BONK, + [ACT_LAVA_BOOST] = ACT_LAVA_BOOST, + [ACT_GETTING_BLOWN] = ACT_GETTING_BLOWN, + [ACT_THROWN_FORWARD] = ACT_THROWN_FORWARD, + [ACT_THROWN_BACKWARD] = ACT_THROWN_BACKWARD, + [ACT_WATER_IDLE] = ACT_WATER_IDLE, + [ACT_HOLD_WATER_IDLE] = ACT_HOLD_WATER_IDLE, + [ACT_WATER_ACTION_END] = ACT_WATER_ACTION_END, + [ACT_HOLD_WATER_ACTION_END] = ACT_HOLD_WATER_ACTION_END, + [ACT_DROWNING] = ACT_DROWNING, + [ACT_BACKWARD_WATER_KB] = ACT_BACKWARD_WATER_KB, + [ACT_FORWARD_WATER_KB] = ACT_FORWARD_WATER_KB, + [ACT_WATER_DEATH] = ACT_WATER_DEATH, + [ACT_WATER_SHOCKED] = ACT_WATER_SHOCKED, + [ACT_BREASTSTROKE] = ACT_BREASTSTROKE, + [ACT_SWIMMING_END] = ACT_SWIMMING_END, + [ACT_FLUTTER_KICK] = ACT_FLUTTER_KICK, + [ACT_HOLD_BREASTSTROKE] = ACT_HOLD_BREASTSTROKE, + [ACT_HOLD_SWIMMING_END] = ACT_HOLD_SWIMMING_END, + [ACT_HOLD_FLUTTER_KICK] = ACT_HOLD_FLUTTER_KICK, + [ACT_WATER_SHELL_SWIMMING] = ACT_WATER_SHELL_SWIMMING, + [ACT_WATER_THROW] = ACT_WATER_THROW, + [ACT_WATER_PUNCH] = ACT_WATER_PUNCH, + [ACT_WATER_PLUNGE] = ACT_WATER_PLUNGE, + [ACT_CAUGHT_IN_WHIRLPOOL] = ACT_CAUGHT_IN_WHIRLPOOL, + [ACT_METAL_WATER_STANDING] = ACT_METAL_WATER_STANDING, + [ACT_HOLD_METAL_WATER_STANDING] = ACT_HOLD_METAL_WATER_STANDING, + [ACT_METAL_WATER_WALKING] = ACT_METAL_WATER_WALKING, + [ACT_HOLD_METAL_WATER_WALKING] = ACT_HOLD_METAL_WATER_WALKING, + [ACT_METAL_WATER_FALLING] = ACT_METAL_WATER_FALLING, + [ACT_HOLD_METAL_WATER_FALLING] = ACT_HOLD_METAL_WATER_FALLING, + [ACT_METAL_WATER_FALL_LAND] = ACT_METAL_WATER_FALL_LAND, + [ACT_HOLD_METAL_WATER_FALL_LAND] = ACT_HOLD_METAL_WATER_FALL_LAND, + [ACT_METAL_WATER_JUMP] = ACT_METAL_WATER_JUMP, + [ACT_HOLD_METAL_WATER_JUMP] = ACT_HOLD_METAL_WATER_JUMP, + [ACT_METAL_WATER_JUMP_LAND] = ACT_METAL_WATER_JUMP_LAND, + [ACT_HOLD_METAL_WATER_JUMP_LAND] = ACT_HOLD_METAL_WATER_JUMP_LAND, + [ACT_DISAPPEARED] = ACT_DISAPPEARED, + [ACT_INTRO_CUTSCENE] = ACT_INTRO_CUTSCENE, + [ACT_STAR_DANCE_EXIT] = ACT_STAR_DANCE_EXIT, + [ACT_STAR_DANCE_WATER] = ACT_STAR_DANCE_WATER, + [ACT_FALL_AFTER_STAR_GRAB] = ACT_FALL_AFTER_STAR_GRAB, + [ACT_READING_AUTOMATIC_DIALOG] = ACT_READING_AUTOMATIC_DIALOG, + [ACT_READING_NPC_DIALOG] = ACT_READING_NPC_DIALOG, + [ACT_STAR_DANCE_NO_EXIT] = ACT_STAR_DANCE_NO_EXIT, + [ACT_READING_SIGN] = ACT_READING_SIGN, + [ACT_JUMBO_STAR_CUTSCENE] = ACT_JUMBO_STAR_CUTSCENE, + [ACT_WAITING_FOR_DIALOG] = ACT_WAITING_FOR_DIALOG, + [ACT_DEBUG_FREE_MOVE] = ACT_DEBUG_FREE_MOVE, + [ACT_STANDING_DEATH] = ACT_STANDING_DEATH, + [ACT_QUICKSAND_DEATH] = ACT_QUICKSAND_DEATH, + [ACT_ELECTROCUTION] = ACT_ELECTROCUTION, + [ACT_SUFFOCATION] = ACT_SUFFOCATION, + [ACT_DEATH_ON_STOMACH] = ACT_DEATH_ON_STOMACH, + [ACT_DEATH_ON_BACK] = ACT_DEATH_ON_BACK, + [ACT_EATEN_BY_BUBBA] = ACT_EATEN_BY_BUBBA, + [ACT_END_PEACH_CUTSCENE] = ACT_END_PEACH_CUTSCENE, + [ACT_CREDITS_CUTSCENE] = ACT_CREDITS_CUTSCENE, + [ACT_END_WAVING_CUTSCENE] = ACT_END_WAVING_CUTSCENE, + [ACT_PULLING_DOOR] = ACT_PULLING_DOOR, + [ACT_PUSHING_DOOR] = ACT_PUSHING_DOOR, + [ACT_WARP_DOOR_SPAWN] = ACT_WARP_DOOR_SPAWN, + [ACT_EMERGE_FROM_PIPE] = ACT_EMERGE_FROM_PIPE, + [ACT_SPAWN_SPIN_AIRBORNE] = ACT_SPAWN_SPIN_AIRBORNE, + [ACT_SPAWN_SPIN_LANDING] = ACT_SPAWN_SPIN_LANDING, + [ACT_EXIT_AIRBORNE] = ACT_EXIT_AIRBORNE, + [ACT_EXIT_LAND_SAVE_DIALOG] = ACT_EXIT_LAND_SAVE_DIALOG, + [ACT_DEATH_EXIT] = ACT_DEATH_EXIT, + [ACT_UNUSED_DEATH_EXIT] = ACT_UNUSED_DEATH_EXIT, + [ACT_FALLING_DEATH_EXIT] = ACT_FALLING_DEATH_EXIT, + [ACT_SPECIAL_EXIT_AIRBORNE] = ACT_SPECIAL_EXIT_AIRBORNE, + [ACT_SPECIAL_DEATH_EXIT] = ACT_SPECIAL_DEATH_EXIT, + [ACT_FALLING_EXIT_AIRBORNE] = ACT_FALLING_EXIT_AIRBORNE, + [ACT_UNLOCKING_KEY_DOOR] = ACT_UNLOCKING_KEY_DOOR, + [ACT_UNLOCKING_STAR_DOOR] = ACT_UNLOCKING_STAR_DOOR, + [ACT_ENTERING_STAR_DOOR] = ACT_ENTERING_STAR_DOOR, + [ACT_SPAWN_NO_SPIN_AIRBORNE] = ACT_SPAWN_NO_SPIN_AIRBORNE, + [ACT_SPAWN_NO_SPIN_LANDING] = ACT_SPAWN_NO_SPIN_LANDING, + [ACT_BBH_ENTER_JUMP] = ACT_BBH_ENTER_JUMP, + [ACT_BBH_ENTER_SPIN] = ACT_BBH_ENTER_SPIN, + [ACT_TELEPORT_FADE_OUT] = ACT_TELEPORT_FADE_OUT, + [ACT_TELEPORT_FADE_IN] = ACT_TELEPORT_FADE_IN, + [ACT_SHOCKED] = ACT_SHOCKED, + [ACT_SQUISHED] = ACT_SQUISHED, + [ACT_HEAD_STUCK_IN_GROUND] = ACT_HEAD_STUCK_IN_GROUND, + [ACT_BUTT_STUCK_IN_GROUND] = ACT_BUTT_STUCK_IN_GROUND, + [ACT_FEET_STUCK_IN_GROUND] = ACT_FEET_STUCK_IN_GROUND, + [ACT_PUTTING_ON_CAP] = ACT_PUTTING_ON_CAP, + [ACT_HOLDING_POLE] = ACT_HOLDING_POLE, + [ACT_GRAB_POLE_SLOW] = ACT_GRAB_POLE_SLOW, + [ACT_GRAB_POLE_FAST] = ACT_GRAB_POLE_FAST, + [ACT_CLIMBING_POLE] = ACT_CLIMBING_POLE, + [ACT_TOP_OF_POLE_TRANSITION] = ACT_TOP_OF_POLE_TRANSITION, + [ACT_TOP_OF_POLE] = ACT_TOP_OF_POLE, + [ACT_START_HANGING] = ACT_START_HANGING, + [ACT_HANGING] = ACT_HANGING, + [ACT_HANG_MOVING] = ACT_HANG_MOVING, + [ACT_LEDGE_GRAB] = ACT_LEDGE_GRAB, + [ACT_LEDGE_CLIMB_SLOW_1] = ACT_LEDGE_CLIMB_SLOW_1, + [ACT_LEDGE_CLIMB_SLOW_2] = ACT_LEDGE_CLIMB_SLOW_2, + [ACT_LEDGE_CLIMB_DOWN] = ACT_LEDGE_CLIMB_DOWN, + [ACT_LEDGE_CLIMB_FAST] = ACT_LEDGE_CLIMB_FAST, + [ACT_GRABBED] = ACT_GRABBED, + [ACT_IN_CANNON] = ACT_IN_CANNON, + [ACT_TORNADO_TWIRLING] = ACT_TORNADO_TWIRLING, + [ACT_BUBBLED] = ACT_BUBBLED, + [ACT_PUNCHING] = ACT_PUNCHING, + [ACT_PICKING_UP] = ACT_PICKING_UP, + [ACT_DIVE_PICKING_UP] = ACT_DIVE_PICKING_UP, + [ACT_STOMACH_SLIDE_STOP] = ACT_STOMACH_SLIDE_STOP, + [ACT_PLACING_DOWN] = ACT_PLACING_DOWN, + [ACT_THROWING] = ACT_THROWING, + [ACT_HEAVY_THROW] = ACT_HEAVY_THROW, + [ACT_PICKING_UP_BOWSER] = ACT_PICKING_UP_BOWSER, + [ACT_HOLDING_BOWSER] = ACT_HOLDING_BOWSER, + [ACT_RELEASING_BOWSER] = ACT_RELEASING_BOWSER, +} + + +---@param m MarioState +function is_mario_in_vanilla_action(m) + return defaultActions[m.action] ~= nil +end + +-- Lazy automation of interpolation on HUD elements +local interpTable = {} + +function djui_set_interpolation(index, x, y, width, height) + interpTable[index] = { + x = x, + y = y, + width = width, + height = height + } +end + +function djui_get_interpolation(index, backUpX, backUpY, backUpWidth, backUpHeight) + return interpTable[index] or {x = backUpX or 0, y = backUpY or 0, width = backUpWidth or 0, height = backUpHeight or 0} +end + +function djui_hud_print_text_auto_interpolated(index, message, x, y, scale) + local interp = djui_get_interpolation(index, x, y, scale, nil) + djui_hud_print_text_interpolated(message, interp.x, interp.y, interp.width, x, y, scale) + djui_set_interpolation(index, x, y, scale, nil) +end + +function djui_hud_render_texture_auto_interpolated(index, texture, x, y, width, height) + local interp = djui_get_interpolation(index, x, y, width, height) + djui_hud_render_texture_interpolated(texture, interp.x, interp.y, interp.width, interp.height, x, y, width, height) + djui_set_interpolation(index, x, y, width, height) +end + +local hasBeenLogged = {} +---@param message string +---@param level ConsoleMessageLevel +function log_to_console_once(message, level) + if not hasBeenLogged[message] then + hasBeenLogged[message] = true + log_to_console("Character Select: "..message, level) + end +end + +function is_power_of_two(n) + return (n & (n - 1)) == 0 +end + +---@param tex TextureInfo +function is_texture_valid(tex) + if tex ~= nil then + return is_power_of_two(tex.width) and is_power_of_two(tex.height) + else + return false + end +end + +function run_func_or_get_var(x, ...) + if type(x) == "function" then + return x(...) + else + return x + end +end + +---@param x integer +function mirror_mode_number(x) + if _G.mirrorMode ~= nil and _G.mirrorMode.is_mirrored() then + return x * -1 + end + return x +end + +---@param str1 string +---@param str2 string +local function levenshtein_distance(str1, str2) + local len1 = #str1 + local len2 = #str2 + + local matrix = {} + for i = 0, len1 do + matrix[i] = {} + matrix[i][0] = i + end + for j = 0, len2 do + matrix[0][j] = j + end + + for i = 1, len1 do + for j = 1, len2 do + local cost = (str1:sub(i, i) == str2:sub(j, j)) and 0 or 1 + local del = matrix[i-1][j] + 1 + local ins = matrix[i][j-1] + 1 + local sub = matrix[i-1][j-1] + cost + matrix[i][j] = math.min(del, ins, sub) + end + end + + return matrix[len1][len2] +end + +---@param str1 string +---@param str2 string +-- Compares two strings and returns simularity (0-1) +function string_sim(str1, str2) + local distance = levenshtein_distance(str1, str2) + local maxLength = math.max(#str1, #str2) + if maxLength == 0 then return 1 end + return (distance / maxLength) +end \ No newline at end of file diff --git a/mods/character-select-coop/actors/armature_geo.bin b/mods/character-select-coop/actors/armature_geo.bin deleted file mode 100644 index 70835e7ed..000000000 Binary files a/mods/character-select-coop/actors/armature_geo.bin and /dev/null differ diff --git a/mods/character-select-coop/anims.lua b/mods/character-select-coop/anims.lua new file mode 100644 index 000000000..3b6c9b498 --- /dev/null +++ b/mods/character-select-coop/anims.lua @@ -0,0 +1,1201 @@ +MARIO_ANIM_CS_MENU = "mario_anim_cs_menu" +smlua_anim_util_register_animation(MARIO_ANIM_CS_MENU, + 0, + 0, + 0, + 0, + 83, + { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0xFFFE, + 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFB, + 0xFFFB, 0xFFFB, 0xFFFB, 0xFFFB, 0xFFFB, 0xFFFB, 0xFFFB, 0xFFFB, 0xFFFB, + 0xFFFB, 0xFFFB, 0xFFFB, 0xFFFB, 0xFFFB, 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFC, + 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x00AD, 0x00AD, 0x00AD, 0x00AC, + 0x00AC, 0x00AC, 0x00AC, 0x00AC, 0x00AC, 0x00AC, 0x00AB, 0x00AB, 0x00AB, + 0x00AB, 0x00AA, 0x00AA, 0x00AA, 0x00AA, 0x00A9, 0x00A9, 0x00A9, 0x00A8, + 0x00A8, 0x00A8, 0x00A8, 0x00A7, 0x00A7, 0x00A7, 0x00A6, 0x00A6, 0x00A6, + 0x00A6, 0x00A5, 0x00A5, 0x00A5, 0x00A5, 0x00A5, 0x00A5, 0x00A4, 0x00A4, + 0x00A4, 0x00A4, 0x00A4, 0x00A4, 0x00A4, 0x00A4, 0x00A4, 0x00A5, 0x00A5, + 0x00A5, 0x00A5, 0x00A5, 0x00A5, 0x00A6, 0x00A6, 0x00A6, 0x00A6, 0x00A7, + 0x00A7, 0x00A7, 0x00A8, 0x00A8, 0x00A8, 0x00A8, 0x00A9, 0x00A9, 0x00A9, + 0x00AA, 0x00AA, 0x00AA, 0x00AA, 0x00AB, 0x00AB, 0x00AB, 0x00AB, 0x00AC, + 0x00AC, 0x00AC, 0x00AC, 0x00AC, 0x00AC, 0x00AC, 0x00AD, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0xFFFE, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFC, 0xFFFB, 0xFFFB, 0xFFFA, 0xFFFA, 0xFFF9, 0xFFF8, + 0xFFF8, 0xFFF7, 0xFFF7, 0xFFF6, 0xFFF5, 0xFFF5, 0xFFF4, 0xFFF4, 0xFFF3, + 0xFFF2, 0xFFF2, 0xFFF1, 0xFFF1, 0xFFF1, 0xFFF0, 0xFFF0, 0xFFEF, 0xFFEF, + 0xFFEF, 0xFFEF, 0xFFEF, 0xFFEE, 0xFFEE, 0xFFEE, 0xFFEF, 0xFFEF, 0xFFEF, + 0xFFEF, 0xFFEF, 0xFFF0, 0xFFF0, 0xFFF1, 0xFFF1, 0xFFF1, 0xFFF2, 0xFFF2, + 0xFFF3, 0xFFF4, 0xFFF4, 0xFFF5, 0xFFF5, 0xFFF6, 0xFFF7, 0xFFF7, 0xFFF8, + 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFA, 0xFFFB, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFE, 0xFFFE, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x3FFF, + 0x0000, 0xDC72, 0x007B, 0x4067, 0xF96D, 0xF96D, 0xF96D, 0xF96D, 0xF96C, + 0xF96B, 0xF96A, 0xF96A, 0xF968, 0xF967, 0xF966, 0xF965, 0xF963, 0xF962, + 0xF960, 0xF95E, 0xF95D, 0xF95B, 0xF959, 0xF957, 0xF956, 0xF954, 0xF952, + 0xF950, 0xF94E, 0xF94D, 0xF94B, 0xF949, 0xF948, 0xF946, 0xF945, 0xF943, + 0xF942, 0xF940, 0xF93F, 0xF93E, 0xF93D, 0xF93C, 0xF93C, 0xF93B, 0xF93B, + 0xF93A, 0xF93A, 0xF93A, 0xF93B, 0xF93B, 0xF93C, 0xF93C, 0xF93D, 0xF93E, + 0xF93F, 0xF940, 0xF942, 0xF943, 0xF945, 0xF946, 0xF948, 0xF949, 0xF94B, + 0xF94D, 0xF94E, 0xF950, 0xF952, 0xF954, 0xF956, 0xF957, 0xF959, 0xF95B, + 0xF95D, 0xF95E, 0xF960, 0xF962, 0xF963, 0xF965, 0xF966, 0xF967, 0xF968, + 0xF96A, 0xF96A, 0xF96B, 0xF96C, 0xF96D, 0xFE3D, 0xFE3D, 0xFE3F, 0xFE41, + 0xFE44, 0xFE48, 0xFE4D, 0xFE52, 0xFE58, 0xFE5F, 0xFE66, 0xFE6D, 0xFE76, + 0xFE7E, 0xFE87, 0xFE90, 0xFE9A, 0xFEA3, 0xFEAD, 0xFEB7, 0xFEC1, 0xFECC, + 0xFED6, 0xFEE0, 0xFEEA, 0xFEF4, 0xFEFD, 0xFF07, 0xFF10, 0xFF19, 0xFF22, + 0xFF2A, 0xFF31, 0xFF38, 0xFF3F, 0xFF45, 0xFF4A, 0xFF4F, 0xFF53, 0xFF56, + 0xFF58, 0xFF5A, 0xFF5A, 0xFF5A, 0xFF58, 0xFF56, 0xFF53, 0xFF4F, 0xFF4A, + 0xFF45, 0xFF3F, 0xFF38, 0xFF31, 0xFF2A, 0xFF22, 0xFF19, 0xFF10, 0xFF07, + 0xFEFD, 0xFEF4, 0xFEEA, 0xFEE0, 0xFED6, 0xFECC, 0xFEC1, 0xFEB7, 0xFEAD, + 0xFEA3, 0xFE9A, 0xFE90, 0xFE87, 0xFE7E, 0xFE76, 0xFE6D, 0xFE66, 0xFE5F, + 0xFE58, 0xFE52, 0xFE4D, 0xFE48, 0xFE44, 0xFE41, 0xFE3F, 0xFE3D, 0xF4CE, + 0xF4D1, 0xF4DA, 0xF4E8, 0xF4FA, 0xF512, 0xF52E, 0xF54E, 0xF572, 0xF59A, + 0xF5C5, 0xF5F3, 0xF624, 0xF657, 0xF68D, 0xF6C5, 0xF6FE, 0xF739, 0xF774, + 0xF7B1, 0xF7EE, 0xF82C, 0xF869, 0xF8A6, 0xF8E3, 0xF91F, 0xF95A, 0xF993, + 0xF9CB, 0xFA00, 0xFA34, 0xFA65, 0xFA93, 0xFABE, 0xFAE6, 0xFB0A, 0xFB2A, + 0xFB46, 0xFB5D, 0xFB70, 0xFB7E, 0xFB86, 0xFB89, 0xFB86, 0xFB7E, 0xFB70, + 0xFB5D, 0xFB46, 0xFB2A, 0xFB0A, 0xFAE6, 0xFABE, 0xFA93, 0xFA65, 0xFA34, + 0xFA00, 0xF9CB, 0xF993, 0xF95A, 0xF91F, 0xF8E3, 0xF8A6, 0xF869, 0xF82C, + 0xF7EE, 0xF7B1, 0xF774, 0xF739, 0xF6FE, 0xF6C5, 0xF68D, 0xF657, 0xF624, + 0xF5F3, 0xF5C5, 0xF59A, 0xF572, 0xF54E, 0xF52E, 0xF512, 0xF4FA, 0xF4E8, + 0xF4DA, 0xF4D1, 0x0BA2, 0x0BA3, 0x0BA6, 0x0BAB, 0x0BB2, 0x0BBA, 0x0BC3, + 0x0BCD, 0x0BD7, 0x0BE2, 0x0BED, 0x0BF9, 0x0C04, 0x0C0E, 0x0C18, 0x0C21, + 0x0C29, 0x0C30, 0x0C34, 0x0C38, 0x0C39, 0x0C38, 0x0C37, 0x0C34, 0x0C31, + 0x0C2D, 0x0C28, 0x0C22, 0x0C1C, 0x0C15, 0x0C0E, 0x0C06, 0x0BFD, 0x0BF4, + 0x0BEB, 0x0BE2, 0x0BD8, 0x0BCE, 0x0BC4, 0x0BB9, 0x0BAF, 0x0BA5, 0x0B9B, + 0x0B90, 0x0B86, 0x0B7D, 0x0B73, 0x0B6A, 0x0B61, 0x0B59, 0x0B51, 0x0B49, + 0x0B42, 0x0B3C, 0x0B36, 0x0B31, 0x0B2D, 0x0B2A, 0x0B28, 0x0B26, 0x0B26, + 0x0B26, 0x0B28, 0x0B2B, 0x0B2F, 0x0B34, 0x0B39, 0x0B3F, 0x0B46, 0x0B4D, + 0x0B54, 0x0B5C, 0x0B64, 0x0B6C, 0x0B73, 0x0B7B, 0x0B82, 0x0B89, 0x0B8F, + 0x0B94, 0x0B99, 0x0B9D, 0x0BA0, 0x0BA2, 0xFA5B, 0xFA5E, 0xFA66, 0xFA74, + 0xFA86, 0xFA9B, 0xFAB4, 0xFACF, 0xFAEC, 0xFB0A, 0xFB29, 0xFB48, 0xFB66, + 0xFB83, 0xFB9E, 0xFBB7, 0xFBCD, 0xFBDF, 0xFBEC, 0xFBF5, 0xFBF8, 0xFBF6, + 0xFBF3, 0xFBED, 0xFBE5, 0xFBDC, 0xFBD0, 0xFBC3, 0xFBB4, 0xFBA4, 0xFB92, + 0xFB7F, 0xFB6B, 0xFB56, 0xFB41, 0xFB2A, 0xFB13, 0xFAFB, 0xFAE3, 0xFACB, + 0xFAB3, 0xFA9A, 0xFA82, 0xFA6A, 0xFA53, 0xFA3B, 0xFA25, 0xFA0F, 0xF9FA, + 0xF9E6, 0xF9D3, 0xF9C2, 0xF9B1, 0xF9A3, 0xF995, 0xF98A, 0xF980, 0xF978, + 0xF973, 0xF96F, 0xF96E, 0xF96F, 0xF972, 0xF978, 0xF97F, 0xF988, 0xF993, + 0xF99F, 0xF9AB, 0xF9B9, 0xF9C7, 0xF9D6, 0xF9E4, 0xF9F3, 0xFA02, 0xFA10, + 0xFA1D, 0xFA2A, 0xFA36, 0xFA40, 0xFA49, 0xFA51, 0xFA56, 0xFA5A, 0x0691, + 0x0687, 0x066B, 0x063E, 0x0603, 0x05BC, 0x056B, 0x0511, 0x04B1, 0x044E, + 0x03E8, 0x0382, 0x031E, 0x02BF, 0x0265, 0x0214, 0x01CD, 0x0192, 0x0165, + 0x0149, 0x013F, 0x0143, 0x014F, 0x0162, 0x017C, 0x019D, 0x01C4, 0x01F1, + 0x0223, 0x025B, 0x0296, 0x02D6, 0x0319, 0x0360, 0x03AA, 0x03F6, 0x0444, + 0x0494, 0x04E5, 0x0537, 0x0589, 0x05DC, 0x062D, 0x067E, 0x06CE, 0x071C, + 0x0769, 0x07B2, 0x07F9, 0x083C, 0x087C, 0x08B8, 0x08EF, 0x0921, 0x094E, + 0x0975, 0x0996, 0x09B0, 0x09C4, 0x09CF, 0x09D3, 0x09CF, 0x09C3, 0x09B0, + 0x0996, 0x0976, 0x0951, 0x0928, 0x08FB, 0x08CB, 0x0899, 0x0866, 0x0832, + 0x07FE, 0x07CB, 0x0799, 0x0769, 0x073C, 0x0713, 0x06EE, 0x06CF, 0x06B5, + 0x06A1, 0x0695, 0x0000, 0xFFFF, 0xBFFF, 0xFBAD, 0xFBAC, 0xFBA9, 0xFBA5, + 0xFB9E, 0xFB96, 0xFB8D, 0xFB82, 0xFB76, 0xFB68, 0xFB5A, 0xFB4A, 0xFB3A, + 0xFB28, 0xFB16, 0xFB03, 0xFAF0, 0xFADC, 0xFAC8, 0xFAB3, 0xFA9F, 0xFA8A, + 0xFA75, 0xFA60, 0xFA4C, 0xFA38, 0xFA24, 0xFA10, 0xF9FE, 0xF9EB, 0xF9DA, + 0xF9CA, 0xF9BA, 0xF9AB, 0xF99E, 0xF992, 0xF987, 0xF97D, 0xF975, 0xF96F, + 0xF96A, 0xF968, 0xF967, 0xF968, 0xF96A, 0xF96F, 0xF975, 0xF97D, 0xF987, + 0xF992, 0xF99E, 0xF9AB, 0xF9BA, 0xF9CA, 0xF9DA, 0xF9EB, 0xF9FE, 0xFA10, + 0xFA24, 0xFA38, 0xFA4C, 0xFA60, 0xFA75, 0xFA8A, 0xFA9F, 0xFAB3, 0xFAC8, + 0xFADC, 0xFAF0, 0xFB03, 0xFB16, 0xFB28, 0xFB3A, 0xFB4A, 0xFB5A, 0xFB68, + 0xFB76, 0xFB82, 0xFB8D, 0xFB96, 0xFB9E, 0xFBA5, 0xFBA9, 0xFBAC, 0xDE3A, + 0xDE3A, 0xDE3A, 0xDE3B, 0xDE3C, 0xDE3D, 0xDE3E, 0xDE3F, 0xDE41, 0xDE43, + 0xDE44, 0xDE46, 0xDE48, 0xDE4B, 0xDE4D, 0xDE4F, 0xDE52, 0xDE54, 0xDE57, + 0xDE59, 0xDE5C, 0xDE5E, 0xDE61, 0xDE63, 0xDE66, 0xDE68, 0xDE6B, 0xDE6D, + 0xDE70, 0xDE72, 0xDE74, 0xDE76, 0xDE78, 0xDE7A, 0xDE7C, 0xDE7D, 0xDE7E, + 0xDE80, 0xDE81, 0xDE81, 0xDE82, 0xDE82, 0xDE82, 0xDE82, 0xDE82, 0xDE81, + 0xDE81, 0xDE80, 0xDE7E, 0xDE7D, 0xDE7C, 0xDE7A, 0xDE78, 0xDE76, 0xDE74, + 0xDE72, 0xDE70, 0xDE6D, 0xDE6B, 0xDE68, 0xDE66, 0xDE63, 0xDE61, 0xDE5E, + 0xDE5C, 0xDE59, 0xDE56, 0xDE54, 0xDE52, 0xDE4F, 0xDE4D, 0xDE4B, 0xDE48, + 0xDE46, 0xDE44, 0xDE43, 0xDE41, 0xDE3F, 0xDE3E, 0xDE3D, 0xDE3C, 0xDE3B, + 0xDE3A, 0xE9B3, 0xE9B4, 0xE9B8, 0xE9BF, 0xE9C7, 0xE9D2, 0xE9DF, 0xE9EE, + 0xE9FE, 0xEA11, 0xEA24, 0xEA3A, 0xEA50, 0xEA68, 0xEA80, 0xEA9A, 0xEAB4, + 0xEACF, 0xEAEB, 0xEB07, 0xEB23, 0xEB3F, 0xEB5C, 0xEB78, 0xEB94, 0xEBAF, + 0xEBCA, 0xEBE5, 0xEBFE, 0xEC17, 0xEC2F, 0xEC45, 0xEC5A, 0xEC6E, 0xEC80, + 0xEC91, 0xECA0, 0xECAD, 0xECB8, 0xECC0, 0xECC6, 0xECCA, 0xECCC, 0xECCA, + 0xECC6, 0xECC0, 0xECB8, 0xECAD, 0xECA0, 0xEC91, 0xEC80, 0xEC6E, 0xEC5A, + 0xEC45, 0xEC2F, 0xEC17, 0xEBFE, 0xEBE5, 0xEBCA, 0xEBAF, 0xEB94, 0xEB78, + 0xEB5C, 0xEB3F, 0xEB23, 0xEB07, 0xEAEB, 0xEACF, 0xEAB4, 0xEA9A, 0xEA80, + 0xEA68, 0xEA50, 0xEA3A, 0xEA24, 0xEA11, 0xE9FE, 0xE9EE, 0xE9DF, 0xE9D2, + 0xE9C7, 0xE9BF, 0xE9B8, 0xE9B4, 0xFFFF, 0x0000, 0x0001, 0x0001, 0x0002, + 0x0003, 0x0005, 0x0006, 0x0008, 0x000A, 0x000C, 0x000E, 0x0011, 0x0014, + 0x0016, 0x0019, 0x001C, 0x0020, 0x0023, 0x0026, 0x002A, 0x002E, 0x0031, + 0x0035, 0x0039, 0x003D, 0x0041, 0x0045, 0x0049, 0x004D, 0x0051, 0x0055, + 0x0059, 0x005D, 0x0061, 0x0065, 0x0069, 0x006D, 0x0071, 0x0074, 0x0078, + 0x007C, 0x007F, 0x0082, 0x0086, 0x0089, 0x008C, 0x008F, 0x0091, 0x0094, + 0x0096, 0x0098, 0x009A, 0x009C, 0x009E, 0x009F, 0x00A0, 0x00A1, 0x00A2, + 0x00A2, 0x00A2, 0x00A1, 0x009F, 0x009B, 0x0096, 0x0090, 0x0089, 0x0081, + 0x0078, 0x006F, 0x0065, 0x005B, 0x0051, 0x0047, 0x003D, 0x0033, 0x002A, + 0x0021, 0x0019, 0x0012, 0x000C, 0x0007, 0x0003, 0x0001, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFE, 0xFFFE, 0xFFFD, 0xFFFD, 0xFFFC, 0xFFFB, 0xFFFB, + 0xFFFA, 0xFFF9, 0xFFF8, 0xFFF7, 0xFFF6, 0xFFF4, 0xFFF3, 0xFFF2, 0xFFF1, + 0xFFEF, 0xFFEE, 0xFFED, 0xFFEB, 0xFFEA, 0xFFE8, 0xFFE7, 0xFFE5, 0xFFE4, + 0xFFE2, 0xFFE1, 0xFFDF, 0xFFDE, 0xFFDC, 0xFFDB, 0xFFD9, 0xFFD8, 0xFFD6, + 0xFFD5, 0xFFD4, 0xFFD2, 0xFFD1, 0xFFD0, 0xFFCE, 0xFFCD, 0xFFCC, 0xFFCB, + 0xFFCA, 0xFFC9, 0xFFC8, 0xFFC7, 0xFFC6, 0xFFC5, 0xFFC5, 0xFFC4, 0xFFC4, + 0xFFC3, 0xFFC3, 0xFFC3, 0xFFC3, 0xFFC3, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC7, + 0xFFC9, 0xFFCC, 0xFFCF, 0xFFD2, 0xFFD6, 0xFFD9, 0xFFDD, 0xFFE1, 0xFFE5, + 0xFFE8, 0xFFEC, 0xFFEF, 0xFFF3, 0xFFF6, 0xFFF8, 0xFFFB, 0xFFFC, 0xFFFE, + 0xFFFF, 0xF5BB, 0xF5BC, 0xF5BE, 0xF5C2, 0xF5C8, 0xF5CE, 0xF5D7, 0xF5E0, + 0xF5EB, 0xF5F7, 0xF604, 0xF613, 0xF622, 0xF632, 0xF644, 0xF656, 0xF669, + 0xF67D, 0xF691, 0xF6A6, 0xF6BC, 0xF6D3, 0xF6E9, 0xF701, 0xF718, 0xF730, + 0xF749, 0xF761, 0xF77A, 0xF792, 0xF7AB, 0xF7C4, 0xF7DD, 0xF7F5, 0xF80E, + 0xF826, 0xF83E, 0xF856, 0xF86D, 0xF884, 0xF89A, 0xF8B0, 0xF8C5, 0xF8DA, + 0xF8ED, 0xF900, 0xF913, 0xF924, 0xF934, 0xF944, 0xF952, 0xF95F, 0xF96B, + 0xF976, 0xF980, 0xF988, 0xF98F, 0xF994, 0xF998, 0xF99B, 0xF99C, 0xF997, + 0xF988, 0xF971, 0xF952, 0xF92C, 0xF900, 0xF8CF, 0xF89A, 0xF861, 0xF826, + 0xF7E9, 0xF7AB, 0xF76D, 0xF730, 0xF6F5, 0xF6BC, 0xF687, 0xF656, 0xF62A, + 0xF604, 0xF5E6, 0xF5CE, 0xF5C0, 0xDE6C, 0xDE6C, 0xDE6B, 0xDE6B, 0xDE6B, + 0xDE6A, 0xDE69, 0xDE68, 0xDE67, 0xDE66, 0xDE65, 0xDE64, 0xDE63, 0xDE61, + 0xDE60, 0xDE5E, 0xDE5D, 0xDE5B, 0xDE5A, 0xDE58, 0xDE56, 0xDE55, 0xDE53, + 0xDE51, 0xDE50, 0xDE4E, 0xDE4D, 0xDE4B, 0xDE4A, 0xDE48, 0xDE47, 0xDE45, + 0xDE44, 0xDE43, 0xDE42, 0xDE41, 0xDE40, 0xDE3F, 0xDE3F, 0xDE3E, 0xDE3E, + 0xDE3E, 0xDE3E, 0xDE3E, 0xDE3E, 0xDE3E, 0xDE3F, 0xDE3F, 0xDE40, 0xDE41, + 0xDE42, 0xDE43, 0xDE44, 0xDE45, 0xDE47, 0xDE48, 0xDE4A, 0xDE4B, 0xDE4D, + 0xDE4E, 0xDE50, 0xDE51, 0xDE53, 0xDE55, 0xDE56, 0xDE58, 0xDE5A, 0xDE5B, + 0xDE5D, 0xDE5E, 0xDE60, 0xDE61, 0xDE63, 0xDE64, 0xDE65, 0xDE66, 0xDE67, + 0xDE68, 0xDE69, 0xDE6A, 0xDE6B, 0xDE6B, 0xDE6B, 0xDE6C, 0xFA75, 0xFA75, + 0xFA77, 0xFA7B, 0xFA80, 0xFA85, 0xFA8D, 0xFA95, 0xFA9E, 0xFAA8, 0xFAB3, + 0xFABE, 0xFACB, 0xFAD7, 0xFAE5, 0xFAF3, 0xFB01, 0xFB10, 0xFB1F, 0xFB2F, + 0xFB3E, 0xFB4D, 0xFB5D, 0xFB6C, 0xFB7C, 0xFB8B, 0xFB99, 0xFBA8, 0xFBB6, + 0xFBC3, 0xFBD0, 0xFBDD, 0xFBE8, 0xFBF3, 0xFBFD, 0xFC06, 0xFC0E, 0xFC15, + 0xFC1B, 0xFC20, 0xFC23, 0xFC26, 0xFC26, 0xFC26, 0xFC23, 0xFC20, 0xFC1B, + 0xFC15, 0xFC0E, 0xFC06, 0xFBFD, 0xFBF3, 0xFBE8, 0xFBDD, 0xFBD0, 0xFBC3, + 0xFBB6, 0xFBA8, 0xFB99, 0xFB8B, 0xFB7C, 0xFB6C, 0xFB5D, 0xFB4D, 0xFB3E, + 0xFB2F, 0xFB1F, 0xFB10, 0xFB01, 0xFAF3, 0xFAE5, 0xFAD7, 0xFACB, 0xFABE, + 0xFAB3, 0xFAA8, 0xFA9E, 0xFA95, 0xFA8D, 0xFA85, 0xFA80, 0xFA7B, 0xFA77, + 0xFA75, 0xF33D, 0xF33D, 0xF33F, 0xF343, 0xF347, 0xF34D, 0xF353, 0xF35B, + 0xF363, 0xF36C, 0xF376, 0xF381, 0xF38D, 0xF399, 0xF3A5, 0xF3B2, 0xF3BF, + 0xF3CD, 0xF3DB, 0xF3E9, 0xF3F8, 0xF406, 0xF414, 0xF423, 0xF431, 0xF43F, + 0xF44C, 0xF45A, 0xF467, 0xF473, 0xF47F, 0xF48B, 0xF496, 0xF4A0, 0xF4A9, + 0xF4B1, 0xF4B9, 0xF4BF, 0xF4C5, 0xF4C9, 0xF4CC, 0xF4CE, 0xF4CF, 0xF4CE, + 0xF4CC, 0xF4C9, 0xF4C5, 0xF4BF, 0xF4B9, 0xF4B1, 0xF4A9, 0xF4A0, 0xF496, + 0xF48B, 0xF47F, 0xF473, 0xF467, 0xF45A, 0xF44C, 0xF43F, 0xF431, 0xF423, + 0xF414, 0xF406, 0xF3F8, 0xF3E9, 0xF3DB, 0xF3CD, 0xF3BF, 0xF3B2, 0xF3A5, + 0xF399, 0xF38D, 0xF381, 0xF376, 0xF36C, 0xF363, 0xF35B, 0xF353, 0xF34D, + 0xF347, 0xF343, 0xF33F, 0xF33D, 0x0000, 0xFFFF, 0xBFFF, 0xEBA7, 0xEBAD, + 0xEBBC, 0xEBD5, 0xEBF8, 0xEC23, 0xEC56, 0xEC91, 0xECD3, 0xED1B, 0xED6A, + 0xEDBF, 0xEE18, 0xEE76, 0xEED8, 0xEF3E, 0xEFA7, 0xF012, 0xF080, 0xF0EE, + 0xF15E, 0xF1CF, 0xF23F, 0xF2AF, 0xF31E, 0xF38C, 0xF3F7, 0xF460, 0xF4C5, + 0xF528, 0xF586, 0xF5DF, 0xF633, 0xF682, 0xF6CB, 0xF70D, 0xF748, 0xF77B, + 0xF7A6, 0xF7C8, 0xF7E1, 0xF7F1, 0xF7F6, 0xF7F1, 0xF7E1, 0xF7C8, 0xF7A6, + 0xF77B, 0xF748, 0xF70D, 0xF6CB, 0xF682, 0xF633, 0xF5DF, 0xF586, 0xF528, + 0xF4C5, 0xF460, 0xF3F7, 0xF38C, 0xF31E, 0xF2AF, 0xF23F, 0xF1CF, 0xF15E, + 0xF0EE, 0xF080, 0xF012, 0xEFA7, 0xEF3E, 0xEED8, 0xEE76, 0xEE18, 0xEDBF, + 0xED6A, 0xED1B, 0xECD3, 0xEC91, 0xEC56, 0xEC23, 0xEBF8, 0xEBD5, 0xEBBC, + 0xEBAD, 0x1A7E, 0x1A7F, 0x1A83, 0x1A89, 0x1A91, 0x1A9B, 0x1AA7, 0x1AB5, + 0x1AC5, 0x1AD7, 0x1AE9, 0x1AFE, 0x1B13, 0x1B2A, 0x1B41, 0x1B59, 0x1B72, + 0x1B8C, 0x1BA6, 0x1BC1, 0x1BDC, 0x1BF6, 0x1C11, 0x1C2C, 0x1C47, 0x1C61, + 0x1C7A, 0x1C93, 0x1CAC, 0x1CC3, 0x1CDA, 0x1CEF, 0x1D03, 0x1D16, 0x1D28, + 0x1D37, 0x1D45, 0x1D52, 0x1D5C, 0x1D64, 0x1D6A, 0x1D6E, 0x1D6F, 0x1D6E, + 0x1D6A, 0x1D64, 0x1D5C, 0x1D52, 0x1D45, 0x1D37, 0x1D28, 0x1D16, 0x1D03, + 0x1CEF, 0x1CDA, 0x1CC3, 0x1CAC, 0x1C93, 0x1C7A, 0x1C61, 0x1C47, 0x1C2C, + 0x1C11, 0x1BF6, 0x1BDC, 0x1BC1, 0x1BA6, 0x1B8C, 0x1B72, 0x1B59, 0x1B41, + 0x1B2A, 0x1B13, 0x1AFE, 0x1AE9, 0x1AD7, 0x1AC5, 0x1AB5, 0x1AA7, 0x1A9B, + 0x1A91, 0x1A89, 0x1A83, 0x1A7F, 0xA99A, 0xA99A, 0xA99A, 0xA99A, 0xA99A, + 0xA99A, 0xA99A, 0xA999, 0xA999, 0xA999, 0xA998, 0xA998, 0xA997, 0xA997, + 0xA996, 0xA996, 0xA995, 0xA995, 0xA994, 0xA994, 0xA993, 0xA993, 0xA992, + 0xA992, 0xA991, 0xA991, 0xA990, 0xA990, 0xA98F, 0xA98F, 0xA98E, 0xA98E, + 0xA98D, 0xA98D, 0xA98C, 0xA98C, 0xA98C, 0xA98C, 0xA98B, 0xA98B, 0xA98B, + 0xA98B, 0xA98B, 0xA98B, 0xA98B, 0xA98B, 0xA98B, 0xA98C, 0xA98C, 0xA98C, + 0xA98C, 0xA98D, 0xA98D, 0xA98E, 0xA98E, 0xA98F, 0xA98F, 0xA990, 0xA990, + 0xA991, 0xA991, 0xA992, 0xA992, 0xA993, 0xA993, 0xA994, 0xA994, 0xA995, + 0xA995, 0xA996, 0xA996, 0xA997, 0xA997, 0xA998, 0xA998, 0xA999, 0xA999, + 0xA999, 0xA99A, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, + 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, + 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xD584, 0x20F5, 0x0D6D, + 0xDAD7, 0xFFFF, 0x0000, 0xBF5E, 0xE6B9, 0xE6B9, 0xE6B8, 0xE6B7, 0xE6B6, + 0xE6B4, 0xE6B2, 0xE6B0, 0xE6AE, 0xE6AB, 0xE6A8, 0xE6A5, 0xE6A2, 0xE69E, + 0xE69A, 0xE697, 0xE693, 0xE68F, 0xE68B, 0xE687, 0xE683, 0xE67E, 0xE67A, + 0xE676, 0xE672, 0xE66E, 0xE66A, 0xE666, 0xE662, 0xE65F, 0xE65B, 0xE658, + 0xE655, 0xE652, 0xE64F, 0xE64D, 0xE64A, 0xE649, 0xE647, 0xE646, 0xE645, + 0xE644, 0xE644, 0xE644, 0xE645, 0xE646, 0xE647, 0xE649, 0xE64A, 0xE64D, + 0xE64F, 0xE652, 0xE655, 0xE658, 0xE65B, 0xE65F, 0xE662, 0xE666, 0xE66A, + 0xE66E, 0xE672, 0xE676, 0xE67A, 0xE67E, 0xE683, 0xE687, 0xE68B, 0xE68F, + 0xE693, 0xE697, 0xE69A, 0xE69E, 0xE6A2, 0xE6A5, 0xE6A8, 0xE6AB, 0xE6AE, + 0xE6B0, 0xE6B2, 0xE6B4, 0xE6B6, 0xE6B7, 0xE6B8, 0xE6B9, 0xED8D, 0xED8A, + 0xED83, 0xED78, 0xED68, 0xED55, 0xED3E, 0xED23, 0xED05, 0xECE4, 0xECC0, + 0xEC9A, 0xEC71, 0xEC46, 0xEC1A, 0xEBEC, 0xEBBC, 0xEB8B, 0xEB5A, 0xEB27, + 0xEAF4, 0xEAC1, 0xEA8E, 0xEA5B, 0xEA29, 0xE9F7, 0xE9C7, 0xE997, 0xE969, + 0xE93C, 0xE911, 0xE8E9, 0xE8C3, 0xE89F, 0xE87E, 0xE860, 0xE845, 0xE82E, + 0xE81A, 0xE80B, 0xE7FF, 0xE7F8, 0xE7F6, 0xE7F8, 0xE7FF, 0xE80B, 0xE81A, + 0xE82E, 0xE845, 0xE860, 0xE87E, 0xE89F, 0xE8C3, 0xE8E9, 0xE911, 0xE93C, + 0xE969, 0xE997, 0xE9C7, 0xE9F7, 0xEA29, 0xEA5B, 0xEA8E, 0xEAC1, 0xEAF4, + 0xEB27, 0xEB5A, 0xEB8B, 0xEBBC, 0xEBEC, 0xEC1A, 0xEC46, 0xEC71, 0xEC9A, + 0xECC0, 0xECE4, 0xED05, 0xED23, 0xED3D, 0xED55, 0xED68, 0xED78, 0xED83, + 0xED8A, 0xC09C, 0xC09A, 0xC095, 0xC08C, 0xC081, 0xC072, 0xC061, 0xC04D, + 0xC036, 0xC01D, 0xC003, 0xBFE6, 0xBFC7, 0xBFA7, 0xBF86, 0xBF63, 0xBF40, + 0xBF1B, 0xBEF6, 0xBED0, 0xBEAA, 0xBE84, 0xBE5E, 0xBE38, 0xBE12, 0xBDED, + 0xBDC8, 0xBDA5, 0xBD82, 0xBD61, 0xBD41, 0xBD22, 0xBD06, 0xBCEB, 0xBCD2, + 0xBCBC, 0xBCA8, 0xBC96, 0xBC88, 0xBC7C, 0xBC73, 0xBC6E, 0xBC6C, 0xBC6E, + 0xBC73, 0xBC7C, 0xBC88, 0xBC96, 0xBCA8, 0xBCBC, 0xBCD2, 0xBCEB, 0xBD06, + 0xBD22, 0xBD41, 0xBD61, 0xBD82, 0xBDA5, 0xBDC8, 0xBDED, 0xBE12, 0xBE38, + 0xBE5E, 0xBE84, 0xBEAA, 0xBED0, 0xBEF6, 0xBF1B, 0xBF40, 0xBF63, 0xBF86, + 0xBFA7, 0xBFC7, 0xBFE6, 0xC003, 0xC01D, 0xC036, 0xC04D, 0xC061, 0xC072, + 0xC081, 0xC08C, 0xC095, 0xC09A, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, + 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, + 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, + 0x0002, 0x0006, 0x000D, 0x0017, 0x0024, 0x0033, 0x0044, 0x0057, 0x006D, + 0x0084, 0x009C, 0x00B6, 0x00D2, 0x00EE, 0x010C, 0x012B, 0x014A, 0x016A, + 0x018A, 0x01AB, 0x01CC, 0x01ED, 0x020D, 0x022E, 0x024E, 0x026D, 0x028C, + 0x02A9, 0x02C6, 0x02E1, 0x02FC, 0x0314, 0x032B, 0x0340, 0x0354, 0x0365, + 0x0374, 0x0380, 0x038A, 0x0392, 0x0396, 0x0398, 0x0396, 0x0392, 0x038A, + 0x0380, 0x0374, 0x0365, 0x0354, 0x0340, 0x032B, 0x0314, 0x02FC, 0x02E1, + 0x02C6, 0x02A9, 0x028C, 0x026D, 0x024E, 0x022E, 0x020D, 0x01ED, 0x01CC, + 0x01AB, 0x018A, 0x016A, 0x014A, 0x012B, 0x010C, 0x00EE, 0x00D2, 0x00B6, + 0x009C, 0x0084, 0x006D, 0x0057, 0x0044, 0x0033, 0x0024, 0x0017, 0x000D, + 0x0006, 0x0002, 0xEE35, 0xEE34, 0xEE34, 0xEE34, 0xEE33, 0xEE33, 0xEE32, + 0xEE31, 0xEE30, 0xEE2F, 0xEE2E, 0xEE2D, 0xEE2C, 0xEE2A, 0xEE29, 0xEE27, + 0xEE26, 0xEE24, 0xEE23, 0xEE21, 0xEE1F, 0xEE1E, 0xEE1C, 0xEE1A, 0xEE19, + 0xEE17, 0xEE16, 0xEE14, 0xEE13, 0xEE11, 0xEE10, 0xEE0F, 0xEE0D, 0xEE0C, + 0xEE0B, 0xEE0A, 0xEE09, 0xEE09, 0xEE08, 0xEE08, 0xEE07, 0xEE07, 0xEE07, + 0xEE07, 0xEE07, 0xEE08, 0xEE08, 0xEE09, 0xEE09, 0xEE0A, 0xEE0B, 0xEE0C, + 0xEE0D, 0xEE0F, 0xEE10, 0xEE11, 0xEE13, 0xEE14, 0xEE16, 0xEE17, 0xEE19, + 0xEE1A, 0xEE1C, 0xEE1E, 0xEE1F, 0xEE21, 0xEE23, 0xEE24, 0xEE26, 0xEE27, + 0xEE29, 0xEE2A, 0xEE2C, 0xEE2D, 0xEE2E, 0xEE2F, 0xEE30, 0xEE31, 0xEE32, + 0xEE33, 0xEE33, 0xEE34, 0xFB94, 0xFB94, 0xFB97, 0xFB9C, 0xFBA2, 0xFBA9, + 0xFBB2, 0xFBBD, 0xFBC9, 0xFBD5, 0xFBE3, 0xFBF2, 0xFC02, 0xFC13, 0xFC24, + 0xFC36, 0xFC49, 0xFC5C, 0xFC6F, 0xFC83, 0xFC97, 0xFCAB, 0xFCBF, 0xFCD3, + 0xFCE6, 0xFCFA, 0xFD0D, 0xFD1F, 0xFD31, 0xFD43, 0xFD53, 0xFD63, 0xFD72, + 0xFD80, 0xFD8D, 0xFD99, 0xFDA3, 0xFDAC, 0xFDB4, 0xFDBA, 0xFDBE, 0xFDC1, + 0xFDC2, 0xFDC1, 0xFDBE, 0xFDBA, 0xFDB4, 0xFDAC, 0xFDA3, 0xFD99, 0xFD8D, + 0xFD80, 0xFD72, 0xFD63, 0xFD53, 0xFD43, 0xFD31, 0xFD1F, 0xFD0D, 0xFCFA, + 0xFCE6, 0xFCD3, 0xFCBF, 0xFCAB, 0xFC97, 0xFC83, 0xFC6F, 0xFC5C, 0xFC49, + 0xFC36, 0xFC24, 0xFC13, 0xFC02, 0xFBF2, 0xFBE3, 0xFBD5, 0xFBC9, 0xFBBD, + 0xFBB2, 0xFBA9, 0xFBA2, 0xFB9C, 0xFB97, 0xFB94, 0xDC44, 0xDC46, 0xDC4A, + 0xDC51, 0xDC5A, 0xDC66, 0xDC74, 0xDC84, 0xDC96, 0xDCAA, 0xDCC0, 0xDCD7, + 0xDCEF, 0xDD09, 0xDD24, 0xDD40, 0xDD5C, 0xDD7A, 0xDD98, 0xDDB6, 0xDDD5, + 0xDDF3, 0xDE12, 0xDE31, 0xDE4F, 0xDE6D, 0xDE8A, 0xDEA7, 0xDEC3, 0xDEDE, + 0xDEF7, 0xDF10, 0xDF27, 0xDF3D, 0xDF50, 0xDF62, 0xDF73, 0xDF81, 0xDF8C, + 0xDF96, 0xDF9D, 0xDFA1, 0xDFA2, 0xDFA1, 0xDF9D, 0xDF96, 0xDF8C, 0xDF81, + 0xDF73, 0xDF62, 0xDF50, 0xDF3D, 0xDF27, 0xDF10, 0xDEF7, 0xDEDE, 0xDEC3, + 0xDEA7, 0xDE8A, 0xDE6D, 0xDE4F, 0xDE31, 0xDE12, 0xDDF3, 0xDDD5, 0xDDB6, + 0xDD98, 0xDD7A, 0xDD5C, 0xDD40, 0xDD24, 0xDD09, 0xDCEF, 0xDCD7, 0xDCC0, + 0xDCAA, 0xDC96, 0xDC84, 0xDC74, 0xDC66, 0xDC5A, 0xDC51, 0xDC4A, 0xDC46, + 0xFFFF, 0x0000, 0xBF5E, 0x08EE, 0x08EE, 0x08EF, 0x08F0, 0x08F1, 0x08F2, + 0x08F4, 0x08F5, 0x08F7, 0x08FA, 0x08FC, 0x08FF, 0x0901, 0x0904, 0x0907, + 0x090A, 0x090D, 0x0911, 0x0914, 0x0917, 0x091B, 0x091E, 0x0922, 0x0925, + 0x0928, 0x092C, 0x092F, 0x0932, 0x0935, 0x0938, 0x093B, 0x093E, 0x0940, + 0x0943, 0x0945, 0x0947, 0x0949, 0x094A, 0x094C, 0x094D, 0x094D, 0x094E, + 0x094E, 0x094E, 0x094D, 0x094D, 0x094C, 0x094A, 0x0949, 0x0947, 0x0945, + 0x0943, 0x0940, 0x093E, 0x093B, 0x0938, 0x0935, 0x0932, 0x092F, 0x092C, + 0x0928, 0x0925, 0x0922, 0x091E, 0x091B, 0x0917, 0x0914, 0x0911, 0x090D, + 0x090A, 0x0907, 0x0904, 0x0901, 0x08FF, 0x08FC, 0x08FA, 0x08F7, 0x08F5, + 0x08F4, 0x08F2, 0x08F1, 0x08F0, 0x08EF, 0x08EE, 0x049F, 0x049D, 0x0498, + 0x0490, 0x0485, 0x0477, 0x0467, 0x0454, 0x043E, 0x0427, 0x040D, 0x03F2, + 0x03D5, 0x03B7, 0x0397, 0x0376, 0x0354, 0x0332, 0x030E, 0x02EA, 0x02C6, + 0x02A2, 0x027E, 0x0259, 0x0236, 0x0212, 0x01EF, 0x01CE, 0x01AD, 0x018D, + 0x016F, 0x0152, 0x0136, 0x011D, 0x0106, 0x00F0, 0x00DD, 0x00CD, 0x00BF, + 0x00B4, 0x00AB, 0x00A6, 0x00A5, 0x00A6, 0x00AB, 0x00B4, 0x00BF, 0x00CD, + 0x00DD, 0x00F0, 0x0106, 0x011D, 0x0136, 0x0152, 0x016F, 0x018D, 0x01AD, + 0x01CE, 0x01EF, 0x0212, 0x0236, 0x0259, 0x027E, 0x02A2, 0x02C6, 0x02EA, + 0x030E, 0x0332, 0x0354, 0x0376, 0x0397, 0x03B7, 0x03D5, 0x03F2, 0x040D, + 0x0427, 0x043E, 0x0454, 0x0467, 0x0477, 0x0485, 0x0490, 0x0498, 0x049D, + 0xACD4, 0xACD2, 0xACCB, 0xACC0, 0xACB0, 0xAC9D, 0xAC86, 0xAC6C, 0xAC4F, + 0xAC2E, 0xAC0B, 0xABE6, 0xABBE, 0xAB94, 0xAB68, 0xAB3B, 0xAB0C, 0xAADC, + 0xAAAB, 0xAA7A, 0xAA48, 0xAA16, 0xA9E3, 0xA9B2, 0xA980, 0xA94F, 0xA91F, + 0xA8F1, 0xA8C3, 0xA898, 0xA86E, 0xA846, 0xA820, 0xA7FD, 0xA7DD, 0xA7BF, + 0xA7A5, 0xA78E, 0xA77B, 0xA76C, 0xA760, 0xA759, 0xA757, 0xA759, 0xA760, + 0xA76C, 0xA77B, 0xA78E, 0xA7A5, 0xA7BF, 0xA7DD, 0xA7FD, 0xA820, 0xA846, + 0xA86E, 0xA898, 0xA8C3, 0xA8F1, 0xA91F, 0xA94F, 0xA980, 0xA9B2, 0xA9E3, + 0xAA16, 0xAA48, 0xAA7A, 0xAAAB, 0xAADC, 0xAB0C, 0xAB3B, 0xAB68, 0xAB94, + 0xABBE, 0xABE6, 0xAC0B, 0xAC2E, 0xAC4F, 0xAC6C, 0xAC86, 0xAC9D, 0xACB0, + 0xACC0, 0xACCB, 0xACD2, 0x0000, 0x0000, 0x0002, 0x0003, 0x0006, 0x0009, + 0x000D, 0x0012, 0x0017, 0x001C, 0x0022, 0x0029, 0x002F, 0x0036, 0x003E, + 0x0046, 0x004E, 0x0056, 0x005E, 0x0066, 0x006F, 0x0077, 0x0080, 0x0088, + 0x0091, 0x0099, 0x00A1, 0x00A9, 0x00B1, 0x00B8, 0x00BF, 0x00C6, 0x00CD, + 0x00D3, 0x00D8, 0x00DD, 0x00E1, 0x00E5, 0x00E9, 0x00EB, 0x00ED, 0x00EE, + 0x00EF, 0x00EE, 0x00ED, 0x00EB, 0x00E9, 0x00E5, 0x00E1, 0x00DD, 0x00D8, + 0x00D3, 0x00CD, 0x00C6, 0x00BF, 0x00B8, 0x00B1, 0x00A9, 0x00A1, 0x0099, + 0x0091, 0x0088, 0x0080, 0x0077, 0x006F, 0x0066, 0x005E, 0x0056, 0x004E, + 0x0046, 0x003E, 0x0036, 0x002F, 0x0029, 0x0022, 0x001C, 0x0017, 0x0012, + 0x000D, 0x0009, 0x0006, 0x0003, 0x0002, 0x0000, 0xFFFF, 0x0001, 0x0003, + 0x0007, 0x000C, 0x0012, 0x001A, 0x0023, 0x002D, 0x0038, 0x0043, 0x0050, + 0x005E, 0x006C, 0x007A, 0x008A, 0x0099, 0x00A9, 0x00BA, 0x00CA, 0x00DB, + 0x00EC, 0x00FD, 0x010D, 0x011E, 0x012E, 0x013F, 0x014E, 0x015D, 0x016C, + 0x017A, 0x0188, 0x0194, 0x01A0, 0x01AB, 0x01B5, 0x01BE, 0x01C5, 0x01CC, + 0x01D1, 0x01D5, 0x01D7, 0x01D8, 0x01D7, 0x01D5, 0x01D1, 0x01CC, 0x01C5, + 0x01BE, 0x01B5, 0x01AB, 0x01A0, 0x0194, 0x0188, 0x017A, 0x016C, 0x015D, + 0x014E, 0x013F, 0x012E, 0x011E, 0x010D, 0x00FD, 0x00EC, 0x00DB, 0x00CA, + 0x00BA, 0x00A9, 0x0099, 0x008A, 0x007A, 0x006C, 0x005E, 0x0050, 0x0043, + 0x0038, 0x002D, 0x0023, 0x001A, 0x0012, 0x000C, 0x0007, 0x0003, 0x0001, + 0x25EE, 0x25F1, 0x25FB, 0x260C, 0x2623, 0x263F, 0x2661, 0x2687, 0x26B3, + 0x26E3, 0x2716, 0x274E, 0x2789, 0x27C7, 0x2807, 0x284A, 0x288F, 0x28D6, + 0x291E, 0x2967, 0x29B1, 0x29FB, 0x2A45, 0x2A8E, 0x2AD7, 0x2B1F, 0x2B66, + 0x2BAB, 0x2BEE, 0x2C2E, 0x2C6C, 0x2CA7, 0x2CDF, 0x2D12, 0x2D42, 0x2D6E, + 0x2D94, 0x2DB6, 0x2DD2, 0x2DE9, 0x2DFA, 0x2E04, 0x2E07, 0x2E04, 0x2DFA, + 0x2DE9, 0x2DD2, 0x2DB6, 0x2D94, 0x2D6E, 0x2D42, 0x2D12, 0x2CDF, 0x2CA7, + 0x2C6C, 0x2C2E, 0x2BEE, 0x2BAB, 0x2B66, 0x2B1F, 0x2AD7, 0x2A8E, 0x2A45, + 0x29FB, 0x29B1, 0x2967, 0x291E, 0x28D6, 0x288F, 0x284A, 0x2807, 0x27C7, + 0x2789, 0x274E, 0x2716, 0x26E3, 0x26B3, 0x2687, 0x2661, 0x263F, 0x2623, + 0x260C, 0x25FB, 0x25F1, 0x0047, 0x0046, 0x0043, 0x003D, 0x0036, 0x002D, + 0x0022, 0x0016, 0x0008, 0xFFF8, 0xFFE7, 0xFFD6, 0xFFC3, 0xFFAF, 0xFF9B, + 0xFF85, 0xFF6F, 0xFF59, 0xFF42, 0xFF2B, 0xFF13, 0xFEFC, 0xFEE4, 0xFECD, + 0xFEB5, 0xFE9E, 0xFE88, 0xFE72, 0xFE5D, 0xFE48, 0xFE34, 0xFE22, 0xFE10, + 0xFDFF, 0xFDF0, 0xFDE2, 0xFDD6, 0xFDCB, 0xFDC2, 0xFDBB, 0xFDB6, 0xFDB3, + 0xFDB1, 0xFDB3, 0xFDB6, 0xFDBB, 0xFDC2, 0xFDCB, 0xFDD6, 0xFDE2, 0xFDF0, + 0xFDFF, 0xFE10, 0xFE22, 0xFE34, 0xFE48, 0xFE5D, 0xFE72, 0xFE88, 0xFE9E, + 0xFEB5, 0xFECD, 0xFEE4, 0xFEFC, 0xFF13, 0xFF2B, 0xFF42, 0xFF59, 0xFF6F, + 0xFF85, 0xFF9B, 0xFFAF, 0xFFC3, 0xFFD6, 0xFFE7, 0xFFF8, 0x0008, 0x0016, + 0x0022, 0x002D, 0x0036, 0x003D, 0x0043, 0x0046, 0xFF3B, 0xFF3C, 0xFF3D, + 0xFF40, 0xFF43, 0xFF47, 0xFF4C, 0xFF51, 0xFF58, 0xFF5E, 0xFF66, 0xFF6E, + 0xFF76, 0xFF7F, 0xFF88, 0xFF92, 0xFF9B, 0xFFA5, 0xFFB0, 0xFFBA, 0xFFC5, + 0xFFCF, 0xFFDA, 0xFFE4, 0xFFEF, 0xFFF9, 0x0004, 0x000E, 0x0017, 0x0020, + 0x0029, 0x0032, 0x003A, 0x0041, 0x0048, 0x004E, 0x0053, 0x0058, 0x005C, + 0x005F, 0x0062, 0x0063, 0x0064, 0x0063, 0x0062, 0x005F, 0x005C, 0x0058, + 0x0053, 0x004E, 0x0048, 0x0041, 0x003A, 0x0032, 0x0029, 0x0020, 0x0017, + 0x000E, 0x0004, 0xFFF9, 0xFFEF, 0xFFE4, 0xFFDA, 0xFFCF, 0xFFC5, 0xFFBA, + 0xFFB0, 0xFFA5, 0xFF9B, 0xFF92, 0xFF88, 0xFF7F, 0xFF76, 0xFF6E, 0xFF66, + 0xFF5E, 0xFF58, 0xFF51, 0xFF4C, 0xFF47, 0xFF43, 0xFF40, 0xFF3D, 0xFF3C, + 0xBBA8, 0xBBA7, 0xBBA2, 0xBB9A, 0xBB90, 0xBB82, 0xBB72, 0xBB60, 0xBB4C, + 0xBB35, 0xBB1D, 0xBB02, 0xBAE7, 0xBAC9, 0xBAAB, 0xBA8B, 0xBA6B, 0xBA49, + 0xBA27, 0xBA05, 0xB9E2, 0xB9BF, 0xB99C, 0xB97A, 0xB957, 0xB935, 0xB914, + 0xB8F3, 0xB8D4, 0xB8B5, 0xB898, 0xB87C, 0xB862, 0xB84A, 0xB833, 0xB81F, + 0xB80C, 0xB7FD, 0xB7EF, 0xB7E4, 0xB7DD, 0xB7D8, 0xB7D6, 0xB7D8, 0xB7DD, + 0xB7E4, 0xB7EF, 0xB7FD, 0xB80C, 0xB81F, 0xB833, 0xB84A, 0xB862, 0xB87C, + 0xB898, 0xB8B5, 0xB8D4, 0xB8F3, 0xB914, 0xB935, 0xB957, 0xB97A, 0xB99C, + 0xB9BF, 0xB9E2, 0xBA05, 0xBA27, 0xBA49, 0xBA6B, 0xBA8B, 0xBAAB, 0xBAC9, + 0xBAE7, 0xBB02, 0xBB1D, 0xBB35, 0xBB4C, 0xBB60, 0xBB72, 0xBB82, 0xBB90, + 0xBB9A, 0xBBA2, 0xBBA7, + },{ + 0x004D, 0x0000, 0x0053, 0x004D, 0x0051, 0x00A0, 0x0001, 0x00F1, 0x0001, + 0x00F2, 0x0001, 0x00F3, 0x0001, 0x00F4, 0x0001, 0x00F5, 0x0001, 0x00F6, + 0x0052, 0x00F7, 0x0054, 0x0149, 0x0054, 0x019D, 0x0054, 0x01F1, 0x0054, + 0x0245, 0x0054, 0x0299, 0x0001, 0x02ED, 0x0001, 0x02EE, 0x0001, 0x02EF, + 0x0054, 0x02F0, 0x0053, 0x0344, 0x0054, 0x0397, 0x0054, 0x03EB, 0x0054, + 0x043F, 0x0054, 0x0493, 0x0054, 0x04E7, 0x0054, 0x053B, 0x0054, 0x058F, + 0x0001, 0x05E3, 0x0001, 0x05E4, 0x0001, 0x05E5, 0x0054, 0x05E6, 0x0054, + 0x063A, 0x004F, 0x068E, 0x004F, 0x06DD, 0x004E, 0x072C, 0x0001, 0x077A, + 0x0001, 0x077B, 0x0001, 0x077C, 0x0001, 0x077D, 0x0001, 0x077E, 0x0001, + 0x077F, 0x0001, 0x0780, 0x0054, 0x0781, 0x0054, 0x07D5, 0x0054, 0x0829, + 0x0054, 0x087D, 0x0052, 0x08D1, 0x0054, 0x0923, 0x0052, 0x0977, 0x0054, + 0x09C9, 0x0054, 0x0A1D, 0x0001, 0x0A71, 0x0001, 0x0A72, 0x0001, 0x0A73, + 0x0054, 0x0A74, 0x0054, 0x0AC8, 0x0054, 0x0B1C, 0x0054, 0x0B70, 0x0054, + 0x0BC4, 0x0054, 0x0C18, 0x0054, 0x0C6C, 0x0054, 0x0CC0, 0x0054, 0x0D14, +}) + +LUIGI_ANIM_CS_MENU = "luigi_anim_cs_menu" +smlua_anim_util_register_animation(LUIGI_ANIM_CS_MENU, + 0, + 0, + 0, + 0, + 41, + { + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, + 0xFFFE, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFC, 0xFFFC, 0xFFFB, 0xFFFB, 0xFFFB, + 0xFFFB, 0xFFFA, 0xFFFA, 0xFFFA, 0xFFFA, 0xFFFA, 0xFFFB, 0xFFFB, 0xFFFB, + 0xFFFB, 0xFFFC, 0xFFFC, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFE, 0xFFFE, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0093, 0x0093, 0x0093, 0x0093, 0x0092, + 0x0092, 0x0091, 0x0091, 0x0090, 0x0090, 0x008F, 0x008E, 0x008E, 0x008D, + 0x008C, 0x008C, 0x008B, 0x008B, 0x008A, 0x008A, 0x008A, 0x008A, 0x008A, + 0x008A, 0x008A, 0x008B, 0x008B, 0x008C, 0x008C, 0x008D, 0x008E, 0x008E, + 0x008F, 0x0090, 0x0090, 0x0091, 0x0091, 0x0092, 0x0092, 0x0093, 0x0000, + 0x0000, 0x3FFF, 0x0000, 0xE332, 0x0F58, 0x5092, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, + 0xF904, 0xF8FA, 0xF8DE, 0xF8B2, 0xF877, 0xF830, 0xF7DE, 0xF784, 0xF723, + 0xF6BD, 0xF654, 0xF5EA, 0xF581, 0xF51B, 0xF4BA, 0xF460, 0xF40E, 0xF3C7, + 0xF38C, 0xF360, 0xF344, 0xF33A, 0xF344, 0xF360, 0xF38C, 0xF3C7, 0xF40E, + 0xF460, 0xF4BA, 0xF51B, 0xF581, 0xF5EA, 0xF654, 0xF6BD, 0xF723, 0xF784, + 0xF7DE, 0xF830, 0xF877, 0xF8B2, 0xF8DE, 0xF8FA, 0x0000, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, + 0x0000, 0xFFFF, 0x0000, 0xEEFC, 0xEF0E, 0xEF3F, 0xEF8E, 0xEFF7, 0xF076, + 0xF107, 0xF1A8, 0xF255, 0xF30A, 0xF3C5, 0xF481, 0xF53C, 0xF5F1, 0xF69E, + 0xF73F, 0xF7D1, 0xF850, 0xF8B8, 0xF907, 0xF939, 0xF94A, 0xF939, 0xF907, + 0xF8B8, 0xF850, 0xF7D1, 0xF73F, 0xF69E, 0xF5F1, 0xF53C, 0xF481, 0xF3C5, + 0xF30A, 0xF255, 0xF1A8, 0xF107, 0xF076, 0xEFF7, 0xEF8E, 0xEF3F, 0xEF0E, + 0x0000, 0xFFFF, 0xBFFF, 0xD4CC, 0xD4D5, 0xD4EE, 0xD514, 0xD548, 0xD586, + 0xD5CE, 0xD61D, 0xD672, 0xD6CB, 0xD727, 0xD784, 0xD7E0, 0xD839, 0xD88E, + 0xD8DD, 0xD925, 0xD963, 0xD997, 0xD9BD, 0xD9D6, 0xD9DE, 0xD9D6, 0xD9BD, + 0xD997, 0xD963, 0xD925, 0xD8DD, 0xD88E, 0xD839, 0xD7E0, 0xD784, 0xD727, + 0xD6CB, 0xD672, 0xD61D, 0xD5CE, 0xD586, 0xD548, 0xD514, 0xD4EE, 0xD4D5, + 0xD877, 0xD86F, 0xD858, 0xD834, 0xD804, 0xD7C9, 0xD786, 0xD73C, 0xD6ED, + 0xD699, 0xD644, 0xD5ED, 0xD597, 0xD544, 0xD4F4, 0xD4AA, 0xD467, 0xD42D, + 0xD3FD, 0xD3D9, 0xD3C2, 0xD3BA, 0xD3C2, 0xD3D9, 0xD3FD, 0xD42D, 0xD467, + 0xD4AA, 0xD4F4, 0xD544, 0xD597, 0xD5ED, 0xD644, 0xD699, 0xD6ED, 0xD73C, + 0xD786, 0xD7C9, 0xD804, 0xD834, 0xD858, 0xD86F, 0xE45A, 0xE450, 0xE433, + 0xE406, 0xE3CA, 0xE381, 0xE32E, 0xE2D2, 0xE26E, 0xE206, 0xE19B, 0xE130, + 0xE0C5, 0xE05D, 0xDFF9, 0xDF9D, 0xDF4A, 0xDF01, 0xDEC5, 0xDE98, 0xDE7B, + 0xDE71, 0xDE7B, 0xDE98, 0xDEC5, 0xDF01, 0xDF4A, 0xDF9D, 0xDFF9, 0xE05D, + 0xE0C5, 0xE130, 0xE19B, 0xE206, 0xE26E, 0xE2D2, 0xE32E, 0xE381, 0xE3CA, + 0xE406, 0xE433, 0xE450, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFF8, 0xFFE3, + 0xFFC1, 0xFF94, 0xFF5B, 0xFF19, 0xFECE, 0xFE7B, 0xFE21, 0xFDC2, 0xFD5D, + 0xFCF5, 0xFC89, 0xFC1C, 0xFBAE, 0xFB3F, 0xFAD2, 0xFA66, 0xF9FE, 0xF999, + 0xF93A, 0xF8E0, 0xF88D, 0xF842, 0xF800, 0xF7C8, 0xF79A, 0xF778, 0xF763, + 0xF75C, 0xF788, 0xF800, 0xF8B6, 0xF999, 0xFA9C, 0xFBAE, 0xFCBF, 0xFDC2, + 0xFEA6, 0xFF5B, 0xFFD4, 0xDA3F, 0xDA47, 0xDA5D, 0xDA81, 0xDAB2, 0xDAEE, + 0xDB34, 0xDB84, 0xDBDC, 0xDC3B, 0xDCA1, 0xDD0C, 0xDD7B, 0xDDED, 0xDE62, + 0xDED7, 0xDF4D, 0xDFC1, 0xE033, 0xE0A2, 0xE10D, 0xE173, 0xE1D3, 0xE22B, + 0xE27B, 0xE2C1, 0xE2FD, 0xE32D, 0xE351, 0xE367, 0xE36F, 0xE341, 0xE2C1, + 0xE200, 0xE10D, 0xDFFB, 0xDED7, 0xDDB4, 0xDCA1, 0xDBAF, 0xDAEE, 0xDA6E, + 0xE991, 0xE999, 0xE9B0, 0xE9D6, 0xEA09, 0xEA48, 0xEA92, 0xEAE6, 0xEB43, + 0xEBA8, 0xEC13, 0xEC84, 0xECF9, 0xED71, 0xEDEC, 0xEE68, 0xEEE3, 0xEF5E, + 0xEFD6, 0xF04B, 0xF0BC, 0xF127, 0xF18C, 0xF1E9, 0xF23D, 0xF287, 0xF2C6, + 0xF2F9, 0xF31F, 0xF336, 0xF33E, 0xF30E, 0xF287, 0xF1BB, 0xF0BC, 0xEF9A, + 0xEE68, 0xED35, 0xEC13, 0xEB14, 0xEA48, 0xE9C1, 0xFD43, 0xFD39, 0xFD1D, + 0xFCF0, 0xFCB3, 0xFC67, 0xFC0F, 0xFBAA, 0xFB3B, 0xFAC3, 0xFA43, 0xF9BC, + 0xF930, 0xF8A0, 0xF80D, 0xF779, 0xF6E5, 0xF652, 0xF5C2, 0xF536, 0xF4B0, + 0xF42F, 0xF3B7, 0xF348, 0xF2E3, 0xF28B, 0xF23F, 0xF202, 0xF1D5, 0xF1B9, + 0xF1AF, 0xF1E9, 0xF28B, 0xF37E, 0xF4B0, 0xF60A, 0xF779, 0xF8E8, 0xFA43, + 0xFB74, 0xFC67, 0xFD09, 0x0000, 0xFFFF, 0xBFFF, 0xF0C9, 0xF0DC, 0xF115, + 0xF16D, 0xF1E3, 0xF272, 0xF316, 0xF3CB, 0xF48E, 0xF55A, 0xF62C, 0xF700, + 0xF7D3, 0xF89F, 0xF962, 0xFA17, 0xFABB, 0xFB4A, 0xFBBF, 0xFC18, 0xFC50, + 0xFC64, 0xFC50, 0xFC18, 0xFBBF, 0xFB4A, 0xFABB, 0xFA17, 0xF962, 0xF89F, + 0xF7D3, 0xF700, 0xF62C, 0xF55A, 0xF48E, 0xF3CB, 0xF316, 0xF272, 0xF1E3, + 0xF16D, 0xF115, 0xF0DC, 0x1465, 0x1460, 0x1453, 0x143D, 0x1421, 0x13FF, + 0x13D7, 0x13AB, 0x137C, 0x134B, 0x1318, 0x12E5, 0x12B2, 0x1281, 0x1252, + 0x1226, 0x11FF, 0x11DC, 0x11C0, 0x11AA, 0x119D, 0x1198, 0x119D, 0x11AA, + 0x11C0, 0x11DC, 0x11FF, 0x1226, 0x1252, 0x1281, 0x12B2, 0x12E5, 0x1318, + 0x134B, 0x137C, 0x13AB, 0x13D7, 0x13FF, 0x1421, 0x143D, 0x1453, 0x1460, + 0x5DB3, 0x5DC7, 0x5DFF, 0x5E58, 0x5ECE, 0x5F5C, 0x6000, 0x60B5, 0x6178, + 0x6245, 0x6317, 0x63EB, 0x64BD, 0x6589, 0x664C, 0x6701, 0x67A5, 0x6834, + 0x68AA, 0x6903, 0x693B, 0x694E, 0x693B, 0x6903, 0x68AA, 0x6834, 0x67A5, + 0x6701, 0x664C, 0x6589, 0x64BD, 0x63EB, 0x6317, 0x6245, 0x6178, 0x60B6, + 0x6000, 0x5F5C, 0x5ECE, 0x5E58, 0x5DFF, 0x5DC7, 0xFFFF, 0x0000, 0xE171, + 0xE16F, 0xE16A, 0xE162, 0xE157, 0xE14A, 0xE13B, 0xE12B, 0xE119, 0xE106, + 0xE0F3, 0xE0E0, 0xE0CD, 0xE0BA, 0xE0A9, 0xE098, 0xE089, 0xE07C, 0xE072, + 0xE06A, 0xE064, 0xE063, 0xE064, 0xE06A, 0xE072, 0xE07C, 0xE089, 0xE098, + 0xE0A9, 0xE0BA, 0xE0CD, 0xE0E0, 0xE0F3, 0xE106, 0xE119, 0xE12B, 0xE13B, + 0xE14A, 0xE157, 0xE162, 0xE16A, 0xE16F, 0x0E24, 0x0E24, 0x0E24, 0x0E25, + 0x0E26, 0x0E27, 0x0E29, 0x0E2A, 0x0E2C, 0x0E2E, 0x0E30, 0x0E32, 0x0E33, + 0x0E35, 0x0E37, 0x0E39, 0x0E3A, 0x0E3B, 0x0E3C, 0x0E3D, 0x0E3E, 0x0E3E, + 0x0E3E, 0x0E3D, 0x0E3C, 0x0E3B, 0x0E3A, 0x0E39, 0x0E37, 0x0E35, 0x0E33, + 0x0E32, 0x0E30, 0x0E2E, 0x0E2C, 0x0E2A, 0x0E29, 0x0E27, 0x0E26, 0x0E25, + 0x0E24, 0x02BF, 0x02BE, 0x02B9, 0x02B2, 0x02A8, 0x029D, 0x028F, 0x0281, + 0x0271, 0x0260, 0x024F, 0x023E, 0x022D, 0x021D, 0x020D, 0x01FE, 0x01F1, + 0x01E6, 0x01DC, 0x01D5, 0x01D0, 0x01CF, 0x01D0, 0x01D5, 0x01DC, 0x01E6, + 0x01F1, 0x01FE, 0x020D, 0x021D, 0x022D, 0x023E, 0x024F, 0x0260, 0x0271, + 0x0281, 0x028F, 0x029D, 0x02A8, 0x02B2, 0x02B9, 0x02BE, 0xF6AE, 0xF6A1, + 0xF67C, 0xF641, 0xF5F4, 0xF596, 0xF52A, 0xF4B3, 0xF433, 0xF3AC, 0xF322, + 0xF297, 0xF20C, 0xF186, 0xF106, 0xF08F, 0xF023, 0xEFC5, 0xEF77, 0xEF3D, + 0xEF18, 0xEF0B, 0xEF18, 0xEF3D, 0xEF77, 0xEFC5, 0xF023, 0xF08F, 0xF106, + 0xF186, 0xF20C, 0xF297, 0xF322, 0xF3AC, 0xF433, 0xF4B3, 0xF52A, 0xF596, + 0xF5F4, 0xF641, 0xF67C, 0xF6A1, 0x0000, 0xFFFF, 0xBF5E, 0xB180, 0xB176, + 0xB15B, 0xB131, 0xB0F8, 0xB0B3, 0xB064, 0xB00D, 0xAFAF, 0xAF4D, 0xAEE8, + 0xAE82, 0xAE1D, 0xADBB, 0xAD5D, 0xAD06, 0xACB7, 0xAC72, 0xAC39, 0xAC0F, + 0xABF4, 0xABEA, 0xABF4, 0xAC0F, 0xAC39, 0xAC72, 0xACB7, 0xAD06, 0xAD5D, + 0xADBB, 0xAE1D, 0xAE82, 0xAEE8, 0xAF4D, 0xAFAF, 0xB00D, 0xB064, 0xB0B3, + 0xB0F8, 0xB131, 0xB15B, 0xB176, 0xE760, 0xE754, 0xE72F, 0xE6F5, 0xE6A8, + 0xE64B, 0xE5E0, 0xE56A, 0xE4EB, 0xE466, 0xE3DD, 0xE352, 0xE2C9, 0xE244, + 0xE1C5, 0xE14F, 0xE0E4, 0xE087, 0xE03A, 0xE000, 0xDFDC, 0xDFCF, 0xDFDC, + 0xE000, 0xE03A, 0xE087, 0xE0E4, 0xE14F, 0xE1C5, 0xE244, 0xE2C9, 0xE352, + 0xE3DD, 0xE466, 0xE4EB, 0xE56A, 0xE5E0, 0xE64B, 0xE6A8, 0xE6F5, 0xE72F, + 0xE754, 0xBA08, 0xBA12, 0xBA2F, 0xBA5D, 0xBA99, 0xBAE3, 0xBB38, 0xBB95, + 0xBBFA, 0xBC63, 0xBCD0, 0xBD3D, 0xBDAA, 0xBE13, 0xBE78, 0xBED5, 0xBF2A, + 0xBF74, 0xBFB1, 0xBFDE, 0xBFFB, 0xC006, 0xBFFB, 0xBFDE, 0xBFB1, 0xBF74, + 0xBF2A, 0xBED5, 0xBE78, 0xBE13, 0xBDAA, 0xBD3D, 0xBCD0, 0xBC63, 0xBBFA, + 0xBB95, 0xBB38, 0xBAE3, 0xBA99, 0xBA5D, 0xBA2F, 0xBA12, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, + 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0018, 0x005C, 0x00C7, 0x0156, + 0x0203, 0x02C9, 0x03A4, 0x0490, 0x0588, 0x0686, 0x0787, 0x0885, 0x097C, + 0x0A68, 0x0B44, 0x0C0A, 0x0CB7, 0x0D45, 0x0DB1, 0x0DF5, 0x0E0D, 0x0DF5, + 0x0DB1, 0x0D45, 0x0CB7, 0x0C0A, 0x0B44, 0x0A68, 0x097C, 0x0885, 0x0787, + 0x0686, 0x0588, 0x0490, 0x03A4, 0x02C9, 0x0203, 0x0156, 0x00C7, 0x005C, + 0x0018, 0xF9B8, 0xF9B8, 0xF9B8, 0xF9B9, 0xF9BA, 0xF9BB, 0xF9BC, 0xF9BD, + 0xF9BF, 0xF9C0, 0xF9C2, 0xF9C3, 0xF9C5, 0xF9C6, 0xF9C8, 0xF9C9, 0xF9CA, + 0xF9CB, 0xF9CC, 0xF9CD, 0xF9CD, 0xF9CD, 0xF9CD, 0xF9CD, 0xF9CC, 0xF9CB, + 0xF9CA, 0xF9C9, 0xF9C8, 0xF9C6, 0xF9C5, 0xF9C3, 0xF9C2, 0xF9C0, 0xF9BF, + 0xF9BD, 0xF9BC, 0xF9BB, 0xF9BA, 0xF9B9, 0xF9B8, 0x01DD, 0x01DA, 0x01D3, + 0x01C7, 0x01B8, 0x01A5, 0x0190, 0x0178, 0x015E, 0x0144, 0x0128, 0x010C, + 0x00F1, 0x00D6, 0x00BD, 0x00A5, 0x0090, 0x007D, 0x006E, 0x0062, 0x005B, + 0x0058, 0x005B, 0x0062, 0x006E, 0x007D, 0x0090, 0x00A5, 0x00BD, 0x00D6, + 0x00F1, 0x010C, 0x0128, 0x0144, 0x015E, 0x0178, 0x0190, 0x01A5, 0x01B8, + 0x01C7, 0x01D3, 0x01DA, 0xEA21, 0xEA19, 0xEA02, 0xE9DE, 0xE9AF, 0xE976, + 0xE934, 0xE8EB, 0xE89C, 0xE84A, 0xE7F6, 0xE7A0, 0xE74C, 0xE6FA, 0xE6AB, + 0xE663, 0xE621, 0xE5E7, 0xE5B8, 0xE594, 0xE57E, 0xE576, 0xE57E, 0xE594, + 0xE5B8, 0xE5E7, 0xE621, 0xE663, 0xE6AB, 0xE6FA, 0xE74C, 0xE7A0, 0xE7F6, + 0xE84A, 0xE89C, 0xE8EB, 0xE934, 0xE976, 0xE9AF, 0xE9DE, 0xEA02, 0xEA19, + 0x0000, 0xFFFF, 0xBF5E, 0x1644, 0x1641, 0x1639, 0x162D, 0x161D, 0x160A, + 0x15F4, 0x15DB, 0x15C1, 0x15A5, 0x1589, 0x156C, 0x1550, 0x1534, 0x151A, + 0x1501, 0x14EB, 0x14D8, 0x14C8, 0x14BC, 0x14B4, 0x14B2, 0x14B4, 0x14BC, + 0x14C8, 0x14D8, 0x14EB, 0x1501, 0x151A, 0x1534, 0x1550, 0x156C, 0x1589, + 0x15A5, 0x15C1, 0x15DB, 0x15F4, 0x160A, 0x161D, 0x162D, 0x1639, 0x1641, + 0x1617, 0x1619, 0x1621, 0x162C, 0x163B, 0x164D, 0x1662, 0x1679, 0x1692, + 0x16AD, 0x16C7, 0x16E3, 0x16FD, 0x1718, 0x1730, 0x1748, 0x175D, 0x176F, + 0x177E, 0x1789, 0x1791, 0x1793, 0x1791, 0x1789, 0x177E, 0x176F, 0x175D, + 0x1748, 0x1730, 0x1718, 0x16FD, 0x16E3, 0x16C7, 0x16AD, 0x1692, 0x1679, + 0x1662, 0x164D, 0x163B, 0x162C, 0x1621, 0x1619, 0x8DFE, 0x8DF9, 0x8DEC, + 0x8DD6, 0x8DB9, 0x8D96, 0x8D6F, 0x8D42, 0x8D13, 0x8CE1, 0x8CAE, 0x8C7A, + 0x8C47, 0x8C15, 0x8BE6, 0x8BBA, 0x8B92, 0x8B6F, 0x8B52, 0x8B3D, 0x8B2F, + 0x8B2A, 0x8B2F, 0x8B3D, 0x8B52, 0x8B6F, 0x8B92, 0x8BBA, 0x8BE6, 0x8C15, + 0x8C47, 0x8C7A, 0x8CAE, 0x8CE1, 0x8D13, 0x8D42, 0x8D6F, 0x8D96, 0x8DB9, + 0x8DD6, 0x8DEC, 0x8DF9, 0xFEDD, 0xFEDD, 0xFEDC, 0xFEDB, 0xFED9, 0xFED7, + 0xFED4, 0xFED2, 0xFECF, 0xFECC, 0xFEC9, 0xFEC5, 0xFEC2, 0xFEBF, 0xFEBC, + 0xFEBA, 0xFEB7, 0xFEB5, 0xFEB3, 0xFEB2, 0xFEB1, 0xFEB1, 0xFEB1, 0xFEB2, + 0xFEB3, 0xFEB5, 0xFEB7, 0xFEBA, 0xFEBC, 0xFEBF, 0xFEC2, 0xFEC5, 0xFEC9, + 0xFECC, 0xFECF, 0xFED2, 0xFED4, 0xFED7, 0xFED9, 0xFEDB, 0xFEDC, 0xFEDD, + 0x0204, 0x0204, 0x0203, 0x0201, 0x01FF, 0x01FC, 0x01FA, 0x01F6, 0x01F3, + 0x01EF, 0x01EB, 0x01E8, 0x01E4, 0x01E0, 0x01DD, 0x01DA, 0x01D7, 0x01D4, + 0x01D2, 0x01D0, 0x01CF, 0x01CF, 0x01CF, 0x01D0, 0x01D2, 0x01D4, 0x01D7, + 0x01DA, 0x01DD, 0x01E0, 0x01E4, 0x01E8, 0x01EB, 0x01EF, 0x01F3, 0x01F6, + 0x01FA, 0x01FC, 0x01FF, 0x0201, 0x0203, 0x0204, 0x3560, 0x356C, 0x3591, + 0x35CA, 0x3616, 0x3673, 0x36DD, 0x3752, 0x37D0, 0x3854, 0x38DC, 0x3966, + 0x39ED, 0x3A72, 0x3AF0, 0x3B65, 0x3BCF, 0x3C2B, 0x3C78, 0x3CB1, 0x3CD5, + 0x3CE2, 0x3CD5, 0x3CB1, 0x3C78, 0x3C2B, 0x3BCF, 0x3B65, 0x3AF0, 0x3A72, + 0x39ED, 0x3966, 0x38DC, 0x3854, 0x37D0, 0x3752, 0x36DD, 0x3673, 0x3616, + 0x35CA, 0x3591, 0x356C, 0x026C, 0x026C, 0x026A, 0x0268, 0x0265, 0x0261, + 0x025C, 0x0257, 0x0252, 0x024D, 0x0247, 0x0241, 0x023B, 0x0236, 0x0231, + 0x022C, 0x0227, 0x0223, 0x0220, 0x021E, 0x021C, 0x021C, 0x021C, 0x021E, + 0x0220, 0x0223, 0x0227, 0x022C, 0x0231, 0x0236, 0x023B, 0x0241, 0x0247, + 0x024D, 0x0252, 0x0257, 0x025C, 0x0261, 0x0265, 0x0268, 0x026A, 0x026C, + 0x00C0, 0x00C0, 0x00C1, 0x00C3, 0x00C6, 0x00CA, 0x00CD, 0x00D2, 0x00D6, + 0x00DB, 0x00E0, 0x00E5, 0x00EA, 0x00EE, 0x00F3, 0x00F7, 0x00FB, 0x00FE, + 0x0101, 0x0103, 0x0104, 0x0105, 0x0104, 0x0103, 0x0101, 0x00FE, 0x00FB, + 0x00F7, 0x00F3, 0x00EE, 0x00EA, 0x00E5, 0x00E0, 0x00DB, 0x00D6, 0x00D2, + 0x00CD, 0x00CA, 0x00C6, 0x00C3, 0x00C1, 0x00C0, 0xBB3A, 0xBB33, 0xBB1C, + 0xBAF9, 0xBACB, 0xBA92, 0xBA52, 0xBA0A, 0xB9BD, 0xB96D, 0xB91A, 0xB8C6, + 0xB873, 0xB822, 0xB7D6, 0xB78E, 0xB74D, 0xB715, 0xB6E7, 0xB6C3, 0xB6AD, + 0xB6A6, 0xB6AD, 0xB6C3, 0xB6E7, 0xB715, 0xB74D, 0xB78E, 0xB7D6, 0xB822, + 0xB873, 0xB8C6, 0xB91A, 0xB96D, 0xB9BD, 0xBA0A, 0xBA52, 0xBA92, 0xBACB, + 0xBAF9, 0xBB1C, 0xBB33, + },{ + 0x0028, 0x0000, 0x0028, 0x0028, 0x0001, 0x0050, 0x0001, 0x0051, 0x0001, + 0x0052, 0x0001, 0x0053, 0x0001, 0x0054, 0x0001, 0x0055, 0x0001, 0x0056, + 0x0024, 0x0057, 0x0015, 0x007B, 0x002A, 0x0090, 0x0029, 0x00BA, 0x0001, + 0x00E3, 0x002A, 0x00E4, 0x0001, 0x010E, 0x0001, 0x010F, 0x0001, 0x0110, + 0x002A, 0x0111, 0x002A, 0x013B, 0x002A, 0x0165, 0x0029, 0x018F, 0x0019, + 0x01B8, 0x002A, 0x01D1, 0x002A, 0x01FB, 0x002A, 0x0225, 0x002A, 0x024F, + 0x0001, 0x0279, 0x0001, 0x027A, 0x0001, 0x027B, 0x002A, 0x027C, 0x002A, + 0x02A6, 0x002A, 0x02D0, 0x0001, 0x02FA, 0x0001, 0x02FB, 0x002A, 0x02FC, + 0x0029, 0x0326, 0x002A, 0x034F, 0x002A, 0x0379, 0x0001, 0x03A3, 0x0001, + 0x03A4, 0x0001, 0x03A5, 0x002A, 0x03A6, 0x002A, 0x03D0, 0x002A, 0x03FA, + 0x0016, 0x0424, 0x0014, 0x043A, 0x002A, 0x044E, 0x0029, 0x0478, 0x002A, + 0x04A1, 0x002A, 0x04CB, 0x0001, 0x04F5, 0x0001, 0x04F6, 0x0001, 0x04F7, + 0x002A, 0x04F8, 0x002A, 0x0522, 0x002A, 0x054C, 0x002A, 0x0576, 0x002A, + 0x05A0, 0x002A, 0x05CA, 0x002A, 0x05F4, 0x002A, 0x061E, 0x002A, 0x0648, +}) + +TOAD_PLAYER_ANIM_CS_MENU = "toad_anim_cs_menu" +smlua_anim_util_register_animation(TOAD_PLAYER_ANIM_CS_MENU, + 0, + 0, + 0, + 0, + 41, + { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0002, 0x0002, 0x0002, 0x0003, 0x0003, 0x0003, 0x0004, 0x0004, 0x0004, + 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, + 0x0004, 0x0003, 0x0003, 0x0003, 0x0002, 0x0002, 0x0002, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0000, 0x012C, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFE, 0xFFFE, 0xFFFD, 0xFFFD, 0xFFFC, 0xFFFB, 0xFFFB, 0xFFFA, + 0xFFFA, 0xFFF9, 0xFFF8, 0xFFF8, 0xFFF8, 0xFFF7, 0xFFF7, 0xFFF7, 0xFFF7, + 0xFFF7, 0xFFF8, 0xFFF8, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFA, 0xFFFB, 0xFFFB, + 0xFFFC, 0xFFFD, 0xFFFD, 0xFFFE, 0xFFFE, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0x3FFF, 0xFFFF, 0xFFE3, 0xFFE3, 0xFFE2, 0xFFE2, 0xFFE1, 0xFFE1, 0xFFE0, + 0xFFDF, 0xFFDE, 0xFFDD, 0xFFDC, 0xFFDB, 0xFFDA, 0xFFD9, 0xFFD8, 0xFFD7, + 0xFFD6, 0xFFD5, 0xFFD5, 0xFFD4, 0xFFD4, 0xFFD4, 0xFFD4, 0xFFD4, 0xFFD5, + 0xFFD5, 0xFFD6, 0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, + 0xFFDE, 0xFFDF, 0xFFE0, 0xFFE1, 0xFFE1, 0xFFE2, 0xFFE2, 0xFFE3, 0xF8E3, + 0xF8DD, 0xF8CC, 0xF8B0, 0xF88C, 0xF861, 0xF82E, 0xF7F7, 0xF7BB, 0xF77D, + 0xF73C, 0xF6FB, 0xF6BB, 0xF67C, 0xF641, 0xF609, 0xF5D7, 0xF5AB, 0xF587, + 0xF56C, 0xF55B, 0xF555, 0xF55B, 0xF56C, 0xF587, 0xF5AB, 0xF5D7, 0xF609, + 0xF641, 0xF67C, 0xF6BB, 0xF6FB, 0xF73C, 0xF77D, 0xF7BB, 0xF7F7, 0xF82E, + 0xF861, 0xF88C, 0xF8B0, 0xF8CC, 0xF8DD, 0x40A3, 0x40A3, 0x40A3, 0x40A3, + 0x40A3, 0x40A3, 0x40A4, 0x40A4, 0x40A4, 0x40A4, 0x40A4, 0x40A5, 0x40A5, + 0x40A5, 0x40A5, 0x40A6, 0x40A6, 0x40A6, 0x40A6, 0x40A6, 0x40A6, 0x40A6, + 0x40A6, 0x40A6, 0x40A6, 0x40A6, 0x40A6, 0x40A6, 0x40A5, 0x40A5, 0x40A5, + 0x40A5, 0x40A4, 0x40A4, 0x40A4, 0x40A4, 0x40A4, 0x40A3, 0xFFFF, 0xFFFF, + 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, + 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, + 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, + 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, + 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0x0000, 0x0884, 0xFC56, 0xFC54, 0xFC50, 0xFC49, 0xFC3F, 0xFC34, 0xFC27, + 0xFC19, 0xFC0A, 0xFBFA, 0xFBE9, 0xFBD8, 0xFBC8, 0xFBB8, 0xFBA9, 0xFB9A, + 0xFB8D, 0xFB82, 0xFB79, 0xFB72, 0xFB6E, 0xFB6C, 0xFB6E, 0xFB72, 0xFB79, + 0xFB82, 0xFB8D, 0xFB9A, 0xFBA9, 0xFBB8, 0xFBC8, 0xFBD8, 0xFBE9, 0xFBFA, + 0xFC0A, 0xFC19, 0xFC27, 0xFC34, 0xFC3F, 0xFC49, 0xFC50, 0xFC54, 0x0A28, + 0x0A31, 0x0A4D, 0x0A78, 0x0AB2, 0x0AF7, 0x0B47, 0x0BA0, 0x0BFF, 0x0C62, + 0x0CC9, 0x0D31, 0x0D97, 0x0DFB, 0x0E5A, 0x0EB2, 0x0F02, 0x0F48, 0x0F81, + 0x0FAD, 0x0FC8, 0x0FD2, 0x0FC8, 0x0FAD, 0x0F81, 0x0F48, 0x0F02, 0x0EB2, + 0x0E5A, 0x0DFB, 0x0D97, 0x0D31, 0x0CC9, 0x0C62, 0x0BFF, 0x0BA0, 0x0B47, + 0x0AF7, 0x0AB2, 0x0A78, 0x0A4D, 0x0A31, 0xF89E, 0xF898, 0xF884, 0xF866, + 0xF83D, 0xF80C, 0xF7D3, 0xF795, 0xF751, 0xF70B, 0xF6C2, 0xF679, 0xF630, + 0xF5EA, 0xF5A7, 0xF568, 0xF530, 0xF4FE, 0xF4D6, 0xF4B7, 0xF4A4, 0xF49D, + 0xF4A4, 0xF4B7, 0xF4D6, 0xF4FE, 0xF530, 0xF568, 0xF5A7, 0xF5EA, 0xF630, + 0xF679, 0xF6C2, 0xF70B, 0xF751, 0xF795, 0xF7D3, 0xF80C, 0xF83D, 0xF866, + 0xF884, 0xF898, 0xFFFE, 0x0001, 0xC170, 0x3654, 0xE59C, 0x3B9C, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, + 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFC3, + 0xFF20, 0xFE31, 0xFD0E, 0xFBD1, 0xFA94, 0xF971, 0xF881, 0xF7DE, 0xF7A3, + 0xF7BD, 0xF80A, 0xF884, 0xF924, 0xF9E6, 0xFAC4, 0xFBB9, 0xFCBE, 0xFDD0, + 0xFEE7, 0x0000, 0x0113, 0x021D, 0x0319, 0x0402, 0x04D4, 0x058A, 0x061F, + 0x0690, 0x06D7, 0x06EF, 0x06C6, 0x0654, 0x05AB, 0x04DA, 0x03F0, 0x02FF, + 0x0215, 0x0144, 0x009B, 0x0029, 0x0000, 0x0023, 0x0044, 0x0065, 0x0083, + 0x009F, 0x00B7, 0x00CB, 0x00DA, 0x00E4, 0x00E7, 0x00E5, 0x00DE, 0x00D3, + 0x00C4, 0x00B1, 0x009B, 0x0082, 0x0065, 0x0046, 0x0024, 0x0000, 0xFFD9, + 0xFFB2, 0xFF8C, 0xFF67, 0xFF44, 0xFF26, 0xFF0C, 0xFEF8, 0xFEEB, 0xFEE6, + 0xFEEA, 0xFEF4, 0xFF03, 0xFF17, 0xFF30, 0xFF4D, 0xFF6D, 0xFF8F, 0xFFB3, + 0xFFD9, 0xF97B, 0xF97D, 0xF980, 0xF982, 0xF984, 0xF986, 0xF988, 0xF989, + 0xF98A, 0xF98B, 0xF98B, 0xF98B, 0xF98A, 0xF988, 0xF986, 0xF984, 0xF982, + 0xF980, 0xF97E, 0xF97C, 0xF97B, 0xF97B, 0xF97C, 0xF97D, 0xF980, 0xF983, + 0xF987, 0xF98A, 0xF98E, 0xF990, 0xF992, 0xF993, 0xF992, 0xF991, 0xF990, + 0xF98E, 0xF98C, 0xF98A, 0xF987, 0xF984, 0xF981, 0xF97E, 0xED8B, 0xECB1, + 0xEBDC, 0xEB0F, 0xEA50, 0xE9A2, 0xE90A, 0xE88C, 0xE82C, 0xE7F0, 0xE7DB, + 0xE7E9, 0xE814, 0xE859, 0xE8B8, 0xE92E, 0xE9BA, 0xEA5B, 0xEB0E, 0xEBD3, + 0xECA8, 0xED8B, 0xEE7A, 0xEF6E, 0xF061, 0xF14B, 0xF224, 0xF2E6, 0xF38A, + 0xF408, 0xF459, 0xF475, 0xF460, 0xF423, 0xF3C2, 0xF341, 0xF2A4, 0xF1EF, + 0xF126, 0xF04D, 0xEF68, 0xEE7C, 0xFFFE, 0x0001, 0xC170, 0x20DC, 0x20E4, + 0x20FA, 0x211D, 0x214C, 0x2184, 0x21C5, 0x220D, 0x225B, 0x22AC, 0x22FF, + 0x2353, 0x23A6, 0x23F7, 0x2445, 0x248C, 0x24CD, 0x2506, 0x2535, 0x2558, + 0x256E, 0x2576, 0x256E, 0x2558, 0x2535, 0x2506, 0x24CD, 0x248C, 0x2445, + 0x23F7, 0x23A6, 0x2353, 0x22FF, 0x22AC, 0x225B, 0x220D, 0x21C5, 0x2184, + 0x214C, 0x211D, 0x20FA, 0x20E4, 0x20E0, 0x20DF, 0x20DB, 0x20D6, 0x20CF, + 0x20C7, 0x20BD, 0x20B3, 0x20A8, 0x209C, 0x208F, 0x2083, 0x2077, 0x206B, + 0x205F, 0x2055, 0x204B, 0x2043, 0x203C, 0x2037, 0x2034, 0x2032, 0x2034, + 0x2037, 0x203C, 0x2043, 0x204B, 0x2055, 0x205F, 0x206B, 0x2077, 0x2083, + 0x208F, 0x209C, 0x20A7, 0x20B3, 0x20BD, 0x20C7, 0x20CF, 0x20D6, 0x20DB, + 0x20DF, 0xD0CB, 0xD0DB, 0xD109, 0xD152, 0xD1B2, 0xD226, 0xD2AC, 0xD340, + 0xD3DF, 0xD485, 0xD531, 0xD5DE, 0xD689, 0xD730, 0xD7CF, 0xD863, 0xD8E8, + 0xD95D, 0xD9BD, 0xDA05, 0xDA33, 0xDA43, 0xDA33, 0xDA05, 0xD9BD, 0xD95D, + 0xD8E8, 0xD863, 0xD7CF, 0xD730, 0xD689, 0xD5DE, 0xD531, 0xD485, 0xD3DF, + 0xD340, 0xD2AC, 0xD226, 0xD1B2, 0xD152, 0xD109, 0xD0DB, 0x0000, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, + 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, + 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFF9, 0xFFE7, 0xFFCA, + 0xFFA4, 0xFF76, 0xFF42, 0xFF07, 0xFEC9, 0xFE87, 0xFE44, 0xFDFF, 0xFDBC, + 0xFD7A, 0xFD3C, 0xFD01, 0xFCCD, 0xFC9F, 0xFC79, 0xFC5C, 0xFC4A, 0xFC44, + 0xFC4A, 0xFC5C, 0xFC79, 0xFC9F, 0xFCCD, 0xFD01, 0xFD3C, 0xFD7A, 0xFDBC, + 0xFDFF, 0xFE44, 0xFE87, 0xFEC9, 0xFF07, 0xFF42, 0xFF76, 0xFFA4, 0xFFCA, + 0xFFE7, 0xFFF9, 0xFFFF, 0x0016, 0x0056, 0x00BB, 0x0141, 0x01E3, 0x029E, + 0x036C, 0x0449, 0x0531, 0x0620, 0x0711, 0x0800, 0x08E9, 0x09C6, 0x0A94, + 0x0B4E, 0x0BF1, 0x0C76, 0x0CDC, 0x0D1B, 0x0D32, 0x0D1B, 0x0CDC, 0x0C76, + 0x0BF1, 0x0B4E, 0x0A94, 0x09C6, 0x08E9, 0x0800, 0x0711, 0x0620, 0x0531, + 0x0449, 0x036C, 0x029E, 0x01E3, 0x0141, 0x00BB, 0x0056, 0x0016, 0xF548, + 0xF547, 0xF544, 0xF540, 0xF53A, 0xF532, 0xF52A, 0xF521, 0xF517, 0xF50C, + 0xF502, 0xF4F7, 0xF4EC, 0xF4E2, 0xF4D8, 0xF4CF, 0xF4C6, 0xF4BF, 0xF4B9, + 0xF4B5, 0xF4B2, 0xF4B1, 0xF4B2, 0xF4B5, 0xF4B9, 0xF4BF, 0xF4C6, 0xF4CF, + 0xF4D8, 0xF4E2, 0xF4EC, 0xF4F7, 0xF502, 0xF50C, 0xF517, 0xF521, 0xF52A, + 0xF532, 0xF53A, 0xF540, 0xF544, 0xF547, 0x0000, 0xFFFF, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, + 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xBF5E, 0xD227, + 0xF622, 0xBEC5, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x2537, + 0x1DEE, 0x1DEB, 0x1DE0, 0x1DCF, 0x1DB9, 0x1D9E, 0x1D7F, 0x1D5D, 0x1D38, + 0x1D12, 0x1CEA, 0x1CC2, 0x1C9B, 0x1C74, 0x1C50, 0x1C2D, 0x1C0F, 0x1BF4, + 0x1BDD, 0x1BCD, 0x1BC2, 0x1BBE, 0x1BC2, 0x1BCD, 0x1BDD, 0x1BF4, 0x1C0F, + 0x1C2D, 0x1C50, 0x1C74, 0x1C9B, 0x1CC2, 0x1CEA, 0x1D12, 0x1D38, 0x1D5D, + 0x1D7F, 0x1D9E, 0x1DB9, 0x1DCF, 0x1DE0, 0x1DEB, 0x105C, 0x1063, 0x1075, + 0x1093, 0x10BA, 0x10EA, 0x1121, 0x115E, 0x119F, 0x11E3, 0x1229, 0x1270, + 0x12B7, 0x12FB, 0x133C, 0x1379, 0x13AF, 0x13DF, 0x1407, 0x1424, 0x1437, + 0x143E, 0x1437, 0x1424, 0x1407, 0x13DF, 0x13AF, 0x1379, 0x133C, 0x12FB, + 0x12B7, 0x1270, 0x1229, 0x11E3, 0x119F, 0x115E, 0x1121, 0x10EA, 0x10BA, + 0x1093, 0x1075, 0x1063, 0xCCA9, 0xCCA0, 0xCC88, 0xCC62, 0xCC2F, 0xCBF1, + 0xCBAA, 0xCB5B, 0xCB07, 0xCAAE, 0xCA53, 0xC9F8, 0xC99D, 0xC944, 0xC8F0, + 0xC8A1, 0xC85A, 0xC81C, 0xC7E9, 0xC7C3, 0xC7AB, 0xC7A2, 0xC7AB, 0xC7C3, + 0xC7E9, 0xC81C, 0xC85A, 0xC8A1, 0xC8F0, 0xC944, 0xC99D, 0xC9F8, 0xCA53, + 0xCAAE, 0xCB07, 0xCB5B, 0xCBAA, 0xCBF1, 0xCC2F, 0xCC62, 0xCC88, 0xCCA0, + 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, + 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, + 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, + 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, + 0xFFFF, 0x0000, 0xBF5E, 0x0C12, 0x0C13, 0x0C17, 0x0C1C, 0x0C23, 0x0C2C, + 0x0C36, 0x0C41, 0x0C4D, 0x0C59, 0x0C66, 0x0C73, 0x0C80, 0x0C8C, 0x0C98, + 0x0CA3, 0x0CAD, 0x0CB6, 0x0CBD, 0x0CC2, 0x0CC6, 0x0CC7, 0x0CC6, 0x0CC2, + 0x0CBD, 0x0CB6, 0x0CAD, 0x0CA3, 0x0C98, 0x0C8C, 0x0C80, 0x0C73, 0x0C66, + 0x0C59, 0x0C4D, 0x0C41, 0x0C36, 0x0C2C, 0x0C23, 0x0C1C, 0x0C17, 0x0C13, + 0x052E, 0x0520, 0x04F9, 0x04BB, 0x0468, 0x0404, 0x0391, 0x0312, 0x0289, + 0x01FA, 0x0166, 0x00D1, 0x003E, 0xFFAE, 0xFF25, 0xFEA6, 0xFE33, 0xFDCF, + 0xFD7C, 0xFD3E, 0xFD16, 0xFD08, 0xFD16, 0xFD3E, 0xFD7C, 0xFDCF, 0xFE33, + 0xFEA6, 0xFF25, 0xFFAE, 0x003E, 0x00D1, 0x0166, 0x01FA, 0x0289, 0x0312, + 0x0391, 0x0404, 0x0468, 0x04BB, 0x04F9, 0x0520, 0xAFF2, 0xB01C, 0xB095, + 0xB154, 0xB252, 0xB386, 0xB4E7, 0xB66E, 0xB812, 0xB9CB, 0xBB90, 0xBD59, + 0xBF1E, 0xC0D6, 0xC27A, 0xC401, 0xC562, 0xC696, 0xC794, 0xC853, 0xC8CC, + 0xC8F7, 0xC8CC, 0xC853, 0xC794, 0xC696, 0xC562, 0xC401, 0xC27A, 0xC0D6, + 0xBF1E, 0xBD59, 0xBB90, 0xB9CB, 0xB812, 0xB66E, 0xB4E7, 0xB386, 0xB252, + 0xB154, 0xB095, 0xB01C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFC2, 0x00E3, 0x00E6, + 0x00EF, 0x00FD, 0x010F, 0x0125, 0x013E, 0x015A, 0x0178, 0x0198, 0x01B8, + 0x01D9, 0x01FA, 0x0219, 0x0237, 0x0253, 0x026D, 0x0283, 0x0295, 0x02A3, + 0x02AB, 0x02AE, 0x02AB, 0x02A3, 0x0295, 0x0283, 0x026D, 0x0253, 0x0237, + 0x0219, 0x01FA, 0x01D9, 0x01B8, 0x0198, 0x0178, 0x015A, 0x013E, 0x0125, + 0x010F, 0x00FD, 0x00EF, 0x00E6, 0x0633, 0x0632, 0x0630, 0x062B, 0x0626, + 0x061F, 0x0618, 0x060F, 0x0606, 0x05FD, 0x05F3, 0x05E9, 0x05E0, 0x05D6, + 0x05CD, 0x05C5, 0x05BD, 0x05B7, 0x05B1, 0x05AD, 0x05AB, 0x05AA, 0x05AB, + 0x05AD, 0x05B1, 0x05B7, 0x05BD, 0x05C5, 0x05CD, 0x05D6, 0x05E0, 0x05E9, + 0x05F3, 0x05FD, 0x0606, 0x060F, 0x0618, 0x061F, 0x0626, 0x062B, 0x0630, + 0x0632, 0xBF73, 0xBF88, 0xBFC3, 0xC021, 0xC09E, 0xC135, 0xC1E2, 0xC2A2, + 0xC370, 0xC448, 0xC526, 0xC606, 0xC6E4, 0xC7BD, 0xC88A, 0xC94A, 0xC9F7, + 0xCA8E, 0xCB0B, 0xCB69, 0xCBA4, 0xCBB9, 0xCBA4, 0xCB69, 0xCB0B, 0xCA8E, + 0xC9F7, 0xC94A, 0xC88A, 0xC7BD, 0xC6E4, 0xC606, 0xC526, 0xC448, 0xC370, + 0xC2A2, 0xC1E2, 0xC135, 0xC09E, 0xC021, 0xBFC3, 0xBF88, + },{ + 0x0027, 0x0000, 0x0001, 0x0027, 0x0028, 0x0028, 0x0001, 0x0050, 0x0001, + 0x0051, 0x0001, 0x0052, 0x002A, 0x0053, 0x002A, 0x007D, 0x0026, 0x00A7, + 0x002A, 0x00CD, 0x002A, 0x00F7, 0x0001, 0x0121, 0x002A, 0x0122, 0x002A, + 0x014C, 0x002A, 0x0176, 0x0001, 0x01A0, 0x0001, 0x01A1, 0x0001, 0x01A2, + 0x0001, 0x01A3, 0x0001, 0x01A4, 0x0001, 0x01A5, 0x0028, 0x01A6, 0x0028, + 0x01CE, 0x002A, 0x01F6, 0x002A, 0x0220, 0x002A, 0x024A, 0x002A, 0x0274, + 0x0001, 0x029E, 0x0001, 0x029F, 0x0001, 0x02A0, 0x002A, 0x02A1, 0x002A, + 0x02CB, 0x002A, 0x02F5, 0x002A, 0x031F, 0x002A, 0x0349, 0x0028, 0x0373, + 0x002A, 0x039B, 0x002A, 0x03C5, 0x002A, 0x03EF, 0x002A, 0x0419, 0x0029, + 0x0443, 0x0001, 0x046C, 0x0001, 0x046D, 0x0001, 0x046E, 0x0001, 0x046F, + 0x0028, 0x0470, 0x0026, 0x0498, 0x0001, 0x04BE, 0x002A, 0x04BF, 0x002A, + 0x04E9, 0x002A, 0x0513, 0x002A, 0x053D, 0x0029, 0x0567, 0x0001, 0x0590, + 0x002A, 0x0591, 0x002A, 0x05BB, 0x002A, 0x05E5, 0x0026, 0x060F, 0x0001, + 0x0635, 0x0001, 0x0636, 0x002A, 0x0637, 0x002A, 0x0661, 0x002A, 0x068B, +}) + +WALUIGI_ANIM_CS_MENU = "waluigi_anim_cs_menu" +smlua_anim_util_register_animation(WALUIGI_ANIM_CS_MENU, + 0, + 0, + 0, + 0, + 41, + { + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0xFFFE, + 0xFFFD, 0xFFFD, 0xFFFC, 0xFFFB, 0xFFFB, 0xFFFA, 0xFFFA, 0xFFFA, 0xFFF9, + 0xFFF9, 0xFFF9, 0xFFF9, 0xFFF8, 0xFFF9, 0xFFF9, 0xFFF9, 0xFFF9, 0xFFFA, + 0xFFFA, 0xFFFA, 0xFFFB, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFD, 0xFFFE, 0xFFFE, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x006A, 0x006A, 0x006A, 0x006A, 0x006A, + 0x006A, 0x006A, 0x006A, 0x006A, 0x006A, 0x006A, 0x006A, 0x006A, 0x0069, + 0x0069, 0x0069, 0x0069, 0x0069, 0x0069, 0x0069, 0x0069, 0x0069, 0x0069, + 0x0069, 0x0069, 0x0069, 0x0069, 0x0069, 0x0069, 0x0069, 0x006A, 0x0000, + 0x0000, 0x36B8, 0x0000, 0xFFFF, 0xFFFF, 0x40A1, 0x0D70, 0x0D77, 0x0D8A, + 0x0DA9, 0x0DD2, 0x0E04, 0x0E3D, 0x0E7C, 0x0EC0, 0x0F07, 0x0F51, 0x0F9B, + 0x0FE4, 0x102B, 0x106F, 0x10AE, 0x10E7, 0x1119, 0x1142, 0x1161, 0x1174, + 0x117B, 0x1174, 0x1161, 0x1142, 0x1119, 0x10E7, 0x10AE, 0x106F, 0x102B, + 0x0FE4, 0x0F9B, 0x0F51, 0x0F07, 0x0EC0, 0x0E7C, 0x0E3D, 0x0E04, 0x0DD2, + 0x0DA9, 0x0D8A, 0x0D77, 0x0C44, 0x0C48, 0x0C53, 0x0C64, 0x0C7B, 0x0C97, + 0x0CB7, 0x0CDA, 0x0D00, 0x0D28, 0x0D51, 0x0D7B, 0x0DA4, 0x0DCC, 0x0DF2, + 0x0E15, 0x0E35, 0x0E51, 0x0E68, 0x0E79, 0x0E84, 0x0E88, 0x0E84, 0x0E79, + 0x0E68, 0x0E51, 0x0E35, 0x0E15, 0x0DF2, 0x0DCC, 0x0DA4, 0x0D7B, 0x0D51, + 0x0D28, 0x0D00, 0x0CDA, 0x0CB7, 0x0C97, 0x0C7B, 0x0C64, 0x0C53, 0x0C48, + 0x27F5, 0x27F9, 0x2805, 0x2818, 0x2832, 0x2850, 0x2873, 0x289A, 0x28C4, + 0x28F0, 0x291D, 0x294B, 0x2978, 0x29A4, 0x29CE, 0x29F4, 0x2A18, 0x2A36, + 0x2A50, 0x2A63, 0x2A6F, 0x2A73, 0x2A6F, 0x2A63, 0x2A50, 0x2A36, 0x2A18, + 0x29F4, 0x29CE, 0x29A4, 0x2978, 0x294B, 0x291D, 0x28F0, 0x28C4, 0x289A, + 0x2873, 0x2850, 0x2832, 0x2818, 0x2805, 0x27F9, 0xF280, 0xF2AF, 0xF2DA, + 0xF2FE, 0xF316, 0xF31F, 0xF31A, 0xF30D, 0xF2F9, 0xF2DE, 0xF2BD, 0xF298, + 0xF270, 0xF245, 0xF218, 0xF1EB, 0xF1BF, 0xF194, 0xF16C, 0xF147, 0xF126, + 0xF10C, 0xF0F7, 0xF0E8, 0xF0DD, 0xF0D7, 0xF0D3, 0xF0D2, 0xF0D1, 0xF0D5, + 0xF0DE, 0xF0ED, 0xF101, 0xF11A, 0xF137, 0xF158, 0xF17C, 0xF1A3, 0xF1CC, + 0xF1F8, 0xF224, 0xF252, 0xF722, 0xF6DF, 0xF6A1, 0xF66F, 0xF64D, 0xF640, + 0xF647, 0xF65C, 0xF67D, 0xF6A8, 0xF6DD, 0xF71A, 0xF75E, 0xF7A7, 0xF7F3, + 0xF842, 0xF892, 0xF8E2, 0xF92F, 0xF97A, 0xF9C0, 0xFA00, 0xFA39, 0xFA6B, + 0xFA94, 0xFAB5, 0xFACD, 0xFADB, 0xFAE0, 0xFAD9, 0xFAC4, 0xFAA3, 0xFA76, + 0xFA3F, 0xF9FE, 0xF9B5, 0xF964, 0xF90D, 0xF8B1, 0xF851, 0xF7EE, 0xF788, + 0xE0D7, 0xE009, 0xDF4C, 0xDEB0, 0xDE46, 0xDE1F, 0xDE34, 0xDE71, 0xDED2, + 0xDF52, 0xDFED, 0xE09F, 0xE163, 0xE236, 0xE313, 0xE3F6, 0xE4DA, 0xE5BC, + 0xE697, 0xE767, 0xE827, 0xE8D4, 0xE96A, 0xE9E8, 0xEA4F, 0xEA9F, 0xEAD8, + 0xEAF9, 0xEB05, 0xEAF1, 0xEAB9, 0xEA5E, 0xE9E4, 0xE94D, 0xE89D, 0xE7D6, + 0xE6FC, 0xE610, 0xE516, 0xE410, 0xE302, 0xE1EE, 0xFFFE, 0x0001, 0xC170, + 0x26EA, 0x26F6, 0x271A, 0x2752, 0x279C, 0x27F6, 0x285D, 0x28D0, 0x294A, + 0x29CB, 0x2A4F, 0x2AD5, 0x2B59, 0x2BDA, 0x2C55, 0x2CC7, 0x2D2F, 0x2D88, + 0x2DD3, 0x2E0B, 0x2E2E, 0x2E3A, 0x2E2E, 0x2E0B, 0x2DD3, 0x2D88, 0x2D2F, + 0x2CC7, 0x2C55, 0x2BDA, 0x2B59, 0x2AD5, 0x2A4F, 0x29CB, 0x294A, 0x28D0, + 0x285D, 0x27F6, 0x279C, 0x2752, 0x271A, 0x26F6, 0xCA92, 0xCA98, 0xCAAC, + 0xCACB, 0xCAF4, 0xCB25, 0xCB5E, 0xCB9D, 0xCBE1, 0xCC28, 0xCC70, 0xCCBA, + 0xCD03, 0xCD4A, 0xCD8E, 0xCDCD, 0xCE05, 0xCE37, 0xCE60, 0xCE7F, 0xCE92, + 0xCE99, 0xCE92, 0xCE7F, 0xCE60, 0xCE37, 0xCE05, 0xCDCD, 0xCD8E, 0xCD4A, + 0xCD03, 0xCCBA, 0xCC70, 0xCC28, 0xCBE1, 0xCB9D, 0xCB5E, 0xCB25, 0xCAF4, + 0xCACB, 0xCAAC, 0xCA98, 0xAF0D, 0xAF01, 0xAEDB, 0xAEA1, 0xAE53, 0xADF5, + 0xAD88, 0xAD11, 0xAC90, 0xAC09, 0xAB7E, 0xAAF2, 0xAA67, 0xA9E0, 0xA960, + 0xA8E8, 0xA87C, 0xA81D, 0xA7D0, 0xA795, 0xA770, 0xA763, 0xA770, 0xA795, + 0xA7D0, 0xA81D, 0xA87C, 0xA8E8, 0xA960, 0xA9E0, 0xAA67, 0xAAF2, 0xAB7E, + 0xAC09, 0xAC90, 0xAD11, 0xAD88, 0xADF5, 0xAE53, 0xAEA1, 0xAEDB, 0xAF00, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xBE3D, 0xBE42, 0xBE50, 0xBE65, 0xBE82, + 0xBEA5, 0xBECC, 0xBEF8, 0xBF28, 0xBF59, 0xBF8C, 0xBFC0, 0xBFF3, 0xC024, + 0xC053, 0xC07F, 0xC0A7, 0xC0CA, 0xC0E6, 0xC0FC, 0xC10A, 0xC10E, 0xC10A, + 0xC0FC, 0xC0E6, 0xC0CA, 0xC0A7, 0xC07F, 0xC053, 0xC024, 0xBFF3, 0xBFC0, + 0xBF8C, 0xBF59, 0xBF28, 0xBEF8, 0xBECC, 0xBEA5, 0xBE82, 0xBE65, 0xBE50, + 0xBE42, 0x0F42, 0xFBB0, 0xDC2A, 0xFFFE, 0x0001, 0xC170, 0x4E55, 0x4E5E, + 0x4E77, 0x4E9F, 0x4ED4, 0xCF14, 0xCF5E, 0xCFB0, 0xD007, 0xD063, 0xD0C2, + 0xD121, 0xD180, 0xD1DC, 0xD233, 0xD285, 0xD2CF, 0xD30F, 0xD344, 0xD36C, + 0xD385, 0xD38E, 0xD385, 0xD36C, 0xD344, 0xD30F, 0xD2CF, 0xD285, 0xD233, + 0xD1DC, 0xD180, 0xD121, 0xD0C2, 0xD063, 0xD007, 0xCFB0, 0xCF5E, 0xCF14, + 0x4ED4, 0x4E9F, 0x4E77, 0x4E5E, 0x58A6, 0x589A, 0x5879, 0x5845, 0x5800, + 0x2853, 0x28B3, 0x291D, 0x298F, 0x2A06, 0x2A81, 0x2AFD, 0x2B78, 0x2BF0, + 0x2C62, 0x2CCC, 0x2D2C, 0x2D7F, 0x2DC4, 0x2DF8, 0x2E19, 0x2E24, 0x2E19, + 0x2DF8, 0x2DC4, 0x2D7F, 0x2D2C, 0x2CCC, 0x2C62, 0x2BF0, 0x2B78, 0x2AFD, + 0x2A81, 0x2A06, 0x298F, 0x291D, 0x28B3, 0x2853, 0x5800, 0x5845, 0x5879, + 0x589A, 0x1897, 0x18A1, 0x18BE, 0x18EC, 0x1929, 0x9972, 0x99C7, 0x9A24, + 0x9A89, 0x9AF3, 0x9B60, 0x9BCD, 0x9C3A, 0x9CA4, 0x9D08, 0x9D66, 0x9DBB, + 0x9E05, 0x9E41, 0x9E6F, 0x9E8C, 0x9E97, 0x9E8C, 0x9E6F, 0x9E41, 0x9E05, + 0x9DBB, 0x9D66, 0x9D08, 0x9CA4, 0x9C3A, 0x9BCD, 0x9B60, 0x9AF3, 0x9A89, + 0x9A24, 0x99C7, 0x9972, 0x1929, 0x18EC, 0x18BE, 0x18A1, 0x0000, 0xFFFF, + 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, + 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, + 0x0000, 0xFFFF, 0x0000, 0xB7ED, 0xB7DE, 0xB7B5, 0xB774, 0xB71E, 0xB6B6, + 0xB63E, 0xB5B9, 0xB52B, 0xB496, 0xB3FC, 0xB361, 0xB2C7, 0xB232, 0xB1A4, + 0xB11F, 0xB0A7, 0xB03F, 0xAFE9, 0xAFA8, 0xAF7F, 0xAF70, 0xAF7F, 0xAFA8, + 0xAFE9, 0xB03F, 0xB0A7, 0xB11F, 0xB1A4, 0xB232, 0xB2C7, 0xB361, 0xB3FC, + 0xB496, 0xB52B, 0xB5B9, 0xB63E, 0xB6B6, 0xB71E, 0xB774, 0xB7B5, 0xB7DE, + 0xE202, 0xE1FC, 0xE1EA, 0xE1CE, 0xE1AA, 0xE17D, 0xE14A, 0xE111, 0xE0D4, + 0xE094, 0xE052, 0xE010, 0xDFCE, 0xDF8E, 0xDF51, 0xDF18, 0xDEE5, 0xDEB8, + 0xDE93, 0xDE78, 0xDE66, 0xDE60, 0xDE66, 0xDE78, 0xDE93, 0xDEB8, 0xDEE5, + 0xDF18, 0xDF51, 0xDF8E, 0xDFCE, 0xE010, 0xE052, 0xE094, 0xE0D4, 0xE111, + 0xE14A, 0xE17D, 0xE1AA, 0xE1CE, 0xE1EA, 0xE1FC, 0xF2BC, 0xF2BF, 0xF2C9, + 0xF2D9, 0xF2EE, 0xF307, 0xF324, 0xF344, 0xF366, 0xF38B, 0xF3B0, 0xF3D5, + 0xF3FB, 0xF41F, 0xF441, 0xF461, 0xF47F, 0xF498, 0xF4AD, 0xF4BC, 0xF4C6, + 0xF4CA, 0xF4C6, 0xF4BC, 0xF4AD, 0xF498, 0xF47F, 0xF461, 0xF441, 0xF41F, + 0xF3FB, 0xF3D5, 0xF3B0, 0xF38B, 0xF366, 0xF344, 0xF324, 0xF307, 0xF2EE, + 0xF2D9, 0xF2C9, 0xF2BF, 0x0B5C, 0x0B62, 0x0B75, 0x0B94, 0x0BBC, 0x0BEC, + 0x0C24, 0x0C61, 0x0CA4, 0x0CE9, 0x0D30, 0x0D78, 0x0DC0, 0x0E05, 0x0E47, + 0x0E85, 0x0EBD, 0x0EED, 0x0F15, 0x0F33, 0x0F46, 0x0F4D, 0x0F46, 0x0F33, + 0x0F15, 0x0EED, 0x0EBD, 0x0E85, 0x0E47, 0x0E05, 0x0DC0, 0x0D78, 0x0D30, + 0x0CE9, 0x0CA4, 0x0C61, 0x0C24, 0x0BEC, 0x0BBC, 0x0B94, 0x0B75, 0x0B62, + 0xFFFF, 0x0000, 0xBF5E, 0xFBBD, 0xD39A, 0x85AE, 0xFFFF, 0x0002, 0x0006, + 0x000D, 0x0017, 0x0022, 0x002F, 0x003E, 0x004E, 0x005E, 0x006F, 0x0080, + 0x0091, 0x00A1, 0x00B1, 0x00C0, 0x00CD, 0x00D8, 0x00E2, 0x00E9, 0x00ED, + 0x00EF, 0x00ED, 0x00E9, 0x00E2, 0x00D8, 0x00CD, 0x00C0, 0x00B1, 0x00A1, + 0x0091, 0x0080, 0x006F, 0x005E, 0x004E, 0x003E, 0x002F, 0x0022, 0x0017, + 0x000D, 0x0006, 0x0002, 0x0000, 0xFFFA, 0xFFEC, 0xFFD6, 0xFFB8, 0xFF94, + 0xFF6B, 0xFF3E, 0xFF0D, 0xFEDA, 0xFEA5, 0xFE70, 0xFE3B, 0xFE08, 0xFDD7, + 0xFDA9, 0xFD80, 0xFD5C, 0xFD3F, 0xFD28, 0xFD1A, 0xFD15, 0xFD1A, 0xFD28, + 0xFD3F, 0xFD5C, 0xFD80, 0xFDA9, 0xFDD7, 0xFE08, 0xFE3B, 0xFE70, 0xFEA5, + 0xFEDA, 0xFF0D, 0xFF3E, 0xFF6B, 0xFF94, 0xFFB8, 0xFFD6, 0xFFEC, 0xFFFA, + 0x35B3, 0x35AD, 0x359F, 0x3588, 0x356A, 0x3545, 0x351A, 0x34EC, 0x34B9, + 0x3485, 0x344E, 0x3418, 0x33E1, 0x33AD, 0x337A, 0x334B, 0x3321, 0x32FC, + 0x32DE, 0x32C7, 0x32B8, 0x32B3, 0x32B8, 0x32C7, 0x32DE, 0x32FC, 0x3321, + 0x334B, 0x337A, 0x33AD, 0x33E1, 0x3418, 0x344E, 0x3485, 0x34B9, 0x34EC, + 0x351A, 0x3545, 0x356A, 0x3588, 0x359F, 0x35AD, 0x0000, 0xFFFA, 0xFFED, + 0xFFD7, 0xFFBB, 0xFF9A, 0xFF74, 0xFF4B, 0xFF20, 0xFEF4, 0xFEC8, 0xFE9D, + 0xFE74, 0xFE4C, 0xFE27, 0xFE04, 0xFDE4, 0xFDC8, 0xFDAE, 0xFD99, 0xFD88, + 0xFD7B, 0xFD73, 0xFD71, 0xFD82, 0xFDAA, 0xFDDA, 0xFE02, 0xFE13, 0xFE02, + 0xFDDA, 0xFDAA, 0xFD82, 0xFD71, 0xFD77, 0xFD90, 0xFDC2, 0xFE13, 0xFE86, + 0xFF08, 0xFF82, 0xFFDC, 0xFFFF, 0x0000, 0x0001, 0x0002, 0x0004, 0x0005, + 0x0007, 0x0009, 0x000A, 0x000B, 0x000B, 0x0008, 0x0001, 0xFFF5, 0xFFE7, + 0xFFD7, 0xFFC6, 0xFFB4, 0xFFA3, 0xFF93, 0xFF85, 0xFF7A, 0xFF73, 0xFF71, + 0xFF86, 0xFFBA, 0xFFF8, 0x002D, 0x0043, 0x002D, 0xFFF8, 0xFFBA, 0xFF86, + 0xFF71, 0xFF91, 0xFFD9, 0x0022, 0x0043, 0x003C, 0x002B, 0x0017, 0x0007, + 0xD567, 0xD576, 0xD59F, 0xD5DC, 0xD625, 0xD675, 0xD6C6, 0xD70F, 0xD74C, + 0xD775, 0xD784, 0xD731, 0xD647, 0xD4E4, 0xD321, 0xD11B, 0xCEEC, 0xCCAF, + 0xCA7F, 0xC879, 0xC6B6, 0xC553, 0xC46A, 0xC416, 0xC608, 0xCAAB, 0xD034, + 0xD4D7, 0xD6C9, 0xD4D7, 0xD034, 0xCAAB, 0xC608, 0xC416, 0xC702, 0xCD6F, + 0xD3DD, 0xD6C9, 0xD6A4, 0xD64C, 0xD5E3, 0xD58B, 0xFFFF, 0x0000, 0xBF5E, + 0x0E87, 0x0E8C, 0x0E9A, 0x0EB1, 0x0ECF, 0x0EF3, 0x0F1D, 0x0F4B, 0x0F7D, + 0x0FB1, 0x0FE7, 0x101D, 0x1052, 0x1086, 0x10B8, 0x10E6, 0x1110, 0x1134, + 0x1152, 0x1169, 0x1177, 0x117C, 0x1177, 0x1169, 0x1152, 0x1134, 0x1110, + 0x10E6, 0x10B8, 0x1086, 0x1052, 0x101D, 0x0FE7, 0x0FB1, 0x0F7D, 0x0F4B, + 0x0F1D, 0x0EF3, 0x0ECF, 0x0EB1, 0x0E9A, 0x0E8C, 0x1C6D, 0x1C6A, 0x1C63, + 0x1C58, 0x1C49, 0x1C36, 0x1C21, 0x1C0A, 0x1BF1, 0x1BD6, 0x1BBB, 0x1BA0, + 0x1B85, 0x1B6B, 0x1B52, 0x1B3A, 0x1B25, 0x1B13, 0x1B04, 0x1AF8, 0x1AF1, + 0x1AEF, 0x1AF1, 0x1AF8, 0x1B04, 0x1B13, 0x1B25, 0x1B3A, 0x1B52, 0x1B6B, + 0x1B85, 0x1BA0, 0x1BBB, 0x1BD6, 0x1BF1, 0x1C0A, 0x1C21, 0x1C36, 0x1C49, + 0x1C58, 0x1C63, 0x1C6A, 0x9566, 0x9569, 0x9572, 0x957F, 0x9591, 0x95A6, + 0x95BE, 0x95D9, 0x95F6, 0x9615, 0x9634, 0x9654, 0x9673, 0x9692, 0x96AF, + 0x96CA, 0x96E2, 0x96F7, 0x9709, 0x9716, 0x971F, 0x9721, 0x971F, 0x9716, + 0x9709, 0x96F7, 0x96E2, 0x96CA, 0x96AF, 0x9692, 0x9673, 0x9654, 0x9634, + 0x9615, 0x95F6, 0x95D9, 0x95BE, 0x95A6, 0x9591, 0x957F, 0x9572, 0x9569, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x520C, 0x5210, + 0x521B, 0x522C, 0x5243, 0x525E, 0x527E, 0x52A1, 0x52C6, 0x52EE, 0x5316, + 0x533F, 0x5368, 0x538F, 0x53B5, 0x53D8, 0x53F7, 0x5413, 0x5429, 0x543B, + 0x5445, 0x5449, 0x5445, 0x543B, 0x5429, 0x5413, 0x53F7, 0x53D8, 0x53B5, + 0x538F, 0x5368, 0x533F, 0x5316, 0x52EE, 0x52C6, 0x52A1, 0x527E, 0x525E, + 0x5243, 0x522C, 0x521B, 0x5210, 0x008D, 0x0089, 0x007F, 0x0070, 0x005B, + 0x0041, 0x0024, 0x0003, 0xFFE0, 0xFFBB, 0xFF96, 0xFF70, 0xFF4A, 0xFF26, + 0xFF03, 0xFEE3, 0xFEC6, 0xFEAC, 0xFE97, 0xFE87, 0xFE7D, 0xFE7A, 0xFE7D, + 0xFE87, 0xFE97, 0xFEAC, 0xFEC6, 0xFEE3, 0xFF03, 0xFF26, 0xFF4A, 0xFF70, + 0xFF96, 0xFFBB, 0xFFE0, 0x0003, 0x0024, 0x0041, 0x005B, 0x0070, 0x007F, + 0x0089, 0xFF66, 0xFF68, 0xFF6C, 0xFF73, 0xFF7C, 0xFF87, 0xFF93, 0xFFA1, + 0xFFB0, 0xFFC0, 0xFFD0, 0xFFE0, 0xFFF0, 0x0001, 0x0010, 0x001E, 0x002A, + 0x0035, 0x003E, 0x0045, 0x0049, 0x004B, 0x0049, 0x0045, 0x003E, 0x0035, + 0x002A, 0x001E, 0x0010, 0x0001, 0xFFF0, 0xFFE0, 0xFFD0, 0xFFC0, 0xFFB0, + 0xFFA1, 0xFF93, 0xFF87, 0xFF7C, 0xFF73, 0xFF6C, 0xFF68, 0xAB83, 0xAB7D, + 0xAB6D, 0xAB53, 0xAB31, 0xAB08, 0xAAD9, 0xAAA5, 0xAA6D, 0xAA33, 0xA9F6, + 0xA9B9, 0xA97D, 0xA942, 0xA90A, 0xA8D6, 0xA8A7, 0xA87E, 0xA85C, 0xA843, + 0xA833, 0xA82D, 0xA833, 0xA843, 0xA85C, 0xA87E, 0xA8A7, 0xA8D6, 0xA90A, + 0xA942, 0xA97D, 0xA9B9, 0xA9F6, 0xAA33, 0xAA6D, 0xAAA5, 0xAAD9, 0xAB08, + 0xAB31, 0xAB53, 0xAB6D, 0xAB7D, + },{ + 0x0028, 0x0000, 0x001F, 0x0028, 0x0001, 0x0047, 0x0001, 0x0048, 0x0001, + 0x0049, 0x0001, 0x004A, 0x0001, 0x004B, 0x0001, 0x004C, 0x0001, 0x004D, + 0x002A, 0x004E, 0x002A, 0x0078, 0x002A, 0x00A2, 0x002A, 0x00CC, 0x002A, + 0x00F6, 0x002A, 0x0120, 0x0001, 0x014A, 0x0001, 0x014B, 0x0001, 0x014C, + 0x002A, 0x014D, 0x002A, 0x0177, 0x002A, 0x01A1, 0x0027, 0x01CB, 0x0001, + 0x01F2, 0x002A, 0x01F3, 0x0001, 0x021D, 0x0001, 0x021E, 0x0001, 0x021F, + 0x0001, 0x0220, 0x0001, 0x0221, 0x0001, 0x0222, 0x002A, 0x0223, 0x002A, + 0x024D, 0x002A, 0x0277, 0x0001, 0x02A1, 0x0028, 0x02A2, 0x002A, 0x02CA, + 0x002A, 0x02F4, 0x002A, 0x031E, 0x002A, 0x0348, 0x0001, 0x0372, 0x0001, + 0x0373, 0x0001, 0x0374, 0x0001, 0x0375, 0x0001, 0x0376, 0x0001, 0x0377, + 0x002A, 0x0378, 0x002A, 0x03A2, 0x002A, 0x03CC, 0x002A, 0x03F6, 0x002A, + 0x0420, 0x002A, 0x044A, 0x0001, 0x0474, 0x0001, 0x0475, 0x0001, 0x0476, + 0x002A, 0x0477, 0x002A, 0x04A1, 0x002A, 0x04CB, 0x0027, 0x04F5, 0x000D, + 0x051C, 0x002A, 0x0529, 0x002A, 0x0553, 0x002A, 0x057D, 0x002A, 0x05A7, +}); + +WARIO_ANIM_CS_MENU = "wario_anim_cs_menu" +smlua_anim_util_register_animation(WARIO_ANIM_CS_MENU, + 0, + 0, + 0, + 0, + 41, + { + 0x0000, 0x00B2, 0x00B2, 0x00B2, 0x00B2, 0x00B2, 0x00B1, 0x00B1, 0x00B0, + 0x00B0, 0x00AF, 0x00AE, 0x00AE, 0x00AD, 0x00AD, 0x00AC, 0x00AB, 0x00AB, + 0x00AB, 0x00AA, 0x00AA, 0x00AA, 0x00AA, 0x00AA, 0x00AA, 0x00AA, 0x00AB, + 0x00AB, 0x00AB, 0x00AC, 0x00AD, 0x00AD, 0x00AE, 0x00AE, 0x00AF, 0x00B0, + 0x00B0, 0x00B1, 0x00B1, 0x00B2, 0x0000, 0x0000, 0x3FFF, 0x0000, 0x5905, + 0xFF7B, 0x3FA3, 0xC1C1, 0xC1C1, 0xC1C1, 0xC1C2, 0xC1C2, 0xC1C3, 0xC1C4, + 0xC1C5, 0xC1C7, 0xC1C8, 0xC1C9, 0xC1CB, 0xC1CC, 0xC1CD, 0xC1CE, 0xC1D0, + 0xC1D1, 0xC1D1, 0xC1D2, 0xC1D3, 0xC1D3, 0xC1D3, 0xC1D3, 0xC1D3, 0xC1D2, + 0xC1D1, 0xC1D1, 0xC1D0, 0xC1CE, 0xC1CD, 0xC1CC, 0xC1CB, 0xC1C9, 0xC1C8, + 0xC1C7, 0xC1C5, 0xC1C4, 0xC1C3, 0xC1C2, 0xC1C2, 0xC1C1, 0xFF11, 0xFF00, + 0xFECC, 0xFE7A, 0xFE0E, 0xFD8B, 0xFCF5, 0xFC4E, 0xFB9B, 0xFAE0, 0xFA1F, + 0xF95C, 0xF89B, 0xF7E0, 0xF72D, 0xF686, 0xF5F0, 0xF56D, 0xF501, 0xF4AF, + 0xF47B, 0xF469, 0xF47B, 0xF4AF, 0xF501, 0xF56D, 0xF5F0, 0xF686, 0xF72D, + 0xF7E0, 0xF89B, 0xF95C, 0xFA1F, 0xFAE0, 0xFB9B, 0xFC4E, 0xFCF5, 0xFD8B, + 0xFE0E, 0xFE7A, 0xFECC, 0xFF00, 0xF9D9, 0xF9D8, 0xF9D6, 0xF9D2, 0xF9CE, + 0xF9C8, 0xF9C1, 0xF9BA, 0xF9B2, 0xF9A9, 0xF9A1, 0xF998, 0xF990, 0xF987, + 0xF97F, 0xF978, 0xF971, 0xF96B, 0xF967, 0xF963, 0xF961, 0xF960, 0xF961, + 0xF963, 0xF967, 0xF96B, 0xF971, 0xF978, 0xF97F, 0xF987, 0xF990, 0xF998, + 0xF9A1, 0xF9A9, 0xF9B2, 0xF9BA, 0xF9C1, 0xF9C8, 0xF9CE, 0xF9D2, 0xF9D6, + 0xF9D8, 0x0A3A, 0x0A39, 0x0A37, 0x0A33, 0x0A2F, 0x0A29, 0x0A23, 0x0A1C, + 0x0A14, 0x0A0C, 0x0A04, 0x09FC, 0x09F4, 0x09EC, 0x09E5, 0x09DE, 0x09D7, + 0x09D2, 0x09CD, 0x09CA, 0x09C8, 0x09C7, 0x09C8, 0x09CA, 0x09CD, 0x09D2, + 0x09D7, 0x09DE, 0x09E5, 0x09EC, 0x09F4, 0x09FC, 0x0A04, 0x0A0C, 0x0A14, + 0x0A1C, 0x0A23, 0x0A29, 0x0A2F, 0x0A33, 0x0A37, 0x0A39, 0xFF75, 0xFF6B, + 0xFF4C, 0xFF1C, 0xFEDC, 0xFE8E, 0xFE35, 0xFDD2, 0xFD68, 0xFCF9, 0xFC87, + 0xFC14, 0xFBA1, 0xFB32, 0xFAC8, 0xFA66, 0xFA0D, 0xF9BF, 0xF97F, 0xF94F, + 0xF930, 0xF925, 0xF930, 0xF94F, 0xF97F, 0xF9BF, 0xFA0D, 0xFA66, 0xFAC8, + 0xFB32, 0xFBA1, 0xFC14, 0xFC87, 0xFCF9, 0xFD68, 0xFDD2, 0xFE35, 0xFE8E, + 0xFEDC, 0xFF1C, 0xFF4C, 0xFF6B, 0xFDB4, 0xFDC7, 0xFDFC, 0xFE51, 0xFEC2, + 0xFF4B, 0xFFE8, 0x0096, 0x0151, 0x0214, 0x02DE, 0x03A9, 0x0472, 0x0535, + 0x05F0, 0x069D, 0x073A, 0x07C3, 0x0834, 0x0889, 0x08BF, 0x08D1, 0x08BF, + 0x0889, 0x0834, 0x07C3, 0x073A, 0x069D, 0x05F0, 0x0535, 0x0472, 0x03A9, + 0x02DE, 0x0214, 0x0151, 0x0096, 0xFFE8, 0xFF4B, 0xFEC2, 0xFE51, 0xFDFC, + 0xFDC7, 0xFFFE, 0x0001, 0xC170, 0xD482, 0xD490, 0xD4B9, 0xD4FD, 0xD55A, + 0xD5CF, 0xD65A, 0xD6FB, 0xD7B1, 0xD879, 0xD954, 0xDA40, 0xDB3B, 0xDC45, + 0xDD5D, 0xDE80, 0xDFAF, 0xE0E8, 0xE22A, 0xE304, 0xE22A, 0xE400, 0xE22A, + 0xE304, 0xE22A, 0xE0E8, 0xDFAF, 0xDE80, 0xDD5D, 0xDC45, 0xDB3B, 0xDA40, + 0xD954, 0xD879, 0xD7B1, 0xD6FB, 0xD65A, 0xD5CF, 0xD55A, 0xD4FD, 0xD4B9, + 0xD490, 0xD13B, 0xD131, 0xD116, 0xD0EB, 0xD0B1, 0xD06B, 0xD01A, 0xCFBF, + 0xCF5C, 0xCEF4, 0xCE87, 0xCE18, 0xCDA7, 0xCD37, 0xCCCA, 0xCC61, 0xCBFD, + 0xCBA1, 0xCB4E, 0xCB1C, 0xCB4E, 0xCAE1, 0xCB4E, 0xCB1C, 0xCB4E, 0xCBA1, + 0xCBFD, 0xCC61, 0xCCCA, 0xCD38, 0xCDA7, 0xCE18, 0xCE87, 0xCEF4, 0xCF5C, + 0xCFBF, 0xD01A, 0xD06B, 0xD0B1, 0xD0EB, 0xD116, 0xD131, 0xB677, 0xB677, + 0xB674, 0xB66E, 0xB662, 0xB64F, 0xB632, 0xB609, 0xB5D3, 0xB58D, 0xB537, + 0xB4CD, 0xB44D, 0xB3B7, 0xB308, 0xB23E, 0xB157, 0xB051, 0xAF2B, 0xAE3C, + 0xAF2B, 0xAD37, 0xAF2B, 0xAE3C, 0xAF2B, 0xB051, 0xB157, 0xB23E, 0xB308, + 0xB3B7, 0xB44D, 0xB4CD, 0xB537, 0xB58D, 0xB5D3, 0xB609, 0xB632, 0xB64F, + 0xB662, 0xB66E, 0xB674, 0xB677, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xCFE0, 0xCFC7, 0xCF7F, + 0xCF0E, 0xCE79, 0xCDC4, 0xCCF4, 0xCC10, 0xCB1B, 0xCA1A, 0xC914, 0xC80C, + 0xC709, 0xC60E, 0xC521, 0xC447, 0xC385, 0xC2E0, 0xC25D, 0xC219, 0xC25D, + 0xC1BE, 0xC25D, 0xC219, 0xC25D, 0xC2E0, 0xC385, 0xC447, 0xC521, 0xC60E, + 0xC709, 0xC80C, 0xC914, 0xCA1A, 0xCB1B, 0xCC10, 0xCCF4, 0xCDC4, 0xCE79, + 0xCF0E, 0xCF7F, 0xCFC7, 0xBDF0, 0xF19F, 0xE2DE, 0xFFFE, 0x0001, 0xC170, + 0x3C6D, 0x3B58, 0x3844, 0x3371, 0x2D1F, 0x258E, 0x1CFD, 0x13AC, 0x09DC, + 0xFFCA, 0x75BB, 0x6BEA, 0x629A, 0x5A09, 0x5277, 0x4C25, 0x4752, 0x443E, + 0x4329, 0x437C, 0x4329, 0x431C, 0x4329, 0x437C, 0x4329, 0x443E, 0x4752, + 0x4C25, 0x5277, 0x5A09, 0x629A, 0x6BEA, 0x75BB, 0xFFCA, 0x09DC, 0x13AC, + 0x1CFD, 0x258E, 0x2D1F, 0x3371, 0x3844, 0x3B58, 0x3B00, 0x3B06, 0x3B15, + 0x3B2E, 0x3B4E, 0x3B75, 0x3BA1, 0x3BD0, 0x3C02, 0x3C36, 0x4396, 0x4364, + 0x4335, 0x4309, 0x42E2, 0x42C2, 0x42AA, 0x429A, 0x4294, 0x42F3, 0x4294, + 0x434E, 0x4294, 0x42F3, 0x4294, 0x429A, 0x42AA, 0x42C2, 0x42E2, 0x4309, + 0x4335, 0x4364, 0x4396, 0x3C36, 0x3C02, 0x3BD0, 0x3BA1, 0x3B75, 0x3B4E, + 0x3B2E, 0x3B15, 0x3B06, 0xC81A, 0xC715, 0xC42F, 0xBFA4, 0xB9B1, 0xB290, + 0xAA7F, 0xA1BA, 0x987C, 0x8F02, 0x0588, 0xFC49, 0xF384, 0xEB73, 0xE452, + 0xDE5E, 0xD9D3, 0xD6EE, 0xD5E9, 0xD62F, 0xD5E9, 0xD5CF, 0xD5E9, 0xD62F, + 0xD5E9, 0xD6EE, 0xD9D3, 0xDE5E, 0xE452, 0xEB73, 0xF384, 0xFC49, 0x0588, + 0x8F02, 0x987C, 0xA1BA, 0xAA7F, 0xB290, 0xB9B1, 0xBFA4, 0xC42F, 0xC715, + 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xD5E1, 0xD5C8, + 0xD581, 0xD510, 0xD47A, 0xD3C5, 0xD2F6, 0xD211, 0xD11C, 0xD01C, 0xCF15, + 0xCE0E, 0xCD0A, 0xCC0F, 0xCB22, 0xCA48, 0xC986, 0xC8E1, 0xC85E, 0xC81A, + 0xC85E, 0xC7BF, 0xC85E, 0xC81A, 0xC85E, 0xC8E1, 0xC986, 0xCA48, 0xCB22, + 0xCC0F, 0xCD0A, 0xCE0E, 0xCF15, 0xD01C, 0xD11C, 0xD211, 0xD2F6, 0xD3C5, + 0xD47A, 0xD510, 0xD581, 0xD5C8, 0x4330, 0x04EE, 0xE37A, 0x0000, 0xFFFF, + 0xBF5E, 0x1C79, 0x1C7A, 0x1C7B, 0x1C7E, 0x1C82, 0x1C86, 0x1C8B, 0x1C91, + 0x1C97, 0x1C9D, 0x1CA4, 0x1CAB, 0x1CB1, 0x1CB7, 0x1CBE, 0x1CC3, 0x1CC8, + 0x1CCD, 0x1CD0, 0x1CD3, 0x1CD5, 0x1CD6, 0x1CD5, 0x1CD3, 0x1CD0, 0x1CCD, + 0x1CC8, 0x1CC3, 0x1CBE, 0x1CB7, 0x1CB1, 0x1CAB, 0x1CA4, 0x1C9D, 0x1C97, + 0x1C91, 0x1C8B, 0x1C86, 0x1C82, 0x1C7E, 0x1C7B, 0x1C7A, 0xF46A, 0xF46C, + 0xF471, 0xF47A, 0xF485, 0xF493, 0xF4A2, 0xF4B4, 0xF4C6, 0xF4DA, 0xF4EE, + 0xF502, 0xF516, 0xF529, 0xF53C, 0xF54D, 0xF55D, 0xF56A, 0xF575, 0xF57E, + 0xF583, 0xF585, 0xF583, 0xF57E, 0xF575, 0xF56A, 0xF55D, 0xF54D, 0xF53C, + 0xF529, 0xF516, 0xF502, 0xF4EE, 0xF4DA, 0xF4C6, 0xF4B4, 0xF4A2, 0xF493, + 0xF485, 0xF47A, 0xF471, 0xF46C, 0xCBF7, 0xCBF5, 0xCBEE, 0xCBE4, 0xCBD6, + 0xCBC6, 0xCBB3, 0xCB9E, 0xCB87, 0xCB6F, 0xCB57, 0xCB3E, 0xCB25, 0xCB0E, + 0xCAF7, 0xCAE2, 0xCACF, 0xCABE, 0xCAB0, 0xCAA6, 0xCAA0, 0xCA9D, 0xCAA0, + 0xCAA6, 0xCAB0, 0xCABE, 0xCACF, 0xCAE2, 0xCAF7, 0xCB0E, 0xCB25, 0xCB3E, + 0xCB57, 0xCB6F, 0xCB87, 0xCB9E, 0xCBB3, 0xCBC6, 0xCBD6, 0xCBE4, 0xCBEE, + 0xCBF5, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x328E, 0x32A9, 0x32F4, + 0x336C, 0x340B, 0x34CB, 0x35A8, 0x369C, 0x37A2, 0x38B5, 0x39D0, 0x3AEE, + 0x3C09, 0x3D1C, 0x3E23, 0x3F17, 0x3FF4, 0x40B4, 0x4153, 0x41CA, 0x4216, + 0x4230, 0x4216, 0x41CA, 0x4153, 0x40B4, 0x3FF4, 0x3F17, 0x3E23, 0x3D1C, + 0x3C09, 0x3AEE, 0x39D0, 0x38B5, 0x37A2, 0x369C, 0x35A8, 0x34CB, 0x340B, + 0x336C, 0x32F4, 0x32A9, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xAD50, + 0xAD40, 0xAD12, 0xACCA, 0xAC69, 0xABF4, 0xAB6E, 0xAADA, 0xAA3A, 0xA993, + 0xA8E7, 0xA839, 0xA78D, 0xA6E6, 0xA647, 0xA5B2, 0xA52C, 0xA4B7, 0xA457, + 0xA40E, 0xA3E0, 0xA3D0, 0xA3E0, 0xA40E, 0xA457, 0xA4B7, 0xA52C, 0xA5B2, + 0xA647, 0xA6E6, 0xA78D, 0xA839, 0xA8E7, 0xA993, 0xAA3A, 0xAADA, 0xAB6E, + 0xABF4, 0xAC69, 0xACCA, 0xAD12, 0xAD40, 0x0000, 0xFFFF, 0xBF5E, 0x22E0, + 0x22DB, 0x22CB, 0x22B1, 0x2290, 0x2267, 0x2238, 0x2204, 0x21CD, 0x2192, + 0x2156, 0x211A, 0x20DE, 0x20A4, 0x206C, 0x2038, 0x2009, 0x1FE1, 0x1FBF, + 0x1FA6, 0x1F96, 0x1F90, 0x1F96, 0x1FA6, 0x1FBF, 0x1FE1, 0x2009, 0x2038, + 0x206C, 0x20A4, 0x20DE, 0x211A, 0x2156, 0x2192, 0x21CD, 0x2204, 0x2238, + 0x2267, 0x2290, 0x22B1, 0x22CB, 0x22DB, 0x1496, 0x149F, 0x14BA, 0x14E4, + 0x151B, 0x155E, 0x15AB, 0x1600, 0x165C, 0x16BC, 0x171F, 0x1783, 0x17E5, + 0x1845, 0x18A1, 0x18F6, 0x1943, 0x1986, 0x19BE, 0x19E8, 0x1A02, 0x1A0B, + 0x1A02, 0x19E8, 0x19BE, 0x1986, 0x1943, 0x18F6, 0x18A1, 0x1845, 0x17E5, + 0x1783, 0x171F, 0x16BC, 0x165C, 0x1600, 0x15AB, 0x155E, 0x151B, 0x14E4, + 0x14BA, 0x149F, 0xAFCA, 0xAFBF, 0xAFA2, 0xAF73, 0xAF35, 0xAEEA, 0xAE94, + 0xAE35, 0xADCF, 0xAD63, 0xACF5, 0xAC85, 0xAC17, 0xABAC, 0xAB45, 0xAAE6, + 0xAA90, 0xAA45, 0xAA07, 0xA9D8, 0xA9BB, 0xA9B1, 0xA9BB, 0xA9D8, 0xAA07, + 0xAA45, 0xAA90, 0xAAE6, 0xAB45, 0xABAC, 0xAC17, 0xAC85, 0xACF5, 0xAD63, + 0xADCF, 0xAE35, 0xAE94, 0xAEEA, 0xAF35, 0xAF73, 0xAFA2, 0xAFBF, 0xFFFF, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, + 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x1E4A, 0x1E63, + 0x1EAB, 0x1F1D, 0x1FB4, 0x206A, 0x213D, 0x2225, 0x231E, 0x2424, 0x2531, + 0x2641, 0x274E, 0x2854, 0x294E, 0x2A36, 0x2B08, 0x2BBF, 0x2C56, 0x2CC7, + 0x2D0F, 0x2D28, 0x2D0F, 0x2CC7, 0x2C56, 0x2BBF, 0x2B08, 0x2A36, 0x294E, + 0x2854, 0x274E, 0x2641, 0x2531, 0x2424, 0x231E, 0x2225, 0x213D, 0x206A, + 0x1FB4, 0x1F1D, 0x1EAB, 0x1E63, 0xFFFF, 0x0000, 0x0001, 0x0002, 0x0004, + 0x0005, 0x0008, 0x000A, 0x000C, 0x000F, 0x0012, 0x0014, 0x0017, 0x001A, + 0x001C, 0x001F, 0x0021, 0x0022, 0x0024, 0x0025, 0x0026, 0x0026, 0x0026, + 0x0025, 0x0024, 0x0022, 0x0021, 0x001F, 0x001C, 0x001A, 0x0017, 0x0014, + 0x0012, 0x000F, 0x000C, 0x000A, 0x0008, 0x0005, 0x0004, 0x0002, 0x0001, + 0x0000, 0xFF2F, 0xFF2F, 0xFF2F, 0xFF2F, 0xFF2F, 0xFF30, 0xFF30, 0xFF30, + 0xFF30, 0xFF30, 0xFF31, 0xFF31, 0xFF31, 0xFF31, 0xFF32, 0xFF32, 0xFF32, + 0xFF32, 0xFF32, 0xFF32, 0xFF33, 0xFF33, 0xFF32, 0xFF32, 0xFF32, 0xFF32, + 0xFF32, 0xFF32, 0xFF32, 0xFF31, 0xFF31, 0xFF31, 0xFF31, 0xFF30, 0xFF30, + 0xFF30, 0xFF30, 0xFF30, 0xFF2F, 0xC9D7, 0xC9CB, 0xC9A6, 0xC96D, 0xC921, + 0xC8C4, 0xC85A, 0xC7E5, 0xC767, 0xC6E3, 0xC65C, 0xC5D2, 0xC54B, 0xC4C7, + 0xC449, 0xC3D4, 0xC36A, 0xC30D, 0xC2C1, 0xC288, 0xC263, 0xC257, 0xC263, + 0xC288, 0xC2C1, 0xC30D, 0xC36A, 0xC3D4, 0xC449, 0xC4C7, 0xC54B, 0xC5D2, + 0xC65C, 0xC6E3, 0xC767, 0xC7E5, 0xC85A, 0xC8C4, 0xC921, 0xC96D, 0xC9A6, + 0xC9CB, + },{ + 0x0001, 0x0000, 0x0027, 0x0001, 0x0001, 0x0028, 0x0001, 0x0029, 0x0001, + 0x002A, 0x0001, 0x002B, 0x0001, 0x002C, 0x0001, 0x002D, 0x0001, 0x002E, + 0x0029, 0x002F, 0x002A, 0x0058, 0x002A, 0x0082, 0x002A, 0x00AC, 0x002A, + 0x00D6, 0x002A, 0x0100, 0x0001, 0x012A, 0x0001, 0x012B, 0x0001, 0x012C, + 0x002A, 0x012D, 0x002A, 0x0157, 0x002A, 0x0181, 0x002A, 0x01AB, 0x000E, + 0x01D5, 0x002A, 0x01E3, 0x0001, 0x020D, 0x0001, 0x020E, 0x0001, 0x020F, + 0x0001, 0x0210, 0x0001, 0x0211, 0x0001, 0x0212, 0x002A, 0x0213, 0x002A, + 0x023D, 0x002A, 0x0267, 0x0001, 0x0291, 0x002A, 0x0292, 0x002A, 0x02BC, + 0x0001, 0x02E6, 0x0001, 0x02E7, 0x0001, 0x02E8, 0x0001, 0x02E9, 0x0001, + 0x02EA, 0x0001, 0x02EB, 0x002A, 0x02EC, 0x002A, 0x0316, 0x002A, 0x0340, + 0x0001, 0x036A, 0x0016, 0x036B, 0x002A, 0x0381, 0x0014, 0x03AB, 0x0015, + 0x03BF, 0x002A, 0x03D4, 0x0001, 0x03FE, 0x0001, 0x03FF, 0x0001, 0x0400, + 0x002A, 0x0401, 0x002A, 0x042B, 0x002A, 0x0455, 0x0029, 0x047F, 0x0015, + 0x04A8, 0x002A, 0x04BD, 0x002A, 0x04E7, 0x0027, 0x0511, 0x002A, 0x0538, +}); diff --git a/mods/character-select-coop/dialog.lua b/mods/character-select-coop/dialog.lua index 25c55666f..059945d4d 100644 --- a/mods/character-select-coop/dialog.lua +++ b/mods/character-select-coop/dialog.lua @@ -1,222 +1,54 @@ 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 +DEFAULT_DIALOG_NAME = "Mario" -local dialogTable = {} -local function define_cs_dialog(dialogId, unused, linesPerBox, leftOffset, width, str) - dialogTable[dialogId] = { - unused = unused, - linesPerBox = linesPerBox, - leftOffset = leftOffset, - width = width, - str = str, - } -end +local ogDialog = {} -local real_dialog_replace = smlua_text_utils_dialog_replace -_G.smlua_text_utils_dialog_replace = define_cs_dialog - --- All Base SM64 Dialog added to the Dialog Table -define_cs_dialog(DIALOG_000, 1, 6, 30, 200, ("Wow! You're smack in the\nmiddle of the battlefield.\nYou'll find the Power\nStars that Bowser stole\ninside the painting\nworlds.\nFirst, talk to the\nBob-omb Buddy. (Press [B]\nto talk.) He'll certainly\nhelp you out, and so will\nhis comrades in other\nareas.\nTo read signs, stop, face\nthem and press [B]. Press [A]\nor [B] to scroll ahead. You\ncan talk to some other\ncharacters by facing them\nand pressing [B].")) -define_cs_dialog(DIALOG_001, 1, 4, 95, 200, ("Watch out! If you wander\naround here, you're liable\nto be plastered by a\nwater bomb!\nThose enemy Bob-ombs love\nto fight, and they're\nalways finding ways to\nattack.\nThis meadow has become\na battlefield ever since\nthe Big Bob-omb got his\npaws on the Power Star.\nCan you recover the Star\nfor us? Cross the bridge\nand go left up the path\nto find the Big Bob-omb.\nPlease come back to see\nme after you've retrieved\nthe Power Star!")) -define_cs_dialog(DIALOG_002, 1, 4, 95, 200, ("Hey, you! It's dangerous\nahead, so listen up! Take\nmy advice.\n\nCross the two\nbridges ahead, then\nwatch for falling\nwater bombs.\nThe Big Bob-omb at the\ntop of the mountain is\nvery powerful--don't let\nhim grab you!\nWe're Bob-omb Buddies,\nand we're on your side.\nYou can talk to us\nwhenever you'd like to!")) -define_cs_dialog(DIALOG_003, 1, 5, 95, 200, ("Thank you, Mario! The Big\nBob-omb is nothing but a\nbig dud now! But the\nbattle for the castle has\njust begun.\nOther enemies are holding\nthe other Power Stars. If\nyou recover more Stars,\nyou can open new doors\nthat lead to new worlds!\nMy Bob-omb Buddies are\nwaiting for you. Be sure\nto talk to them--they'll\nset up cannons for you.")) -define_cs_dialog(DIALOG_004, 1, 3, 95, 200, ("We're peace-loving\nBob-ombs, so we don't use\ncannons.\nBut if you'd like\nto blast off, we don't\nmind. Help yourself.\nWe'll prepare all of the\ncannons in this course for\nyou to use. Bon Voyage!")) -define_cs_dialog(DIALOG_005, 1, 3, 30, 200, ("Hey, Mario! Is it true\nthat you beat the Big\nBob-omb? Cool!\nYou must be strong. And\npretty fast. So, how fast\nare you, anyway?\nFast enough to beat me...\nKoopa the Quick? I don't\nthink so. Just try me.\nHow about a race to the\nmountaintop, where the\nBig Bob-omb was?\nWhaddya say? When I say\n『Go,』 let the race begin!\n\nReady....\n\n//Go!////Don't Go")) -define_cs_dialog(DIALOG_006, 1, 3, 30, 200, ("Hey!!! Don't try to scam\nME. You've gotta run\nthe whole course.\nLater. Look me up when\nyou want to race for\nreal.")) -define_cs_dialog(DIALOG_007, 1, 5, 30, 200, ("Hufff...fff...pufff...\nWhoa! You...really...are...\nfast! A human blur!\nHere you go--you've won\nit, fair and square!")) -define_cs_dialog(DIALOG_008, 1, 4, 30, 200, ("BEWARE OF CHAIN CHOMP\nExtreme Danger!\nGet close and press [C]▲\nfor a better look.\nScary, huh?\nSee the Red Coin on top\nof the stake?\n\nWhen you collect eight of\nthem, a Power Star will\nappear in the meadow\nacross the bridge.")) -define_cs_dialog(DIALOG_009, 1, 5, 30, 200, ("Long time, no see! Wow,\nhave you gotten fast!\nHave you been training\non the sly, or is it the\npower of the Stars?\nI've been feeling down\nabout losing the last\nrace. This is my home\ncourse--how about a\nrematch?\nThe goal is in\nWindswept Valley.\nReady?\n\n//Go//// Don't Go")) -define_cs_dialog(DIALOG_010, 1, 4, 30, 200, ("You've stepped on the\nWing Cap Switch. Wearing\nthe Wing Cap, you can\nsoar through the sky.\nNow Wing Caps will pop\nout of all the red blocks\nyou find.\n\nWould you like to Save?\n\n//Yes////No")) -define_cs_dialog(DIALOG_011, 1, 4, 30, 200, ("You've just stepped on\nthe Metal Cap Switch!\nThe Metal Cap makes\nMario invincible.\nNow Metal Caps will\npop out of all of the\ngreen blocks you find.\n\nWould you like to Save?\n\n//Yes////No")) -define_cs_dialog(DIALOG_012, 1, 4, 30, 200, ("You've just stepped on\nthe Vanish Cap Switch.\nThe Vanish Cap makes\nMario disappear.\nNow Vanish Caps will pop\nfrom all of the blue\nblocks you find.\n\nWould you like to Save?\n\n//Yes////No")) -define_cs_dialog(DIALOG_013, 1, 5, 30, 200, ("You've collected 100\ncoins! Mario gains more\npower from the castle.\nDo you want to Save?\n//Yes////No")) -define_cs_dialog(DIALOG_014, 1, 4, 30, 200, ("Wow! Another Power Star!\nMario gains more courage\nfrom the power of the\ncastle.\nDo you want to Save?\n\n//You Bet//Not Now")) -define_cs_dialog(DIALOG_015, 1, 4, 30, 200, ("You can punch enemies to\nknock them down. Press [A]\nto jump, [B] to punch.\nPress [A] then [B] to Kick.\nTo pick something up,\npress [B], too. To throw\nsomething you're holding,\npress [B] again.")) -define_cs_dialog(DIALOG_016, 1, 3, 30, 200, ("Hop on the shiny shell and\nride wherever you want to\ngo! Shred those enemies!")) -define_cs_dialog(DIALOG_017, 1, 4, 30, 200, ("I'm the Big Bob-omb, lord\nof all blasting matter,\nking of ka-booms the\nworld over!\nHow dare you scale my\nmountain? By what right\ndo you set foot on my\nimperial mountaintop?\nYou may have eluded my\nguards, but you'll never\nescape my grasp...\n\n...and you'll never take\naway my Power Star. I\nhereby challenge you,\nMario!\nIf you want the Star I\nhold, you must prove\nyourself in battle.\n\nCan you pick me up from\nthe back and hurl me to\nthis royal turf? I think\nthat you cannot!")) -define_cs_dialog(DIALOG_018, 1, 4, 30, 200, ("I'm sleeping because...\n...I'm sleepy. I don't\nlike being disturbed.\nPlease walk quietly.")) -define_cs_dialog(DIALOG_019, 1, 2, 30, 200, ("Shhh! Please walk\nquietly in the hallway!")) -define_cs_dialog(DIALOG_020, 1, 6, 95, 150, ("Dear Mario:\nPlease come to the\ncastle. I've baked\na cake for you.\nYours truly--\nPrincess Toadstool")) -define_cs_dialog(DIALOG_021, 1, 5, 95, 200, ("Welcome.\nNo one's home!\nNow scram--\nand don't come back!\nGwa ha ha!")) -define_cs_dialog(DIALOG_022, 1, 2, 95, 200, ("You need a key to open\nthis door.")) -define_cs_dialog(DIALOG_023, 1, 3, 95, 200, ("This key doesn't fit!\nMaybe it's for the\nbasement...")) -define_cs_dialog(DIALOG_024, 1, 5, 95, 200, ("You need Star power to\nopen this door. Recover a\nPower Star from an enemy\ninside one of the castle's\npaintings.")) -define_cs_dialog(DIALOG_025, 1, 4, 95, 200, ("It takes the power of\n3 Stars to open this\ndoor. You need [%] more\nStars.")) -define_cs_dialog(DIALOG_026, 1, 4, 95, 200, ("It takes the power of\n8 Stars to open this\ndoor. You need [%] more\nStars.")) -define_cs_dialog(DIALOG_027, 1, 4, 95, 200, ("It takes the power of\n30 Stars to open this\ndoor. You need [%] more\nStars.")) -define_cs_dialog(DIALOG_028, 1, 4, 95, 200, ("It takes the power of\n50 Stars to open this\ndoor. You need [%] more\nStars.")) -define_cs_dialog(DIALOG_029, 1, 5, 95, 200, ("To open the door that\nleads to the 『endless』\nstairs, you need 70\nStars.\nBwa ha ha!")) -define_cs_dialog(DIALOG_030, 1, 6, 30, 200, ("Hello! The Lakitu Bros.,\ncutting in with a live\nupdate on Mario's\nprogress. He's about to\nlearn a technique for\nsneaking up on enemies.\nThe trick is this: He has\nto walk very slowly in\norder to walk quietly.\n\n\n\nAnd wrapping up filming\ntechniques reported on\nearlier, you can take a\nlook around using [C]▶ and\n[C]◀. Press [C]▼ to view the\naction from a distance.\nWhen you can't move the\ncamera any farther, the\nbuzzer will sound. This is\nthe Lakitu Bros.,\nsigning off.")) -define_cs_dialog(DIALOG_031, 1, 5, 30, 200, ("No way! You beat me...\nagain!! And I just spent\nmy entire savings on\nthese new Koopa\nMach 1 Sprint shoes!\nHere, I guess I have to\nhand over this Star to\nthe winner of the race.\nCongrats, Mario!")) -define_cs_dialog(DIALOG_032, 1, 5, 30, 200, ("If you get the Wing Cap,\nyou can fly! Put the cap\non, then do a Triple\nJump--jump three times\nin a row--to take off.\nYou can fly even higher\nif you blast out of a\ncannon wearing the\nWing Cap!\n\nUse the [C] Buttons to look\naround while flying, and\npress [Z] to land.")) -define_cs_dialog(DIALOG_033, 1, 6, 30, 200, ("Ciao! You've reached\nPrincess Toadstool's\ncastle via a warp pipe.\nUsing the controller is a\npiece of cake. Press [A] to\njump and [B] to attack.\nPress [B] to read signs,\ntoo. Use the Control Stick\nin the center of the\ncontroller to move Mario\naround. Now, head for\nthe castle.")) -define_cs_dialog(DIALOG_034, 1, 6, 30, 200, ("Good afternoon. The\nLakitu Bros., here,\nreporting live from just\noutside the Princess's\ncastle.\n\nMario has just arrived\non the scene, and we'll\nbe filming the action live\nas he enters the castle\nand pursues the missing\nPower Stars.\nAs seasoned cameramen,\nwe'll be shooting from the\nrecommended angle, but\nyou can change the\ncamera angle by pressing\nthe [C] Buttons.\nIf we can't adjust the\nview any further, we'll\nbuzz. To take a look at\nthe surroundings, stop\nand press [C]▲.\n\nPress [A] to resume play.\nSwitch camera modes with\nthe [R] Button. Signs along\nthe way will review these\ninstructions.\n\nFor now, reporting live,\nthis has been the\nLakitu Bros.")) -define_cs_dialog(DIALOG_035, 1, 5, 30, 200, ("There are four camera, or\n『[C],』 Buttons. Press [C]▲\nto look around using the\nControl Stick.\n\nYou'll usually see Mario\nthrough Lakitu's camera.\nIt is the camera\nrecommended for normal\nplay.\nYou can change angles by\npressing [C]▶. If you press\n[R], the view switches to\nMario's camera, which\nis directly behind him.\nPress [R] again to return\nto Lakitu's camera. Press\n[C]▼ to see Mario from\nafar, using either\nLakitu's or Mario's view.")) -define_cs_dialog(DIALOG_036, 1, 5, 30, 200, ("OBSERVATION PLATFORM\nPress [C]▲ to take a look\naround. Don't miss\nanything!\n\nPress [R] to switch to\nMario's camera. It\nalways follows Mario.\nPress [R] again to switch\nto Lakitu's camera.\nPause the game and\nswitch the mode to 『fix』\nthe camera in place while\nholding [R]. Give it a try!")) -define_cs_dialog(DIALOG_037, 1, 2, 30, 200, ("I win! You lose!\nHa ha ha ha!\nYou're no slouch, but I'm\na better sledder!\nBetter luck next time!")) -define_cs_dialog(DIALOG_038, 1, 3, 95, 200, ("Reacting to the Star\npower, the door slowly\nopens.")) -define_cs_dialog(DIALOG_039, 1, 4, 30, 200, ("No visitors allowed,\nby decree of\nthe Big Bob-omb\n\nI shall never surrender my\nStars, for they hold the\npower of the castle in\ntheir glow.\nThey were a gift from\nBowser, the Koopa King\nhimself, and they lie well\nhidden within my realm.\nNot a whisper of their\nwhereabouts shall leave\nmy lips. Oh, all right,\nperhaps one hint:\nHeed the Star names at\nthe beginning of the\ncourse.\n//--The Big Bob-omb")) -define_cs_dialog(DIALOG_040, 1, 3, 30, 200, ("Warning!\nCold, Cold Crevasse\nBelow!")) -define_cs_dialog(DIALOG_041, 1, 3, 30, 200, ("I win! You lose!\nHa ha ha!\n\nThat's what you get for\nmessin' with Koopa the\nQuick.\nBetter luck next time!")) -define_cs_dialog(DIALOG_042, 1, 4, 30, 200, ("Caution! Narrow Bridge!\nCross slowly!\n\n\nYou can jump to the edge\nof the cliff and hang on,\nand you can climb off the\nedge if you move slowly.\nWhen you want to let go,\neither press [Z] or press\nthe Control Stick in the\ndirection of Mario's back.\nTo climb up, press Up on\nthe Control Stick. To\nscurry up quickly, press\nthe [A] Button.")) -define_cs_dialog(DIALOG_043, 1, 5, 30, 200, ("If you jump and hold the\n[A] Button, you can hang on\nto some objects overhead.\nIt's the same as grabbing\na flying bird!")) -define_cs_dialog(DIALOG_044, 1, 5, 95, 200, ("Whooo's there? Whooo\nwoke me up? It's still\ndaylight--I should be\nsleeping!\n\nHey, as long as I'm\nawake, why not take a\nshort flight with me?\nPress and hold [A] to grab\non. Release [A] to let go.\nI'll take you wherever\nyou want to go, as long\nas my wings hold out.\nWatch my shadow, and\ngrab on.")) -define_cs_dialog(DIALOG_045, 1, 6, 95, 200, ("Whew! I'm just about\nflapped out. You should\nlay off the pasta, Mario!\nThat's it for now. Press\n[A] to let go. Okay,\nbye byyyyyyeeee!")) -define_cs_dialog(DIALOG_046, 1, 5, 30, 200, ("You have to master three\nimportant jumping\ntechniques.\nFirst try the Triple Jump.\n\nRun fast, then jump three\ntimes, one, two, three.\nIf you time the jumps\nright, you'll hop, skip,\nthen jump really high.\nNext, go for distance\nwith the Long Jump. Run,\npress [Z] to crouch then [A]\nto jump really far.\n\nTo do the Wall Kick, press\n[A] to jump at a wall, then\njump again when you hit\nthe wall.\n\nGot that? Triple Jump,\nLong Jump, Wall Kick.\nPractice, practice,\npractice. You don't stand\na chance without them.")) -define_cs_dialog(DIALOG_047, 1, 2, 95, 200, ("Hi! I'll prepare the\ncannon for you!")) -define_cs_dialog(DIALOG_048, 1, 4, 30, 200, ("Snow Mountain Summit\nWatch for slippery\nconditions! Please enter\nthe cottage first.")) -define_cs_dialog(DIALOG_049, 1, 5, 30, 200, ("Remember that tricky Wall\nKick jump? It's a\ntechnique you'll have to\nmaster in order to reach\nhigh places.\nUse it to jump from wall\nto wall. Press the\nControl Stick in the\ndirection you want to\nbounce to gain momentum.\nPractice makes perfect!")) -define_cs_dialog(DIALOG_050, 1, 4, 30, 200, ("Hold [Z] to crouch and\nslide down a slope.\nOr press [Z] while in the\nair to Pound the Ground!\nIf you stop, crouch, then\njump, you'll do a\nBackward Somersault!\nGot that?\nThere's more. Crouch and\nthen jump to do a\nLong Jump! Or crouch and\nwalk to...never mind.")) -define_cs_dialog(DIALOG_051, 1, 6, 30, 200, ("Climbing's easy! When you\njump at trees, poles or\npillars, you'll grab them\nautomatically. Press [A] to\njump off backward.\n\nTo rotate around the\nobject, press Right or\nLeft on the Control Stick.\nWhen you reach the top,\npress Up to do a\nhandstand!\nJump off from the\nhandstand for a high,\nstylin' dismount.")) -define_cs_dialog(DIALOG_052, 1, 5, 30, 200, ("Stop and press [Z] to\ncrouch, then press [A]\nto do a high, Backward\nSomersault!\n\nTo perform a Side\nSomersault, run, do a\nsharp U-turn and jump.\nYou can catch lots of\nair with both jumps.")) -define_cs_dialog(DIALOG_053, 1, 5, 30, 200, ("Sometimes, if you pass\nthrough a coin ring or\nfind a secret point in a\ncourse, a red number will\nappear.\nIf you trigger five red\nnumbers, a secret Star\nwill show up.")) -define_cs_dialog(DIALOG_054, 1, 5, 30, 200, ("Welcome to the snow\nslide! Hop on! To speed\nup, press forward on the\nControl Stick. To slow\ndown, pull back.")) -define_cs_dialog(DIALOG_055, 1, 4, 30, 200, ("Hey-ey, Mario, buddy,\nhowzit goin'? Step right\nup. You look like a fast\nsleddin' kind of guy.\nI know speed when I see\nit, yes siree--I'm the\nworld champion sledder,\nyou know. Whaddya say?\nHow about a race?\nReady...\n\n//Go//// Don't Go")) -define_cs_dialog(DIALOG_056, 1, 6, 30, 200, ("You brrrr-oke my record!\nUnbelievable! I knew\nthat you were the coolest.\nNow you've proven\nthat you're also the\nfastest!\nI can't award you a gold\nmedal, but here, take this\nStar instead. You've\nearned it!")) -define_cs_dialog(DIALOG_057, 1, 4, 30, 200, ("Egad! My baby!! Have you\nseen my baby??? She's\nthe most precious baby in\nthe whole wide world.\n(They say she has my\nbeak...) I just can't\nremember where I left\nher.\nLet's see...I stopped\nfor herring and ice cubes,\nthen I...oohh! I just\ndon't know!")) -define_cs_dialog(DIALOG_058, 1, 4, 30, 200, ("You found my precious,\nprecious baby! Where\nhave you been? How can\nI ever thank you, Mario?\nOh, I do have this...\n...Star. Here, take it\nwith my eternal\ngratitude.")) -define_cs_dialog(DIALOG_059, 1, 4, 30, 200, ("That's not my baby! She\nlooks nothing like me!\nHer parents must be\nworried sick!")) -define_cs_dialog(DIALOG_060, 1, 4, 30, 200, ("ATTENTION!\nRead Before Diving In!\n\n\nIf you stay under the\nwater for too long, you'll\nrun out of oxygen.\n\nReturn to the surface for\nair or find an air bubble\nor coins to breathe while\nunderwater.\nPress [A] to swim. Hold [A]\nto swim slow and steady.\nTap [A] with smooth timing\nto gain speed.\nPress Up on the\nControl Stick and press [A]\nto dive.\n\nPress Down on the Control\nStick and press [A] to\nreturn to the surface.\n\nHold Down and press [A]\nwhile on the surface near\nthe edge of the water to\njump out.")) -define_cs_dialog(DIALOG_061, 1, 4, 30, 200, ("BRRR! Frostbite Danger!\nDo not swim here.\nI'm serious.\n/--The Penguin")) -define_cs_dialog(DIALOG_062, 1, 3, 30, 200, ("Hidden inside the green\nblock is the amazing\nMetal Cap.\nWearing it, you won't\ncatch fire or be hurt\nby enemy attacks.\nYou don't even have to\nbreathe while wearing it.\n\nThe only problem:\nYou can't swim in it.")) -define_cs_dialog(DIALOG_063, 1, 5, 30, 200, ("The Vanish Cap is inside\nthe blue block. Mr. I.\nwill be surprised, since\nyou'll be invisible when\nyou wear it!\nEven the Big Boo will be\nfooled--and you can walk\nthrough secret walls, too.")) -define_cs_dialog(DIALOG_064, 1, 5, 30, 200, ("When you put on the Wing\nCap that comes from a\nred block, do the Triple\nJump to soar high into\nthe sky.\nUse the Control Stick to\nguide Mario. Pull back to\nto fly up, press forward\nto nose down, and press [Z]\nto land.")) -define_cs_dialog(DIALOG_065, 1, 6, 30, 200, ("Swimming Lessons!\nTap [A] to do the breast\nstroke. If you time the\ntaps right, you'll swim\nfast.\n\nPress and hold [A] to do a\nslow, steady flutter kick.\nPress Up on the Control\nStick to dive, and pull\nback on the stick to head\nfor the surface.\nTo jump out of the water,\nhold Down on the Control\nStick, then press [A].\nEasy as pie, right?\n\n\nBut remember:\nMario can't breathe under\nthe water! Return to the\nsurface for air when the\nPower Meter runs low.\n\nAnd one last thing: You\ncan't open doors that\nare underwater.")) -define_cs_dialog(DIALOG_066, 1, 5, 30, 200, ("Mario, it's Peach!\nPlease be careful! Bowser\nis so wicked! He will try\nto burn you with his\nhorrible flame breath.\nRun around behind and\ngrab him by the tail with\nthe [B] Button. Once you\ngrab hold, swing him\naround in great circles.\nRotate the Control Stick\nto go faster and faster.\nThe faster you swing him,\nthe farther he'll fly.\n\nUse the [C] Buttons to look\naround, Mario. You have\nto throw Bowser into one\nof the bombs in the four\ncorners.\nAim well, then press [B]\nagain to launch Bowser.\nGood luck, Mario! Our\nfate is in your hands.")) -define_cs_dialog(DIALOG_067, 1, 5, 30, 200, ("Tough luck, Mario!\nPrincess Toadstool isn't\nhere...Gwa ha ha!! Go\nahead--just try to grab\nme by the tail!\nYou'll never be able to\nswing ME around! A wimp\nlike you won't throw me\nout of here! Never! Ha!")) -define_cs_dialog(DIALOG_068, 1, 5, 30, 200, ("It's Lethal Lava Land!\nIf you catch fire or fall\ninto a pool of flames,\nyou'll be hopping mad, but\ndon't lose your cool.\nYou can still control\nMario--just try to keep\ncalm!")) -define_cs_dialog(DIALOG_069, 1, 6, 30, 200, ("Sometimes you'll bump into\ninvisible walls at the\nedges of the painting\nworlds. If you hit a wall\nwhile flying, you'll bounce\nback.")) -define_cs_dialog(DIALOG_070, 1, 5, 30, 200, ("You can return to the\ncastle's main hall at any\ntime from the painting\nworlds where the enemies\nlive.\nJust stop, stand still,\npress Start to pause the\ngame, then select\n『Exit Course.』\n\nYou don't have to collect\nall Power Stars in one\ncourse before going on to\nthe next.\n\nReturn later, when you're\nmore experienced, to pick\nup difficult ones.\n\n\nWhenever you find a Star,\na hint for finding the\nnext one will appear on\nthe course's start screen.\n\nYou can, however, collect\nany of the remaining\nStars next. You don't\nhave to recover the one\ndescribed by the hint.")) -define_cs_dialog(DIALOG_071, 1, 3, 30, 200, ("Danger Ahead!\nBeware of the strange\ncloud! Don't inhale!\nIf you feel faint, run for\nhigher ground and fresh\nair!\nCircle: Shelter\nArrow: Entrance-Exit")) -define_cs_dialog(DIALOG_072, 1, 5, 30, 200, ("High winds ahead!\nPull your Cap down tight.\nIf it blows off, you'll\nhave to find it on this\nmountain.")) -define_cs_dialog(DIALOG_073, 1, 4, 95, 200, ("Aarrgh! Ahoy, matey. I\nhave sunken treasure,\nhere, I do.\n\nBut to pluck the plunder,\nyou must open the\nTreasure Chests in the\nright order.\nWhat order is that,\nye say?\n\n\nI'll never tell!\n\n//--The Cap'n")) -define_cs_dialog(DIALOG_074, 1, 5, 30, 200, ("You can grab on to the\nedge of a cliff or ledge\nwith your fingertips and\nhang down from it.\n\nTo drop from the edge,\neither press the Control\nStick in the direction of\nMario's back or press the\n[Z] Button.\nTo get up onto the ledge,\neither press Up on the\nControl Stick or press [A]\nas soon as you grab the\nledge to climb up quickly.")) -define_cs_dialog(DIALOG_075, 1, 5, 30, 200, ("Mario!! My castle is in\ngreat peril. I know that\nBowser is the cause...and\nI know that only you can\nstop him!\nThe doors in the castle\nthat have been sealed by\nBowser can be opened only\nwith Star Power.\n\nBut there are secret\npaths in the castle,\npaths that Bowser hasn't\nfound.\n\nOne of those paths is in\nthis room, and it holds\none of the castle's Secret\nStars!\n\nFind that Secret Star,\nMario! It will help you\non your quest. Please,\nMario, you have to\nhelp us!\nRetrieve all of the\nPower Stars in the castle\nand free us from this\nawful prison!\nPlease!")) -define_cs_dialog(DIALOG_076, 1, 6, 30, 200, ("Thanks to the power of\nthe Stars, life is\nreturning to the castle.\nPlease, Mario, you have\nto give Bowser the boot!\n\nHere, let me tell you a\nlittle something about the\ncastle. In the room with\nthe mirrors, look carefully\nfor anything that's not\nreflected in the mirror.\nAnd when you go to the\nwater town, you can flood\nit with a high jump into\nthe painting. Oh, by the\nway, look what I found!")) -define_cs_dialog(DIALOG_077, 1, 2, 150, 200, ("It is decreed that one\nshall pound the pillars.")) -define_cs_dialog(DIALOG_078, 1, 5, 30, 200, ("Break open the Blue Coin\nBlock by Pounding the\nGround with the [Z] Button.\nOne Blue Coin is worth\nfive Yellow Coins.\nBut you have to hurry!\nThe coins will disappear\nif you're not quick to\ncollect them! Too bad.")) -define_cs_dialog(DIALOG_079, 1, 4, 30, 200, ("Owwwuu! Let me go!\nUukee-kee! I was only\nteasing! Can't you take\na joke?\nI'll tell you what, let's\ntrade. If you let me go,\nI'll give you something\nreally good.\nSo, how about it?\n\n//Free him/ Hold on")) -define_cs_dialog(DIALOG_080, 1, 1, 30, 200, ("Eeeh hee hee hee!")) -define_cs_dialog(DIALOG_081, 1, 4, 30, 200, ("The mystery is of Wet\nor Dry.\nAnd where does the\nsolution lie?\nThe city welcomes visitors\nwith the depth they bring\nas they enter.")) -define_cs_dialog(DIALOG_082, 1, 4, 30, 200, ("Hold on to your hat! If\nyou lose it, you'll be\ninjured easily.\n\nIf you do lose your Cap,\nyou'll have to find it in\nthe course where you\nlost it.\nOh, boy, it's not looking\ngood for Peach. She's\nstill trapped somewhere\ninside the walls.\nPlease, Mario, you have\nto help her! Did you know\nthat there are enemy\nworlds inside the walls?\nYup. It's true. Bowser's\ntroops are there, too.\nOh, here, take this. I've\nbeen keeping it for you.")) -define_cs_dialog(DIALOG_083, 1, 6, 30, 200, ("There's something strange\nabout that clock. As you\njump inside, watch the\nposition of the big hand.\nOh, look what I found!\nHere, Mario, catch!")) -define_cs_dialog(DIALOG_084, 1, 3, 30, 200, ("Yeeoww! Unhand me,\nbrute! I'm late, so late,\nI must make haste!\nThis shiny thing? Mine!\nIt's mine. Finders,\nkeepers, losers...\nLate, late, late...\nOuch! Take it then! A\ngift from Bowser, it was.\nNow let me be! I have a\ndate! I cannot be late\nfor tea!")) -define_cs_dialog(DIALOG_085, 1, 5, 30, 200, ("You don't stand a ghost\nof a chance in this house.\nIf you walk out of here,\nyou deserve...\n...a Ghoul Medal...")) -define_cs_dialog(DIALOG_086, 1, 3, 30, 200, ("Running around in circles\nmakes some bad guys roll\ntheir eyes.")) -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_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!")) -define_cs_dialog(DIALOG_094, 1, 4, 30, 200, ("Get a good run up the\nslope! Do you remember\nthe Long Jump? Run, press\n[Z], then jump!")) -define_cs_dialog(DIALOG_095, 1, 4, 30, 200, ("To read a sign, stand in\nfront of it and press [B],\nlike you did just now.\n\nWhen you want to talk to\na Koopa Troopa or other\nanimal, stand right in\nfront of it.\nPlease recover the Stars\nthat were stolen by\nBowser in this course.")) -define_cs_dialog(DIALOG_096, 1, 4, 30, 200, ("The path is narrow here.\nEasy does it! No one is\nallowed on top of the\nmountain!\nAnd if you know what's\ngood for you, you won't\nwake anyone who's\nsleeping!\nMove slowly,\ntread lightly.")) -define_cs_dialog(DIALOG_097, 1, 5, 30, 200, ("Don't be a pushover!\nIf anyone tries to shove\nyou around, push back!\nIt's one-on-one, with a\nfiery finish for the loser!")) -define_cs_dialog(DIALOG_098, 1, 2, 95, 200, ("Come on in here...\n...heh, heh, heh...")) -define_cs_dialog(DIALOG_099, 1, 5, 95, 200, ("Eh he he...\nYou're mine, now, hee hee!\nI'll pass right through\nthis wall. Can you do\nthat? Heh, heh, heh!")) -- unused -define_cs_dialog(DIALOG_100, 1, 3, 95, 200, ("Ukkiki...Wakkiki...kee kee!\nHa! I snagged it!\nIt's mine! Heeheeheeee!")) -define_cs_dialog(DIALOG_101, 1, 3, 95, 200, ("Ackk! Let...go...\nYou're...choking...me...\nCough...I've been framed!\nThis Cap? Oh, all right,\ntake it. It's a cool Cap,\nbut I'll give it back.\nI think it looks better on\nme than it does on you,\nthough! Eeeee! Kee keee!")) -define_cs_dialog(DIALOG_102, 1, 5, 30, 200, ("Pssst! The Boos are super\nshy. If you look them\nin the eyes, they fade\naway, but if you turn\nyour back, they reappear.\nIt's no use trying to hit\nthem when they're fading\naway. Instead, sneak up\nbehind them and punch.")) -define_cs_dialog(DIALOG_103, 1, 4, 95, 200, ("Upon four towers\none must alight...\nThen at the peak\nshall shine the light...")) -define_cs_dialog(DIALOG_104, 1, 5, 30, 200, ("The shadowy star in front\nof you is a 『Star\nMarker.』 When you collect\nall 8 Red Coins, the Star\nwill appear here.")) -define_cs_dialog(DIALOG_105, 1, 3, 95, 200, ("Ready for blastoff! Come\non, hop into the cannon!\n\nYou can reach the Star on\nthe floating island by\nusing the four cannons.\nUse the Control Stick to\naim, then press [A] to fire.\n\nIf you're handy, you can\ngrab on to trees or poles\nto land.")) -define_cs_dialog(DIALOG_106, 1, 2, 95, 200, ("Ready for blastoff! Come\non, hop into the cannon!")) -define_cs_dialog(DIALOG_107, 1, 3, 95, 200, ("Ghosts...\n...don't...\n...DIE!\nHeh, heh, heh!\nCan you get out of here...\n...alive?")) -define_cs_dialog(DIALOG_108, 1, 2, 95, 200, ("Boooooo-m! Here comes\nthe master of mischief,\nthe tower of terror,\nthe Big Boo!\nKa ha ha ha...")) -define_cs_dialog(DIALOG_109, 1, 4, 95, 200, ("Ooooo Nooooo!\nTalk about out-of-body\nexperiences--my body\nhas melted away!\nHave you run in to any\nheadhunters lately??\nI could sure use a new\nbody!\nBrrr! My face might\nfreeze like this!")) -define_cs_dialog(DIALOG_110, 1, 5, 95, 200, ("I need a good head on my\nshoulders. Do you know of\nanybody in need of a good\nbody? Please! I'll follow\nyou if you do!")) -define_cs_dialog(DIALOG_111, 1, 4, 95, 200, ("Perfect! What a great\nnew body! Here--this is a\npresent for you. It's sure\nto warm you up.")) -define_cs_dialog(DIALOG_112, 1, 4, 30, 200, ("Collect as many coins as\npossible! They'll refill\nyour Power Meter.\n\nYou can check to see how\nmany coins you've\ncollected in each of the\n15 enemy worlds.\nYou can also recover\npower by touching the\nSpinning Heart.\n\nThe faster you run\nthrough the heart, the\nmore power you'll recover.")) -define_cs_dialog(DIALOG_113, 1, 6, 30, 200, ("There are special Caps in\nthe red, green and blue\nblocks. Step on the\nswitches in the hidden\ncourses to activate the\nCap Blocks.")) -define_cs_dialog(DIALOG_114, 1, 5, 95, 200, ("It makes me so mad! We\nbuild your houses, your\ncastles. We pave your\nroads, and still you\nwalk all over us.\nDo you ever say thank\nyou? No! Well, you're not\ngoing to wipe your feet\non me! I think I'll crush\nyou just for fun!\nDo you have a problem\nwith that? Just try to\npound me, wimp! Ha!")) -define_cs_dialog(DIALOG_115, 1, 5, 95, 200, ("No! Crushed again!\nI'm just a stepping stone,\nafter all. I won't gravel,\ner, grovel. Here, you win.\nTake this with you!")) -define_cs_dialog(DIALOG_116, 1, 5, 95, 200, ("Whaaa....Whaaat?\nCan it be that a\npipsqueak like you has\ndefused the Bob-omb\nking????\nYou might be fast enough\nto ground me, but you'll\nhave to pick up the pace\nif you want to take King\nBowser by the tail.\nMethinks my troops could\nlearn a lesson from you!\nHere is your Star, as I\npromised, Mario.\n\nIf you want to see me\nagain, select this Star\nfrom the menu. For now,\nfarewell.")) -define_cs_dialog(DIALOG_117, 1, 1, 95, 200, ("Who...walk...here?\nWho...break...seal?\nWake..ancient..ones?\nWe no like light...\nRrrrummbbble...\nWe no like...intruders!\nNow battle...\n...hand...\n...to...\n...hand!")) -define_cs_dialog(DIALOG_118, 1, 6, 95, 200, ("Grrrrumbbble!\nWhat...happen?\nWe...crushed like pebble.\nYou so strong!\nYou rule ancient pyramid!\nFor today...\nNow, take Star of Power.\nWe...sleep...darkness.")) -define_cs_dialog(DIALOG_119, 1, 6, 30, 200, ("Grrr! I was a bit\ncareless. This is not as I\nhad planned...but I still\nhold the power of the\nStars, and I still have\nPeach.\nBwa ha ha! You'll get no\nmore Stars from me! I'm\nnot finished with you yet,\nbut I'll let you go for\nnow. You'll pay for this...\nlater!")) -define_cs_dialog(DIALOG_120, 1, 4, 30, 200, ("Ooowaah! Can it be that\nI've lost??? The power of\nthe Stars has failed me...\nthis time.\nConsider this a draw.\nNext time, I'll be in\nperfect condition.\n\nNow, if you want to see\nyour precious Princess,\ncome to the top of the\ntower.\nI'll be waiting!\nGwa ha ha ha!")) -define_cs_dialog(DIALOG_121, 1, 5, 30, 200, ("Nooo! It can't be!\nYou've really beaten me,\nMario?!! I gave those\ntroops power, but now\nit's fading away!\nArrgghh! I can see peace\nreturning to the world! I\ncan't stand it! Hmmm...\nIt's not over yet...\n\nC'mon troops! Let's watch\nthe ending together!\nBwa ha ha!")) -define_cs_dialog(DIALOG_122, 1, 4, 30, 200, ("The Black Hole\nRight: Work Elevator\n/// Cloudy Maze\nLeft: Underground Lake")) -define_cs_dialog(DIALOG_123, 1, 4, 30, 200, ("Metal Cavern\nRight: To Waterfall\nLeft: Metal Cap Switch")) -define_cs_dialog(DIALOG_124, 1, 4, 30, 200, ("Work Elevator\nDanger!!\nRead instructions\nthoroughly!\nElevator continues in the\ndirection of the arrow\nactivated.")) -define_cs_dialog(DIALOG_125, 1, 3, 30, 200, ("Hazy Maze-Exit\nDanger! Closed.\nTurn back now.")) -define_cs_dialog(DIALOG_126, 2, 3, 30, 200, ("Up: Black Hole\nRight: Work Elevator\n/// Hazy Maze")) -define_cs_dialog(DIALOG_127, 3, 4, 30, 200, ("Underground Lake\nRight: Metal Cave\nLeft: Abandoned Mine\n///(Closed)\nA gentle sea dragon lives\nhere. Pound on his back to\nmake him lower his head.\nDon't become his lunch.")) -define_cs_dialog(DIALOG_128, 1, 4, 95, 200, ("You must fight with\nhonor! It is against the\nroyal rules to throw the\nking out of the ring!")) -define_cs_dialog(DIALOG_129, 1, 5, 30, 200, ("Welcome to the Vanish\nCap Switch Course! All of\nthe blue blocks you find\nwill become solid once you\nstep on the Cap Switch.\nYou'll disappear when you\nput on the Vanish Cap, so\nyou'll be able to elude\nenemies and walk through\nmany things. Try it out!")) -define_cs_dialog(DIALOG_130, 1, 5, 30, 200, ("Welcome to the Metal Cap\nSwitch Course! Once you\nstep on the Cap Switch,\nthe green blocks will\nbecome solid.\nWhen you turn your body\ninto metal with the Metal\nCap, you can walk\nunderwater! Try it!")) -define_cs_dialog(DIALOG_131, 1, 5, 30, 200, ("Welcome to the Wing Cap\nCourse! Step on the red\nswitch at the top of the\ntower, in the center of\nthe rainbow ring.\nWhen you trigger the\nswitch, all of the red\nblocks you find will\nbecome solid.\n\nTry out the Wing Cap! Do\nthe Triple Jump to take\noff and press [Z] to land.\n\n\nPull back on the Control\nStick to go up and push\nforward to nose down,\njust as you would when\nflying an airplane.")) -define_cs_dialog(DIALOG_132, 1, 4, 30, 200, ("Whoa, Mario, pal, you\naren't trying to cheat,\nare you? Shortcuts aren't\nallowed.\nNow, I know that you\nknow better. You're\ndisqualified! Next time,\nplay fair!")) -define_cs_dialog(DIALOG_133, 1, 6, 30, 200, ("Am I glad to see you! The\nPrincess...and I...and,\nwell, everybody...we're all\ntrapped inside the castle\nwalls.\n\nBowser has stolen the\ncastle's Stars, and he's\nusing their power to\ncreate his own world in\nthe paintings and walls.\n\nPlease recover the Power\nStars! As you find them,\nyou can use their power\nto open the doors that\nBowser has sealed.\n\nThere are four rooms on\nthe first floor. Start in\nthe one with the painting\nof Bob-omb inside. It's\nthe only room that Bowser\nhasn't sealed.\nWhen you collect eight\nPower Stars, you'll be\nable to open the door\nwith the big star. The\nPrincess must be inside!")) -define_cs_dialog(DIALOG_134, 1, 5, 30, 200, ("The names of the Stars\nare also hints for\nfinding them. They are\ndisplayed at the beginning\nof each course.\nYou can collect the Stars\nin any order. You won't\nfind some Stars, enemies\nor items unless you select\na specific Star.\nAfter you collect some\nStars, you can try\nanother course.\nWe're all waiting for\nyour help!")) -define_cs_dialog(DIALOG_135, 1, 5, 30, 200, ("It was Bowser who stole\nthe Stars. I saw him with\nmy own eyes!\n\n\nHe's hidden six Stars in\neach course, but you\nwon't find all of them in\nsome courses until you\npress the Cap Switches.\nThe Stars you've found\nwill show on each course's\nstarting screen.\n\n\nIf you want to see some\nof the enemies you've\nalready defeated, select\nthe Stars you recovered\nfrom them.")) -define_cs_dialog(DIALOG_136, 1, 6, 30, 200, ("Wow! You've already\nrecovered that many\nStars? Way to go, Mario!\nI'll bet you'll have us out\nof here in no time!\n\nBe careful, though.\nBowser and his band\nwrote the book on 『bad.』\nTake my advice: When you\nneed to recover from\ninjuries, collect coins.\nYellow Coins refill one\npiece of the Power Meter,\nRed Coins refill two\npieces, and Blue Coins\nrefill five.\n\nTo make Blue Coins\nappear, pound on Blue\nCoin Blocks.\n\n\n\nAlso, if you fall from\nhigh places, you'll\nminimize damage if you\nPound the Ground as you\nland.")) -define_cs_dialog(DIALOG_137, 1, 6, 30, 200, ("Thanks, Mario! The castle\nis recovering its energy\nas you retrieve Power\nStars, and you've chased\nBowser right out of here,\non to some area ahead.\nOh, by the by, are you\ncollecting coins? Special\nStars appear when you\ncollect 100 coins in each\nof the 15 courses!")) -define_cs_dialog(DIALOG_138, 1, 3, 30, 200, ("Down: Underground Lake\nLeft: Black Hole\nRight: Hazy Maze (Closed)")) -define_cs_dialog(DIALOG_139, 1, 6, 30, 200, ("Above: Automatic Elevator\nElevator begins\nautomatically and follows\npre-set course.\nIt disappears\nautomatically, too.")) -define_cs_dialog(DIALOG_140, 1, 6, 30, 200, ("Elevator Area\nRight: Hazy Maze\n/// Entrance\nLeft: Black Hole\n///Elevator 1\nArrow: You are here")) -define_cs_dialog(DIALOG_141, 1, 5, 150, 200, ("You've recovered one of\nthe stolen Power Stars!\nNow you can open some of\nthe sealed doors in the\ncastle.\nTry the Princess's room\non the second floor and\nthe room with the\npainting of Whomp's\nFortress on Floor 1.\nBowser's troops are still\ngaining power, so you\ncan't give up. Save us,\nMario! Keep searching for\nStars!")) -define_cs_dialog(DIALOG_142, 1, 5, 150, 200, ("You've recovered three\nPower Stars! Now you can\nopen any door with a 3\non its star.\n\nYou can come and go from\nthe open courses as you\nplease. The enemies ahead\nare even meaner, so be\ncareful!")) -define_cs_dialog(DIALOG_143, 1, 6, 150, 200, ("You've recovered eight of\nthe Power Stars! Now you\ncan open the door with\nthe big Star! But Bowser\nis just ahead...can you\nhear the Princess calling?")) -define_cs_dialog(DIALOG_144, 1, 6, 150, 200, ("You've recovered 30\nPower Stars! Now you can\nopen the door with the\nbig Star! But before you\nmove on, how's it going\notherwise?\nDid you pound the two\ncolumns down? You didn't\nlose your hat, did you?\nIf you did, you'll have to\nstomp on the condor to\nget it back!\nThey say that Bowser has\nsneaked out of the sea\nand into the underground.\nHave you finally\ncornered him?")) -define_cs_dialog(DIALOG_145, 1, 6, 150, 200, ("You've recovered 50\nPower Stars! Now you can\nopen the Star Door on the\nthird floor. Bowser's\nthere, you know.\n\nOh! You've found all of\nthe Cap Switches, haven't\nyou? Red, green and blue?\nThe Caps you get from the\ncolored blocks are really\nhelpful.\nHurry along, now. The\nthird floor is just ahead.")) -define_cs_dialog(DIALOG_146, 1, 6, 150, 200, ("You've found 70 Power\nStars! The mystery of the\nendless stairs is solved,\nthanks to you--and is\nBowser ever upset! Now,\non to the final bout!")) -define_cs_dialog(DIALOG_147, 1, 5, 30, 200, ("Are you using the Cap\nBlocks? You really should,\nyou know.\n\n\nTo make them solid so you\ncan break them, you have\nto press the colored Cap\nSwitches in the castle's\nhidden courses.\nYou'll find the hidden\ncourses only after\nregaining some of the\nPower Stars.\n\nThe Cap Blocks are a big\nhelp! Red for the Wing\nCap, green for the Metal\nCap, blue for the Vanish\nCap.")) -define_cs_dialog(DIALOG_148, 1, 6, 30, 200, ("Snowman Mountain ahead.\nKeep out! And don't try\nthe Triple Jump over the\nice block shooter.\n\n\nIf you fall into the\nfreezing pond, your power\ndecreases quickly, and\nyou won't recover\nautomatically.\n//--The Snowman")) -define_cs_dialog(DIALOG_149, 1, 3, 30, 200, ("Welcome to\nPrincess Toadstool's\nsecret slide!\nThere's a Star hidden\nhere that Bowser couldn't\nfind.\nWhen you slide, press\nforward to speed up,\npull back to slow down.\nIf you slide really\nfast, you'll win the Star!")) -define_cs_dialog(DIALOG_150, 1, 5, 30, 200, ("Waaaa! You've flooded my\nhouse! Wh-why?? Look at\nthis mess! What am I\ngoing to do now?\n\nThe ceiling's ruined, the\nfloor is soaked...what to\ndo, what to do? Huff...\nhuff...it makes me so...\nMAD!!!\nEverything's been going\nwrong ever since I got\nthis Star...It's so shiny,\nbut it makes me feel...\nstrange...")) -define_cs_dialog(DIALOG_151, 1, 4, 30, 200, ("I can't take this\nanymore! First you get\nme all wet, then you\nstomp on me!\nNow I'm really, really,\nREALLY mad!\nWaaaaaaaaaaaaaaaaa!!!")) -define_cs_dialog(DIALOG_152, 1, 3, 30, 200, ("Owwch! Uncle! Uncle!\nOkay, I give. Take this\nStar!\nWhew! I feel better now.\nI don't really need it\nanymore, anyway--\nI can see the stars\nthrough my ceiling at\nnight.\nThey make me feel...\n...peaceful. Please, come\nback and visit anytime.")) -define_cs_dialog(DIALOG_153, 1, 4, 30, 200, ("Hey! Who's there?\nWhat's climbing on me?\nIs it an ice ant?\nA snow flea?\nWhatever it is, it's\nbugging me! I think I'll\nblow it away!")) -define_cs_dialog(DIALOG_154, 1, 5, 30, 200, ("Hold on to your hat! If\nyou lose it, you'll be\neasily injured. If you\nlose it, look for it in the\ncourse where you lost it.\nSpeaking of lost, the\nPrincess is still stuck in\nthe walls somewhere.\nPlease help, Mario!\n\nOh, you know that there\nare secret worlds in the\nwalls as well as in the\npaintings, right?")) -define_cs_dialog(DIALOG_155, 1, 6, 30, 200, ("Thanks to the power of\nthe Stars, life is\nreturning to the castle.\nPlease, Mario, you have\nto give Bowser the boot!\n\nHere, let me tell you a\nlittle something about the\ncastle. In the room with\nthe mirrors, look carefully\nfor anything that's not\nreflected in the mirror.\nAnd when you go to the\nwater town, you can flood\nit with a high jump into\nthe painting.")) -define_cs_dialog(DIALOG_156, 1, 5, 30, 200, ("The world inside the\nclock is so strange!\nWhen you jump inside,\nwatch the position of\nthe big hand!")) -define_cs_dialog(DIALOG_157, 1, 5, 30, 200, ("Watch out! Don't let\nyourself be swallowed by\nquicksand.\n\n\nIf you sink into the sand,\nyou won't be able to\njump, and if your head\ngoes under, you'll be\nsmothered.\nThe dark areas are\nbottomless pits.")) -define_cs_dialog(DIALOG_158, 1, 6, 30, 200, ("1. If you jump repeatedly\nand time it right, you'll\njump higher and higher.\nIf you run really fast and\ntime three jumps right,\nyou can do a Triple Jump.\n2. Jump into a solid wall,\nthen jump again when you\nhit the wall. You can\nbounce to a higher level\nusing this Wall Kick.")) -define_cs_dialog(DIALOG_159, 1, 6, 30, 200, ("3. If you stop, press [Z]\nto crouch, then jump, you\ncan perform a Backward\nSomersault. To do a Long\nJump, run fast, press [Z],\nthen jump.")) -define_cs_dialog(DIALOG_160, 1, 4, 30, 200, ("Press [B] while running\nfast to do a Body Slide\nattack. To stand while\nsliding, press [A] or [B].")) -define_cs_dialog(DIALOG_161, 1, 4, 30, 200, ("Mario!!!\nIt that really you???\nIt has been so long since\nour last adventure!\nThey told me that I might\nsee you if I waited here,\nbut I'd just about given\nup hope!\nIs it true? Have you\nreally beaten Bowser? And\nrestored the Stars to the\ncastle?\nAnd saved the Princess?\nI knew you could do it!\nNow I have a very special\nmessage for you.\nThanks for playing Super\nMario 64! This is the\nend of the game, but not\nthe end of the fun.\nWe want you to keep on\nplaying, so we have a\nlittle something for you.\nWe hope that you like it!\nEnjoy!!!\n\nThe Super Mario 64 Team")) -define_cs_dialog(DIALOG_162, 1, 4, 30, 200, ("No, no, no! Not you\nagain! I'm in a great\nhurry, can't you see?\n\nI've no time to squabble\nover Stars. Here, have it.\nI never meant to hide it\nfrom you...\nIt's just that I'm in such\na rush. That's it, that's\nall. Now, I must be off.\nOwww! Let me go!")) -define_cs_dialog(DIALOG_163, 1, 5, 30, 200, ("Noooo! You've really\nbeaten me this time,\nMario! I can't stand\nlosing to you!\n\nMy troops...worthless!\nThey've turned over all\nthe Power Stars! What?!\nThere are 120 in all???\n\nAmazing! There were some\nin the castle that I\nmissed??!!\n\n\nNow I see peace\nreturning to the world...\nOooo! I really hate that!\nI can't watch--\nI'm outta here!\nJust you wait until next\ntime. Until then, keep\nthat Control Stick\nsmokin'!\nBuwaa ha ha!")) -define_cs_dialog(DIALOG_164, 1, 4, 30, 200, ("Mario! What's up, pal?\nI haven't been on the\nslide lately, so I'm out\nof shape.\nStill, I'm always up for a\ngood race, especially\nagainst an old sleddin'\nbuddy.\nWhaddya say?\nReady...set...\n\n//Go//// Don't Go")) -define_cs_dialog(DIALOG_165, 1, 5, 30, 200, ("I take no responsibility\nwhatsoever for those who\nget dizzy and pass out\nfrom running around\nthis post.")) -define_cs_dialog(DIALOG_166, 1, 4, 30, 200, ("I'll be back soon.\nI'm out training now,\nso come back later.\n//--Koopa the Quick")) -define_cs_dialog(DIALOG_167, 1, 4, 30, 200, ("Princess Toadstool's\ncastle is just ahead.\n\n\nPress [A] to jump, [Z] to\ncrouch, and [B] to punch,\nread a sign, or grab\nsomething.\nPress [B] again to throw\nsomething you're holding.")) -define_cs_dialog(DIALOG_168, 1, 5, 30, 200, ("Hey! Knock it off! That's\nthe second time you've\nnailed me. Now you're\nasking for it, linguine\nbreath!")) -define_cs_dialog(DIALOG_169, 1, 4, 30, 200, ("Keep out!\nThat means you!\nArrgghh!\n\nAnyone entering this cave\nwithout permission will\nmeet certain disaster.")) - -local DIALOG_NAME = "Mario" - ----@param name string -function dialog_set_replace_name(name) - DIALOG_NAME = name -end - -local prevCharName = "" - -local function dialog_swap(charName) - for i = DIALOG_000, #dialogTable do - if dialogTable[i] ~= nil then - local dialog = dialogTable[i] - 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 +local function dialog_update(dialogId) + -- Save Original Dialog + if ogDialog[dialogId] == nil then + local dialog = smlua_text_utils_dialog_get(dialogId) + ogDialog[dialogId] = { + unused = dialog.unused, + linesPerBox = dialog.linesPerBox, + leftOffset = dialog.leftOffset, + width = dialog.width, + text = dialog.text + } end -end -local function update() - -- Query Character Swapped - local charName = characterTable[currChar][characterTable[currChar].currAlt].name - if prevCharName ~= charName then - dialog_swap(charName) - prevCharName = charName + local dialog = ogDialog[dialogId] + local charName = characterTable[currChar].nickname + local charAuto = characterTable[currChar].autoDialog + -- Check for Override Dialog and use it instead + local colorDialog = false + if characterDialog[currChar] ~= nil and characterDialog[currChar][dialogId] ~= nil then + dialog = characterDialog[currChar][dialogId] + colorDialog = true + elseif charAuto then + dialog.text = dialog.text:gsub(DEFAULT_DIALOG_NAME, charName) + colorDialog = true end + + -- Set color if Dialog has Character's Name + reset_dialog_override_color() + if colorDialog then + local charColor = characterTable[currChar][characterTable[currChar].currAlt].color + set_dialog_override_color(charColor.r*0.3, charColor.g*0.3, charColor.b*0.3, 150, 255, 255, 255, 255) + end + + -- Apply Text Changes + smlua_text_utils_dialog_replace( + dialogId, + dialog.unused, + dialog.linesPerBox, + dialog.leftOffset, + dialog.width, + dialog.text + ) + + -- Reminder to later change this to true, string + return true end -hook_event(HOOK_UPDATE, update) \ No newline at end of file +hook_event(HOOK_ON_DIALOG, dialog_update) \ No newline at end of file diff --git a/mods/character-select-coop/n-hud.lua b/mods/character-select-coop/hud.lua similarity index 57% rename from mods/character-select-coop/n-hud.lua rename to mods/character-select-coop/hud.lua index 57f1aa4cc..f3b79400c 100644 --- a/mods/character-select-coop/n-hud.lua +++ b/mods/character-select-coop/hud.lua @@ -4,20 +4,14 @@ if incompatibleClient then return 0 end --- localize functions to improve performance - n-hud.lua -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 - Color hud code written by EmilyEmmi - Djui box code written by xLuigiGamerx (Use outside of character select is forbidden as these functions were made for another mod I'm planning to release) -]] +local og_hud_get_value = hud_get_value +local og_hud_set_value = hud_set_value ---@param text string ----@return nil, number, number, number, number +---@return number?, number?, number?, number? local function convert_color(text) if text:sub(2, 2) ~= "#" then - return nil + return end text = text:sub(3, -2) local rstring, gstring, bstring = "", "", "" @@ -39,7 +33,7 @@ end ---@param text string ---@param get_color boolean|nil ----@return string, string, string, boolean +---@return string, string?, string? local function remove_color(text, get_color) local start = text:find("\\") local next = 1 @@ -137,12 +131,12 @@ local function djui_hud_print_text_with_color(text, x, y, scale, red, green, blu while render ~= nil do local r, g, b, a = convert_color(color) if alpha then a = alpha end - djui_hud_print_text(render, x + space, y, scale); + djui_hud_print_text(render, x + space, y, scale) if r then djui_hud_set_color(r, g, b, a) end space = space + djui_hud_measure_text(render) * scale text, color, render = remove_color(text, true) end - djui_hud_print_text(text, x + space, y, scale); + djui_hud_print_text(text, x + space, y, scale) end ---@param text string Message @@ -175,36 +169,39 @@ end -- Real HUD Stuffs -- --------------------- +-- Updates the Chracter Select hud flags along with the vanilla hud flags + +local hiddenList = HUD_DISPLAY_FLAG_LIVES | HUD_DISPLAY_FLAG_STAR_COUNT | HUD_DISPLAY_FLAG_CAMERA | HUD_DISPLAY_FLAG_POWER +local sCharSelectHudDisplayFlags = og_hud_get_value(HUD_DISPLAY_FLAGS) | hiddenList -- Initializes custom hud flags + +function flags_update() + sCharSelectHudDisplayFlags = sCharSelectHudDisplayFlags & (og_hud_get_value(HUD_DISPLAY_FLAGS) | hiddenList) -- Updated the custom flags + og_hud_set_value(HUD_DISPLAY_FLAGS, og_hud_get_value(HUD_DISPLAY_FLAGS) & ~(hiddenList)) -- Update the vanilla flags +end +hook_event(HOOK_ON_HUD_RENDER_BEHIND, flags_update) + -- 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 +---@param type HudDisplayValue +---@return integer function _G.hud_get_value(type) if type == HUD_DISPLAY_FLAGS then - return sCharSelectHudDisplayFlags + return sCharSelectHudDisplayFlags | og_hud_get_value(HUD_DISPLAY_FLAGS) else return og_hud_get_value(type) end end ---- @param type HudDisplayValue ---- @param value integer +---@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 + og_hud_set_value(type, value & ~(hiddenList)) else og_hud_set_value(type, value) end @@ -215,7 +212,7 @@ end ---Hides the specified custom hud element ---@param hudElement HUDDisplayFlag function hud_hide_element(hudElement) - --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) + log_to_console_once("`charSelect.hud_hide_element` function is deprecated, please use 'hud_set_value'", CONSOLE_MESSAGE_WARNING) hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) & ~hudElement) return true end @@ -223,7 +220,7 @@ end ---Shows the specified custom hud element ---@param hudElement HUDDisplayFlag function hud_show_element(hudElement) - --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) + log_to_console_once("`hud_show_element` function is deprecated, please use 'hud_set_value'", CONSOLE_MESSAGE_WARNING) hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) | hudElement) return true end @@ -232,26 +229,24 @@ end ---@param hudElement HUDDisplayFlag ---@return boolean function hud_get_element(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)) + log_to_console_once("`charSelect.hud_get_element` function is deprecated, please use 'hud_set_value'", CONSOLE_MESSAGE_WARNING) return (hud_get_value(HUD_DISPLAY_FLAGS) & hudElement) ~= 0 end local MATH_DIVIDE_16 = 1/16 local MATH_DIVIDE_32 = 1/32 local MATH_DIVIDE_64 = 1/64 -local MATH_DIVIDE_HEALTH = 1/0x100 local FONT_USER = FONT_NORMAL ---- @param localIndex integer ---- @return string +---@param localIndex integer +---@return string --- This assumes multiple characters will not have the same model, --- Icons can only be seen by users who have the character avalible to them function name_from_local_index(localIndex) if localIndex == nil then localIndex = 0 end local p = gCSPlayers[localIndex] - for i = 1, #characterTable do + for i = 0, #characterTable do if characterTable[i].saveName == p.saveName then return characterTable[i][(p.currAlt and p.currAlt or 1)].name end @@ -259,14 +254,14 @@ function name_from_local_index(localIndex) return "???" end ---- @param localIndex integer ---- @return table +---@param localIndex integer +---@return table --- This assumes multiple characters will not have the same model, --- Icons can only be seen by users who have the character avalible to them function color_from_local_index(localIndex) if localIndex == nil then localIndex = 0 end local p = gCSPlayers[localIndex] - for i = 1, #characterTable do + for i = 0, #characterTable do if characterTable[i].saveName == p.saveName then return characterTable[i][(p.currAlt and p.currAlt or 1)].color end @@ -274,15 +269,15 @@ function color_from_local_index(localIndex) return {r = 255, g = 255, b = 255} end ---- @param localIndex integer ---- @return TextureInfo|string +---@param localIndex integer +---@return TextureInfo|string --- This assumes multiple characters will not have the same model, --- Icons can only be seen by users who have the character avalible to them. --- This function can return nil. if this is the case, render `djui_hud_print_text("?", x, y, 1)` function life_icon_from_local_index(localIndex) if localIndex == nil then localIndex = 0 end local p = gCSPlayers[localIndex] - for i = 1, #characterTable do + for i = 0, #characterTable do local char = characterTable[i] if char.saveName == p.saveName then return char[(p.currAlt and p.currAlt or 1)].lifeIcon @@ -291,14 +286,14 @@ function life_icon_from_local_index(localIndex) return "?" end ---- @param localIndex integer ---- @return TextureInfo +---@param localIndex integer +---@return TextureInfo --- This assumes multiple characters will not have the same model, --- Icons can only be seen by users who have the character avalible to them function star_icon_from_local_index(localIndex) if localIndex == nil then localIndex = 0 end local p = gCSPlayers[localIndex] - for i = 1, #characterTable do + for i = 0, #characterTable do local char = characterTable[i] if char.saveName == p.saveName then return char[(p.currAlt and p.currAlt or 1)].starIcon @@ -308,10 +303,10 @@ function star_icon_from_local_index(localIndex) end local TYPE_STRING = "string" ---- @param localIndex integer ---- @param x integer ---- @param y integer ---- @param scale integer +---@param localIndex integer +---@param x integer +---@param y integer +---@param scale integer function render_life_icon_from_local_index(localIndex, x, y, scale) if localIndex == nil then localIndex = 0 end local lifeIcon = life_icon_from_local_index(localIndex) @@ -331,13 +326,13 @@ function render_life_icon_from_local_index(localIndex, x, y, scale) end end ---- @param localIndex integer ---- @param prevX integer ---- @param prevY integer ---- @param prevScale integer ---- @param x integer ---- @param y integer ---- @param scale integer +---@param localIndex integer +---@param prevX integer +---@param prevY integer +---@param prevScale integer +---@param x integer +---@param y integer +---@param scale integer function render_life_icon_from_local_index_interpolated(localIndex, prevX, prevY, prevScale, x, y, scale) if localIndex == nil then localIndex = 0 end local lifeIcon = life_icon_from_local_index(localIndex) @@ -357,20 +352,20 @@ function render_life_icon_from_local_index_interpolated(localIndex, prevX, prevY end end ---- @param localIndex integer ---- @param x integer ---- @param y integer ---- @param scale integer +---@param localIndex integer +---@param x integer +---@param y integer +---@param scale integer function render_star_icon_from_local_index(localIndex, x, y, scale) if localIndex == nil then localIndex = 0 end local starIcon = star_icon_from_local_index(localIndex) djui_hud_render_texture(starIcon, x, y, scale / (starIcon.width * MATH_DIVIDE_16), scale / (starIcon.height * MATH_DIVIDE_16)) end ---- @param localIndex integer ---- @param x integer ---- @param y integer ---- @param scale integer +---@param localIndex integer +---@param x integer +---@param y integer +---@param scale integer function render_star_icon_from_local_index_interpolated(localIndex, prevX, prevY, prevScale, x, y, scale) if localIndex == nil then localIndex = 0 end local starIcon = star_icon_from_local_index(localIndex) @@ -378,7 +373,7 @@ function render_star_icon_from_local_index_interpolated(localIndex, prevX, prevY end -- Health Meter -- -local TEXT_DEFAULT_METER_PREFIX = "char-select-custom-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") local TEX_DEFAULT_METER_PIE1 = get_texture_info(TEXT_DEFAULT_METER_PREFIX.."pie1") @@ -389,7 +384,7 @@ local TEX_DEFAULT_METER_PIE5 = get_texture_info(TEXT_DEFAULT_METER_PREFIX.."pie5 local TEX_DEFAULT_METER_PIE6 = get_texture_info(TEXT_DEFAULT_METER_PREFIX.."pie6") local TEX_DEFAULT_METER_PIE7 = get_texture_info(TEXT_DEFAULT_METER_PREFIX.."pie7") local TEX_DEFAULT_METER_PIE8 = get_texture_info(TEXT_DEFAULT_METER_PREFIX.."pie8") -local defaultMeterInfo = { +defaultMeterInfo = { label = { left = TEX_DEFAULT_METER_LEFT, right = TEX_DEFAULT_METER_RIGHT, @@ -406,85 +401,230 @@ local defaultMeterInfo = { } } -local TEXT_DEFAULT_COURSE_PREFIX = "char-select-custom-course-" -local TEX_DEFAULT_METER_LEFT = get_texture_info(TEXT_DEFAULT_COURSE_PREFIX.."top") -local TEX_DEFAULT_METER_RIGHT = get_texture_info(TEXT_DEFAULT_COURSE_PREFIX.."bottom") +local TEXT_DEFAULT_COURSE_PREFIX = "char_select_custom_course_" +local TEX_DEFAULT_COURSE_TOP = get_texture_info(TEXT_DEFAULT_COURSE_PREFIX.."top") +local TEX_DEFAULT_COURSE_BOTTOM = get_texture_info(TEXT_DEFAULT_COURSE_PREFIX.."bottom") local defaultCourseInfo = { - top = TEX_DEFAULT_METER_LEFT, - bottom = TEX_DEFAULT_METER_RIGHT, + top = TEX_DEFAULT_COURSE_TOP, + bottom = TEX_DEFAULT_COURSE_BOTTOM, } ---- @param localIndex integer ---- @return table +---@param localIndex integer +---@return table --- This assumes multiple characters will not have the same model, --- Icons can only be seen by users who have the character avalible to them function health_meter_from_local_index(localIndex) - if localIndex == nil then localIndex = 0 end + localIndex = localIndex or 0 local p = gCSPlayers[localIndex] - for i = 1, #characterTable do + for i = 0, #characterTable do local char = characterTable[i] - if char.saveName == p.saveName and char[(p.currAlt and p.currAlt or 1)].healthTexture ~= nil then - return char[(p.currAlt and p.currAlt or 1)].healthTexture + local healthMeter = (char[p.currAlt] and char[p.currAlt].healthMeter) or char[1].healthMeter + if char.saveName == p.saveName and healthMeter ~= nil then + return healthMeter end end return defaultMeterInfo end ---- @param localIndex integer ---- @param x integer ---- @param y integer ---- @param scaleX integer ---- @param scaleY integer +---@param localIndex integer +---@param health integer +---@param x integer +---@param y integer +---@param scaleX integer +---@param scaleY integer function render_health_meter_from_local_index(localIndex, health, x, y, scaleX, scaleY) - if localIndex == nil then localIndex = 0 end - local health = math.floor(health*MATH_DIVIDE_HEALTH) - local textureTable = health_meter_from_local_index(localIndex) - local tex = textureTable.label.left - djui_hud_render_texture(tex, x, y, scaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, scaleY / (tex.height * MATH_DIVIDE_64) * MATH_DIVIDE_64) - local tex = textureTable.label.right - djui_hud_render_texture(tex, x + 31*scaleX*MATH_DIVIDE_64, y, scaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, scaleY / (tex.height * MATH_DIVIDE_64) * MATH_DIVIDE_64) - if health > 0 then - local tex = textureTable.pie[health] - djui_hud_render_texture(tex, x + 15*scaleX*MATH_DIVIDE_64, y + 16*scaleY*MATH_DIVIDE_64, scaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, scaleY / (tex.height * MATH_DIVIDE_32) * MATH_DIVIDE_64) + local color = djui_hud_get_color() + localIndex = localIndex or 0 + local meter = health_meter_from_local_index(localIndex) + if type(meter) == "function" then + meter(localIndex, health, x, y, scaleX, scaleY, x, y, scaleX, scaleY) + else + health = health >> 8 + local tex = meter.label.left + djui_hud_render_texture(tex, x, y, scaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, scaleY / (tex.height * MATH_DIVIDE_64) * MATH_DIVIDE_64) + tex = meter.label.right + djui_hud_render_texture(tex, x + 31*scaleX*MATH_DIVIDE_64, y, scaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, scaleY / (tex.height * MATH_DIVIDE_64) * MATH_DIVIDE_64) + if health > 0 then + tex = meter.pie[health] + djui_hud_render_texture(tex, x + 15*scaleX*MATH_DIVIDE_64, y + 16*scaleY*MATH_DIVIDE_64, scaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, scaleY / (tex.height * MATH_DIVIDE_32) * MATH_DIVIDE_64) + end + end + djui_hud_set_color(color.r, color.g, color.b, color.a) +end + +---@param localIndex integer +---@param health integer +---@param prevX integer +---@param prevY integer +---@param prevScaleX integer +---@param prevScaleY integer +---@param x integer +---@param y integer +---@param scaleX integer +---@param scaleY integer +function render_health_meter_from_local_index_interpolated(localIndex, health, prevX, prevY, prevScaleX, prevScaleY, x, y, scaleX, scaleY) + local color = djui_hud_get_color() + localIndex = localIndex or 0 + local meter = health_meter_from_local_index(localIndex) + if type(meter) == "function" then + meter(localIndex, health, prevX, prevY, prevScaleX, prevScaleY, x, y, scaleX, scaleY) + else + health = health >> 8 + local tex = meter.label.left + djui_hud_render_texture_interpolated(tex, prevX, prevY, prevScaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, prevScaleY / (tex.height * MATH_DIVIDE_64) * MATH_DIVIDE_64, x, y, scaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, scaleY / (tex.height * MATH_DIVIDE_64) * MATH_DIVIDE_64) + tex = meter.label.right + djui_hud_render_texture_interpolated(tex, prevX + 31*prevScaleX*MATH_DIVIDE_64, prevY, prevScaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, prevScaleY / (tex.height * MATH_DIVIDE_64) * MATH_DIVIDE_64, x + 31*scaleX*MATH_DIVIDE_64, y, scaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, scaleY / (tex.height * MATH_DIVIDE_64) * MATH_DIVIDE_64) + if health > 0 then + tex = meter.pie[health] + djui_hud_render_texture_interpolated(tex, prevX + 15*prevScaleX*MATH_DIVIDE_64, prevY + 16*scaleY*MATH_DIVIDE_64, prevScaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, prevScaleY / (tex.height * MATH_DIVIDE_32) * MATH_DIVIDE_64, x + 15*scaleX*MATH_DIVIDE_64, y + 16*scaleY*MATH_DIVIDE_64, scaleX / (tex.width * MATH_DIVIDE_32) * MATH_DIVIDE_64, scaleY / (tex.height * MATH_DIVIDE_32) * MATH_DIVIDE_64) + end + end + djui_hud_set_color(color.r, color.g, color.b, color.a) +end + +-- Force Default Health function to render CS' Meter + +_G.hud_render_power_meter = function(health, x, y, scaleX, scaleY) + render_health_meter_from_local_index(0, health, x, y, scaleX, scaleY) +end +_G.hud_render_power_meter_interpolated = function(health, prevX, prevY, prevScaleX, prevScaleY, x, y, scaleX, scaleY) + render_health_meter_from_local_index_interpolated(0, health, prevX, prevY, prevScaleX, prevScaleY, x, y, scaleX, scaleY) +end + +-- Health Meter Code +local POWER_METER_HIDDEN = 0 +local POWER_METER_EMPHASIZED = 1 +local POWER_METER_DEEMPHASIZING = 2 +local POWER_METER_HIDING = 3 +local POWER_METER_VISIBLE = 4 + +local sPowerMeterHUD = { + animation = POWER_METER_HIDDEN, + x = 140, + y = 166, + unused = 1.0, +}; +local sPowerMeterVisibleTimer = 0 +local sPowerMeterStoredHealth = 0 + +local function animate_power_meter_emphasized() + local hudDisplayFlags = hud_get_value(HUD_DISPLAY_FLAGS) + + if ((hudDisplayFlags & HUD_DISPLAY_FLAG_EMPHASIZE_POWER) == 0) then + if (sPowerMeterVisibleTimer == 45.0) then + sPowerMeterHUD.animation = POWER_METER_DEEMPHASIZING; + end + else + sPowerMeterVisibleTimer = 0; end end -local pieTextureNames = { - "one_segments", - "two_segments", - "three_segments", - "four_segments", - "five_segments", - "six_segments", - "seven_segments", - "full", -} -local function render_hud_health() - 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 - texture_override_reset("texture_power_meter_" .. pieTextureNames[i]) - end - return +-- Power meter animation called after emphasized mode. +-- Moves power meter y pos speed until it's at 200 to be visible. +local function animate_power_meter_deemphasizing() + local speed = 5; + + if (sPowerMeterHUD.y >= 181) then + speed = 3; end - local textureTable = characterTable[currChar][characterTable[currChar].currAlt].healthTexture - if textureTable then -- sets health HUD to custom textures - if textureTable.label.left and textureTable.label.right then -- if left and right label textures exist. BOTH have to exist to be set! - texture_override_set("texture_power_meter_left_side", textureTable.label.left) - texture_override_set("texture_power_meter_right_side", textureTable.label.right) - end - for i = 1, 8 do - texture_override_set("texture_power_meter_" .. pieTextureNames[i], (textureTable.pie and textureTable.pie[i]) and textureTable.pie[i] or defaultMeterInfo.pie[i]) + + if (sPowerMeterHUD.y >= 191) then + speed = 2; + end + + if (sPowerMeterHUD.y >= 196) then + speed = 1; + end + + sPowerMeterHUD.y = sPowerMeterHUD.y + speed; + + if (sPowerMeterHUD.y >= 201) then + sPowerMeterHUD.y = 200; + sPowerMeterPrevY = 200; + sPowerMeterHUD.animation = POWER_METER_VISIBLE; + end +end + + +-- Power meter animation called when there's 8 health segments. +-- Moves power meter y pos quickly until it's at 301 to be hidden. + +local function animate_power_meter_hiding() + sPowerMeterHUD.y = sPowerMeterHUD.y + 20; + if (sPowerMeterHUD.y >= 301) then + sPowerMeterHUD.animation = POWER_METER_HIDDEN; + sPowerMeterVisibleTimer = 0; + end +end + +-- Handles power meter actions depending of the health segments values. +local function handle_power_meter_actions(numHealthWedges) + local gPlayerCameraState = gMarioStates[0].statusForCamera + + -- Show power meter if health is not full, less than 8 + if (numHealthWedges < 8 and sPowerMeterStoredHealth == 8 and sPowerMeterHUD.animation == POWER_METER_HIDDEN) then + sPowerMeterHUD.animation = POWER_METER_EMPHASIZED; + sPowerMeterHUD.y = 166; + sPowerMeterPrevY = 166; + end + + -- Show power meter if health is full, has 8 + if (numHealthWedges == 8 and sPowerMeterStoredHealth == 7) then + sPowerMeterVisibleTimer = 0; + end + + -- After health is full, hide power meter + if (numHealthWedges == 8 and sPowerMeterVisibleTimer > 45.0) then + sPowerMeterHUD.animation = POWER_METER_HIDING; + end + + -- Update to match health value + sPowerMeterStoredHealth = numHealthWedges; + + -- If Mario is swimming, keep power meter visible + if (gPlayerCameraState.action & ACT_FLAG_SWIMMING ~= 0) then + if (sPowerMeterHUD.animation == POWER_METER_HIDDEN + or sPowerMeterHUD.animation == POWER_METER_EMPHASIZED) then + sPowerMeterHUD.animation = POWER_METER_DEEMPHASIZING; + sPowerMeterHUD.y = 166; + sPowerMeterPrevY = 166; 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) - for i = 1, 8 do - texture_override_set("texture_power_meter_" .. pieTextureNames[i], defaultMeterInfo.pie[i]) - end - end + sPowerMeterVisibleTimer = 0; + end +end + + +-- Renders the power meter that shows when Mario is in underwater +-- or has taken damage and has less than 8 health segments. +-- And calls a power meter animation function depending of the value defined. +local function render_hud_power_meter() + local shownHealthWedges = hud_get_value(HUD_DISPLAY_WEDGES); + sPowerMeterHUD.x = djui_hud_get_screen_width()*0.5 - 51 + + if (sPowerMeterHUD.animation ~= POWER_METER_HIDING) then + handle_power_meter_actions(shownHealthWedges); + end + + if (sPowerMeterHUD.animation == POWER_METER_HIDDEN) then + return; + end + + local powerMeterPrevY = sPowerMeterHUD.y + + local anim = sPowerMeterHUD.animation + if anim == POWER_METER_EMPHASIZED then + animate_power_meter_emphasized(); + elseif anim == POWER_METER_DEEMPHASIZING then + animate_power_meter_deemphasizing(); + elseif anim == POWER_METER_HIDING then + animate_power_meter_hiding(); + end + + --render_dl_power_meter(shownHealthWedges); + render_health_meter_from_local_index_interpolated(0, gMarioStates[0].health, sPowerMeterHUD.x, 208 - powerMeterPrevY, 64, 64, sPowerMeterHUD.x, 208 - sPowerMeterHUD.y, 64, 64) + + sPowerMeterVisibleTimer = sPowerMeterVisibleTimer + 1; end local function render_hud_act_select_course() @@ -506,8 +646,6 @@ local function render_hud_act_select_course() end local function render_hud_mario_lives() - og_hud_set_value(HUD_DISPLAY_FLAGS, og_hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_LIVES) - if (hud_get_value(HUD_DISPLAY_FLAGS) & HUD_DISPLAY_FLAG_LIVES) == 0 then return end local x = 22 @@ -518,8 +656,6 @@ local function render_hud_mario_lives() end local function render_hud_stars() - og_hud_set_value(HUD_DISPLAY_FLAGS, og_hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_STAR_COUNT) - 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 @@ -530,11 +666,11 @@ local function render_hud_stars() end end - local x = math_ceil(djui_hud_get_screen_width() - 76) + local x = math.ceil(djui_hud_get_screen_width() - 76) if x % 2 ~= 0 then x = x - 1 end - local y = math_ceil(240 - 209 - 16) + local y = math.ceil(240 - 209 - 16) local showX = 0 local hudDisplayStars = hud_get_value(HUD_DISPLAY_STARS) @@ -548,15 +684,11 @@ local function render_hud_stars() end local function render_hud_camera_status() - if not HUD_DISPLAY_CAMERA_STATUS then return end - - og_hud_set_value(HUD_DISPLAY_FLAGS, og_hud_get_value(HUD_DISPLAY_FLAGS) & ~HUD_DISPLAY_FLAG_CAMERA) - - if (hud_get_value(HUD_DISPLAY_FLAGS) & HUD_DISPLAY_FLAG_CAMERA) == 0 then return end + if (hud_get_value(HUD_DISPLAY_FLAGS) & HUD_DISPLAY_FLAG_CAMERA) == 0 or (hud_get_value(HUD_DISPLAY_FLAGS) & HUD_DISPLAY_FLAG_CAMERA_AND_POWER) == 0 then return end local x = djui_hud_get_screen_width() - 54 local y = 205 - local cameraHudStatus = hud_get_value(HUD_DISPLAY_CAMERA_STATUS) + local cameraHudStatus = hud_get_value(HUD_DISPLAY_CAMERA_STATUS) -- doesn't show the status of freecam because it's currently bugged when we hide the hud camera -- TODO: keep nagging the coopers to "fix `hud_get_value(HUD_DISPLAY_CAMERA_STATUS)` when using freecam and hiding the hud camera" :trollface: if cameraHudStatus == CAM_STATUS_NONE then return end @@ -585,24 +717,86 @@ local function render_hud_camera_status() end -- Act Select Hud -- + +local STAR_SELECTOR_NOT_SELECTED = 0 +local STAR_SELECTOR_SELECTED = 1 +local STAR_SELECTOR_100_COINS = 2 + +local sVisibleStars = 0 local function render_act_select_hud() local course = gNetworkPlayers[0].currCourseNum - if gServerSettings.enablePlayersInLevelDisplay == 0 or course == 0 or obj_get_first_with_behavior_id(id_bhvActSelector) == nil or act_select_hud_is_hidden(ACT_SELECT_HUD_PLAYERS_IN_LEVEL) then return end + if course == 0 or not obj_get_first_with_behavior_id(id_bhvActSelector) then return end - local starBhvCount = count_objects_with_behavior(get_behavior_from_id(id_bhvActSelectorStarType)) - local sVisibleStars = starBhvCount < 6 and starBhvCount or 6 + if sVisibleStars == 0 then + local starObj = obj_get_first_with_behavior_id(id_bhvActSelectorStarType) + while starObj do + if starObj.oStarSelectorType ~= STAR_SELECTOR_100_COINS then + sVisibleStars = sVisibleStars + 1 + end + starObj = obj_get_next_with_same_behavior_id(starObj) + end + end for a = 1, sVisibleStars do local x = (139 - sVisibleStars * 17 + a * 34) + (djui_hud_get_screen_width() / 2) - 160 + 0.5 - for j = 1, MAX_PLAYERS - 1 do -- 0 is not needed due to the due to the fact that you are never supposed to see yourself in the act + for j = 1, MAX_PLAYERS - 1 do -- 0 is not needed, you're never supposed to see yourself in act select local np = gNetworkPlayers[j] if np and np.connected and np.currCourseNum == course and np.currActNum == a then - djui_hud_render_rect(x - 4, 17, 16, 16) render_life_icon_from_local_index(j, x - 4, 17, 1) break end end end + + local selectedStar = obj_get_first_with_behavior_id(id_bhvActSelectorStarType) + local starsList = {} + while selectedStar do + table.insert(starsList, selectedStar) + selectedStar = obj_get_next_with_same_behavior_id(selectedStar) + end + + if (sVisibleStars > 0) then + local playersInAct = 0 + local sSelectedActIndex = 0 + for i = 1, #starsList do + local curStar = starsList[i] + if curStar.oStarSelectorType == STAR_SELECTOR_SELECTED then + sSelectedActIndex = i - 1 + end + end + local gCurrCourseNum = gNetworkPlayers[0].currCourseNum + for j = 1, MAX_PLAYERS - 1 do + local np = gNetworkPlayers[j] + if not (np or np.connected) then goto continue end + if (np.currCourseNum ~= gCurrCourseNum) then goto continue end + if (np.currActNum ~= sSelectedActIndex + 1) then goto continue end + playersInAct = playersInAct + 1 + ::continue:: + end + + if (playersInAct > 0) then + local message = "" + if (playersInAct == 1) then + message = message .. " Join " + else + message = message .. string.format("%d Players", playersInAct) + end + + djui_hud_set_font(FONT_NORMAL) + djui_hud_set_color(100, 100, 100, 255) + local textScale = .5 + local textWidth = djui_hud_measure_text(message) * textScale + + local xPos = ((sSelectedActIndex + 1) * 34 - sVisibleStars * 17 + 139 - (textWidth / 2) + 4) + (djui_hud_get_screen_width() / 2) - 160 + 2 + local yPos = -1 + + if message:find("Players") then + message = string.format("%d Player", playersInAct) + end + djui_hud_print_text(message, xPos, yPos, textScale) -- Not fully accurate because the font in act select is stretched in a way unachievable with normal fonts, will revisit in the future + + end + end end ---@param table table @@ -670,10 +864,11 @@ function render_playerlist_and_modlist() local entryY = y + 88 + ((entryHeight + 4) * (i-1)) djui_hud_render_rect(entryX, entryY, entryWidth, entryHeight) + local capColor = network_player_get_override_palette_color(np, CAP) playerNameColor = { - r = 127 + network_player_get_override_palette_color_channel(np, CAP, 0) / 2, - g = 127 + network_player_get_override_palette_color_channel(np, CAP, 1) / 2, - b = 127 + network_player_get_override_palette_color_channel(np, CAP, 2) / 2 + r = 127 + capColor.r/2, + g = 127 + capColor.g/2, + b = 127 + capColor.b/2 } djui_hud_set_color(255, 255, 255, 255) @@ -733,7 +928,6 @@ function render_playerlist_and_modlist() end -- Yes the ending stuffs is hardcoded, no there's not much of a better way to do it - local DIALOG_ENDING_REPLACE_1 = "$CHARNAME!" local DIALOG_ENDING_REPLACE_2 = "Thank you $CHARNAME!" local DIALOG_ENDING_REPLACE_3 = "...for $CHARNAME..." @@ -751,7 +945,7 @@ local function render_hud_ending_dialog() local width = djui_hud_get_screen_width() - local charName = characterTable[currChar][characterTable[currChar].currAlt].name + local charName = characterTable[currChar].nickname local string = "" local startTime = 0 local endTime = 0 @@ -792,47 +986,184 @@ local function render_hud_ending_dialog() end end +-- Nametags Powermeter Hud -- + +local nametagsActionBlacklist = { + [ACT_START_CROUCHING] = true, + [ACT_CROUCHING] = true, + [ACT_STOP_CROUCHING] = true, + [ACT_START_CRAWLING] = true, + [ACT_CRAWLING] = true, + [ACT_STOP_CRAWLING] = true, + [ACT_IN_CANNON] = true, + [ACT_DISAPPEARED] = true, +} + +local FADE_SCALE = 4.0 + +--- @class StateExtras +--- @field public prevPos Vec3f +--- @field public prevScale number +--- @field public inited boolean + +--- @type StateExtras[] +local sStateExtras = {} + +for i = 0, MAX_PLAYERS - 1 do + sStateExtras[i] = {} + local _ENV = setmetatable(sStateExtras[i], { __index = _G }) + prevPos = gVec3fZero() + prevScale = 0.0 + inited = false +end + +local function render_nametag_powermeter() + local sGlobalTimer = get_global_timer() + for i = 1, MAX_PLAYERS - 1 do + local m = gMarioStates[i] + if is_player_active(m) == 0 then goto continue end + local np = gNetworkPlayers[i] + if not np.currAreaSyncValid then goto continue end + + if nametagsActionBlacklist[m.action] then goto continue end + + if (m.marioBodyState.mirrorMario or m.marioBodyState.updateHeadPosTime ~= sGlobalTimer) then goto continue end + + local pos = gVec3fZero() + local out = gVec3fZero() + + vec3f_copy(pos, m.marioBodyState.headPos) + pos.y = pos.y + 100 + + if not djui_hud_world_pos_to_screen_pos(pos, out) then + goto continue + end + + local scale = -300 / out.z * djui_hud_get_fov_coeff() + + out.y = out.y - 16 * scale + + local alpha = (math.min(np.fadeOpacity << 3, 255)) * math.clamp(FADE_SCALE - scale, 0.0, 1.0) + + local e = sStateExtras[i] + if not e.inited then + vec3f_copy(e.prevPos, out) + e.prevScale = scale + e.inited = true + end + + if gNametagsSettings.showHealth then + djui_hud_set_color(255, 255, 255, alpha) + local healthScale = 90 * scale + local prevHealthScale = 90 * e.prevScale + render_health_meter_from_local_index_interpolated(i, m.health, + e.prevPos.x - (prevHealthScale * 0.5), e.prevPos.y - 72 * scale, prevHealthScale, prevHealthScale, + out.x - ( healthScale * 0.5), out.y - 72 * scale, healthScale, healthScale + ) + end + + vec3f_copy(e.prevPos, out) + e.prevScale = scale + + ::continue:: + end +end + +local function nametags_reset() + for i = 0, MAX_PLAYERS - 1 do + sStateExtras[i].inited = false + end +end + +local function on_level_init() + nametags_reset() +end + +hook_event(HOOK_ON_LEVEL_INIT, on_level_init) + +local sServerSettings = gServerSettings +local sNametagsSettings = gNametagsSettings + +_G.gServerSettings = { + enablePlayerList = sServerSettings.enablePlayerList, + enablePlayersInLevelDisplay = sServerSettings.enablePlayersInLevelDisplay, +} + +_G.gNametagsSettings = { + showHealth = sNametagsSettings.showHealth, +} + +local _ServerSettingsMetaTable = { + __index = function (t, k) + return rawget(t, k) or sServerSettings[k] + end, + __newindex = function (_, k, v) + sServerSettings[k] = v + end, +} + +local _NametagsSettingsMetaTable = { + __index = function (t, k) + return rawget(t, k) or sNametagsSettings[k] + end, + __newindex = function (_, k, v) + sNametagsSettings[k] = v + end, +} + +setmetatable(gServerSettings, _ServerSettingsMetaTable) +setmetatable(gNametagsSettings, _NametagsSettingsMetaTable) + +function nametags_settings() + if sNametagsSettings.showHealth then + gNametagsSettings.showHealth = not gNametagsSettings.showHealth + end + sNametagsSettings.showHealth = false +end + +hook_event(HOOK_ON_NAMETAGS_RENDER, nametags_settings) + local function on_hud_render_behind() FONT_USER = djui_menu_get_font() djui_hud_set_resolution(RESOLUTION_N64) djui_hud_set_font(FONT_HUD) + + render_nametag_powermeter() -- Render before setting the color, it sets its own + djui_hud_set_color(255, 255, 255, 255) - if gNetworkPlayers[0].currActNum == 99 or gMarioStates[0].action == ACT_INTRO_CUTSCENE or hud_is_hidden() then - return - end + if gNetworkPlayers[0].currActNum == 99 or gMarioStates[0].action == ACT_INTRO_CUTSCENE or hud_is_hidden() then return end - if obj_get_first_with_behavior_id(id_bhvActSelector) == nil then + sServerSettings.enablePlayersInLevelDisplay = 0 -- Disables the original playersInLevel Display + + local enablePlayersInLevelDisplay = gServerSettings.enablePlayersInLevelDisplay + if not obj_get_first_with_behavior_id(id_bhvActSelector) then render_hud_mario_lives() render_hud_stars() render_hud_camera_status() - render_hud_health() + render_hud_power_meter() + sVisibleStars = 0 else + if enablePlayersInLevelDisplay then + render_act_select_hud() + end render_hud_act_select_course() end end --- Can't name this charSelect due to o-api.lua overriding it, if I did so, using character select with no packs would make it nil -_G.gServerSettingsCS = { - enablePlayerList = true -- Set to false to disable the playerlist -} local function on_hud_render() djui_hud_set_resolution(RESOLUTION_N64) djui_hud_set_font(FONT_HUD) djui_hud_set_color(255, 255, 255, 255) - if obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then - render_act_select_hud() - end - if gNetworkPlayers[0].currActNum == 99 then render_hud_ending_dialog() end - gServerSettings.enablePlayerList = false -- Disables the original playerlist and modlist + sServerSettings.enablePlayerList = 0 -- Disables the original playerlist and modlist - local enablePlayerList = gServerSettingsCS.enablePlayerList -- gServerSettings.enablePlayerList but for the character select playerlist + local enablePlayerList = gServerSettings.enablePlayerList djui_hud_set_resolution(RESOLUTION_DJUI) if djui_attempting_to_open_playerlist() and enablePlayerList then diff --git a/mods/character-select-coop/main.lua b/mods/character-select-coop/main.lua index 6cc963dae..e15e77b6b 100644 --- a/mods/character-select-coop/main.lua +++ b/mods/character-select-coop/main.lua @@ -1,11 +1,11 @@ -- name: Character Select --- 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 +-- description:\\#ffff33\\-- Character Select Coop v1.16 --\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 +---@param hookEventType LuaHookedEventType local function create_hook_wrapper(hookEventType) local callbacks = {} @@ -22,37 +22,98 @@ 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 - menu = false menuAndTransition = false -options = false -local credits = false -local creditsAndTransition = false -currChar = 1 -currCharRender = 1 +gridMenu = mod_storage_load_bool("PrefGridView") +options = nil; OPTIONS_MAIN = 0; OPTIONS_CREDITS = 1 +prevOptions = nil; optionsTimer = 0 +bootChar = CT_MARIO +if gMarioStates[0].character ~= nil then + bootChar = gMarioStates[0].character.type +end +currChar = bootChar +local prevChar = bootChar +currCharRender = bootChar currCategory = 1 local currOption = 1 -local creditScroll = 0 -local prevCreditScroll = creditScroll -local creditScrollRange = 0 +local currCredits = 1 +local currCreditScroll = 0 +local creditScrollMin = 6 +local totalPlaytime = 0 local menuCrossFade = 7 local menuCrossFadeCap = menuCrossFade local menuCrossFadeMath = 255 / menuCrossFade -local creditsCrossFade = 7 -local creditsCrossFadeCap = creditsCrossFade -local creditsCrossFadeMath = 255 / creditsCrossFade +local TYPE_FUNCTION = "function" +local TYPE_BOOLEAN = "boolean" +local TYPE_STRING = "string" +local TYPE_INTEGER = "number" +local TYPE_TABLE = "table" -local TEX_HEADER = get_texture_info("char-select-text") -local TEX_OVERRIDE_HEADER = nil +local MENU_BINDS_DEFAULT = 1 +local MENU_BINDS_GRID = 2 +local MENU_BINDS_OPTIONS = 3 +local MENU_BINDS_CREDITS = 4 +local TEXT_TABLE_MENU_BINDS = { + [MENU_BINDS_DEFAULT] = { + {bind = "Up / Down", desc = "Change Character"}, + {bind = "Left / Right", desc = "Change Costume"}, + {bind = "A Button", desc = "Set Preferred Character"}, + {bind = "B Button", desc = "Exit Menu"}, + {bind = "X Button", desc = "Toggle Grid View"}, + {bind = "Y Button", desc = "Toggle Palette"}, + {bind = "L/R Triggers", desc = "Change Categories"}, + {bind = "Start Button", desc = "Options Menu"}, + }, + [MENU_BINDS_GRID] = { + {bind = "Up / Down / Left / Right", desc = "Change Character"}, + {bind = "A Button", desc = "Set Preferred Character"}, + {bind = "B Button", desc = "Exit Menu"}, + {bind = "X Button", desc = "Toggle List View"}, + {bind = "Y Button", desc = "Toggle Palette"}, + {bind = "L/R Triggers", desc = "Change Categories"}, + {bind = "Start Button", desc = "Options Menu"}, + }, + [MENU_BINDS_OPTIONS] = { + {bind = "Up / Down", desc = "Scroll Options"}, + {bind = "Left / Right", desc = "Toggle Option"}, + {bind = "B Button", desc = "Exit Options Menu"}, + }, + [MENU_BINDS_CREDITS] = { + {bind = "Up / Down", desc = "Scroll Credits"}, + {bind = "Left / Right", desc = "Switch Page"}, + {bind = "B Button", desc = "Exit Credits Menu"}, + }, +} ----@param texture TextureInfo|nil -function header_set_texture(texture) - TEX_OVERRIDE_HEADER = texture -end +local TEX_LOGO = get_texture_info("char_select_logo") +local TEX_WALL_LEFT = get_texture_info("char_select_wall_left") +local TEX_WALL_RIGHT = get_texture_info("char_select_wall_right") +TEX_GRAFFITI_DEFAULT = get_texture_info("char_select_graffiti_default") +local TEX_NAMEPLATE = get_texture_info("char_select_list_button") +local TEX_ALBUM_LAYER1 = get_texture_info("char_select_album_back") +local TEX_ALBUM_LAYER2 = get_texture_info("char_select_album_front") +local TEX_ALBUM_LAYER3 = get_texture_info("char_select_album_overlay") +local TEX_CD_LAYER1 = get_texture_info("char_select_cd_layer1") +local TEX_CD_LAYER2 = get_texture_info("char_select_cd_layer2") +local TEX_CD_LAYER3 = get_texture_info("char_select_cd_layer3") +local TEX_CD_LAYER4 = get_texture_info("char_select_cd_layer4") +local TEX_RECORD = get_texture_info("char_select_record") +local TEX_PALETTE_BUCKET = get_texture_info("char_select_palette_bucket") +local TEX_OPTIONS_TV = get_texture_info("char_select_options_tv") +local TEX_GEAR = get_texture_info("char_select_gear") + +LOCKED_NEVER = 0 +LOCKED_TRUE = 1 +LOCKED_FALSE = 2 + +local SOUND_CHAR_SELECT_THEME = audio_stream_load("char_select_menu_theme.ogg") +local SOUND_CHAR_SELECT_DIAL = audio_stream_load("char_select_dial_wind.ogg") +local menuThemeTargetVolume = 0 +local menuThemeVolume = menuThemeTargetVolume +audio_stream_set_looping(SOUND_CHAR_SELECT_THEME, true) +audio_stream_set_loop_points(SOUND_CHAR_SELECT_THEME, 0, 93.659*22050) CS_ANIM_MENU = CHAR_ANIM_MAX + 1 @@ -67,169 +128,227 @@ local TEXT_PREF_LOAD_ALT = 1 ]] characterTable = { - [1] = { - saveName = "Default", + [CT_MARIO] = { + saveName = "Mario_CoopDX", + nickname = "Mario", category = "All_CoopDX", - ogNum = 1, + ogNum = CT_MARIO, currAlt = 1, hasMoveset = false, - locked = false, + locked = LOCKED_NEVER, + playtime = 0, + autoDialog = true, + replaceModels = {}, [1] = { name = "Mario", - description = { - "The iconic Italian plumber himself!", - "He's quite confident and brave,", - "always prepared to jump into action", - "to save the Mushroom Kingdom!", - }, - credit = "Nintendo / Coop Team", + description = "The iconic Italian plumber himself! He's quite confident and brave, always prepared to jump into action to save the Mushroom Kingdom!", + credit = "Nintendo/CoopDX", color = { r = 255, g = 50, b = 50 }, model = E_MODEL_MARIO, ogModel = E_MODEL_MARIO, - forceChar = CT_MARIO, + baseChar = CT_MARIO, lifeIcon = gTextures.mario_head, starIcon = gTextures.star, camScale = 1.0, + healthMeter = { + label = { + left = get_texture_info("texture_power_meter_left_side"), + right = get_texture_info("texture_power_meter_right_side"), + }, + pie = { + [1] = get_texture_info("texture_power_meter_one_segments"), + [2] = get_texture_info("texture_power_meter_two_segments"), + [3] = get_texture_info("texture_power_meter_three_segments"), + [4] = get_texture_info("texture_power_meter_four_segments"), + [5] = get_texture_info("texture_power_meter_five_segments"), + [6] = get_texture_info("texture_power_meter_six_segments"), + [7] = get_texture_info("texture_power_meter_seven_segments"), + [8] = get_texture_info("texture_power_meter_full"), + } + } }, - [2] = { + }, + [CT_LUIGI] = { + saveName = "Luigi_CoopDX", + nickname = "Luigi", + category = "All_CoopDX", + ogNum = CT_LUIGI, + currAlt = 1, + hasMoveset = false, + locked = LOCKED_NEVER, + playtime = 0, + autoDialog = true, + replaceModels = {}, + [1] = { name = "Luigi", - description = { - "The other iconic Italian plumber!", - "He's a bit shy and scares easily,", - "but he's willing to follow his brother", - "Mario through any battle that may", - "come their way!", - }, - credit = "Nintendo / Coop Team", + description = "The other iconic Italian plumber! He's a bit shy and scares easily, but he's willing to follow his brother Mario through any battle that may come their way!", + credit = "Nintendo/CoopDX", color = { r = 50, g = 255, b = 50 }, model = E_MODEL_LUIGI, ogModel = E_MODEL_LUIGI, - forceChar = CT_LUIGI, + baseChar = CT_LUIGI, lifeIcon = gTextures.luigi_head, starIcon = gTextures.star, camScale = 1.0, - healthTexture = { + healthMeter = { label = { - left = get_texture_info("char-select-luigi-meter-left"), - right = get_texture_info("char-select-luigi-meter-right"), - } + left = get_texture_info("char_select_luigi_meter_left"), + right = get_texture_info("char_select_luigi_meter_right"), + }, + pie = defaultMeterInfo.pie } }, - [3] = { + }, + [CT_TOAD] = { + saveName = "Toad_CoopDX", + nickname = "Toad", + category = "All_CoopDX", + ogNum = CT_TOAD, + currAlt = 1, + hasMoveset = false, + locked = LOCKED_NEVER, + playtime = 0, + autoDialog = true, + replaceModels = {}, + [1] = { name = "Toad", - description = { - "Princess Peach's little attendant!", - "He's an energetic little mushroom", - "that's never afraid to follow", - "Mario and Luigi on their adventures!", - }, - credit = "Nintendo / Coop Team", + description = "Princess Peach's little attendant! He's an energetic little mushroom that's never afraid to follow Mario and Luigi on their adventures!", + credit = "Nintendo/CoopDX", color = { r = 50, g = 50, b = 255 }, model = E_MODEL_TOAD_PLAYER, ogModel = E_MODEL_TOAD_PLAYER, - forceChar = CT_TOAD, + baseChar = CT_TOAD, lifeIcon = gTextures.toad_head, starIcon = gTextures.star, camScale = 0.8, - healthTexture = { + healthMeter = { label = { - left = get_texture_info("char-select-toad-meter-left"), - right = get_texture_info("char-select-toad-meter-right"), - } + left = get_texture_info("char_select_toad_meter_left"), + right = get_texture_info("char_select_toad_meter_right"), + }, + pie = defaultMeterInfo.pie } }, - [4] = { + }, + [CT_WALUIGI] = { + saveName = "Waluigi_CoopDX", + nickname = "Waluigi", + category = "All_CoopDX", + ogNum = CT_WALUIGI, + currAlt = 1, + hasMoveset = false, + locked = LOCKED_NEVER, + playtime = 0, + autoDialog = true, + replaceModels = {}, + [1] = { name = "Waluigi", - description = { - "The mischievous rival of Luigi!", - "He's a narcissistic competitor", - "that takes great taste in others", - "getting pummeled from his success!", - }, - credit = "Nintendo / Coop Team", + description = "The mischievous rival of Luigi! He's a narcissistic competitor that takes great taste in others getting pummeled from his success!", + credit = "Nintendo/CoopDX", color = { r = 130, g = 25, b = 130 }, model = E_MODEL_WALUIGI, ogModel = E_MODEL_WALUIGI, - forceChar = CT_WALUIGI, + baseChar = CT_WALUIGI, lifeIcon = gTextures.waluigi_head, starIcon = gTextures.star, camScale = 1.1, - healthTexture = { + healthMeter = { label = { - left = get_texture_info("char-select-waluigi-meter-left"), - right = get_texture_info("char-select-waluigi-meter-right"), - } + left = get_texture_info("char_select_waluigi_meter_left"), + right = get_texture_info("char_select_waluigi_meter_right"), + }, + pie = defaultMeterInfo.pie } }, - [5] = { + }, + [CT_WARIO] = { + saveName = "Wario_CoopDX", + nickname = "Wario", + category = "All_CoopDX", + ogNum = CT_WARIO, + currAlt = 1, + hasMoveset = false, + locked = LOCKED_NEVER, + playtime = 0, + autoDialog = true, + replaceModels = {}, + [1] = { name = "Wario", - description = { - "The mischievous rival of Mario!", - "He's a greed-filled treasure hunter", - "obsessed with money and gold coins.", - "He's always ready for a brawl if his", - "money is on the line!", - }, - credit = "Nintendo / Coop Team", + description = "The mischievous rival of Mario! He's a greed-filled treasure hunter obsessed with money and gold coins. He's always ready for a brawl if his money is on the line!", + credit = "Nintendo/CoopDX", color = { r = 255, g = 255, b = 50 }, model = E_MODEL_WARIO, ogModel = E_MODEL_WARIO, - forceChar = CT_WARIO, + baseChar = CT_WARIO, lifeIcon = gTextures.wario_head, starIcon = gTextures.star, - camScale = 1.0, - healthTexture = { + camScale = 1.1, + healthMeter = { label = { - left = get_texture_info("char-select-wario-meter-left"), - right = get_texture_info("char-select-wario-meter-right"), - } + left = get_texture_info("char_select_wario_meter_left"), + right = get_texture_info("char_select_wario_meter_right"), + }, + pie = defaultMeterInfo.pie } }, }, } +function character_is_vanilla(charNum) + if charNum == nil then charNum = currChar end + return charNum < CT_MAX +end + characterCategories = { - "All", - "CoopDX", - "Locked", + {name = "All", icon1 = CT_MARIO, icon2 = CT_LUIGI}, + {name = "CoopDX", icon1 = CT_WARIO, icon2 = CT_WALUIGI}, } 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 = {} -characterAnims = {} -characterMovesets = {[1] = {}} +characterpeachletter = {} --the custom texture a character uses for peach's letter in the opening +characterAnims = { + [E_MODEL_MARIO] = { + anims = {[CS_ANIM_MENU] = MARIO_ANIM_CS_MENU}, + eyes = {[CS_ANIM_MENU] = MARIO_EYES_LOOK_RIGHT}, + }, + [E_MODEL_LUIGI] = { + anims = {[CS_ANIM_MENU] = LUIGI_ANIM_CS_MENU}, + eyes = {[CS_ANIM_MENU] = MARIO_EYES_LOOK_RIGHT}, + hands = {[CS_ANIM_MENU] = MARIO_HAND_OPEN} + }, + [E_MODEL_TOAD_PLAYER] = { + anims = {[CS_ANIM_MENU] = TOAD_PLAYER_ANIM_CS_MENU}, + hands = {[CS_ANIM_MENU] = MARIO_HAND_OPEN} + }, + [E_MODEL_WALUIGI] = { + anims = {[CS_ANIM_MENU] = WALUIGI_ANIM_CS_MENU}, + eyes = {[CS_ANIM_MENU] = MARIO_EYES_LOOK_RIGHT}, + }, + [E_MODEL_WARIO] = { + anims = {[CS_ANIM_MENU] = WARIO_ANIM_CS_MENU}, + eyes = {[CS_ANIM_MENU] = MARIO_EYES_LOOK_LEFT}, + }, +} +characterMovesets = { + [CT_MARIO] = {}, + [CT_LUIGI] = {}, + [CT_TOAD] = {}, + [CT_WALUIGI] = {}, + [CT_WARIO] = {}, +} characterUnlock = {} +characterInstrumentals = {} +characterGraffiti = { + [CT_MARIO] = get_texture_info("char_select_graffiti_mario"), + [CT_LUIGI] = get_texture_info("char_select_graffiti_luigi"), + [CT_TOAD] = get_texture_info("char_select_graffiti_toad"), + [CT_WALUIGI] = get_texture_info("char_select_graffiti_waluigi"), + [CT_WARIO] = get_texture_info("char_select_graffiti_wario"), +} +characterDialog = {} tableRefNum = 0 local function make_table_ref_num() @@ -237,26 +356,35 @@ local function make_table_ref_num() return tableRefNum end +OPTION_MENU = "Menu" +OPTION_CHAR = "Character" +OPTION_MISC = "Misc" +OPTION_MOD = "Host" +OPTION_API = "Packs" + optionTableRef = { -- Menu openInputs = make_table_ref_num(), notification = make_table_ref_num(), menuColor = make_table_ref_num(), - anims = make_table_ref_num(), + music = make_table_ref_num(), inputLatency = make_table_ref_num(), -- Characters localMoveset = make_table_ref_num(), - localModels = make_table_ref_num(), localVoices = make_table_ref_num(), + localVisuals = make_table_ref_num(), -- CS credits = make_table_ref_num(), - debugInfo = make_table_ref_num(), resetSaveData = make_table_ref_num(), + -- Moderation + --restrictPalettes = make_table_ref_num(), + restrictMovesets = make_table_ref_num(), } optionTable = { [optionTableRef.openInputs] = { - name = "Open Binds", + name = "Menu Bind", + category = OPTION_MENU, toggle = tonumber(mod_storage_load("MenuInput")), toggleSaveName = "MenuInput", toggleDefault = 1, @@ -266,15 +394,17 @@ optionTable = { }, [optionTableRef.notification] = { name = "Notifications", + category = OPTION_MENU, toggle = tonumber(mod_storage_load("notifs")), toggleSaveName = "notifs", toggleDefault = 1, toggleMax = 2, toggleNames = {"Off", "On", "Pop-ups Only"}, - description = {"Toggles whether Pop-ups and", "Chat Messages display"} + description = {"Toggles whether Pop-ups and", "Chat Messages display."} }, [optionTableRef.menuColor] = { name = "Menu Color", + category = OPTION_MENU, toggle = tonumber(mod_storage_load("MenuColor")), toggleSaveName = "MenuColor", toggleDefault = 0, @@ -282,17 +412,19 @@ optionTable = { toggleNames = {"Auto", "Saved", "Red", "Orange", "Yellow", "Green", "Blue", "Pink", "Purple", "White", "Black"}, description = {"Toggles the Menu Color"} }, - [optionTableRef.anims] = { - name = "Menu Anims", - toggle = tonumber(mod_storage_load("Anims")), - toggleSaveName = "Anims", + [optionTableRef.music] = { + name = "Menu Music", + category = OPTION_MENU, + toggle = tonumber(mod_storage_load("Music")), + toggleSaveName = "Music", toggleDefault = 1, - toggleMax = 1, - toggleNames = {"Off", "On"}, - description = {"Toggles Animations In-Menu,", "Turning these off may", "Save Performance"} + toggleMax = 3, + toggleNames = {"Off", "On", "Breakroom Only", "Character Only"}, + description = {"Toggles which music plays", "in the menu."} }, [optionTableRef.inputLatency] = { - name = "Scroll Speed", + name = "Menu Scroll Speed", + category = OPTION_MENU, toggle = tonumber(mod_storage_load("Latency")), toggleSaveName = "Latency", toggleDefault = 1, @@ -300,70 +432,175 @@ optionTable = { toggleNames = {"Slow", "Normal", "Fast"}, description = {"Sets how fast you scroll", "throughout the Menu"} }, + [optionTableRef.localVoices] = { + name = "Character Voices", + category = OPTION_CHAR, + toggle = tonumber(mod_storage_load("localVoices")), + toggleSaveName = "localVoices", + toggleDefault = 1, + toggleMax = 2, + toggleNames = {"Off", "On", "Local Only"}, + description = {"Toggle if Custom Voicelines play", "for Characters who support it"} + }, + [optionTableRef.localVisuals] = { + name = "Character Visuals", + category = OPTION_CHAR, + toggle = tonumber(mod_storage_load("localVisuals")), + toggleSaveName = "localVisuals", + toggleDefault = 1, + toggleMax = 1, + description = {"Toggle if Characters can", "change how objects/textures appear"} + }, [optionTableRef.localMoveset] = { name = "Character Moveset", + category = OPTION_CHAR, toggle = tonumber(mod_storage_load("localMoveset")), toggleSaveName = "localMoveset", toggleDefault = 1, toggleMax = 1, - description = {"Toggles if Custom Movesets", "are active on compatible", "characters"} - }, - [optionTableRef.localModels] = { - name = "Locally Display Models", - toggle = tonumber(mod_storage_load("localModels")), - toggleSaveName = "localModels", - toggleDefault = 1, - toggleMax = 1, - description = {"Toggles if Custom Models display", "on your client, practically", "disables Character Select if", "Toggled Off"} - }, - [optionTableRef.localVoices] = { - name = "Custom Voices", - toggle = tonumber(mod_storage_load("localVoices")), - toggleSaveName = "localVoices", - toggleDefault = 1, - toggleMax = 1, - description = {"Toggle if Custom Voicelines play", "for Characters who support it"} + description = {"Toggles if Custom Movesets", "are active on compatible", "characters"}, + lock = function () + if gGlobalSyncTable.charSelectRestrictMovesets ~= 0 then + return "Forced Off" + end + end, }, [optionTableRef.credits] = { name = "Credits", + category = OPTION_MISC, toggle = 0, toggleDefault = 0, toggleMax = 1, - toggleNames = {"", ""}, + toggleNames = {"Open Credits", "Open Credits"}, description = {"Thank you for choosing", "Character Select!"} }, - [optionTableRef.debugInfo] = { - name = "Debugging Info", - toggle = tonumber(mod_storage_load("debuginfo")), - toggleSaveName = "debuginfo", - toggleDefault = 0, - toggleMax = 1, - description = {"Replaces the Character", "Description with Character", "Debugging Information"} - }, [optionTableRef.resetSaveData] = { name = "Reset Save Data", + category = OPTION_MISC, toggle = 0, toggleDefault = 0, toggleMax = 1, - toggleNames = {"", ""}, + toggleNames = {"Reset Save Data", "Reset Save Data"}, description = {"Resets Character Select's", "Save Data"} }, + [optionTableRef.restrictMovesets] = { + name = "Restrict Movesets", + category = OPTION_MOD, + toggle = 0, + toggleDefault = 1, + toggleMax = 1, + description = {"Restricts turning on movesets", "(Host Only)"}, + lock = function () + if gGlobalSyncTable.charSelectRestrictMovesets < 2 then + if not network_is_server() then + return "Host Only" + end + else + return "API Only" + end + end, + }, } +local gridYOffset = 0 +local function update_character_render_table() + gridYOffset = -100 + local ogNum = currChar + local insertNum = 0 + currChar = 0 + currCharRender = 0 + local category = characterCategories[currCategory] + if category == nil then return false end + characterTableRender = {} + for i = 0, #characterTable do + local charCategories = string_split(characterTable[i].category, "_") + if characterTable[i].locked ~= LOCKED_TRUE then + for c = 1, #charCategories do + if category.name == charCategories[c] then + characterTableRender[insertNum] = characterTable[i] + characterTableRender[insertNum].UIOffset = 0 + if ogNum == i then + currChar = ogNum + currCharRender = num_wrap(insertNum, 0, #characterTableRender) + end + insertNum = insertNum + 1 + end + end + end + end + + if #characterTableRender > 0 then + -- Get icons for category based on name similarity + if category.icon1 == nil or category.icon2 == nil then + local sorted = {} + for i = 0, #characterTableRender do + local char = characterTableRender[i] + table.insert(sorted, {ogNum = char.ogNum, sim = string_sim(char.saveName, category.name)}) + end + table.sort(sorted, function(a, b) + log_to_console_once(tostring(a.ogNum) .. " - " .. tostring(a.sim), CONSOLE_MESSAGE_INFO) + log_to_console_once(tostring(b.ogNum) .. " - " .. tostring(b.sim), CONSOLE_MESSAGE_INFO) + return a.sim < b.sim + end) + category.icon1 = category.icon1 or sorted[1].ogNum + category.icon2 = category.icon2 or sorted[2].ogNum + end + -- Set Character if they are in the category + currChar = (characterTableRender[currCharRender] and characterTableRender[currCharRender].ogNum or characterTableRender[0].ogNum) + return true + else + return false + end +end + +function force_set_character(charNum, charAlt) + if not charNum then charNum = gNetworkPlayers[0].modelIndex end + if not charAlt then charAlt = 1 end + currCategory = 1 + currChar = charNum + characterTable[currChar].currAlt = charAlt + currCharRender = charNum + charBeingSet = true + update_character_render_table() +end + +---@description A function that gets an option's status from the Character Select Options Menu +---@param tableNum integer The table position of the option +---@return number? +function get_options_status(tableNum) + if type(tableNum) ~= TYPE_INTEGER then return nil end + return optionTable[tableNum].toggle +end + +---@class Credits +---@field packName string + +---@class Credit +---@field creditee string +---@field credit string + +---@type Credits[] creditTable = { - { + [1] = { packName = "Character Select Coop", - {creditTo = "Squishy6094", creditFor = "Creator"}, - {creditTo = "AngelicMiracles", creditFor = "Concepts / CoopDX"}, - {creditTo = "AgentX", creditFor = "Main Contributer / CoopDX"}, - {creditTo = "xLuigiGamerx", creditFor = "Main Contributer"}, - {creditTo = "OneCalledRPG", creditFor = "Contributer"}, - {creditTo = "SuperKirbyLover", creditFor = "Custom Health Meters"}, - {creditTo = "EliteMasterEric", creditFor = "Dialog Replacement"} + { creditee = "Squishy6094", credit = "Creator" }, + { creditee = "JerThePear", credit = "Menu Assets/Anims" }, + { creditee = "Trashcam", credit = "Menu Music" }, + { creditee = "Charity", credit = "Sound Design" }, + { creditee = "WinbowBreaker", credit = "Menu Asset Renders" }, + { creditee = "xLuigiGamerx", credit = "HUD Accuracy" }, + { creditee = "Wibblus", credit = "Menu Anims Code" }, } } -local defaultOptionCount = #optionTable +if CREDIT_SUPPORTERS ~= nil then + creditTable[0] = { + packName = "Character Select Supporters", + } + for i = 1, #CREDIT_SUPPORTERS do + table.insert(creditTable[0], { creditee = CREDIT_SUPPORTERS[i]}) + end +end local latencyValueTable = {12, 6, 3} @@ -407,45 +644,50 @@ end local prefCharColor = {r = 255, g = 50, b = 50} local function load_preferred_char() + local m = gMarioStates[0] local savedChar = mod_storage_load("PrefChar") + local savedNick = mod_storage_load("PrefNick") 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" + mod_storage_save("PrefChar", characterTable[bootChar].saveName) + savedChar = characterTable[bootChar].saveName end if savedAlt == nil then mod_storage_save("PrefAlt", "1") savedAlt = 1 end if savedPalette == nil then - local paletteSave = savedChar ~= "Default" and 1 or 0 + local paletteSave = 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 - 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 + + -- Find Saved Character + local charFound = false + for i = 0, #characterTable do + local char = characterTable[i] + if char.saveName == savedChar and char.locked ~= LOCKED_TRUE then + currChar = i + currCharRender = i + charFound = true + 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 - - characterTable[1].currAlt = gNetworkPlayers[0].modelIndex + 1 + + -- Set Alt + savedAlt = math.clamp(savedAlt, 1, #characterTable[currChar]) + characterTable[currChar].currAlt = savedAlt + + -- Set Palette + local model = characterTable[currChar][savedAlt].model + if characterColorPresets[model] ~= nil then + gCSPlayers[0].presetPalette = charFound and savedPalette or 0 + characterColorPresets[model].currPalette = gCSPlayers[0].presetPalette + end local savedCharColors = mod_storage_load("PrefCharColor") if savedCharColors ~= nil and savedCharColors ~= "" then @@ -459,22 +701,32 @@ local function load_preferred_char() mod_storage_save("PrefCharColor", "255_50_50") end - if #characterTable == 1 then + if #characterTable < CT_MAX then if optionTable[optionTableRef.notification].toggle > 0 then djui_popup_create("Character Select:\nNo Characters were Found", 2) end + else + if not charFound then + if savedNick ~= nil then + djui_popup_create('Character Select:\nYour Preferred Character\n"' .. string_underscore_to_space(savedNick) .. '"\nwas not found.', 4) + else + djui_popup_create('Character Select:\nYour Preferred Character\nwas not found.', 3) + end + end end - TEXT_PREF_LOAD_NAME = savedChar + TEXT_PREF_LOAD_NAME = string_space_to_underscore(savedNick or savedChar) TEXT_PREF_LOAD_ALT = savedAlt update_character_render_table() end local function mod_storage_save_pref_char(charTable) + charTable = charTable or characterTable[bootChar] mod_storage_save("PrefChar", charTable.saveName) + mod_storage_save("PrefNick", string_space_to_underscore(charTable.nickname)) 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 + mod_storage_save("PrefCharColor", tostring(charTable[charTable.currAlt].color.r) .. "_" .. tostring(charTable[charTable.currAlt].color.g) .. "_" .. tostring(charTable[charTable.currAlt].color.b)) + TEXT_PREF_LOAD_NAME = string_space_to_underscore(charTable.nickname) TEXT_PREF_LOAD_ALT = charTable.currAlt prefCharColor = charTable[charTable.currAlt].color end @@ -497,15 +749,13 @@ function failsafe_options() end end +hookTableOnReset = {} local promptedAreYouSure = false - local function reset_options(wasChatTriggered) if not promptedAreYouSure then djui_chat_message_create("\\#ffdcdc\\Are you sure you want to reset your Save Data for Character Select, including your Preferred Character\nand Settings?\n" .. (wasChatTriggered and "Type \\#ff3333\\/char-select reset\\#ffdcdc\\ to confirm." or "Press the \\#ff3333\\" .. optionTable[optionTableRef.resetSaveData].name .. "\\#ffdcdc\\ Option again to confirm." )) promptedAreYouSure = true else - djui_chat_message_create("\\#ff3333\\Character Select Save Data Reset!") - djui_chat_message_create("Note: If your issue has not been resolved, you may need to manually delete your save data via the directory below:\n\\#dcdcFF\\%appdata%/sm64coopdx/sav/character-select-coop.sav") for i = 1, #optionTable do optionTable[i].toggle = optionTable[i].toggleDefault if optionTable[i].toggleSaveName ~= nil then @@ -515,20 +765,32 @@ local function reset_options(wasChatTriggered) optionTable[i].toggleNames = { "Off", "On" } end end - currChar = 1 - for i = 1, #characterTable do + for i = 0, #characterTable do characterTable[i].currAlt = 1 + characterTable[i].locked = characterTable[i].locked == LOCKED_NEVER and LOCKED_NEVER or LOCKED_TRUE end - mod_storage_save_pref_char(characterTable[1]) + mod_storage_save_pref_char() + + if #hookTableOnReset > 0 then + for i = 1, #hookTableOnReset do + hookTableOnReset[i]() + end + end + + force_set_character() + + djui_chat_message_create("\\#ff3333\\Character Select Save Data Reset!") + djui_chat_message_create("Note: If your issue has not been resolved, you may need to manually delete your save data via the directory below:\n\\#dcdcFF\\%appdata%/sm64coopdx/sav/character-select-coop.sav") promptedAreYouSure = false end end local function boot_note() - if #characterTable > 1 then - djui_chat_message_create("Character Select has " .. (#characterTable - 1) .. " character" .. (#characterTable > 2 and "s" or "") .." available!\nYou can use \\#ffff33\\/char-select \\#ffffff\\to open the menu!") - if #characterTable > 32 and network_is_server() then - djui_chat_message_create("\\#FFAAAA\\Warning: Having more than 32 Characters\nmay be unstable, For a better experience please\ndisable a few packs!") + local charCount = (#characterTable + 1) - CT_MAX + if charCount > 0 then + djui_chat_message_create("Character Select has " .. charCount .. " character" .. (charCount > 1 and "s" or "") .." available!\nYou can use \\#ffff33\\/char-select \\#ffffff\\to open the menu!") + if charCount > 32 and network_is_server() then + djui_chat_message_create("\\#FFAAAA\\Warning: Having a lot of characters\nmay be unstable, For a better experience please\ndisable a few packs!") end else djui_chat_message_create("Character Select is active!\nYou can use \\#ffff33\\/char-select \\#ffffff\\to open the menu!") @@ -552,6 +814,7 @@ local function menu_is_allowed(m) end -- Cutscene Check + if m.action & ACT_GROUP_CUTSCENE ~= 0 then return false end if gNetworkPlayers[0].currActNum == 99 then return false end if m.action == ACT_INTRO_CUTSCENE then return false end if obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then return false end @@ -559,54 +822,93 @@ 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 - return i +hookTableOnCharacterChange = { + [1] = function (prevChar, currChar) + -- Check for Non-Vanilla Actions when switching Characters + local m = gMarioStates[0] + if is_mario_in_vanilla_action(m) or m.health < 256 then return end + if m.action & ACT_FLAG_RIDING_SHELL ~= 0 then + set_mario_action(m, ACT_RIDING_SHELL_FALL, 0) + elseif m.action & ACT_FLAG_ALLOW_FIRST_PERSON ~= 0 then + set_mario_action(m, ACT_IDLE, 0) + elseif m.action & ACT_GROUP_MOVING ~= 0 or m.action & ACT_FLAG_MOVING ~= 0 then + set_mario_action(m, ACT_WALKING, 0) + elseif m.action & ACT_GROUP_SUBMERGED ~= 0 or m.action & ACT_FLAG_SWIMMING ~= 0 then + -- Need to fix upwarping + set_mario_action(m, ACT_WATER_IDLE, 0) + else + set_mario_action(m, ACT_FREEFALL, 0) end - end - return 1 -end -local function get_last_unlocked_char() - for i = currChar, 1, -1 do - if not characterTable[i].locked then - return i - end + -- Switch all models to either Vanilla or the Character's + set_all_models() + end +} + +local function on_character_change(prevChar, currChar) + for i = 1, #hookTableOnCharacterChange do + hookTableOnCharacterChange[i](prevChar, currChar) end - return 1 end -]] ------------------- -- Model Handler -- ------------------- -local stallFrame = 0 +-- Port of SM64's idle action without transistion bs +local ACT_CS_MENU_IDLE = allocate_mario_action(ACT_FLAG_STATIONARY | ACT_FLAG_IDLE | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT) +---@param m MarioState +local function act_cs_menu_idle(m) + if not m then return 0 end + local p = gCSPlayers[m.playerIndex] + if (m.quicksandDepth > 30.0) then + return set_mario_action(m, ACT_IN_QUICKSAND, 0); + end + + if (check_common_idle_cancels(m) ~= 0) then + return 1; + end + + m.actionState = 0 + m.actionTimer = 0 + + local customIdleExists = (characterAnims[p.modelId] and characterAnims[p.modelId].anims and characterAnims[p.modelId].anims[CS_ANIM_MENU]) + set_character_animation(m, customIdleExists and CS_ANIM_MENU or CHAR_ANIM_FIRST_PERSON) + + stationary_ground_step(m); + + return 0 +end +hook_mario_action(ACT_CS_MENU_IDLE, act_cs_menu_idle) CUTSCENE_CS_MENU = 0xFA -local TYPE_FUNCTION = "function" -local TYPE_BOOLEAN = "boolean" -local TYPE_STRING = "string" -local TYPE_INTEGER = "number" -local TYPE_TABLE = "table" - -local MATH_PI = math.pi - local prevBaseCharFrame = gNetworkPlayers[0].modelIndex -local prevAnim = 0 -local animTimer = 0 -local faceAngle = 0 -local eyeState = MARIO_EYES_OPEN -local prevFOV = 40 -local menuFOV = 45 ---- @param m MarioState +local prevBasePalette = { + [PANTS] = network_player_get_palette_color(gNetworkPlayers[0], PANTS), + [SHIRT] = network_player_get_palette_color(gNetworkPlayers[0], SHIRT), + [GLOVES] = network_player_get_palette_color(gNetworkPlayers[0], GLOVES), + [SHOES] = network_player_get_palette_color(gNetworkPlayers[0], SHOES), + [HAIR] = network_player_get_palette_color(gNetworkPlayers[0], HAIR), + [SKIN] = network_player_get_palette_color(gNetworkPlayers[0], SKIN), + [CAP] = network_player_get_palette_color(gNetworkPlayers[0], CAP), + [EMBLEM] = network_player_get_palette_color(gNetworkPlayers[0], EMBLEM), +} +local worldColor = { + lighting = {r = 255, g = 255, b = 255}, + skybox = {r = 255, g = 255, b = 255}, + fog = {r = 255, g = 255, b = 255}, + vertex = {r = 255, g = 255, b = 255}, + ambient = {r = 255, g = 255, b = 255} +} +local menuOffsetX = 0 +local menuOffsetY = 0 +local camScale = 1 +local prevMusicToggle = 1 +local prevVisualToggle = 1 +---@param m MarioState local function mario_update(m) - local np = gNetworkPlayers[m.playerIndex] - local p = gCSPlayers[m.playerIndex] - if stallFrame == 1 or queueStorageFailsafe then + if m.playerIndex == 0 and (startup_init_stall(1) or queueStorageFailsafe) then failsafe_options() if not queueStorageFailsafe then load_preferred_char() @@ -614,104 +916,254 @@ local function mario_update(m) boot_note() end end + set_all_models() queueStorageFailsafe = false end - - if stallFrame < 3 then - stallFrame = stallFrame + 1 - end - - if m.playerIndex == 0 and stallFrame > 1 then - if djui_hud_is_pause_menu_created() and prevBaseCharFrame ~= np.modelIndex then - characterTable[1].currAlt = np.modelIndex + 1 - currChar = 1 - p.presetPalette = 0 - end - prevBaseCharFrame = np.modelIndex - - 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 - 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 + local np = gNetworkPlayers[m.playerIndex] + local p = gCSPlayers[m.playerIndex] - if menuAndTransition then - --play_secondary_music(0, 0, 0.5, 0) - camera_freeze() - hud_hide() - if m.area.camera.cutscene == 0 then - m.area.camera.cutscene = CUTSCENE_CS_MENU - end - local camScale = charTable[charTable.currAlt].camScale - local focusPos = { - x = m.pos.x, - y = m.pos.y + 120 * camScale, - z = m.pos.z, - } - set_override_fov(menuFOV) - vec3f_copy(gLakituState.focus, focusPos) - m.marioBodyState.eyeState = eyeState - 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) .. " (CoopDX)") - p.inMenu = true - else - if p.inMenu then - --stop_secondary_music(50) - camera_unfreeze() - hud_show() - set_override_fov(prevFOV) - if m.area.camera.cutscene == CUTSCENE_CS_MENU then - m.area.camera.cutscene = CUTSCENE_STOP - end - p.inMenu = false - reset_window_title() - end - local currFOV = get_current_fov() - if currFOV ~= menuFOV then - prevFOV = currFOV - end - end + if m.playerIndex == 0 then + -- Used for Viewport stuffs + m.marioObj.header.gfx.sharedChild.hookProcess = 1 -- Check for Locked Chars - for i = 2, #characterTable do - local currChar = characterTable[i] - if currChar.locked then + for i = CT_MAX, #characterTable do + local char = characterTable[i] + if char.locked ~= LOCKED_NEVER then local unlock = characterUnlock[i].check local notif = characterUnlock[i].notif + local prevLockState = char.locked if type(unlock) == TYPE_FUNCTION then - if unlock() then - currChar.locked = false - end + char.locked = (unlock() ~= false) and LOCKED_FALSE or LOCKED_TRUE elseif type(unlock) == TYPE_BOOLEAN then - currChar.locked = not unlock + char.locked = (unlock ~= false) and LOCKED_FALSE or LOCKED_TRUE end - if not currChar.locked then -- Character was unlocked + if char.locked ~= prevLockState then 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) + if prevLockState == LOCKED_TRUE then -- Character was unlocked + if startup_init_stall() and notif then + if optionTable[optionTableRef.notification].toggle > 0 then + djui_popup_create('Character Select:\nUnlocked '..tostring(char[1].name)..'\nas a Playable Character!', 3) + end end end end end end + if djui_hud_is_pause_menu_created() then + if prevBaseCharFrame ~= np.modelIndex then + force_set_character(np.modelIndex) + p.presetPalette = 0 + end + + if gCSPlayers[0].presetPalette ~= 0 then + for i = PANTS, EMBLEM do + local prevColor = prevBasePalette[i] + local currColor = network_player_get_palette_color(np, i) + if prevColor.r ~= currColor.r or prevColor.g ~= currColor.g or prevColor.b ~= currColor.b then + local model = characterTable[currChar][characterTable[currChar].currAlt].model + gCSPlayers[0].presetPalette = 0 + characterColorPresets[model].currPalette = 0 + prevColor.r = currColor.r + prevColor.g = currColor.g + prevColor.b = currColor.b + end + end + end + end + prevBaseCharFrame = np.modelIndex + + local charTable = characterTable[currChar] + p.saveName = charTable.saveName + p.currAlt = charTable.currAlt + + p.modelId = charTable[charTable.currAlt].model + if charTable[charTable.currAlt].baseChar ~= nil then + p.baseChar = charTable[charTable.currAlt].baseChar + end + p.modelEditOffset = charTable[charTable.currAlt].model - charTable[charTable.currAlt].ogModel + m.marioObj.hookRender = 1 + + if menu and m.action == ACT_SLEEPING then + set_mario_action(m, ACT_WAKING_UP, m.actionArg) + end + + if menu and options == OPTIONS_MAIN then + if (network_is_server() or network_is_moderator()) and gGlobalSyncTable.charSelectRestrictMovesets < 2 then + gGlobalSyncTable.charSelectRestrictMovesets = optionTable[optionTableRef.restrictMovesets].toggle + end + else + optionTable[optionTableRef.restrictMovesets].toggle = gGlobalSyncTable.charSelectRestrictMovesets + end + + if prevVisualToggle ~= optionTable[optionTableRef.localVisuals].toggle then + set_all_models() + prevVisualToggle = optionTable[optionTableRef.localVisuals].toggle + end + + if menuAndTransition then + local musicToggle = optionTable[optionTableRef.music].toggle + local charInst = characterInstrumentals[currChar] + if not p.inMenu or prevMusicToggle ~= musicToggle or prevChar ~= currChar then + local levelMusic = false + if musicToggle == 0 then + levelMusic = true + end + audio_stream_play(SOUND_CHAR_SELECT_THEME, false, 0) + if musicToggle ~= 0 and musicToggle ~= 3 then + menuThemeTargetVolume = 1 + levelMusic = false + else + menuThemeTargetVolume = 0 + end + + -- Set Target Volumes + for i = 0, #characterTable do + local charInst = characterInstrumentals[i] + if charInst ~= nil then + audio_stream_play(charInst.audio, false, 1) + charInst.targetVolume = 0 + end + end + if musicToggle ~= 0 and musicToggle ~= 2 then + if charInst ~= nil then + charInst.targetVolume = 1 + levelMusic = false + elseif menuThemeTargetVolume == 0 then + levelMusic = true + end + end + + if levelMusic then + stop_secondary_music(50) + else + play_secondary_music(0, 0, 0, 50) + end + prevMusicToggle = musicToggle + p.inMenu = true + end + + -- Update Volumes + menuThemeVolume = math.lerp(menuThemeVolume, menuThemeTargetVolume, 0.1) + audio_stream_set_volume(SOUND_CHAR_SELECT_THEME, menuThemeVolume) + + for i = 0, #characterTable do + local charInst = characterInstrumentals[i] + if charInst ~= nil then + charInst.volume = math.lerp(charInst.volume, charInst.targetVolume, 0.1) + audio_stream_set_volume(charInst.audio, charInst.volume) + end + end + + camera_freeze() + hud_hide() + djui_hud_set_resolution(RESOLUTION_N64) + local widthScale = djui_hud_get_screen_width()/320 + if m.area.camera.cutscene == 0 then + m.area.camera.cutscene = CUTSCENE_CS_MENU + end + m.marioBodyState.eyeState = MARIO_EYES_OPEN + camScale = math.lerp(camScale, charTable[charTable.currAlt].camScale, 0.1) + local camDist = 400 * camScale + local camAngle = m.faceAngle.y + 0x800 + local camOffsetX = mirror_mode_number(-menuOffsetX) + local focusPos = { + x = m.pos.x + sins(camAngle - 0x4000)*camOffsetX*camScale, + y = m.pos.y + (100 - menuOffsetY) * camScale , + z = m.pos.z + coss(camAngle - 0x4000)*camOffsetX*camScale, + } + vec3f_copy(gLakituState.focus, focusPos) + + local camPos = { + x = (m.pos.x + sins(camAngle) * camDist + sins(camAngle - 0x4000)*camOffsetX), + y = m.pos.y - (menuOffsetY*camScale), + z = (m.pos.z + coss(camAngle) * camDist + sins(camAngle - 0x4000)*camOffsetX), + } + camPos.y = collision_find_surface_on_ray(camPos.x, camPos.y + 300, camPos.z, 0, -300, 0).hitPos.y + 20 + + local camHit = collision_find_surface_on_ray(focusPos.x, focusPos.y, focusPos.z, camPos.x - focusPos.x, camPos.y - focusPos.y, camPos.z - focusPos.z).hitPos + vec3f_copy(gLakituState.pos, camHit) + set_override_fov(45/widthScale) + + set_lighting_color(0, (menuColor.r*0.33 + 255*0.66) * worldColor.lighting.r/255) + set_lighting_color(1, (menuColor.g*0.33 + 255*0.66) * worldColor.lighting.g/255) + set_lighting_color(2, (menuColor.b*0.33 + 255*0.66) * worldColor.lighting.b/255) + set_lighting_color_ambient(0, (menuColor.r*0.33 + 255*0.66) * worldColor.ambient.r/127) + set_lighting_color_ambient(1, (menuColor.g*0.33 + 255*0.66) * worldColor.ambient.g/127) + set_lighting_color_ambient(2, (menuColor.b*0.33 + 255*0.66) * worldColor.ambient.b/127) + set_skybox_color(0, menuColor.r * worldColor.lighting.r/255) + set_skybox_color(1, menuColor.g * worldColor.lighting.g/255) + set_skybox_color(2, menuColor.b * worldColor.lighting.b/255) + set_fog_color(0, menuColor.r * worldColor.lighting.r/255) + set_fog_color(1, menuColor.g * worldColor.lighting.g/255) + set_fog_color(2, menuColor.b * worldColor.lighting.b/255) + set_vertex_color(0, menuColor.r * worldColor.lighting.r/255) + set_vertex_color(1, menuColor.g * worldColor.lighting.g/255) + set_vertex_color(2, menuColor.b * worldColor.lighting.b/255) + else + if p.inMenu then + audio_stream_stop(SOUND_CHAR_SELECT_THEME) + for i = 0, #characterTable do + local charInst = characterInstrumentals[i] + if charInst ~= nil then + audio_stream_stop(charInst.audio) + end + end + stop_secondary_music(50) + m.marioObj.header.gfx.sharedChild.hookProcess = 1 + camera_unfreeze() + hud_show() + set_override_fov(0) + if m.area.camera.cutscene == CUTSCENE_CS_MENU then + m.area.camera.cutscene = CUTSCENE_STOP + end + set_lighting_color(0, worldColor.lighting.r) + set_lighting_color(1, worldColor.lighting.g) + set_lighting_color(2, worldColor.lighting.b) + set_lighting_color_ambient(0, worldColor.ambient.r) + set_lighting_color_ambient(1, worldColor.ambient.g) + set_lighting_color_ambient(2, worldColor.ambient.b) + set_skybox_color(0, worldColor.skybox.r) + set_skybox_color(1, worldColor.skybox.g) + set_skybox_color(2, worldColor.skybox.b) + set_fog_color(0, worldColor.fog.r) + set_fog_color(1, worldColor.fog.g) + set_fog_color(2, worldColor.fog.b) + set_vertex_color(0, worldColor.vertex.r) + set_vertex_color(1, worldColor.vertex.g) + set_vertex_color(2, worldColor.vertex.b) + p.inMenu = false + end + + worldColor.lighting.r = get_lighting_color(0) + worldColor.lighting.g = get_lighting_color(1) + worldColor.lighting.b = get_lighting_color(2) + worldColor.ambient.r = get_lighting_color_ambient(0) + worldColor.ambient.g = get_lighting_color_ambient(1) + worldColor.ambient.b = get_lighting_color_ambient(2) + worldColor.skybox.r = get_skybox_color(0) + worldColor.skybox.g = get_skybox_color(1) + worldColor.skybox.b = get_skybox_color(2) + worldColor.fog.r = get_fog_color(0) + worldColor.fog.g = get_fog_color(1) + worldColor.fog.b = get_fog_color(2) + worldColor.vertex.r = get_vertex_color(0) + worldColor.vertex.g = get_vertex_color(1) + worldColor.vertex.b = get_vertex_color(2) + + if startup_init_stall() then + -- Update playtime + characterTable[currChar].playtime = characterTable[currChar].playtime + 1 + totalPlaytime = totalPlaytime + 1 + end + end + --Open Credits if optionTable[optionTableRef.credits].toggle > 0 then - credits = true + options = OPTIONS_CREDITS + currOption = 1 optionTable[optionTableRef.credits].toggle = 0 end @@ -726,63 +1178,94 @@ local function mario_update(m) end p.movesetToggle = optionTable[optionTableRef.localMoveset].toggle ~= 0 - end - - 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 + if prevChar ~= currChar then + on_character_change(prevChar, currChar) + prevChar = currChar + end end - local marioGfx = m.marioObj.header.gfx - if prevAnim ~= marioGfx.animInfo.animID then - prevAnim = marioGfx.animInfo.animID - animTimer = 0 + if p.inMenu and m.action & ACT_FLAG_ALLOW_FIRST_PERSON ~= 0 then + set_mario_action(m, ACT_CS_MENU_IDLE, 0) + m.actionArg = 0 + m.actionState = 0xFFFF + + -- reset menu anim on character change, starts them at frame 0 and prevents lua anim issues + if p.prevModelId ~= p.modelId then + p.prevModelId = p.modelId + m.marioObj.header.gfx.animInfo.animID = -1 + end + + m.marioObj.header.gfx.angle.y = m.faceAngle.y + elseif m.action == ACT_CS_MENU_IDLE then + set_mario_action(m, ACT_IDLE, 0) end - animTimer = animTimer + 1 - - np.overrideModelIndex = p.forceChar ~= nil and p.forceChar or CT_MARIO + + np.overrideModelIndex = p.baseChar ~= nil and p.baseChar or CT_MARIO -- Character Animations if characterAnims[p.modelId] then - local animID = characterAnims[p.modelId][m.marioObj.header.gfx.animInfo.animID] + local animInfo = m.marioObj.header.gfx.animInfo + local animID = characterAnims[p.modelId].anims and run_func_or_get_var(characterAnims[p.modelId].anims[animInfo.animID], m, animInfo.animFrame) if animID then smlua_anim_util_set_animation(m.marioObj, animID) end - end -end - -local sCapBhvs = { - [id_bhvWingCap] = true, - [id_bhvVanishCap] = true, - [id_bhvMetalCap] = true -} - ---- @param o Object ---- @param model integer -local BowserKey = false -local function on_star_or_key_grab(m, o, type) - if type == INTERACT_STAR_OR_KEY then - if get_id_from_behavior(o.behavior) == id_bhvBowserKey then - BowserKey = true - else - BowserKey = false + local eyeState = characterAnims[p.modelId].eyes and run_func_or_get_var(characterAnims[p.modelId].eyes[animInfo.animID], m, animInfo.animFrame) + if eyeState then + m.marioBodyState.eyeState = eyeState + end + local handState = characterAnims[p.modelId].hands and run_func_or_get_var(characterAnims[p.modelId].hands[animInfo.animID], m, animInfo.animFrame) + if handState then + m.marioBodyState.handState = handState end end end +function geo_function() + local viewport = geo_get_current_root() + if menuAndTransition then + djui_hud_set_resolution(RESOLUTION_N64) + viewport.x = 320*0.85 + viewport.y = 205*0.5 + viewport.width = 320*0.15 + viewport.height = 205*0.5 + else + viewport.x = 320*0.5 + viewport.y = 240*0.5 + viewport.width = 320*0.5 + viewport.height = 240*0.5 + end +end + +hook_event(HOOK_ON_GEO_PROCESS, geo_function) + +local sCapBhvs = { + [id_bhvNormalCap] = true, + [id_bhvWingCap] = true, + [id_bhvVanishCap] = true, + [id_bhvMetalCap] = true, +} + +define_custom_obj_fields({ + oOriginalModel = 'u32', + oModelHasBeenReplaced = 'u32', +}) + +---@param o Object function set_model(o, model) - if optionTable[optionTableRef.localModels].toggle == 0 then return end + -- Extended Model Incompatible + if obj_get_model_id_extended(o) == E_MODEL_ERROR_MODEL then return end + + local visualToggle = optionTable[optionTableRef.localVisuals].toggle == 1 -- 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 + for c = 0, #characterTable do if gCSPlayers[i].saveName == characterTable[c].saveName then if gCSPlayers[i].currAlt <= #characterTable[c] then localModelData = characterTable[c][gCSPlayers[i].currAlt].ogModel + gCSPlayers[i].modelEditOffset + break end end end @@ -797,176 +1280,216 @@ function set_model(o, model) end end return - end + elseif sCapBhvs[get_id_from_behavior(o.behavior)] then -- Cap Behaviors + local playerToObj = nearest_player_to_object(o.parentObj) + o.globalPlayerIndex = playerToObj and playerToObj.globalPlayerIndex or 0 - -- 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 - obj_set_model_extended(o, starModel) + local i = network_local_index_from_global(o.globalPlayerIndex) + + local c = gMarioStates[i].character + if model == c.capModelId or + model == c.capWingModelId or + model == c.capMetalModelId or + model == c.capMetalWingModelId then + local capModels = characterCaps[gCSPlayers[i].modelId] + if capModels ~= nil then + local capModel = E_MODEL_NONE + if model == c.capModelId then + capModel = capModels.normal + elseif model == c.capWingModelId then + capModel = capModels.wing + elseif model == c.capMetalModelId then + capModel = capModels.metal + elseif model == c.capMetalWingModelId then + capModel = capModels.metalWing + end + if capModel ~= E_MODEL_NONE and capModel ~= E_MODEL_ERROR_MODEL and capModel ~= nil then + if obj_has_model_extended(o, capModel) == 0 then + obj_set_model_extended(o, capModel) + end + return + end + end + end + elseif characterTable[currChar].replaceModels ~= nil then -- Other Custom Models + local currReplace = characterTable[currChar].replaceModels[get_id_from_behavior(o.behavior)] + if o.oOriginalModel == 0 then + o.oOriginalModel = obj_get_model_id_extended(o) + end + + local model = run_func_or_get_var(currReplace, o, o.oOriginalModel) + + if model ~= nil and visualToggle then + o.oModelHasBeenReplaced = 1 + if obj_has_model_extended(o, model) == 0 then + obj_set_model_extended(o, model) + end + elseif o.oModelHasBeenReplaced ~= 0 then + if obj_has_model_extended(o, o.oOriginalModel) == 0 then + obj_set_model_extended(o, o.oOriginalModel) + end end return end +end - if sCapBhvs[get_id_from_behavior(o.behavior)] then - o.globalPlayerIndex = nearest_player_to_object(o.parentObj).globalPlayerIndex - end - local i = network_local_index_from_global(o.globalPlayerIndex) - - local c = gMarioStates[i].character - if model == c.capModelId or - model == c.capWingModelId or - model == c.capMetalModelId or - model == c.capMetalWingModelId then - local capModels = characterCaps[gCSPlayers[i].modelId] - if capModels ~= nil then - local capModel = E_MODEL_NONE - if model == c.capModelId then - capModel = capModels.normal - elseif model == c.capWingModelId then - capModel = capModels.wing - elseif model == c.capMetalModelId then - capModel = capModels.metal - elseif model == c.capMetalWingModelId then - capModel = capModels.metalWing +function set_all_models() + for i = 0, NUM_OBJ_LISTS - 1 do + local o = obj_get_first(i) + repeat + if o ~= nil then + set_model(o, o.oOriginalModel) end - if capModel ~= E_MODEL_NONE and capModel ~= E_MODEL_ERROR_MODEL and capModel ~= nil then - obj_set_model_extended(o, capModel) - end - end + o = obj_get_next(o) + until o == nil end end ---hook_event(HOOK_MARIO_UPDATE, mario_update) +local function koopa_model_update(o) + if o.oKoopaMovementType == KOOPA_BP_UNSHELLED then + o.oOriginalModel = E_MODEL_KOOPA_WITHOUT_SHELL + else + o.oOriginalModel = E_MODEL_KOOPA_WITH_SHELL + end + set_model(o) +end +hook_behavior(id_bhvKoopa, OBJ_LIST_PUSHABLE, false, nil, koopa_model_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) ------------------ -- Menu Handler -- ------------------ -local buttonAnimTimer = 0 -local buttonScroll = 0 -local buttonScrollCap = 30 +local function button_to_analog(controller, negInput, posInput) + local num = 0 + num = num - (controller.buttonDown & negInput ~= 0 and 127 or 0) + num = num + (controller.buttonDown & posInput ~= 0 and 127 or 0) + return num +end + +local TEX_CAUTION_TAPE = get_texture_info("char_select_caution_tape") +-- Renders caution tape from xy1 to xy2, tape extends based on dist (0 - 1) +local function djui_hud_render_caution_tape(x1, y1, x2, y2, dist, scale) + if not scale then scale = 0.5 end + local totalDist = math.sqrt((y2 - y1)^2 + (x2 - x1)^2) * dist + local angle = angle_from_2d_points(x1, y1, x2, y2) + djui_hud_set_rotation(angle, 0, 0.5) + local texWidth = TEX_CAUTION_TAPE.width*scale + local texHeight = TEX_CAUTION_TAPE.height*scale + local tapeSegments = totalDist/texWidth + local tapeRemainder = tapeSegments + while tapeRemainder > 1 do + tapeRemainder = tapeRemainder - 1 + end + for i = 0, math.floor(tapeSegments) do + local remainder = i == math.floor(tapeSegments) and tapeRemainder or 1 + djui_hud_render_texture_tile(TEX_CAUTION_TAPE, + x1 + texWidth*coss(angle)*i, + y1 - texWidth*sins(angle)*i, + TEX_CAUTION_TAPE.height/TEX_CAUTION_TAPE.width*scale, 1*scale, 0, 0, TEX_CAUTION_TAPE.width*remainder, TEX_CAUTION_TAPE.height) + end + djui_hud_set_rotation(0, 0, 0) +end local optionAnimTimer = -200 local optionAnimTimerCap = optionAnimTimer -local inputStallTimerButton = 0 -local inputStallTimerDirectional = 0 -local inputStallToDirectional = 12 -local inputStallToButton = 10 - --Basic Menu Text -local TEXT_OPTIONS_HEADER = "Menu Options" -local TEXT_OPTIONS_HEADER_API = "API Options" 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 = "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: " local TEXT_MOVESET_RESTRICTED = "Movesets are Restricted" local TEXT_PALETTE_RESTRICTED = "Palettes are Restricted" local TEXT_MOVESET_AND_PALETTE_RESTRICTED = "Moveset and Palettes are Restricted" -local TEXT_CHAR_LOCKED = "Locked" -- Easter Egg if you get lucky loading the mod -- Referencing the original sm64ex DynOS options by PeachyPeach >v< -if math_random(100) == 64 then +if math.random(100) == 64 then TEXT_PAUSE_Z_OPEN = "Z - DynOS" TEXT_PAUSE_CURR_CHAR = "Model: " end ---Debug Text -local TEXT_DEBUGGING = "Character Debug" -local TEXT_DESCRIPTION_SHORT = "Description:" -local TEXT_LIFE_ICON = "Life Icon:" -local TEXT_STAR_ICON = "Star Icon:" -local TEXT_FORCED_CHAR = "Forced: " -local TEXT_TABLE_POS = "Table Position: " -local TEXT_PALETTE = "Palette: " - ---Options Text -local TEXT_OPTIONS_OPEN = "Press START to open Options" -local TEXT_MENU_CLOSE = "Press B to Exit Menu" -local TEXT_OPTIONS_SELECT = "A - Select | B - Exit " -local TEXT_LOCAL_MODEL_OFF = "Locally Display Models is Off" -local TEXT_LOCAL_MODEL_OFF_OPTIONS = "You can turn it back on in the Options Menu" +--Options/Credits Text 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" - -local forceCharStrings = { - [CT_MARIO] = "CT_MARIO", - [CT_LUIGI] = "CT_LUIGI", - [CT_TOAD] = "CT_TOAD", - [CT_WALUIGI] = "CT_WALUIGI", - [CT_WARIO] = "CT_WARIO" -} +local TEXT_KOFI_LINK = "ko-fi.com/squishy6094" +local TEXT_CREDITS_HEADER = "CREDITS" local MATH_DIVIDE_320 = 1/320 -local MATH_DIVIDE_64 = 1/64 -local MATH_DIVIDE_32 = 1/32 -local MATH_DIVIDE_30 = 1/30 local MATH_DIVIDE_16 = 1/16 local targetMenuColor = {r = 0 , g = 0, b = 0} menuColor = targetMenuColor local menuColorHalf = menuColor +local menuColorTint = menuColor local transSpeed = 0.1 -local prevBindText = "" -local bindText = 1 -local bindTextTimerLoop = 150 -local bindTextTimer = 0 -local bindTextOpacity = -255 +local playerShirt = network_player_get_override_palette_color(gNetworkPlayers[0], SHIRT) +local playerPants = network_player_get_override_palette_color(gNetworkPlayers[0], PANTS) function update_menu_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.r = targetMenuColor.r - menuColor.g = targetMenuColor.g - menuColor.b = targetMenuColor.b + 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] = 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 + menuColor.r = math.lerp(menuColor.r, targetMenuColor.r, transSpeed) + menuColor.g = math.lerp(menuColor.g, targetMenuColor.g, transSpeed) + menuColor.b = math.lerp(menuColor.b, targetMenuColor.b, transSpeed) menuColorHalf = { r = menuColor.r * 0.5 + 127, g = menuColor.g * 0.5 + 127, b = menuColor.b * 0.5 + 127 } + menuColorTint = { + r = 205 + 50*menuColor.r/256, + g = 205 + 50*menuColor.g/256, + b = 205 + 50*menuColor.b/256 + } + + -- Update BG Wall Color + local shirtColor = network_player_get_override_palette_color(gNetworkPlayers[0], SHIRT) + local pantsColor = network_player_get_override_palette_color(gNetworkPlayers[0], PANTS) + playerShirt.r = math.lerp(playerShirt.r, shirtColor.r, transSpeed) + playerShirt.g = math.lerp(playerShirt.g, shirtColor.g, transSpeed) + playerShirt.b = math.lerp(playerShirt.b, shirtColor.b, transSpeed) + playerPants.r = math.lerp(playerPants.r, pantsColor.r, transSpeed) + playerPants.g = math.lerp(playerPants.g, pantsColor.g, transSpeed) + playerPants.b = math.lerp(playerPants.b, pantsColor.b, transSpeed) return menuColor end -local TEX_TRIANGLE = get_texture_info("char-select-triangle") -local function djui_hud_render_triangle(x, y, width, height) - djui_hud_render_texture(TEX_TRIANGLE, x, y, width*MATH_DIVIDE_64, height*MATH_DIVIDE_32) +local function djui_hud_render_life_icon(char, x, y, scale) + local icon = char and char.lifeIcon or "?" + local color = char and char.color or {r = 255, g = 255, b = 255} + local djuiColor = djui_hud_get_color() + if type(icon) == TYPE_STRING then + local font = djui_hud_get_font() + djui_hud_set_font(FONT_RECOLOR_HUD) + djui_hud_set_color(color.r * djuiColor.r/255, color.g * djuiColor.g/255, color.b * djuiColor.b/255, djuiColor.a) + djui_hud_print_text(icon, x, y, scale) + djui_hud_set_font(font) + else + djui_hud_set_color(djuiColor.r, djuiColor.g, djuiColor.b, djuiColor.a) + djui_hud_render_texture(icon, x, y, scale / (icon.width * MATH_DIVIDE_16), scale / (icon.height * MATH_DIVIDE_16)) + end + djui_hud_set_color(djuiColor.r, djuiColor.g, djuiColor.b, djuiColor.a) end -local buttonAltAnim = 0 -local menuOpacity = 245 -local menuText = {} +local gridButtonsPerRow = 5 +local paletteXOffset = 0 +local gearRotationTarget = 0 +local gearRotation = 0 +local paletteTrans = 0 +local optionsMenuOffset = 0 +local optionsMenuOffsetMax = 210 local function on_hud_render() local FONT_USER = djui_menu_get_font() djui_hud_set_font(FONT_ALIASED) @@ -974,577 +1497,476 @@ local function on_hud_render() 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 width = math.max(djuiWidth * (240/djuiHeight), 320) -- Get accurate, unrounded width local height = 240 - local widthHalf = width * 0.5 - local heightHalf = height * 0.5 - local widthScale = maxf(width, 320) * MATH_DIVIDE_320 + local widthScale = math.max(width, 320) * MATH_DIVIDE_320 - update_menu_color() + if startup_init_stall() then + update_menu_color() + if not menu_is_allowed() then + menu = false + end + end if menuAndTransition then - - if optionTable[optionTableRef.localModels].toggle == 0 then + if characterTable[currChar][characterTable[currChar].currAlt].model == E_MODEL_ERROR_MODEL then djui_hud_set_color(0, 0, 0, 200) djui_hud_render_rect(0, 0, width, height) djui_hud_set_color(255, 255, 255, 255) - djui_hud_print_text(TEXT_LOCAL_MODEL_OFF, widthHalf - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF) * 0.15 * widthScale, heightHalf, 0.3 * widthScale) - djui_hud_print_text(TEXT_LOCAL_MODEL_OFF_OPTIONS, widthHalf - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF_OPTIONS) * 0.1 * widthScale, heightHalf + 10 * widthScale, 0.2 * widthScale) + djui_hud_print_text(TEXT_LOCAL_MODEL_ERROR, width*0.85 - djui_hud_measure_text(TEXT_LOCAL_MODEL_ERROR) * 0.15 * widthScale, height * 0.5, 0.3 * widthScale) + djui_hud_print_text(TEXT_LOCAL_MODEL_ERROR_FIX, width*0.85 - djui_hud_measure_text(TEXT_LOCAL_MODEL_ERROR_FIX) * 0.1 * widthScale, height * 0.5 + 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 - djui_hud_set_color(menuColorHalf.r * 0.1, menuColorHalf.g * 0.1, menuColorHalf.b * 0.1, menuOpacity) - -- Description - djui_hud_render_rect(width - x + 2, 2 + 46, x - 4, height - 4 - 46) - -- Buttons - djui_hud_render_rect(2, 2 + 46, x - 4, height - 4 - 46) - -- 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 - renderInMenuTable.back[i]() - end - end - - --Character Description - djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) - djui_hud_render_rect(width - x, 50, 2, height - 50) - djui_hud_render_rect(width - x, height - 2, x, 2) - djui_hud_render_rect(width - 2, 50, 2, height - 50) - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - djui_hud_set_font(FONT_ALIASED) - local character = characterTable[currChar] - local TEXT_SAVE_NAME = "Save Name: " .. character.saveName - local TEXT_MOVESET = "Has Moveset: "..(character.hasMoveset and "Yes" or "No") - local TEXT_ALT = "Alt: " .. character.currAlt .. "/" .. #character - character = characterTable[currChar][character.currAlt] - local paletteCount = characterColorPresets[gCSPlayers[0].modelId] ~= nil and #characterColorPresets[gCSPlayers[0].modelId] or 0 - local currPaletteTable = characterColorPresets[gCSPlayers[0].modelId] and characterColorPresets[gCSPlayers[0].modelId] or {currPalette = 0} - if optionTable[optionTableRef.debugInfo].toggle == 0 then - -- Actual Description -- - local TEXT_NAME = string_underscore_to_space(character.name) - local TEXT_CREDIT = "Credit: " .. character.credit - local TEXT_DESCRIPTION_TABLE = character.description - local TEXT_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) - djui_hud_set_font(FONT_TINY) - local creditScale = 0.6 - creditScale = math_min(creditScale, 100/djui_hud_measure_text(TEXT_CREDIT)) - djui_hud_print_text(TEXT_CREDIT, width - textX - djui_hud_measure_text(TEXT_CREDIT) * creditScale *0.5, 74, creditScale) - djui_hud_set_font(FONT_ALIASED) - djui_hud_print_text(TEXT_DESCRIPTION, width - textX - djui_hud_measure_text(TEXT_DESCRIPTION) * 0.2, 85, 0.4) - if widthScale < 1.65 then - for i = 1, #TEXT_DESCRIPTION_TABLE do - djui_hud_print_text(TEXT_DESCRIPTION_TABLE[i], width - textX - djui_hud_measure_text(TEXT_DESCRIPTION_TABLE[i]) * 0.15, 90 + i * 9, 0.3) - end - else - for i = 1, math_ceil(#TEXT_DESCRIPTION_TABLE*0.5) do - local tablePos = (i * 2) - 1 - if TEXT_DESCRIPTION_TABLE[tablePos] and TEXT_DESCRIPTION_TABLE[tablePos + 1] then - local TEXT_STRING = TEXT_DESCRIPTION_TABLE[tablePos] .. " " .. TEXT_DESCRIPTION_TABLE[tablePos + 1] - djui_hud_print_text(TEXT_STRING, width - textX - djui_hud_measure_text(TEXT_STRING) * 0.15, 90 + i * 9, 0.3) - elseif TEXT_DESCRIPTION_TABLE[tablePos] then - local TEXT_STRING = TEXT_DESCRIPTION_TABLE[tablePos] - djui_hud_print_text(TEXT_STRING, width - textX - djui_hud_measure_text(TEXT_STRING) * 0.15, 90 + i * 9, 0.3) - end - end - end - - menuText = { - TEXT_PREF_SAVE .. " - " .. TEXT_PREF_LOAD_NAME - } - local modelId = gCSPlayers[0].modelId - 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 - table_insert(menuText, TEXT_PREF_PALETTE .. " - " .. TEXT_PRESET_TOGGLE) - elseif stopPalettes then - table_insert(menuText, TEXT_PALETTE_RESTRICTED) - end - 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 - local TEXT_CREDIT = "Credit: " .. character.credit - local TEXT_DESCRIPTION_TABLE = character.description - local TEXT_COLOR = "Color: R-" .. character.color.r ..", G-" ..character.color.g ..", B-"..character.color.b - local TEX_LIFE_ICON = character.lifeIcon - local TEX_STAR_ICON = character.starIcon - local TEXT_SCALE = "Camera Scale: " .. character.camScale - local TEXT_PRESET = "Preset Palette: ("..currPaletteTable.currPalette.."/"..paletteCount..")" - local TEXT_PREF = "Preferred: " .. TEXT_PREF_LOAD_NAME .. " ("..TEXT_PREF_LOAD_ALT..")" - local TEXT_PREF_COLOR = "Pref Color: R-" .. prefCharColor.r .. ", G-" .. prefCharColor.g .. ", B-" .. prefCharColor.b - - local textX = x * 0.5 - djui_hud_print_text(TEXT_DEBUGGING, width - textX - djui_hud_measure_text(TEXT_DEBUGGING) * 0.3, 55, 0.6) - djui_hud_set_font(FONT_TINY) - local y = 72 - djui_hud_print_text(TEXT_NAME, width - x + 8, y, 0.5) - y = y + 7 - djui_hud_print_text(TEXT_SAVE_NAME, width - x + 8, y, 0.5) - y = y + 7 - djui_hud_print_text(TEXT_ALT, width - x + 8, y, 0.5) - y = y + 7 - djui_hud_print_text(TEXT_CREDIT, width - x + 8, y, 0.5) - y = y + 7 - if TEXT_DESCRIPTION_TABLE[1] ~= "No description has been provided" then - djui_hud_print_text(TEXT_DESCRIPTION_SHORT, width - x + 8, y, 0.5) - y = y + 2 - local removeLine = 0 - for i = 1, #TEXT_DESCRIPTION_TABLE do - if TEXT_DESCRIPTION_TABLE[i] ~= "" then - djui_hud_set_font(FONT_ALIASED) - local TEXT_DESCRIPTION_LINE = TEXT_DESCRIPTION_TABLE[i] - if (djui_hud_measure_text(TEXT_DESCRIPTION_TABLE[i]) * 0.3 > 100) then - TEXT_DESCRIPTION_LINE = "(!) " .. TEXT_DESCRIPTION_LINE - else - TEXT_DESCRIPTION_LINE = " " .. TEXT_DESCRIPTION_LINE - end - djui_hud_set_font(FONT_TINY) - djui_hud_print_text(TEXT_DESCRIPTION_LINE, width - x + 5, y + (i-removeLine) * 5, 0.4) - else - removeLine = removeLine + 1 - end - end - local descriptionOffset = (#TEXT_DESCRIPTION_TABLE - removeLine) * 5 - y = y + 5 + descriptionOffset - end - djui_hud_set_color(character.color.r, character.color.g, character.color.b, 255) - djui_hud_print_text(TEXT_COLOR, width - x + 8, y, 0.5) - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - y = y + 7 - if type(TEX_LIFE_ICON) ~= TYPE_STRING then - djui_hud_print_text(TEXT_LIFE_ICON .. " (" .. TEX_LIFE_ICON.width .. "x" .. TEX_LIFE_ICON.height .. ")", width - x + 8, y, 0.5) - djui_hud_set_color(255, 255, 255, 255) - djui_hud_render_texture(TEX_LIFE_ICON, width - x + 33, y + 1, 0.4 / (TEX_LIFE_ICON.width * MATH_DIVIDE_16), 0.4 / (TEX_LIFE_ICON.height * MATH_DIVIDE_16)) - else - djui_hud_print_text(TEXT_LIFE_ICON .. " (FONT_HUD)", width - x + 8, y, 0.5) - djui_hud_set_font(FONT_HUD) - djui_hud_set_color(255, 255, 255, 255) - djui_hud_print_text(TEX_LIFE_ICON, width - x + 33, y + 1, 0.4) - djui_hud_set_font(FONT_TINY) - end - y = y + 7 - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - djui_hud_print_text(TEXT_STAR_ICON .. " (" .. TEX_STAR_ICON.width .. "x" .. TEX_STAR_ICON.height .. ")", width - x + 8, y, 0.5) - djui_hud_set_color(255, 255, 255, 255) - djui_hud_render_texture(TEX_STAR_ICON, width - x + 35, y + 1, 0.4 / (TEX_STAR_ICON.width * MATH_DIVIDE_16), 0.4 / (TEX_STAR_ICON.height * MATH_DIVIDE_16)) - y = y + 7 - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - djui_hud_print_text(TEXT_FORCED_CHAR .. forceCharStrings[character.forceChar], width - x + 8, y, 0.5) - y = y + 7 - djui_hud_print_text(TEXT_TABLE_POS .. currChar, width - x + 8, y, 0.5) - y = y + 7 - djui_hud_print_text(TEXT_SCALE, width - x + 8, y, 0.5) - local modelId = gCSPlayers[0].modelId - y = y + 7 - if characterColorPresets[modelId] ~= nil then - djui_hud_print_text(TEXT_PALETTE, width - x + 8, y, 0.5) - local x = x - djui_hud_measure_text(TEXT_PALETTE)*0.5 - local currPalette = currPaletteTable.currPalette > 0 and currPaletteTable.currPalette or 1 - local paletteTable = currPaletteTable[currPalette] - for i = 0, #paletteTable do - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - djui_hud_render_rect(width - x + 6.5 + (6.5 * i), y + 1.5, 6, 6) - djui_hud_set_color(paletteTable[i].r, paletteTable[i].g, paletteTable[i].b, 255) - djui_hud_render_rect(width - x + 7 + (6.5 * i), y + 2, 5, 5) - end - y = y + 7 - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - end - djui_hud_print_text(TEXT_MOVESET, width - x + 8, y, 0.5) - y = y + 7 - djui_hud_print_text(TEXT_PRESET, width - x + 8, height - 29, 0.5) - djui_hud_print_text(TEXT_PREF, width - x + 8, height - 22, 0.5) - djui_hud_set_color(prefCharColor.r, prefCharColor.g, prefCharColor.b, 255) - djui_hud_print_text(TEXT_PREF_COLOR, width - x + 8, height - 15, 0.5) - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - end - - --Character Buttons - djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) - djui_hud_render_rect(0, 50, 2, height - 50) - djui_hud_render_rect(x - 2, 50, 2, height - 50) - djui_hud_render_rect(0, height - 2, x, 2) - - local leftRightAnim = 0 - if optionTable[optionTableRef.anims].toggle > 0 then - buttonAnimTimer = buttonAnimTimer + 1 - leftRightAnim = buttonAltAnim/inputStallToDirectional - if buttonAltAnim ~= 0 then - if buttonAltAnim > 0 then - buttonAltAnim = buttonAltAnim - 3 - else - buttonAltAnim = buttonAltAnim + 3 - end - end - end - if optionTable[optionTableRef.anims].toggle == 0 then - buttonScroll = 0 - elseif math_abs(buttonScroll) > 0.1 then - buttonScroll = buttonScroll * 0.05 * inputStallToDirectional - end - - local buttonColor = {} - local buttonX = 20 * widthScale - local buttonAnimX = buttonX + math_sin(buttonAnimTimer * 0.05) * 2.5 + 5 - local charNum = -1 - for i = -1, 4 do - -- Hide Locked Characters based on Toggle - charNum = currCharRender + i - local char = characterTableRender[charNum] - if char ~= nil then - if not char.locked then - buttonColor = char[char.currAlt].color - else - buttonColor = {r = char[char.currAlt].color.r*0.5, g = char[char.currAlt].color.g*0.5, b = char[char.currAlt].color.b*0.5} - end - djui_hud_set_color(buttonColor.r, buttonColor.g, buttonColor.b, 255) - local x = buttonX - local y = 104 + buttonScroll - if i == 0 then - if optionTable[optionTableRef.anims].toggle > 0 then - x = buttonAnimX - else - x = buttonX + 5 - end - if #char > 1 then - djui_hud_set_rotation(0x4000, 0, 0) - djui_hud_render_triangle(x - 6 + math_min(leftRightAnim, 0), y, 8, 4) - djui_hud_set_rotation(-0x4000, 0, 0) - djui_hud_render_triangle(x + 76 + math_max(leftRightAnim, 0), y - 8 - 1*MATH_DIVIDE_16, 8, 4) - djui_hud_set_rotation(0, 0, 0) - end - end - local y = (i + 3) * 30 + buttonScroll - djui_hud_render_rect(x, y, 1, 20) - djui_hud_render_rect(x, y, 70, 1) - djui_hud_render_rect(x + 69, y, 1, 20) - djui_hud_render_rect(x, y + 19, 70, 1) - djui_hud_set_color(buttonColor.r * 0.1, buttonColor.g * 0.1, buttonColor.b * 0.1, menuOpacity) - djui_hud_render_rect(x + 1, y + 1, 68, 18) - djui_hud_set_font(FONT_TINY) - djui_hud_set_color(buttonColor.r, buttonColor.g, buttonColor.b, 255) - local charName = char[char.currAlt].name - if char.locked then - charName = TEXT_CHAR_LOCKED - end - djui_hud_set_color(buttonColor.r * 0.5 + 127, buttonColor.g * 0.5 + 127, buttonColor.b * 0.5 + 127, 255) - djui_hud_print_text(charName, x + 5, y + 5, 0.6) - end - end - - -- Scroll Bar - 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) - djui_hud_render_rect(MATH_7_WIDTHSCALE, 55, 7, 1) - djui_hud_render_rect(MATH_7_WIDTHSCALE + 6, 55, 1, 170) - djui_hud_render_rect(MATH_7_WIDTHSCALE, 224, 7, 1) - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - 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 = 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) - djui_hud_render_rect(0, 0, width, 2) - djui_hud_render_rect(0, 0, 2, 50) - djui_hud_render_rect(0, 48, width, 2) - djui_hud_render_rect(width - 2, 0, 2, 50) - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - if TEX_OVERRIDE_HEADER ~= nil then -- Render Override Header - djui_hud_render_texture(TEX_OVERRIDE_HEADER, widthHalf - 128, 10, 1 / (TEX_OVERRIDE_HEADER.height*MATH_DIVIDE_32), 1 / (TEX_OVERRIDE_HEADER.height*MATH_DIVIDE_32)) - else - djui_hud_render_texture(TEX_HEADER, widthHalf - 128, 10, 1, 1) - end - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - djui_hud_set_font(FONT_TINY) - djui_hud_print_text(optionTable[optionTableRef.debugInfo].toggle == 0 and TEXT_VERSION or MOD_VERSION_DEBUG, 5, 3, 0.5) + optionsMenuOffset = lerp(optionsMenuOffset, options and optionsMenuOffsetMax or 0, 0.1) --Unsupported Res Warning if width < 319 or width > 575 then djui_hud_print_text(TEXT_RATIO_UNSUPPORTED, 5, 39, 0.5) end - -- API Rendering (Above Text) - djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) - if #renderInMenuTable.front > 0 then - for i = 1, #renderInMenuTable.front do - renderInMenuTable.front[i]() - end - end djui_hud_set_resolution(RESOLUTION_N64) - --Options display - local optionTableCount = #optionTable - if options or optionAnimTimer > optionAnimTimerCap then - djui_hud_set_color(menuColor.r * 0.25, menuColor.g * 0.25, menuColor.b * 0.25, 205 + maxf(-200, optionAnimTimer)) - djui_hud_render_rect(0, 0, width, height) - djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) - djui_hud_render_rect(width * 0.5 - 50 * widthScale, minf(55 - optionAnimTimer, height - 25 * widthScale), 100 * widthScale, 200) - djui_hud_set_color(menuColor.r * 0.1, menuColor.g * 0.1, menuColor.b * 0.1, menuOpacity) - djui_hud_render_rect(width * 0.5 - 50 * widthScale + 2, minf(55 - optionAnimTimer + 2, height - 25 * widthScale + 2), 100 * widthScale - 4, 196) - djui_hud_set_font(FONT_ALIASED) - - if not creditsAndTransition then - local widthScaleLimited = minf(widthScale, 1.5) - -- Up Arrow - if currOption > 3 then - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - djui_hud_render_triangle(widthHalf - 3.5*widthScaleLimited, 94 - optionAnimTimer, 6*widthScaleLimited, 3*widthScaleLimited) - end - - -- Down Arrow - if currOption < optionTableCount - 2 then - local yOffset = 90 - optionAnimTimer + 45 * widthScaleLimited - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - djui_hud_set_rotation(0x8000, 0.5, 0.5) - djui_hud_render_triangle(widthHalf - 3.5*widthScaleLimited, yOffset + 10 + 3*widthScaleLimited, 6*widthScaleLimited, 3*widthScaleLimited) - djui_hud_set_rotation(0, 0, 0) - end - - -- Options - for i = currOption - 2, currOption + 2 do - if not (i < 1 or i > optionTableCount) then - local toggleName = optionTable[i].name - local scale = 0.5 - local yOffset = 100 - optionAnimTimer + (i - currOption + 2) * 9 * widthScaleLimited - if i == currOption then - djui_hud_set_font(FONT_ALIASED) - scale = 0.3 - yOffset = yOffset - 1 - local currToggleName = optionTable[i].toggleNames[optionTable[i].toggle + 1] - currToggleName = currToggleName and currToggleName or "???" - if currToggleName ~= "" then - toggleName = toggleName .. " - " .. currToggleName - else - toggleName = toggleName - end - else - djui_hud_set_font(FONT_TINY) - end - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - scale = scale * widthScaleLimited - djui_hud_print_text(toggleName, widthHalf - djui_hud_measure_text(toggleName) * scale * 0.5, yOffset, scale) - end - end - - -- Description - if optionTable[currOption].description ~= nil then - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - for i = 1, #optionTable[currOption].description do - djui_hud_set_font(FONT_ALIASED) - local line = optionTable[currOption].description[i] - djui_hud_print_text(line, widthHalf - djui_hud_measure_text(line) * 0.15, 180 - optionAnimTimer + 15 * widthScaleLimited + 8 * i - 8 * #optionTable[currOption].description, 0.3) - end - end - -- Footer - djui_hud_set_font(FONT_TINY) - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - djui_hud_print_text(TEXT_OPTIONS_SELECT, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_SELECT) * 0.3, height - 20 - optionAnimTimer, 0.6) - else - local renderList = {} - for i = 1, #creditTable do - local credit = creditTable[i] - table_insert(renderList, {textLeft = credit.packName, font = FONT_ALIASED}) - for i = 1, #credit do - local credit = credit[i] - table_insert(renderList, {textLeft = credit.creditTo, textRight = credit.creditFor, font = FONT_NORMAL}) - end - end - - local xLeft = widthHalf - 50 * widthScale + 8 - local xRight = widthHalf + 50 * widthScale - 8 - local y = 80 + 10*widthScale - optionAnimTimer - creditScroll - local prevY = 80 + 10*widthScale - optionAnimTimer - prevCreditScroll - for i = 1, #renderList do - local credit = renderList[i] - local header = (credit.font == FONT_ALIASED) - if y > 62 and y < height then - djui_hud_set_font(credit.font) - if not header then - djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) - else - djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) - end - local x = xLeft - (header and 3 or 0) - local scale = (header and 0.3 or 0.2)*widthScale - djui_hud_print_text_interpolated(credit.textLeft, x, prevY, scale, x, y, scale) - if credit.textRight then - local x = xRight - djui_hud_measure_text(credit.textRight)*scale - local scale = 0.2*widthScale - djui_hud_print_text_interpolated(credit.textRight, x, prevY, scale, x, y, scale) - end - end - y = y + (header and 9 or 6)*widthScale - prevY = prevY + (header and 9 or 6)*widthScale - if renderList[i + 1] ~= nil and renderList[i + 1].font == FONT_ALIASED then - y = y + 2 - prevY = prevY + 2 - end - end - creditScrollRange = math_max(((y + creditScroll)) - (height - 36), 0) - prevCreditScroll = creditScroll - - for i = 1, 8 do - djui_hud_set_color(menuColor.r * 0.1, menuColor.g * 0.1, menuColor.b * 0.1, 100) - djui_hud_render_rect(widthHalf - 50 * widthScale + 2, 60 - optionAnimTimer, 100 * widthScale - 4, i*4) - djui_hud_render_rect(widthHalf - 50 * widthScale + 2, height - 2 - i*4, 96 * widthScale, i*4) - end - end - - -- Render Header - djui_hud_set_font(FONT_ALIASED) - djui_hud_set_color(menuColor.r * 0.5 + 127, menuColor.g * 0.5 + 127, menuColor.b * 0.5 + 127, 255) - local text = TEXT_OPTIONS_HEADER - if creditsAndTransition then - text = TEXT_CREDITS_HEADER - elseif currOption > defaultOptionCount then - text = TEXT_OPTIONS_HEADER_API - end - djui_hud_print_text(text, widthHalf - djui_hud_measure_text(text) * 0.3 * minf(widthScale, 1.5), 65 + optionAnimTimer * -1, 0.6 * minf(widthScale, 1.5)) - - -- Fade in/out of credits - if optionTable[optionTableRef.anims].toggle == 1 then - if credits and creditsCrossFade > -creditsCrossFadeCap then - creditsCrossFade = creditsCrossFade - 1 - if creditsCrossFade == 0 then creditsCrossFade = creditsCrossFade - 1 end - end - if not credits and creditsCrossFade < creditsCrossFadeCap then - creditsCrossFade = creditsCrossFade + 1 - if creditsCrossFade == 0 then creditsCrossFade = creditsCrossFade + 1 end - end - if creditsCrossFade < 0 then - creditsAndTransition = true - else - creditsAndTransition = false - end - else - if credits then - creditsCrossFade = -creditsCrossFadeCap - else - creditsCrossFade = creditsCrossFadeCap - end - creditsAndTransition = credits - end - - djui_hud_set_resolution(RESOLUTION_N64) - djui_hud_set_color(0, 0, 0, (math_abs(creditsCrossFade)) * -creditsCrossFadeMath) - djui_hud_render_rect(width * 0.5 - 50 * widthScale + 2, minf(55 - optionAnimTimer + 2, height - 25 * widthScale + 2), 100 * widthScale - 4, 196) - else - -- How to open options display - 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(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) - djui_hud_set_font(FONT_ALIASED) - djui_hud_print_text(TEXT_OPTIONS_OPEN, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_OPEN) * 0.175 * widthScaleLimited, height - 23 * widthScaleLimited + optionAnimTimer + 202, 0.35 * widthScaleLimited) - djui_hud_set_font(FONT_TINY) - djui_hud_print_text(TEXT_MENU_CLOSE, widthHalf - djui_hud_measure_text(TEXT_MENU_CLOSE) * 0.25 * widthScaleLimited, height - 13 * widthScaleLimited + optionAnimTimer + 202, 0.5 * widthScaleLimited) - end djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) djui_hud_render_rect(width * 0.5 - 50 * widthScale, height - 2, 100 * widthScale, 2) + -- Render Character Name + local angle1 = angle_from_2d_points(width*0.7, 8, width*1.1, 30) + local angle2 = angle_from_2d_points(width*0.7, 40, width*1.1, 35) + djui_hud_set_color(menuColor.r*0.1, menuColor.g*0.1, menuColor.b*0.1, 200) + djui_hud_set_rotation(angle1, 0, 1) + djui_hud_render_rect(width*0.7, -50, width*0.4, 59) + djui_hud_set_rotation(angle2, 0, 1) + djui_hud_render_rect(width*0.7, -50, width*0.4, 96) + djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) + djui_hud_set_rotation(angle1, 0, 1) + djui_hud_render_caution_tape(width*0.7, 8, width*1.1, 30, 1) + djui_hud_set_rotation(angle2, 0, 1) + djui_hud_render_caution_tape(width*0.7, 40, width*1.1, 35, 1) + + djui_hud_set_font(FONT_CHARACTERISTIC) + local charName = string.upper(characterTable[currChar][characterTable[currChar].currAlt].name) + local nameScale = math.min(width*0.23/djui_hud_measure_text(charName), 1) + local charCreator = string.upper(characterTable[currChar][characterTable[currChar].currAlt].credit) + local creatorScale = math.min(width*0.23/djui_hud_measure_text(charCreator), 0.4) + djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) + djui_hud_print_text_auto_interpolated("topName", charName, width*0.85 - djui_hud_measure_text(charName)*0.5*nameScale - 2 + menuOffsetX*0.3, 21 - 16*nameScale + menuOffsetY*0.3, nameScale) + djui_hud_print_text_auto_interpolated("topCreator", charCreator, width*0.85 - djui_hud_measure_text(charCreator)*0.5*creatorScale - 2 + menuOffsetX*0.2, 42 - 16*creatorScale + menuOffsetY*0.2, creatorScale) + + -- Palette Selection + local charColor = characterTableRender[currCharRender][characterTableRender[currCharRender].currAlt].color + local palettes = characterColorPresets[characterTableRender[currCharRender][characterTableRender[currCharRender].currAlt].model] + if palettes then + local bucketSpacing = 24 + paletteXOffset = lerp(paletteXOffset, palettes.currPalette*bucketSpacing, 0.1) + paletteTrans = math.max(paletteTrans - 6, 0) + local bottomTapeAngle = angle_from_2d_points(-10, height - 50, width + 10, height - 35) + + for i = 0, #palettes do + local x = width*0.85 - 16 - paletteXOffset + coss(bottomTapeAngle)*bucketSpacing*i + local y = height*0.72 - math.abs(math.cos((get_global_timer() - i*10)*0.05))*3 - sins(bottomTapeAngle)*bucketSpacing*(i - paletteXOffset/bucketSpacing) + local paletteShirt = nil + local palettePants = nil + if i == 0 then + paletteShirt = network_player_get_palette_color(gNetworkPlayers[0], SHIRT) + palettePants = network_player_get_palette_color(gNetworkPlayers[0], PANTS) + paletteName = "Custom" + else + paletteShirt = palettes[i][SHIRT] + palettePants = palettes[i][PANTS] + paletteName = palettes[i].name + end + if paletteShirt and palettePants then + local bucketFrame = (math.floor((get_global_timer() + i*10)*0.2)%10) * 32 + local bucketPaintFrame = (math.floor(get_global_timer()*0.3)%10) * 32 + djui_hud_set_color(charColor.r*0.5 + 127, charColor.g*0.5 + 127, charColor.b*0.5 + 127, math.min(paletteTrans, 255)) + djui_hud_render_texture_tile(TEX_PALETTE_BUCKET, x, y, 1, 1, 0, bucketFrame, 32, 32) + djui_hud_set_color(paletteShirt.r, paletteShirt.g, paletteShirt.b, math.min(paletteTrans, 255)) + djui_hud_render_texture_tile(TEX_PALETTE_BUCKET, x, y, 1, 1, 32, bucketFrame, 32, 32) + djui_hud_set_color(palettePants.r, palettePants.g, palettePants.b, math.min(paletteTrans, 255)) + djui_hud_render_texture_tile(TEX_PALETTE_BUCKET, x, y, 1, 1, 64, bucketFrame, 32, 32) + + if i == palettes.currPalette then + djui_hud_set_color(paletteShirt.r, paletteShirt.g, paletteShirt.b, math.min(paletteTrans, 255)) + djui_hud_render_texture_tile(TEX_PALETTE_BUCKET, x, y, 1, 1, 96, bucketPaintFrame, 32, 32) + djui_hud_set_color(palettePants.r, palettePants.g, palettePants.b, math.min(paletteTrans, 255)) + djui_hud_render_texture_tile(TEX_PALETTE_BUCKET, x, y, 1, 1, 128, bucketPaintFrame, 32, 32) + end + end + end + + local paletteName = (palettes.currPalette == 0) and "Custom" or (palettes[palettes.currPalette].name or ("Palette "..palettes.currPalette)) + djui_hud_set_font(FONT_RECOLOR_HUD) + local x = width*0.85 - djui_hud_measure_text(paletteName)*0.25 + local y = height*0.68 - math.abs(math.cos((get_global_timer() - palettes.currPalette*10)*0.05))*3 + djui_hud_set_color(charColor.r*0.5 + 127, charColor.g*0.5 + 127, charColor.b*0.5 + 127, math.min(paletteTrans, 255)) + djui_hud_print_text(paletteName, x, y, 0.5) + end + + -- Render Background Wall + local wallWidth = TEX_WALL_LEFT.width + local wallHeight = TEX_WALL_LEFT.height + local wallScale = 0.4 * widthScale + local wallMiddle = width*(0.35 - ((optionsMenuOffset - optionsMenuOffsetMax*0.5)/optionsMenuOffsetMax)*0.3) + local x = wallMiddle - wallWidth*wallScale*0.5 - menuOffsetX + local y = height*0.42 - wallHeight*wallScale*0.5 - menuOffsetY + local scissorWidth = math.max(320/djui_hud_get_screen_width(), 1)*320*0.7 -- Ensure Wall Space doesn't break when under 4:3 + djui_hud_set_scissor(0, 0, scissorWidth, height) + djui_hud_set_color(playerShirt.r, playerShirt.g, playerShirt.b, 255) + djui_hud_render_texture_auto_interpolated("wall-l", TEX_WALL_LEFT, x, y, wallScale, wallScale) + djui_hud_set_color(playerPants.r, playerPants.g, playerPants.b, 255) + djui_hud_render_texture_auto_interpolated("wall-r", TEX_WALL_RIGHT, x, y, wallScale, wallScale) + + -- Render Graffiti + local graffiti = characterGraffiti[currChar] or TEX_GRAFFITI_DEFAULT + local graffitiWidthScale = 120/graffiti.width + local graffitiHeightScale = 120/graffiti.width + djui_hud_set_color(255, 255, 255, 150) + djui_hud_render_texture_auto_interpolated("graffiti", graffiti, wallMiddle - graffiti.width*0.5*graffitiWidthScale - menuOffsetX, height*0.5 - graffiti.height*0.5*graffitiHeightScale - menuOffsetY, graffitiWidthScale, graffitiHeightScale) + + -- API Rendering (Below Text) + if #hookTableRenderInMenu.back > 0 then + for i = 1, #hookTableRenderInMenu.back do + hookTableRenderInMenu.back[i]() + end + end + + if prevOptions ~= options then + optionsTimer = 0 + prevOptions = options + end + + local scale = 0.35 + local textScale = scale*1.5 + local buttonSpacing = 32 + + if not gridMenu then + -- Render Character List + gridYOffset = lerp(gridYOffset, currCharRender*buttonSpacing, 0.1) + djui_hud_set_font(FONT_SPECIAL) + for i = 0, #characterTableRender do + local currCharScoll = math.floor(gridYOffset/buttonSpacing) + if i >= currCharScoll - 3 and i <= currCharScoll + 3 then -- Only render if visible + local charTable = characterTableRender[i] + local currAlt = characterTableRender[i].currAlt + local char = characterTableRender[i][currAlt] + local charName = charTable.nickname + local charAltName = char.name + local charNameLength = djui_hud_measure_text(charName) + local charColor = char.color + local x = -(math.abs(i - gridYOffset/buttonSpacing)^2)*5 + 32 - menuOffsetX*0.2 - optionsMenuOffset + local y = height*0.45 - buttonSpacing*0.5 + i*buttonSpacing - gridYOffset - menuOffsetY*0.2 + local segmentsMeasured = (math.ceil(((charNameLength*textScale + 16*scale))/(16*scale))) + local segments = segmentsMeasured + local charAltCount = #characterTableRender[i] + local channel = characterInstrumentals[i] and tostring(math.floor(879 + hash(characterTableRender[i].saveName)%(1029 - 879))*0.1) .. " FM " or "---.- -- " + channel = channel .. tostring(math.ceil(charTable.playtime / totalPlaytime * 100)) .. "%" + -- Backlight + djui_hud_set_color(charColor.r*0.5 + 127, charColor.g*0.5 + 127, charColor.b*0.5 + 127, 255) + djui_hud_render_rect(x + 96*scale, y + 24*scale, (128*scale + segments*16*scale), 80*scale) + -- Name Screen + djui_hud_set_color(charColor.r*0.5, charColor.g*0.5, charColor.b*0.5, 255) + djui_hud_print_text(charName, x + 112*scale + segments*16*scale*0.5 - charNameLength*textScale*0.5, y + 32*scale, textScale) + + -- Bottom Info + djui_hud_render_rect(x + 112*scale, y + 84*scale, segments*16*scale, scale) + djui_hud_print_text(channel, x + 112*scale, y + 85*scale, 0.3*scale) + djui_hud_print_text(charAltName, x + segments*16*scale + 112*scale - djui_hud_measure_text(charAltName)*0.3*scale, y + 85*scale, 0.3*scale) + + -- Icon + djui_hud_set_color(charColor.r, charColor.g, charColor.b, 150) + djui_hud_render_life_icon(char, x + 112*scale + segments*16*scale + 45*scale, y + 40*scale, scale*3) + -- Nameplate Rendering + djui_hud_set_color(menuColorTint.r, menuColorTint.g, menuColorTint.b, 255) + djui_hud_render_texture_tile(TEX_NAMEPLATE, 0, y, (128/8)*x*0.5*scale, scale, 0, 0, 8, 128) -- stretch to left side of screen + djui_hud_render_texture_tile(TEX_NAMEPLATE, x, y, (128/112)*scale, scale, 0, 0, 112, 128) + for s = 1, segments do + djui_hud_render_texture_tile(TEX_NAMEPLATE, x + (112 + (s-1)*16)*scale, y, scale*8, scale, 112, 0, 16, 128) + end + djui_hud_render_texture_tile(TEX_NAMEPLATE, x + (112 + segments*16)*scale, y, scale*128/192, scale, 128, 0, 192, 128) + local angle = -0x10000*((characterTableRender[i].currAlt - 1)/charAltCount) + if i == currCharRender then + djui_hud_render_texture_tile(TEX_NAMEPLATE, x + 33*scale, y + 48*scale, scale, scale, 320, 48, 32, 32) + end + if charTable.dialAnim == nil then charTable.dialAnim = 0 end + angleAnim = -0x10000*((1/charAltCount))*charTable.dialAnim/10 + charTable.dialAnim = math.lerp(charTable.dialAnim, 0, 0.2) + djui_hud_set_rotation(angle + angleAnim, 0.5, 0.5) + djui_hud_render_texture_tile(TEX_NAMEPLATE, x + (112 + segments*16 + 134)*scale, y + 48*scale, scale, scale, 352, 48, 32, 32) + djui_hud_set_rotation(0, 0, 0) + for a = 1, charAltCount do + local angle = -0x10000*((a - 1)/charAltCount) + 0x8000 + local altColor = characterTableRender[i][a].color + djui_hud_set_color(altColor.r * 0.5 + 127, altColor.g * 0.5 + 127, altColor.b * 0.5 + 127, 255) + djui_hud_render_texture_tile(TEX_NAMEPLATE, x + (112 + segments*16 + (134 + 14) + sins(angle)*16)*scale, y + (62 + coss(angle)*16)*scale, scale, scale, 384, 48 + (currAlt ~= a and 16 or 0), 4, 4) + end + end + end + else + -- Render Character Grid + local currRow = math.floor((currCharRender)/gridButtonsPerRow) + gridYOffset = lerp(gridYOffset, currRow*buttonSpacing, 0.1) + for i = 0, #characterTableRender do + local row = math.floor(i/gridButtonsPerRow) + local column = i%gridButtonsPerRow + local charIcon = characterTableRender[i][characterTableRender[i].currAlt].lifeIcon + local charColor = characterTableRender[i][characterTableRender[i].currAlt].color + local x = 40 + buttonSpacing*column - math.abs(row - gridYOffset/buttonSpacing)^2*3 + math.sin((get_global_timer() + i*10)*0.1) - menuOffsetX*0.5 - optionsMenuOffset + 4 + local y = height*0.5 - buttonSpacing*0.5 + row*buttonSpacing - gridYOffset + math.cos((get_global_timer() + i*10)*0.1) - characterTableRender[i].UIOffset*0.5 - menuOffsetY*0.5 + 4 + djui_hud_set_color(charColor.r, charColor.g, charColor.b, 255) + if characterInstrumentals[i] ~= nil then + djui_hud_render_texture(TEX_ALBUM_LAYER1, x + 3, y, 0.1875, 0.1875) + local discColors = {charColor, charColor, charColor} + local palettes = characterColorPresets[characterTableRender[i][characterTableRender[i].currAlt].model] + if palettes ~= nil then + local paletteIndex = math.max(palettes.currPalette, 1) + discColors = {palettes[paletteIndex][PANTS], palettes[paletteIndex][CAP], palettes[paletteIndex][EMBLEM]} + end + local discX = x + 6 + local discY = y + 2 + if (i == currCharRender) then + discX = x + 13 + discY = y + 2 + djui_hud_set_rotation(math.s16(get_global_timer()*-0x1000), 0.5, 0.5) + x = x - 4 + end + djui_hud_set_color(discColors[1].r, discColors[1].g, discColors[1].b, 255) + djui_hud_render_texture(TEX_CD_LAYER1, discX, discY, 0.15625, 0.15625) + djui_hud_set_color(discColors[2].r, discColors[2].g, discColors[2].b, 255) + djui_hud_render_texture(TEX_CD_LAYER2, discX, discY, 0.15625, 0.15625) + djui_hud_set_color(discColors[3].r, discColors[3].g, discColors[3].b, 255) + djui_hud_render_texture(TEX_CD_LAYER3, discX, discY, 0.15625, 0.15625) + djui_hud_set_color(255, 255, 255, 255) + djui_hud_render_texture(TEX_CD_LAYER4, discX, discY, 0.15625, 0.15625) + djui_hud_set_rotation(0, 0.5, 0.5) + elseif i == currCharRender then + djui_hud_render_texture(TEX_ALBUM_LAYER1, x + 6, y, 0.1875, 0.1875) + x = x - 4 + else + djui_hud_render_texture(TEX_ALBUM_LAYER1, x + 3, y, 0.1875, 0.1875) + end + djui_hud_set_color(charColor.r, charColor.g, charColor.b, 255) + djui_hud_render_texture(TEX_ALBUM_LAYER2, x, y, 0.1875, 0.1875) + x = x + 4 + y = y + 4 + djui_hud_set_color(255, 255, 255, 255) + if type(charIcon) == TYPE_STRING then + djui_hud_set_font(FONT_RECOLOR_HUD) + djui_hud_set_color(charColor.r, charColor.g, charColor.b, 255) + djui_hud_print_text(charIcon, x, y, 1) + else + djui_hud_render_texture(charIcon, x, y, 1 / (charIcon.width * MATH_DIVIDE_16), 1 / (charIcon.height * MATH_DIVIDE_16)) + end + djui_hud_render_texture(TEX_ALBUM_LAYER3, x - 4, y - 4, 0.1875, 0.1875) + + characterTableRender[i].UIOffset = lerp(characterTableRender[i].UIOffset, currCharRender == i and 15 or 0, 0.1) + end + end + + -- Render OST Record + djui_hud_set_color(255, 255, 255, 255) + djui_hud_set_rotation(get_global_timer() * 0x10, 0.5, 0.5) + djui_hud_render_texture(TEX_RECORD, -152 - menuOffsetX*0.1 - optionsMenuOffset, height*0.5 - 96 - menuOffsetY*0.1, 0.75, 0.75) + djui_hud_set_rotation(0, 0, 0) + + -- Render Category Gear + djui_hud_set_color(menuColorTint.r, menuColorTint.g, menuColorTint.b, 255) + djui_hud_set_rotation(gearRotation, 0.5, 0.5) + gearRotation = math.lerp(gearRotation, gearRotationTarget, 0.1) + djui_hud_render_texture(TEX_GEAR, width*0.7 - 15 - TEX_GEAR.width*0.175 - menuOffsetX*0.1, -TEX_GEAR.height*0.175 - menuOffsetY*0.1, 0.35, 0.35) + djui_hud_set_rotation(0, 0, 0) + local icon1 = characterCategories[currCategory].icon1 + local icon2 = characterCategories[currCategory].icon2 + local name = characterCategories[currCategory].name + local char1 = characterTable[icon1] and characterTable[icon1][1] + local char2 = characterTable[icon2] and characterTable[icon2][1] + djui_hud_render_life_icon(char1, width*0.7 - 30 - 4 - menuOffsetX*0.1, 10 - 4 - menuOffsetY*0.1, 1) + djui_hud_render_life_icon(char2, width*0.7 - 30 + 4 - menuOffsetX*0.1, 10 + 4 - menuOffsetY*0.1, 1) + djui_hud_set_font(FONT_NORMAL) + djui_hud_print_text(name, width*0.7 - 65 - djui_hud_measure_text(name)*0.4 - menuOffsetX*0.1, 2 - menuOffsetY*0.1, 0.4) + djui_hud_set_color(255, 255, 255, 255) + + -- Render Options Menu + local tvScale = 0.5 + local tvX = width*0.7 - 170 + (optionsMenuOffsetMax - optionsMenuOffset) + 15 - menuOffsetX*0.2 + local tvY = 70 + (optionsMenuOffsetMax - optionsMenuOffset)*0.2 - menuOffsetY*0.2 + local tvWidth = (320 - 133)*tvScale + local tvHeight = (323 - 168)*tvScale + local optionData = optionTable[currOption] + djui_hud_set_color(255, 255, 255, 255) + djui_hud_render_rect(tvX, tvY, tvWidth, tvHeight) + if options == OPTIONS_MAIN then + djui_hud_set_font(FONT_TINY) + djui_hud_set_color(0, 0, 0, 255) + djui_hud_print_text(optionData.name, tvX + 12 + (tvWidth - 12)*0.5 - djui_hud_measure_text(optionData.name)*0.35, tvY + 20, 0.7) + local locked = optionTable[currOption].lock ~= nil and optionTable[currOption].lock() or nil + local toggleString = (locked == nil and "< " .. optionData.toggleNames[optionData.toggle + 1] .. " >" or locked) + djui_hud_print_text(toggleString, tvX + 12 + (tvWidth - 12)*0.5 - djui_hud_measure_text(toggleString)*0.25, tvY + 30, 0.5) + + for i = 1, #optionData.description do + local textMeasure = djui_hud_measure_text(optionData.description[i]) + local x = tvX + 12 + (tvWidth - 12)*0.5 - textMeasure*0.225 + local y = tvY + tvHeight - 7*(#optionData.description + 2) + 7*i + djui_hud_set_color(0, 0, 0, 255) + djui_hud_render_rect(x - 2, y, textMeasure*0.45 + 4, 8) + djui_hud_set_color(255, 255, 255, 255) + djui_hud_print_text(optionData.description[i], x, y, 0.45) + end + + -- Render Header + djui_hud_set_color(0, 0, 0, 255) + djui_hud_render_rect(tvX, tvY, tvWidth, 18) + djui_hud_set_font(FONT_ALIASED) + djui_hud_set_color(255, 255, 255, 255) + djui_hud_print_text("OPTIONS", tvX + 13, tvY + 2, 0.5) + djui_hud_set_font(FONT_NORMAL) + local optionCategory = "... " .. string.upper(optionData.category) + djui_hud_print_text(optionCategory, tvX + 13 + djui_hud_measure_text("OPTIONS")*0.5, tvY + 8, 0.25) + + -- Render Sidebar + djui_hud_set_color(0, 0, 0, 255) + djui_hud_render_rect(tvX, tvY, 10, tvHeight) + for i = 1, #optionTable do + if i == currOption then + djui_hud_set_color(255, 255, 255, 255) + else + djui_hud_set_color(100, 100, 100, 255) + end + djui_hud_render_rect(tvX + 4, tvY + (tvHeight - 10)*(i/#optionTable), 2, 2) + end + elseif options == OPTIONS_CREDITS then + -- Render Scroll Bar + djui_hud_set_color(0, 0, 0, 255) + djui_hud_render_rect(tvX + 3, tvY + 24, 1, 40) + local creditSize = math.min(1, creditScrollMin/(#creditTable[currCredits] / (currCredits > 0 and 1 or 3))) + djui_hud_render_rect(tvX + 2, tvY + 24 + (currCreditScroll/(#creditTable[currCredits] - creditScrollMin))*(40*(1 - creditSize)), 3, 40*creditSize) + -- Render Credits + djui_hud_set_color(0, 0, 0, 255) + djui_hud_set_font(FONT_TINY) + if currCredits > 0 then + for i = 1, #creditTable[currCredits] do + local creditData = creditTable[currCredits][i] + djui_hud_print_text(creditData.creditee, tvX + tvWidth*0.5 - 1 - djui_hud_measure_text(creditData.creditee)*0.4, tvY + 19 + creditScrollMin*(i - currCreditScroll), 0.4) + djui_hud_print_text(creditData.credit, tvX + tvWidth*0.5 + 1, tvY + 19 + creditScrollMin*(i - currCreditScroll), 0.4) + end + else + for i = 1, #creditTable[currCredits] do + local creditData = creditTable[currCredits][i] + djui_hud_print_text(creditData.creditee, tvX - tvWidth*0.1 + tvWidth*0.3*(((i - 1)%3) + 1) - djui_hud_measure_text(creditData.creditee)*0.2, tvY + 19 + creditScrollMin*(math.ceil(i/3) - currCreditScroll), 0.4) + end + + -- Render Support Link + djui_hud_set_color(0, 0, 0, 255) + djui_hud_render_rect(tvX, tvY + tvHeight - 10, tvWidth, 11) + djui_hud_set_color(255, 255, 255, 255) + djui_hud_set_font(FONT_TINY) + djui_hud_print_text(TEXT_KOFI_LINK, tvX + tvWidth*0.5 - djui_hud_measure_text(TEXT_KOFI_LINK)*0.25, tvY + tvHeight - 10, 0.5) + end + -- Render Pack Name + djui_hud_set_color(0, 0, 0, 255) + djui_hud_render_rect(tvX, tvY, tvWidth, 21) + djui_hud_set_color(255, 255, 255, 255) + djui_hud_set_font(FONT_ALIASED) + djui_hud_print_text(TEXT_CREDITS_HEADER, tvX + tvWidth*0.5 - djui_hud_measure_text(TEXT_CREDITS_HEADER)*0.2, tvY + 2, 0.4) + djui_hud_set_font(FONT_SPECIAL) + djui_hud_print_text(creditTable[currCredits].packName, tvX + tvWidth*0.5 - djui_hud_measure_text(creditTable[currCredits].packName)*0.1, tvY + 14, 0.2) + else + local tvShutOffHeight = tvHeight*0.5*(optionsMenuOffsetMax^3.5 - optionsMenuOffset^3.5)/optionsMenuOffsetMax^3.5 + djui_hud_set_color(0, 0, 0, 255) + djui_hud_render_rect(tvX, tvY, tvWidth, tvShutOffHeight) + djui_hud_render_rect(tvX, tvY + tvHeight - tvShutOffHeight, tvWidth, tvShutOffHeight) + end + + djui_hud_set_color(menuColorTint.r, menuColorTint.g, menuColorTint.b, 255) + djui_hud_render_texture_auto_interpolated("tvBoarder", TEX_OPTIONS_TV, tvX - 133*tvScale, tvY - 168*tvScale, tvScale, tvScale) + + djui_hud_reset_scissor() + + -- Render Character Description + djui_hud_set_rotation(angle_from_2d_points(-10, height - 50, width + 10, height - 35), 0, 0) + djui_hud_set_color(0, 0, 0, 255) + djui_hud_render_rect(-10, height - 50, width*1.5, 100) + djui_hud_set_rotation(0, 0, 0) + + djui_hud_set_font(FONT_TINY) + djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) + local credit = characterTable[currChar][characterTable[currChar].currAlt].credit + local desc = characterTable[currChar][characterTable[currChar].currAlt].description + local descRender = desc .. " - " .. desc + while djui_hud_measure_text(descRender)*0.8 < width do + descRender = descRender .. " - " .. desc + end + descRender = descRender .. " - " .. desc + djui_hud_print_text_interpolated(descRender, 5 - (get_global_timer()%djui_hud_measure_text(desc .. " - ") - 1)*0.8 - menuOffsetX*0.1, height - 25 + menuOffsetY*0.15, 0.8, 5 - get_global_timer()%djui_hud_measure_text(desc .. " - ")*0.8 - menuOffsetX*0.1, height - 25 + menuOffsetY*0.15, 0.8) + + djui_hud_set_rotation(angle_from_2d_points(-10, height - 50, width + 10, height - 35), 0, 0) + djui_hud_set_color(0, 0, 0, 255) + djui_hud_render_rect(0, height - 45, width*0.3, 100) + djui_hud_set_rotation(0, 0, 0) + + djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) + djui_hud_print_text(TEXT_VERSION, 2, height - 7, 0.4) + local currMenu = gridMenu and MENU_BINDS_GRID or MENU_BINDS_DEFAULT + if options == OPTIONS_MAIN then + currMenu = MENU_BINDS_OPTIONS + elseif options == OPTIONS_CREDITS then + currMenu = MENU_BINDS_GRID + end + local bindInfo = TEXT_TABLE_MENU_BINDS[currMenu][math.floor(get_global_timer()/150)%(#TEXT_TABLE_MENU_BINDS[currMenu]) + 1] + djui_hud_print_text(bindInfo.bind, width*0.15 - djui_hud_measure_text(bindInfo.bind)*0.4, height - 35, 0.8) + djui_hud_print_text(bindInfo.desc, width*0.15 - djui_hud_measure_text(bindInfo.desc)*0.4, height - 25, 0.8) + + -- API Rendering (Above Text) + djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) + if #hookTableRenderInMenu.front > 0 then + for i = 1, #hookTableRenderInMenu.front do + hookTableRenderInMenu.front[i]() + end + end + + -- Render Header BG + djui_hud_set_rotation(angle_from_2d_points(-10, 50, 160, -10), 0.5, 0.5) + djui_hud_set_color(0, 0, 0, 255) + djui_hud_render_rect(-150, -50, 300, 100) + + -- Render Tape + djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255) + djui_hud_render_caution_tape(-10, 50, 160, -10, 1) -- Top Tape + djui_hud_render_caution_tape(width*0.7 - 5, -10, width*0.7 + 5, height - 35, 1, 0.6) -- Right Tape + djui_hud_render_caution_tape(width*0.3, height - 45, width*0.3 - 5, height, 1, 0.5) -- Left Bottom Tape + djui_hud_render_caution_tape(-10, height - 50, width + 10, height - 35, 1) -- Bottom Tape + + -- Render Header + djui_hud_set_rotation(0, 0, 0) + djui_hud_set_color(menuColorHalf.r, menuColorHalf.g, menuColorHalf.b, 255) + djui_hud_render_texture_auto_interpolated("logo", TEX_LOGO, menuOffsetX*0.1, menuOffsetY*0.1, 0.25, 0.25) -- Anim logic if options then - if optionTable[optionTableRef.anims].toggle > 0 then - if optionAnimTimer < -1 then - optionAnimTimer = optionAnimTimer * 0.9 - end - else - optionAnimTimer = -1 + if optionAnimTimer < -1 then + optionAnimTimer = optionAnimTimer * 0.9 end else - if optionTable[optionTableRef.anims].toggle > 0 then - if optionAnimTimer > optionAnimTimerCap then - optionAnimTimer = optionAnimTimer * 1.3 - end - else - optionAnimTimer = optionAnimTimerCap + if optionAnimTimer > optionAnimTimerCap then + optionAnimTimer = optionAnimTimer * 1.3 end end - optionAnimTimer = maxf(optionAnimTimer, -200) + optionAnimTimer = math.max(optionAnimTimer, -200) else - options = false + options = nil optionAnimTimer = optionAnimTimerCap - credits = false - creditsCrossFade = 0 bindTextTimer = 0 end -- Fade in/out of menu - if optionTable[optionTableRef.anims].toggle == 1 then - if menu and menuCrossFade > -menuCrossFadeCap then - menuCrossFade = menuCrossFade - 1 - if menuCrossFade == 0 then menuCrossFade = menuCrossFade - 1 end - end - if not menu and menuCrossFade < menuCrossFadeCap then - menuCrossFade = menuCrossFade + 1 - if menuCrossFade == 0 then menuCrossFade = menuCrossFade + 1 end - end - if menuCrossFade < 0 then - menuAndTransition = true - else - menuAndTransition = false - end - else - if menu then - menuCrossFade = -menuCrossFadeCap - else - menuCrossFade = menuCrossFadeCap - end - menuAndTransition = menu + if menu and menuCrossFade > -menuCrossFadeCap then + menuCrossFade = menuCrossFade - 1 + if menuCrossFade == 0 then menuCrossFade = menuCrossFade - 1 end end + if not menu and menuCrossFade < menuCrossFadeCap then + menuCrossFade = menuCrossFade + 1 + if menuCrossFade == 0 then menuCrossFade = menuCrossFade + 1 end + end + menuAndTransition = menuCrossFade < 0 -- Info / Z Open Bind on Pause Menu if is_game_paused() and not djui_hud_is_pause_menu_created() and gMarioStates[0].action ~= ACT_EXIT_LAND_SAVE_DIALOG then @@ -1559,28 +1981,22 @@ local function on_hud_render() djui_hud_print_text(text, width - 20, 16, 1) end - if optionTable[optionTableRef.localModels].toggle == 1 then - local character = characterTable[currChar][characterTable[currChar].currAlt] - local charName = string_underscore_to_space(character.name) - local TEXT_PAUSE_CURR_CHAR_WITH_NAME = TEXT_PAUSE_CURR_CHAR .. charName - width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_PAUSE_CURR_CHAR_WITH_NAME) - local charColor = character.color - djui_hud_set_color(255, 255, 255, 255) - djui_hud_print_text(TEXT_PAUSE_CURR_CHAR, width - 20, 16 + currCharY, 1) - djui_hud_set_color(charColor.r, charColor.g, charColor.b, 255) - djui_hud_print_text(charName, djui_hud_get_screen_width() - djui_hud_measure_text(charName) - 20, 16 + currCharY, 1) - else - width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF) - djui_hud_set_color(255, 255, 255, 255) - djui_hud_print_text(TEXT_LOCAL_MODEL_OFF, width - 20, 16 + currCharY, 1) - end + local character = characterTable[currChar][characterTable[currChar].currAlt] + local charName = string_underscore_to_space(character.name) + local TEXT_PAUSE_CURR_CHAR_WITH_NAME = TEXT_PAUSE_CURR_CHAR .. charName + width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_PAUSE_CURR_CHAR_WITH_NAME) + local charColor = character.color + djui_hud_set_color(255, 255, 255, 255) + djui_hud_print_text(TEXT_PAUSE_CURR_CHAR, width - 20, 16 + currCharY, 1) + djui_hud_set_color(charColor.r, charColor.g, charColor.b, 255) + djui_hud_print_text(charName, djui_hud_get_screen_width() - djui_hud_measure_text(charName) - 20, 16 + currCharY, 1) local text = nil - if stopMovesets and stopPalettes then + if gGlobalSyncTable.charSelectRestrictMovesets > 0 and gGlobalSyncTable.charSelectRestrictPalettes > 0 then text = TEXT_MOVESET_AND_PALETTE_RESTRICTED - elseif stopMovesets then + elseif gGlobalSyncTable.charSelectRestrictMovesets > 0 then text = TEXT_MOVESET_RESTRICTED - elseif stopPalettes then + elseif gGlobalSyncTable.charSelectRestrictPalettes > 0 then text = TEXT_PALETTE_RESTRICTED end if text ~= nil then @@ -1593,20 +2009,43 @@ local function on_hud_render() -- Cross Fade to Menu djui_hud_set_resolution(RESOLUTION_N64) - djui_hud_set_color(0, 0, 0, (math_abs(menuCrossFade)) * -menuCrossFadeMath) + djui_hud_set_color(0, 0, 0, (math.abs(menuCrossFade)) * -menuCrossFadeMath) djui_hud_render_rect(0, 0, width, height) end -local prevMouseScroll = 0 +local FUNC_INDEX_MISC = 0 +local FUNC_INDEX_HORIZONTAL = 1 +local FUNC_INDEX_VERTICAL = 2 +local FUNC_INDEX_CATEGORY = 3 +local FUNC_INDEX_PREFERENCE = 4 +local FUNC_INDEX_PALETTE = 5 +local FUNC_INDEX_ALT = 6 +local FUNC_INDEX_GRID = 7 + +local menuInputCooldowns = {} +function run_func_with_condition_and_cooldown(funcIndex, condition, func, cooldown) + if menuInputCooldowns[funcIndex] == nil then + menuInputCooldowns[funcIndex] = 0 + end + if not condition then return end + local cooldown = cooldown and cooldown or latencyValueTable[optionTable[optionTableRef.inputLatency].toggle + 1] + if menuInputCooldowns[funcIndex] == 0 then + func() + menuInputCooldowns[funcIndex] = cooldown + end +end + local mouseScroll = 0 +---@param m MarioState local function before_mario_update(m) if m.playerIndex ~= 0 then return end + if not startup_init_stall() then return end local controller = m.controller - if inputStallTimerButton > 0 then inputStallTimerButton = inputStallTimerButton - 1 end - if inputStallTimerDirectional > 0 then inputStallTimerDirectional = inputStallTimerDirectional - 1 end - - if menu and inputStallToDirectional ~= latencyValueTable[optionTable[optionTableRef.inputLatency].toggle + 1] then - inputStallToDirectional = latencyValueTable[optionTable[optionTableRef.inputLatency].toggle + 1] + local character = characterTable[currChar] + for index, num in pairs(menuInputCooldowns) do + if num and num > 0 then + menuInputCooldowns[index] = num - 1 + end end -- Menu Inputs @@ -1617,7 +2056,6 @@ local function before_mario_update(m) if (controller.buttonDown & R_TRIG) ~= 0 or not ommActive then menu = true end - inputStallTimerDirectional = inputStallToDirectional end if not menu_is_allowed(m) then @@ -1625,226 +2063,315 @@ local function before_mario_update(m) return end - mouseScroll = mouseScroll + djui_hud_get_mouse_scroll_y() + mouseScroll = mouseScroll - djui_hud_get_mouse_scroll_y() + + -- Yo Melee called + local menuOffsetXRaw = (m.controller.extStickX ~= 0 and m.controller.extStickX or button_to_analog(charSelect.controller, L_CBUTTONS, R_CBUTTONS))*0.1 + local menuOffsetYRaw = (m.controller.extStickY ~= 0 and -m.controller.extStickY or button_to_analog(charSelect.controller, U_CBUTTONS, D_CBUTTONS))*0.1 + menuOffsetX = lerp(menuOffsetX, menuOffsetXRaw, 0.2) + menuOffsetY = lerp(menuOffsetY, menuOffsetYRaw, 0.2) local cameraToObject = m.marioObj.header.gfx.cameraToObject if menuAndTransition and not options then + run_func_with_condition_and_cooldown(FUNC_INDEX_GRID, + (controller.buttonPressed & X_BUTTON) ~= 0, + function () + gridMenu = not gridMenu + mod_storage_save_bool("PrefGridView", gridMenu) + play_sound(SOUND_MENU_CLICK_CHANGE_VIEW, cameraToObject) + end + ) if menu then - if inputStallTimerDirectional == 0 and not charBeingSet then + -- Category Switching + run_func_with_condition_and_cooldown(FUNC_INDEX_CATEGORY, + (controller.buttonPressed & L_TRIG) ~= 0, + function () + repeat + currCategory = num_wrap(currCategory - 1, 1, #characterCategories) + until update_character_render_table() + gearRotationTarget = gearRotationTarget + 0x10000/#characterCategories + categoryOpenTimer = 150 + + play_sound(SOUND_MENU_CAMERA_TURN, cameraToObject) + end + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_CATEGORY, + (controller.buttonPressed & R_TRIG) ~= 0, + function () + repeat + currCategory = num_wrap(currCategory + 1, 1, #characterCategories) + until update_character_render_table() + gearRotationTarget = gearRotationTarget - 0x10000/#characterCategories + categoryOpenTimer = 150 + update_character_render_table() + play_sound(SOUND_MENU_CAMERA_TURN, cameraToObject) + end + ) + + if not gridMenu then + -- List Controls + run_func_with_condition_and_cooldown(FUNC_INDEX_VERTICAL, + (controller.buttonPressed & D_JPAD) ~= 0 or controller.stickY < -45 --[[or prevMouseScroll < mouseScroll]], + function () + currCharRender = num_wrap(currCharRender + 1, 0, #characterTableRender) + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) + end + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_VERTICAL, + (controller.buttonPressed & U_JPAD) ~= 0 or controller.stickY > 45 --[[or prevMouseScroll > mouseScroll]], + function () + currCharRender = num_wrap(currCharRender - 1, 0, #characterTableRender) + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) + end + ) + -- Alt switcher if #characterTable[currChar] > 1 then - local character = characterTable[currChar] - if (controller.buttonPressed & R_JPAD) ~= 0 or controller.stickX > 60 then - character.currAlt = character.currAlt + 1 - inputStallTimerDirectional = inputStallToDirectional - play_sound(SOUND_MENU_CLICK_CHANGE_VIEW, cameraToObject) - buttonAltAnim = inputStallToDirectional - end - if (controller.buttonPressed & L_JPAD) ~= 0 or controller.stickX < -60 then - character.currAlt = character.currAlt ~= 0 and character.currAlt - 1 or #character - inputStallTimerDirectional = inputStallToDirectional - play_sound(SOUND_MENU_CLICK_CHANGE_VIEW, cameraToObject) - buttonAltAnim = -inputStallToDirectional - end - if character.currAlt > #character then character.currAlt = 1 end - if character.currAlt < 1 then character.currAlt = #character end + if characterTableRender[currCharRender].dialAnim == nil then characterTableRender[currCharRender].dialAnim = 0 end + run_func_with_condition_and_cooldown(FUNC_INDEX_HORIZONTAL, + (controller.buttonPressed & R_JPAD) ~= 0 or controller.stickX > 60, + function () + character.currAlt = num_wrap(character.currAlt + 1, 1, #character) + characterTableRender[currCharRender].dialAnim = characterTableRender[currCharRender].dialAnim - 10 + audio_stream_set_frequency(SOUND_CHAR_SELECT_DIAL, math.random(20, 80)*0.01 + 0.5) + audio_stream_play(SOUND_CHAR_SELECT_DIAL, true, 0.75) + end + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_HORIZONTAL, + (controller.buttonPressed & L_JPAD) ~= 0 or controller.stickX < -60, + function () + character.currAlt = num_wrap(character.currAlt - 1, 1, #character) + characterTableRender[currCharRender].dialAnim = characterTableRender[currCharRender].dialAnim + 10 + audio_stream_set_frequency(SOUND_CHAR_SELECT_DIAL, math.random(20, 80)*0.01 + 0.5) + audio_stream_play(SOUND_CHAR_SELECT_DIAL, true, 0.75) + 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 + + else + -- Grid Controls + run_func_with_condition_and_cooldown(FUNC_INDEX_VERTICAL, + (controller.buttonPressed & D_JPAD) ~= 0 or controller.stickY < -45 --[[or prevMouseScroll < mouseScroll]], + function () + currCharRender = num_wrap(currCharRender + 5, currCharRender%5, #characterTableRender) 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) + run_func_with_condition_and_cooldown(FUNC_INDEX_VERTICAL, + (controller.buttonPressed & U_JPAD) ~= 0 or controller.stickY > 45 --[[or prevMouseScroll > mouseScroll]], + function () + local tableCap = #characterTableRender - #characterTableRender%5 + currCharRender%5 + tableCap = tableCap - (tableCap > #characterTable and 5 or 0) + currCharRender = num_wrap(currCharRender - 5, currCharRender%5, tableCap) + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, 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) + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_HORIZONTAL, + (controller.buttonPressed & R_JPAD) ~= 0 or controller.stickX > 60, + function () + currCharRender = num_wrap(currCharRender + 1, 0, #characterTableRender) + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) end + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_HORIZONTAL, + (controller.buttonPressed & L_JPAD) ~= 0 or controller.stickX < -60, + function () + currCharRender = num_wrap(currCharRender - 1, 0, #characterTableRender) + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) + end + ) + + -- Alt switcher + if #characterTable[currChar] > 1 then + run_func_with_condition_and_cooldown(FUNC_INDEX_ALT, + (controller.buttonPressed & R_CBUTTONS) ~= 0, + function () + character.currAlt = num_wrap(character.currAlt + 1, 1, #character) + audio_stream_set_frequency(SOUND_CHAR_SELECT_DIAL, math.random(20, 80)*0.01 + 0.5) + audio_stream_play(SOUND_CHAR_SELECT_DIAL, true, 0.75) + end + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_ALT, + (controller.buttonPressed & L_CBUTTONS) ~= 0, + function () + character.currAlt = num_wrap(character.currAlt - 1, 1, #character) + audio_stream_set_frequency(SOUND_CHAR_SELECT_DIAL, math.random(20, 80)*0.01 + 0.5) + audio_stream_play(SOUND_CHAR_SELECT_DIAL, true, 0.75) + end + ) end end - if inputStallTimerButton == 0 then - if (controller.buttonPressed & A_BUTTON) ~= 0 then + + run_func_with_condition_and_cooldown(FUNC_INDEX_PREFERENCE, + (controller.buttonPressed & A_BUTTON) ~= 0, + function () if characterTable[currChar] ~= nil then mod_storage_save_pref_char(characterTable[currChar]) - inputStallTimerButton = inputStallToButton play_sound(SOUND_MENU_CLICK_FILE_SELECT, cameraToObject) + play_character_sound(m, CHAR_SOUND_LETS_A_GO) 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 - end - if (controller.buttonPressed & START_BUTTON) ~= 0 then - options = true - end - local modelId = gCSPlayers[0].modelId - local paletteCount = characterColorPresets[gCSPlayers[0].modelId] ~= nil and #characterColorPresets[gCSPlayers[0].modelId] or 0 - local currPaletteTable = characterColorPresets[gCSPlayers[0].modelId] and characterColorPresets[gCSPlayers[0].modelId] or {currPalette = 0} + ) - if (controller.buttonPressed & Y_BUTTON) ~= 0 then - if characterColorPresets[modelId] and optionTable[optionTableRef.localModels].toggle > 0 and not stopPalettes then + run_func_with_condition_and_cooldown(FUNC_INDEX_PALETTE, + (controller.buttonPressed & Y_BUTTON) ~= 0, + function () + local currPaletteTable = characterColorPresets[gCSPlayers[0].modelId] and characterColorPresets[gCSPlayers[0].modelId] or {currPalette = 0} + if #currPaletteTable > 0 and gGlobalSyncTable.charSelectRestrictPalettes == 0 then play_sound(SOUND_MENU_CLICK_FILE_SELECT, cameraToObject) currPaletteTable.currPalette = currPaletteTable.currPalette + 1 - inputStallTimerButton = inputStallToButton else play_sound(SOUND_MENU_CAMERA_BUZZ, cameraToObject) - inputStallTimerButton = inputStallToButton end + paletteTrans = 1000 + currPaletteTable.currPalette = num_wrap(currPaletteTable.currPalette, 0, #currPaletteTable) + end + ) - -- Set bottom right text - bindText = 2 - bindTextTimer = 1 + run_func_with_condition_and_cooldown(FUNC_INDEX_MISC, + (controller.buttonPressed & B_BUTTON) ~= 0, + function () + menu = false end - if characterColorPresets[gCSPlayers[0].modelId] ~= nil then - if paletteCount < currPaletteTable.currPalette then currPaletteTable.currPalette = 0 end + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_MISC, + (controller.buttonPressed & START_BUTTON) ~= 0, + function () + options = OPTIONS_MAIN end - end + ) end -- Handles Camera Posistioning - faceAngle = m.faceAngle.y + camAngle = m.faceAngle.y + 0x800 eyeState = MARIO_EYES_OPEN - if controller.buttonPressed & R_CBUTTONS ~= 0 then - faceAngle = faceAngle + 0x1000 - eyeState = MARIO_EYES_LOOK_RIGHT - end - if controller.buttonPressed & L_CBUTTONS ~= 0 then - faceAngle = faceAngle - 0x1000 - eyeState = MARIO_EYES_LOOK_LEFT - end nullify_inputs(m) if is_game_paused() then - controller.buttonPressed = START_BUTTON + game_unpause() end end - if options and not creditsAndTransition then - if inputStallTimerDirectional == 0 then - if (controller.buttonPressed & D_JPAD) ~= 0 or controller.stickY < -60 then - currOption = currOption + 1 - inputStallTimerDirectional = inputStallToDirectional + if options == OPTIONS_MAIN then + run_func_with_condition_and_cooldown(FUNC_INDEX_VERTICAL, + (controller.buttonPressed & D_JPAD) ~= 0 or controller.stickY < -60, + function () + currOption = num_wrap(currOption + 1, 1, #optionTable) play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) end - if (controller.buttonPressed & U_JPAD) ~= 0 or controller.stickY > 60 then - currOption = currOption - 1 - inputStallTimerDirectional = inputStallToDirectional - play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) - end - end + ) - if inputStallTimerButton == 0 then - if (controller.buttonPressed & A_BUTTON) ~= 0 and not optionTable[currOption].optionBeingSet then - optionTable[currOption].toggle = optionTable[currOption].toggle + 1 - if optionTable[currOption].toggle > optionTable[currOption].toggleMax then optionTable[currOption].toggle = 0 end - if optionTable[currOption].toggleSaveName ~= nil then - mod_storage_save(optionTable[currOption].toggleSaveName, tostring(optionTable[currOption].toggle)) + run_func_with_condition_and_cooldown(FUNC_INDEX_VERTICAL, + (controller.buttonPressed & U_JPAD) ~= 0 or controller.stickY > 60, + function () + currOption = num_wrap(currOption - 1, 1, #optionTable) + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) + end + ) + + + run_func_with_condition_and_cooldown(FUNC_INDEX_HORIZONTAL, + (controller.buttonPressed & L_JPAD) ~= 0 or controller.stickX < -60, + function () + local locked = optionTable[currOption].lock ~= nil and optionTable[currOption].lock() or nil + if locked == nil then + optionTable[currOption].toggle = num_wrap(optionTable[currOption].toggle - 1, 0, optionTable[currOption].toggleMax) + if optionTable[currOption].toggleSaveName ~= nil then + mod_storage_save(optionTable[currOption].toggleSaveName, tostring(optionTable[currOption].toggle)) + end + play_sound(SOUND_MENU_CHANGE_SELECT, cameraToObject) + else + play_sound(SOUND_MENU_CAMERA_BUZZ, cameraToObject) end - inputStallTimerButton = inputStallToButton - play_sound(SOUND_MENU_CHANGE_SELECT, cameraToObject) end - if (controller.buttonPressed & B_BUTTON) ~= 0 then - options = false - inputStallTimerButton = inputStallToButton + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_HORIZONTAL, + (controller.buttonPressed & R_JPAD) ~= 0 or controller.stickX > 60, + function () + local locked = optionTable[currOption].lock ~= nil and optionTable[currOption].lock() or nil + if locked == nil then + optionTable[currOption].toggle = num_wrap(optionTable[currOption].toggle + 1, 0, optionTable[currOption].toggleMax) + if optionTable[currOption].toggleSaveName ~= nil then + mod_storage_save(optionTable[currOption].toggleSaveName, tostring(optionTable[currOption].toggle)) + end + play_sound(SOUND_MENU_CHANGE_SELECT, cameraToObject) + else + play_sound(SOUND_MENU_CAMERA_BUZZ, cameraToObject) + end end + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_MISC, + (controller.buttonPressed & B_BUTTON) ~= 0, + function () + options = nil + end + ) + + nullify_inputs(m) + + elseif options == OPTIONS_CREDITS then + run_func_with_condition_and_cooldown(FUNC_INDEX_HORIZONTAL, + (controller.buttonPressed & L_JPAD) ~= 0 or controller.stickX < -60, + function () + currCredits = num_wrap(currCredits - 1, 0, #creditTable) + currCreditScroll = 0 + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) + end + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_HORIZONTAL, + (controller.buttonPressed & R_JPAD) ~= 0 or controller.stickX > 60, + function () + currCredits = num_wrap(currCredits + 1, 0, #creditTable) + currCreditScroll = 0 + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) + end + ) + + if #creditTable[currCredits] > creditScrollMin then + run_func_with_condition_and_cooldown(FUNC_INDEX_VERTICAL, + (controller.buttonPressed & U_JPAD) ~= 0 or controller.stickY > 60, + function () + currCreditScroll = num_wrap(currCreditScroll - 1, 0, math.max(0, math.ceil(#creditTable[currCredits] / (currCredits > 0 and 1 or 3)) - creditScrollMin)) + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) + end + ) + + run_func_with_condition_and_cooldown(FUNC_INDEX_VERTICAL, + (controller.buttonPressed & D_JPAD) ~= 0 or controller.stickY < -60, + function () + currCreditScroll = num_wrap(currCreditScroll + 1, 0, math.max(0, #creditTable[currCredits] / math.ceil(currCredits > 0 and 1 or 3) - creditScrollMin)) + play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject) + end + ) end - if currOption > #optionTable then currOption = 1 end - if currOption < 1 then currOption = #optionTable end + + run_func_with_condition_and_cooldown(FUNC_INDEX_MISC, + (controller.buttonPressed & (B_BUTTON | Z_TRIG)) ~= 0, + function () + options = OPTIONS_MAIN + currOption = optionTableRef.credits + end + ) + nullify_inputs(m) end - if creditsAndTransition then - if (controller.buttonDown & U_JPAD) ~= 0 then - creditScroll = creditScroll - 1.5 - elseif (controller.buttonDown & D_JPAD) ~= 0 then - creditScroll = creditScroll + 1.5 - elseif math.abs(controller.stickY) > 30 then - creditScroll = creditScroll + controller.stickY*-0.03 - end - - if inputStallTimerButton == 0 then - if (controller.buttonPressed & A_BUTTON) ~= 0 or (controller.buttonPressed & B_BUTTON) ~= 0 or (controller.buttonPressed & START_BUTTON) ~= 0 then - credits = false - end - end - nullify_inputs(m) - if creditScroll < 0 then creditScroll = 0 end - if creditScroll > creditScrollRange then creditScroll = creditScrollRange end - else - creditScroll = 0 - end - + -- Checks + currChar = characterTableRender[currCharRender].ogNum end hook_event(HOOK_BEFORE_MARIO_UPDATE, before_mario_update) @@ -1857,7 +2384,7 @@ hook_event(HOOK_ON_HUD_RENDER, on_hud_render) promptedAreYouSure = false local function chat_command(msg) - msg = string_lower(msg) + msg = string.lower(msg) -- Open Menu Check if (msg == "" or msg == "menu") then @@ -1893,17 +2420,12 @@ local function chat_command(msg) end -- Name Check - for i = 1, #characterTable do - if not characterTable[i].locked then - local saveName = string_underscore_to_space(string_lower(characterTable[i].saveName)) + for i = 0, #characterTable do + if characterTable[i].locked ~= LOCKED_TRUE then + 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 + if msg == string.lower(characterTable[i][a].name) or msg == saveName then + force_set_character(i, msg ~= saveName and a or 1) djui_chat_message_create('Character set to "' .. characterTable[i][characterTable[i].currAlt].name .. '" Successfully!') return true end @@ -1917,28 +2439,15 @@ local function chat_command(msg) local charNum = tonumber(msgSplit[1]) local altNum = tonumber(msgSplit[2]) altNum = altNum and altNum or 1 - if charNum > 0 and charNum <= #characterTable and not characterTable[charNum].locked then - currChar = charNum - characterTable[charNum].currAlt = altNum + if charNum > 0 and charNum <= #characterTable and characterTable[charNum].locked ~= LOCKED_TRUE then + force_set_character(charNum, altNum) djui_chat_message_create('Character set to "' .. characterTable[charNum][altNum].name .. '" Successfully!') return true end end + djui_chat_message_create("Character Not Found") return true end hook_chat_command("char-select", "- Opens the Character Select Menu", chat_command) - ---[[ -local function mod_menu_open_cs() - local m = gMarioStates[0] - if menu_is_allowed(m) then - gMarioStates[0].controller.buttonPressed = START_BUTTON - menu = true - else - play_sound(SOUND_MENU_CAMERA_BUZZ, m.pos) - end -end -hook_mod_menu_button("Open Menu", mod_menu_open_cs) -]] \ No newline at end of file diff --git a/mods/character-select-coop/z-moveset.lua b/mods/character-select-coop/moveset.lua similarity index 53% rename from mods/character-select-coop/z-moveset.lua rename to mods/character-select-coop/moveset.lua index ea5bc9087..9ef60a227 100644 --- a/mods/character-select-coop/z-moveset.lua +++ b/mods/character-select-coop/moveset.lua @@ -2,173 +2,245 @@ if incompatibleClient then return 0 end local function find_character_number(index) + if not startup_init_stall() then return 0 end if index == nil then index = 0 end for i = 1, #characterTable do if characterTable[i].saveName == gCSPlayers[index].saveName then return i end end - return 1 + return 0 +end + +local function is_moveset_restricted() + return gGlobalSyncTable.charSelectRestrictMovesets > 0 end local function mario_update(m) - if stopMovesets or not gCSPlayers[m.playerIndex].movesetToggle then return end + if is_moveset_restricted() or not gCSPlayers[m.playerIndex].movesetToggle then return end local hook = HOOK_MARIO_UPDATE local currMoveset = characterMovesets[find_character_number(m.playerIndex)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook](m) + local returnVar = currMoveset[hook](m) + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_MARIO_UPDATE, mario_update) local function before_mario_update(m) - if stopMovesets or not gCSPlayers[m.playerIndex].movesetToggle then return end + if is_moveset_restricted() or not gCSPlayers[m.playerIndex].movesetToggle then return end local hook = HOOK_BEFORE_MARIO_UPDATE local currMoveset = characterMovesets[find_character_number(m.playerIndex)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook](m) + local returnVar = currMoveset[hook](m) + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_BEFORE_MARIO_UPDATE, before_mario_update) -local function before_phys_step(m, stepType) - if stopMovesets or not gCSPlayers[m.playerIndex].movesetToggle then return end +local function before_phys_step(m, stepType, stepArg) + if is_moveset_restricted() or not gCSPlayers[m.playerIndex].movesetToggle then return end local hook = HOOK_BEFORE_PHYS_STEP local currMoveset = characterMovesets[find_character_number(m.playerIndex)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook](m, stepType) + local returnVar = currMoveset[hook](m, stepType, stepArg) + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_BEFORE_PHYS_STEP, before_phys_step) local function allow_pvp_attack(attacker, victim, int) - if stopMovesets then return end + if is_moveset_restricted() then return end local hook = HOOK_ALLOW_PVP_ATTACK local attackerMoveset = characterMovesets[find_character_number(attacker.playerIndex)] local victimMoveset = characterMovesets[find_character_number(victim.playerIndex)] + local returnVar if gCSPlayers[attacker.playerIndex].movesetToggle then if (attackerMoveset ~= nil and attackerMoveset[hook] ~= nil) then - attackerMoveset[hook](attacker, victim, int) + returnVar = attackerMoveset[hook](attacker, victim, int) + if returnVar ~= nil then + return returnVar + end end end if gCSPlayers[victim.playerIndex].movesetToggle then if (victimMoveset ~= nil and victimMoveset[hook] ~= nil) then - victimMoveset[hook](attacker, victim, int) + returnVar = victimMoveset[hook](attacker, victim, int) + if returnVar ~= nil then + return returnVar + end end end end hook_event(HOOK_ALLOW_PVP_ATTACK, allow_pvp_attack) local function on_pvp_attack(attacker, victim, int) - if stopMovesets then return end + if is_moveset_restricted() then return end local hook = HOOK_ON_PVP_ATTACK local attackerMoveset = characterMovesets[find_character_number(attacker.playerIndex)] local victimMoveset = characterMovesets[find_character_number(victim.playerIndex)] if gCSPlayers[attacker.playerIndex].movesetToggle then if (attackerMoveset ~= nil and attackerMoveset[hook] ~= nil) then - attackerMoveset[hook](attacker, victim, int) + local returnVar = attackerMoveset[hook](attacker, victim, int) + if returnVar ~= nil then + return returnVar + end end end if gCSPlayers[victim.playerIndex].movesetToggle then if (victimMoveset ~= nil and victimMoveset[hook] ~= nil) then - victimMoveset[hook](attacker, victim, int) + local returnVar = victimMoveset[hook](attacker, victim, int) + if returnVar ~= nil then + return returnVar + end end end end hook_event(HOOK_ON_PVP_ATTACK, on_pvp_attack) local function on_interact(m, o, intType, intValue) - if stopMovesets or not gCSPlayers[m.playerIndex].movesetToggle then return end + if is_moveset_restricted() or not gCSPlayers[m.playerIndex].movesetToggle then return end local hook = HOOK_ON_INTERACT local currMoveset = characterMovesets[find_character_number(m.playerIndex)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook](m, o, intType, intValue) + local returnVar = currMoveset[hook](m, o, intType, intValue) + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_ON_INTERACT, on_interact) local function allow_interact(m, o, intType) - if stopMovesets or not gCSPlayers[m.playerIndex].movesetToggle then return end + if is_moveset_restricted() or not gCSPlayers[m.playerIndex].movesetToggle then return end local hook = HOOK_ALLOW_INTERACT local currMoveset = characterMovesets[find_character_number(m.playerIndex)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook](m, o, intType) + local returnVar = currMoveset[hook](m, o, intType) + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_ALLOW_INTERACT, allow_interact) local function on_set_mario_action(m) - if stopMovesets or not gCSPlayers[m.playerIndex].movesetToggle then return end + if is_moveset_restricted() or not gCSPlayers[m.playerIndex].movesetToggle then return end local hook = HOOK_ON_SET_MARIO_ACTION local currMoveset = characterMovesets[find_character_number(m.playerIndex)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook](m) + local returnVar = currMoveset[hook](m) + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_ON_SET_MARIO_ACTION, on_set_mario_action) -local function before_set_mario_action(m, nextAct) - if stopMovesets or not gCSPlayers[m.playerIndex].movesetToggle then return end +local function before_set_mario_action(m, nextAct, actionArg) + if is_moveset_restricted() or not gCSPlayers[m.playerIndex].movesetToggle then return end local hook = HOOK_BEFORE_SET_MARIO_ACTION local currMoveset = characterMovesets[find_character_number(m.playerIndex)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook](m, nextAct) + local returnVar = currMoveset[hook](m, nextAct, actionArg) + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_BEFORE_SET_MARIO_ACTION, before_set_mario_action) local function on_death(m) - if stopMovesets or not gCSPlayers[m.playerIndex].movesetToggle then return end + if is_moveset_restricted() or not gCSPlayers[m.playerIndex].movesetToggle then return end local hook = HOOK_ON_DEATH local currMoveset = characterMovesets[find_character_number(m.playerIndex)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook](m) + local returnVar = currMoveset[hook](m) + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_ON_DEATH, on_death) local function hud_render() - if stopMovesets or not gCSPlayers[0].movesetToggle then return end + if is_moveset_restricted() or not gCSPlayers[0].movesetToggle then return end local hook = HOOK_ON_HUD_RENDER local currMoveset = characterMovesets[find_character_number(0)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook]() + local returnVar = currMoveset[hook]() + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_ON_HUD_RENDER, hud_render) local function hud_render_behind() - if stopMovesets or not gCSPlayers[0].movesetToggle then return end + if is_moveset_restricted() or not gCSPlayers[0].movesetToggle then return end local hook = HOOK_ON_HUD_RENDER_BEHIND local currMoveset = characterMovesets[find_character_number(0)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook]() + local returnVar = currMoveset[hook]() + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_ON_HUD_RENDER_BEHIND, hud_render_behind) -local function level_init() - if stopMovesets or not gCSPlayers[0].movesetToggle then return end +local function level_init(type, levelNum, areaIdx, nodeId, arg) + if is_moveset_restricted() or not gCSPlayers[0].movesetToggle then return end local hook = HOOK_ON_LEVEL_INIT local currMoveset = characterMovesets[find_character_number(0)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook]() + local returnVar = currMoveset[hook](type, levelNum, areaIdx, nodeId, arg) + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_ON_LEVEL_INIT, level_init) local function sync_valid() - if stopMovesets or not gCSPlayers[0].movesetToggle then return end + if is_moveset_restricted() or not gCSPlayers[0].movesetToggle then return end local hook = HOOK_ON_SYNC_VALID local currMoveset = characterMovesets[find_character_number(0)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook]() + local returnVar = currMoveset[hook]() + if returnVar ~= nil then + return returnVar + end end hook_event(HOOK_ON_SYNC_VALID, sync_valid) local function object_render(obj) - if stopMovesets or not gCSPlayers[0].movesetToggle then return end + if is_moveset_restricted() or not gCSPlayers[0].movesetToggle then return end local hook = HOOK_ON_OBJECT_RENDER local currMoveset = characterMovesets[find_character_number(0)] if currMoveset == nil or currMoveset[hook] == nil then return end - return currMoveset[hook](obj) + local returnVar = currMoveset[hook](obj) + if returnVar ~= nil then + return returnVar + end end 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 + if is_moveset_restricted() 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) + local returnVar = currMoveset[hook](m, water) + if returnVar ~= nil then + return returnVar + end end -hook_event(HOOK_ALLOW_FORCE_WATER_ACTION, allow_water_action) \ No newline at end of file +hook_event(HOOK_ALLOW_FORCE_WATER_ACTION, allow_water_action) + +local function mario_override_floor_class(m, floorClass) + if is_moveset_restricted() 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 + local returnVar = currMoveset[hook](m, floorClass) + if returnVar ~= nil then + return returnVar + end +end +hook_event(HOOK_MARIO_OVERRIDE_FLOOR_CLASS, mario_override_floor_class) diff --git a/mods/character-select-coop/palettes.lua b/mods/character-select-coop/palettes.lua new file mode 100644 index 000000000..779d2ead0 --- /dev/null +++ b/mods/character-select-coop/palettes.lua @@ -0,0 +1,391 @@ +if incompatibleClient then return 0 end + +-- localize functions to improve performance - z-palettes.lua +local network_player_set_override_palette_color,network_player_reset_override_palette = network_player_set_override_palette_color,network_player_reset_override_palette + +characterColorPresets = { + [E_MODEL_MARIO] = { + currPalette = 1, + { + name = "Default", + [PANTS] = { r = 0x00, g = 0x00, b = 0xff }, + [SHIRT] = { r = 0xff, g = 0x00, b = 0x00 }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0x72, g = 0x1c, b = 0x0e }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, + [CAP] = { r = 0xff, g = 0x00, b = 0x00 }, + [EMBLEM] = { r = 0xff, g = 0x00, b = 0x00 }, + }, + { + name = "New Game +", + [PANTS] = { r = 0x19, g = 0x4b, b = 0xa3 }, + [SHIRT] = { r = 0xff, g = 0x30, b = 0x33 }, + [GLOVES] = { r = 0xdd, g = 0xdd, b = 0xdd }, + [SHOES] = { r = 0x51, g = 0x28, b = 0x00 }, + [HAIR] = { r = 0x58, g = 0x09, b = 0x00 }, + [SKIN] = { r = 0xff, g = 0xaf, b = 0x8c }, + [CAP] = { r = 0xff, g = 0x30, b = 0x33 }, + [EMBLEM] = { r = 0xff, g = 0x30, b = 0x33 }, + }, + { + name = "Fire Flower", + [PANTS] = { r = 0xb2, g = 0x28, b = 0x18 }, + [SHIRT] = { r = 0xff, g = 0xe0, b = 0xe0 }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0x72, g = 0x1c, b = 0x0e }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, + [CAP] = { r = 0xff, g = 0xe0, b = 0xe0 }, + [EMBLEM] = { r = 0xff, g = 0x00, b = 0x00 }, + }, + { + name = "Burgundy", + [PANTS] = { r = 0x23, g = 0x11, b = 0x03 }, + [SHIRT] = { r = 0x68, g = 0x0A, b = 0x17 }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x72, g = 0x1C, b = 0x0E }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0x68, g = 0x0A, b = 0x17 }, + [EMBLEM] = { r = 0x68, g = 0x0A, b = 0x17 }, + }, + { + name = "Raspberry", + [PANTS] = { r = 0xD6, g = 0x35, b = 0x4D }, + [SHIRT] = { r = 0x3B, g = 0x8F, b = 0xF7 }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x72, g = 0x1C, b = 0x0E }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0x3B, g = 0x8F, b = 0xF7 }, + [EMBLEM] = { r = 0x3B, g = 0x8F, b = 0xF7 }, + }, + + }, + [E_MODEL_LUIGI] = { + currPalette = 1, + { + name = "Default", + [PANTS] = { r = 0x00, g = 0x00, b = 0xff }, + [SHIRT] = { r = 0x00, g = 0xff, b = 0x00 }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0x72, g = 0x1c, b = 0x0e }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, + [CAP] = { r = 0x00, g = 0xff, b = 0x00 }, + [EMBLEM] = { r = 0x00, g = 0xff, b = 0x00 }, + }, + { + name = "Mint", + [PANTS] = { r = 0x53, g = 0x39, b = 0x3D }, + [SHIRT] = { r = 0x95, g = 0xD0, b = 0x8F }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x72, g = 0x1C, b = 0x0E }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0x95, g = 0xD0, b = 0x8F }, + [EMBLEM] = { r = 0x95, g = 0xD0, b = 0x8F }, + }, + { + name = "Cold Crevase", + [PANTS] = { r = 0xD4, g = 0xDF, b = 0xE7 }, + [SHIRT] = { r = 0x51, g = 0xA9, b = 0x9C }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x6B, g = 0x41, b = 0x00 }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0xD4, g = 0xDF, b = 0xE7 }, + [EMBLEM] = { r = 0x51, g = 0xA9, b = 0x9C }, + }, + { + name = "Greedy", + [PANTS] = { r = 0x00, g = 0x48, b = 0x8a }, + [SHIRT] = { r = 0xf7, g = 0xaf, b = 0x25 }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0xc0, g = 0x21, b = 0x00 }, + [HAIR] = { r = 0x00, g = 0x00, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, + [CAP] = { r = 0x00, g = 0x48, b = 0x8a }, + [EMBLEM] = { r = 0x00, g = 0x00, b = 0x00 }, + }, + { + name = "Kindness", + [PANTS] = { r = 0xff, g = 0x44, b = 0xff }, + [SHIRT] = { r = 0x93, g = 0x00, b = 0x90 }, + [GLOVES] = { r = 0xff, g = 0x99, b = 0xff }, + [SHOES] = { r = 0xaa, g = 0x2c, b = 0x66 }, + [HAIR] = { r = 0xf3, g = 0x65, b = 0xda }, + [SKIN] = { r = 0xc8, g = 0x6b, b = 0x9d }, + [CAP] = { r = 0xef, g = 0x2b, b = 0xea }, + [EMBLEM] = { r = 0xef, g = 0x2b, b = 0xea }, + }, + }, + [E_MODEL_TOAD_PLAYER] = { + currPalette = 1, + { + name = "Default", + [PANTS] = { r = 0xff, g = 0xff, b = 0xff }, + [SHIRT] = { r = 0x4c, g = 0x2c, b = 0xd3 }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0x68, g = 0x40, b = 0x1b }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xd5, b = 0xa1 }, + [CAP] = { r = 0xff, g = 0x00, b = 0x00 }, + [EMBLEM] = { r = 0xff, g = 0x00, b = 0x00 }, + }, + { + name = "Bucken Berry", + [PANTS] = { r = 0xff, g = 0xff, b = 0xff }, + [SHIRT] = { r = 0x00, g = 0x00, b = 0xff }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0x68, g = 0x40, b = 0x1b }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xd5, b = 0xa1 }, + [CAP] = { r = 0x00, g = 0x00, b = 0xff }, + [EMBLEM] = { r = 0x00, g = 0x00, b = 0xff }, + }, + { + name = "Ala Gold", + [PANTS] = { r = 0xff, g = 0xff, b = 0xff }, + [SHIRT] = { r = 0xff, g = 0xff, b = 0x00 }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0x68, g = 0x40, b = 0x1b }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xd5, b = 0xa1 }, + [CAP] = { r = 0xff, g = 0xff, b = 0x00 }, + [EMBLEM] = { r = 0xff, g = 0xff, b = 0x00 }, + }, + { + name = "Jet Black", + [PANTS] = { r = 0x1A, g = 0x1A, b = 0x1A }, + [SHIRT] = { r = 0x2C, g = 0x2C, b = 0x2C }, + [GLOVES] = { r = 0x64, g = 0x64, b = 0x64 }, + [SHOES] = { r = 0x64, g = 0x64, b = 0x64 }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0x1A, g = 0x1A, b = 0x1A }, + [EMBLEM] = { r = 0x1A, g = 0x1A, b = 0x1A }, + }, + { + name = "Hot Pink", + [PANTS] = { r = 0x34, g = 0x16, b = 0x0D }, + [SHIRT] = { r = 0xC1, g = 0x2C, b = 0x72 }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x72, g = 0x1C, b = 0x0E }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0xC1, g = 0x2C, b = 0x72 }, + [EMBLEM] = { r = 0xC1, g = 0x2C, b = 0x72 }, + }, + { + name = "Goomba", + [PANTS] = { r = 0xC6, g = 0xB1, b = 0x32 }, + [SHIRT] = { r = 0x95, g = 0x43, b = 0x01 }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x72, g = 0x1C, b = 0x0E }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0x95, g = 0x43, b = 0x01 }, + [EMBLEM] = { r = 0x95, g = 0x43, b = 0x01 }, + }, + + }, + [E_MODEL_WALUIGI] = { + currPalette = 1, + { + name = "Default", + [PANTS] = { r = 0x16, g = 0x16, b = 0x27 }, + [SHIRT] = { r = 0x61, g = 0x26, b = 0xb0 }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0xfe, g = 0x76, b = 0x00 }, + [HAIR] = { r = 0x73, g = 0x53, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, + [CAP] = { r = 0x61, g = 0x26, b = 0xb0 }, + [EMBLEM] = { r = 0xff, g = 0xde, b = 0x00 }, + }, + { + name = "Cobalt", + [PANTS] = { r = 0x3F, g = 0x3F, b = 0xFF }, + [SHIRT] = { r = 0x0A, g = 0x0A, b = 0x28 }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x39, g = 0x0E, b = 0x07 }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0x3F, g = 0x3F, b = 0xFF }, + [EMBLEM] = { r = 0x3F, g = 0x3F, b = 0xFF }, + }, + { + name = "Clover", + [PANTS] = { r = 0x14, g = 0x19, b = 0x14 }, + [SHIRT] = { r = 0x4C, g = 0x5F, b = 0x20 }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x72, g = 0x1C, b = 0x0E }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0x4C, g = 0x5F, b = 0x20 }, + [EMBLEM] = { r = 0x4C, g = 0x5F, b = 0x20 }, + }, + { + name = "Blueberry Pie", + [PANTS] = { r = 0xEB, g = 0x8A, b = 0x4B }, + [SHIRT] = { r = 0x10, g = 0x1B, b = 0x2E }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x72, g = 0x1C, b = 0x0E }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0x10, g = 0x1B, b = 0x2E }, + [EMBLEM] = { r = 0x10, g = 0x1B, b = 0x2E }, + }, + { + name = "Tennis Loser", + [PANTS] = { r = 0x16, g = 0x16, b = 0x27 }, + [SHIRT] = { r = 0x5A, g = 0x39, b = 0x21 }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x5A, g = 0x00, b = 0xCE }, + [HAIR] = { r = 0x29, g = 0x10, b = 0x00 }, + [SKIN] = { r = 0xE7, g = 0xB5, b = 0x94 }, + [CAP] = { r = 0x5A, g = 0x39, b = 0x21 }, + [EMBLEM] = { r = 0xFF, g = 0xDE, b = 0x00 }, + }, + { + name = "Sealed Away", + [PANTS] = { r = 0x00, g = 0x98, b = 0x00 }, + [SHIRT] = { r = 0x47, g = 0xc5, b = 0xff }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0x72, g = 0x1c, b = 0x0e }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, + [CAP] = { r = 0x47, g = 0xc5, b = 0xff }, + [EMBLEM] = { r = 0xff, g = 0xde, b = 0x00 }, + }, + + }, + [E_MODEL_WARIO] = { + currPalette = 1, + { + name = "Default", + [PANTS] = { r = 0x7f, g = 0x20, b = 0x7a }, + [SHIRT] = { r = 0xff, g = 0xbd, b = 0x00 }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0x0e, g = 0x72, b = 0x1c }, + [HAIR] = { r = 0x73, g = 0x53, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, + [CAP] = { r = 0xff, g = 0xbd, b = 0x00 }, + [EMBLEM] = { r = 0x00, g = 0x00, b = 0xff }, + }, + { + name = "Ruby", + [PANTS] = { r = 0xE1, g = 0x05, b = 0x31 }, + [SHIRT] = { r = 0x28, g = 0x0A, b = 0x0A }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x39, g = 0x0E, b = 0x07 }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0xE1, g = 0x05, b = 0x31 }, + [EMBLEM] = { r = 0xE1, g = 0x05, b = 0x31 }, + }, + { + name = "Eggplant", + [PANTS] = { r = 0xE6, g = 0xE3, b = 0xFF }, + [SHIRT] = { r = 0x37, g = 0x32, b = 0x42 }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x72, g = 0x1C, b = 0x0E }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0x37, g = 0x32, b = 0x42 }, + [EMBLEM] = { r = 0x37, g = 0x32, b = 0x42 }, + }, + { + name = "Battlements", + [PANTS] = { r = 0xF7, g = 0xC2, b = 0x45 }, + [SHIRT] = { r = 0x55, g = 0x92, b = 0xB2 }, + [GLOVES] = { r = 0xFF, g = 0xFF, b = 0xFF }, + [SHOES] = { r = 0x72, g = 0x1C, b = 0x0E }, + [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, + [SKIN] = { r = 0xFE, g = 0xC1, b = 0x79 }, + [CAP] = { r = 0x55, g = 0x92, b = 0xB2 }, + [EMBLEM] = { r = 0x55, g = 0x92, b = 0xB2 }, + }, + { + name = "Cotten Candy", + [PANTS] = { r = 0x69, g = 0xa1, b = 0xff }, + [SHIRT] = { r = 0xff, g = 0x7d, b = 0x89 }, + [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, + [SHOES] = { r = 0xb9, g = 0x48, b = 0xff }, + [HAIR] = { r = 0x73, g = 0x53, b = 0x00 }, + [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, + [CAP] = { r = 0x69, g = 0xa1, b = 0xff }, + [EMBLEM] = { r = 0xb9, g = 0x48, b = 0xff }, + }, + } +} + +local paletteLoop = #characterColorPresets[E_MODEL_MARIO][1] + +local function network_player_set_full_override_palette(networkPlayer, colorTable) + if colorTable == nil then return end + for i = 0, paletteLoop do + network_player_set_override_palette_color(networkPlayer, i, colorTable[i]) + end +end + +---@param np NetworkPlayer +function update_preset_palette(np) + local p = gCSPlayers[np.localIndex] + local modelId = p.modelId + if np.connected and gCSPlayers[0].presetPalette > 0 and characterColorPresets[modelId] and gGlobalSyncTable.charSelectRestrictPalettes == 0 then + network_player_set_full_override_palette(np, characterColorPresets[modelId][p.presetPalette]) + end +end + +local prevPresetPalette = {} +local prevModel = {} + +local function mario_update(m) + local np = gNetworkPlayers[m.playerIndex] + local p = gCSPlayers[m.playerIndex] + if not startup_init_stall() then return end + + if m.playerIndex == 0 and not p.isUpdating then + p.isUpdating = true + for i = 1, MAX_PLAYERS - 1 do + prevPresetPalette[i] = gCSPlayers[i].presetPalette + prevModel[i] = gCSPlayers[i].modelId + end + end + + if m.playerIndex == 0 then + if gGlobalSyncTable.charSelectRestrictPalettes == 0 then + gCSPlayers[0].presetPalette = characterColorPresets[gCSPlayers[0].modelId] ~= nil and characterColorPresets[gCSPlayers[0].modelId].currPalette or 0 + end + end + + if np.connected then + if p.presetPalette == nil or characterColorPresets[p.modelId] == nil then + if p.presetPalette == nil then + prevPresetPalette[m.playerIndex] = 0 + end + p.presetPalette = 0 + end + + if (prevPresetPalette[m.playerIndex] ~= p.presetPalette or prevModel[m.playerIndex] ~= p.modelId) then + if p.presetPalette == 0 or not characterColorPresets[p.modelId] then + network_player_reset_override_palette(np) + end + end + + prevPresetPalette[m.playerIndex] = p.presetPalette + prevModel[m.playerIndex] = p.modelId + + if p.presetPalette > 0 and characterColorPresets[p.modelId] and gGlobalSyncTable.charSelectRestrictPalettes == 0 then + network_player_set_full_override_palette(np, characterColorPresets[p.modelId][p.presetPalette]) + end + else + if p.isUpdating then + p.isUpdating = false + end + end +end + +hook_event(HOOK_MARIO_UPDATE, mario_update) diff --git a/mods/character-select-coop/sound/00_waluigi_jump_hoo.aiff b/mods/character-select-coop/sound/00_waluigi_jump_hoo.aiff new file mode 100644 index 000000000..78c4055e6 Binary files /dev/null and b/mods/character-select-coop/sound/00_waluigi_jump_hoo.aiff differ diff --git a/mods/character-select-coop/sound/00_waluigi_waaaooow.aiff b/mods/character-select-coop/sound/00_waluigi_waaaooow.aiff new file mode 100644 index 000000000..877c49398 Binary files /dev/null and b/mods/character-select-coop/sound/00_waluigi_waaaooow.aiff differ diff --git a/mods/character-select-coop/sound/01_waluigi_hoohoo.aiff b/mods/character-select-coop/sound/01_waluigi_hoohoo.aiff new file mode 100644 index 000000000..2ef1f6918 Binary files /dev/null and b/mods/character-select-coop/sound/01_waluigi_hoohoo.aiff differ diff --git a/mods/character-select-coop/sound/01_waluigi_jump_wah.aiff b/mods/character-select-coop/sound/01_waluigi_jump_wah.aiff new file mode 100644 index 000000000..ad4f2dd2b Binary files /dev/null and b/mods/character-select-coop/sound/01_waluigi_jump_wah.aiff differ diff --git a/mods/character-select-coop/sound/02_waluigi_panting.aiff b/mods/character-select-coop/sound/02_waluigi_panting.aiff new file mode 100644 index 000000000..7e85371a0 Binary files /dev/null and b/mods/character-select-coop/sound/02_waluigi_panting.aiff differ diff --git a/mods/character-select-coop/sound/02_waluigi_yah.aiff b/mods/character-select-coop/sound/02_waluigi_yah.aiff new file mode 100644 index 000000000..c3ac89a9b Binary files /dev/null and b/mods/character-select-coop/sound/02_waluigi_yah.aiff differ diff --git a/mods/character-select-coop/sound/03_waluigi_dying.aiff b/mods/character-select-coop/sound/03_waluigi_dying.aiff new file mode 100644 index 000000000..0eed8f920 Binary files /dev/null and b/mods/character-select-coop/sound/03_waluigi_dying.aiff differ diff --git a/mods/character-select-coop/sound/03_waluigi_haha.aiff b/mods/character-select-coop/sound/03_waluigi_haha.aiff new file mode 100644 index 000000000..2452e58c2 Binary files /dev/null and b/mods/character-select-coop/sound/03_waluigi_haha.aiff differ diff --git a/mods/character-select-coop/sound/04_waluigi_on_fire.aiff b/mods/character-select-coop/sound/04_waluigi_on_fire.aiff new file mode 100644 index 000000000..381e143e9 Binary files /dev/null and b/mods/character-select-coop/sound/04_waluigi_on_fire.aiff differ diff --git a/mods/character-select-coop/sound/04_waluigi_yahoo.aiff b/mods/character-select-coop/sound/04_waluigi_yahoo.aiff new file mode 100644 index 000000000..386ff8b0c Binary files /dev/null and b/mods/character-select-coop/sound/04_waluigi_yahoo.aiff differ diff --git a/mods/character-select-coop/sound/05_waluigi_uh.aiff b/mods/character-select-coop/sound/05_waluigi_uh.aiff new file mode 100644 index 000000000..5f42e68ba Binary files /dev/null and b/mods/character-select-coop/sound/05_waluigi_uh.aiff differ diff --git a/mods/character-select-coop/sound/05_waluigi_uh2.aiff b/mods/character-select-coop/sound/05_waluigi_uh2.aiff new file mode 100644 index 000000000..0a3632979 Binary files /dev/null and b/mods/character-select-coop/sound/05_waluigi_uh2.aiff differ diff --git a/mods/character-select-coop/sound/06_waluigi_coughing.aiff b/mods/character-select-coop/sound/06_waluigi_coughing.aiff new file mode 100644 index 000000000..7a1efc6e3 Binary files /dev/null and b/mods/character-select-coop/sound/06_waluigi_coughing.aiff differ diff --git a/mods/character-select-coop/sound/06_waluigi_hrmm.aiff b/mods/character-select-coop/sound/06_waluigi_hrmm.aiff new file mode 100644 index 000000000..0335421d6 Binary files /dev/null and b/mods/character-select-coop/sound/06_waluigi_hrmm.aiff differ diff --git a/mods/character-select-coop/sound/07_waluigi_its_a_me_mario.aiff b/mods/character-select-coop/sound/07_waluigi_its_a_me_mario.aiff new file mode 100644 index 000000000..86303bf2b Binary files /dev/null and b/mods/character-select-coop/sound/07_waluigi_its_a_me_mario.aiff differ diff --git a/mods/character-select-coop/sound/07_waluigi_wah2.aiff b/mods/character-select-coop/sound/07_waluigi_wah2.aiff new file mode 100644 index 000000000..891804a47 Binary files /dev/null and b/mods/character-select-coop/sound/07_waluigi_wah2.aiff differ diff --git a/mods/character-select-coop/sound/08_waluigi_punch_yah.aiff b/mods/character-select-coop/sound/08_waluigi_punch_yah.aiff new file mode 100644 index 000000000..cc5399d62 Binary files /dev/null and b/mods/character-select-coop/sound/08_waluigi_punch_yah.aiff differ diff --git a/mods/character-select-coop/sound/08_waluigi_whoa.aiff b/mods/character-select-coop/sound/08_waluigi_whoa.aiff new file mode 100644 index 000000000..e8d0b493f Binary files /dev/null and b/mods/character-select-coop/sound/08_waluigi_whoa.aiff differ diff --git a/mods/character-select-coop/sound/09_waluigi_eeuh.aiff b/mods/character-select-coop/sound/09_waluigi_eeuh.aiff new file mode 100644 index 000000000..c353bc689 Binary files /dev/null and b/mods/character-select-coop/sound/09_waluigi_eeuh.aiff differ diff --git a/mods/character-select-coop/sound/09_waluigi_punch_hoo.aiff b/mods/character-select-coop/sound/09_waluigi_punch_hoo.aiff new file mode 100644 index 000000000..8cf50f618 Binary files /dev/null and b/mods/character-select-coop/sound/09_waluigi_punch_hoo.aiff differ diff --git a/mods/character-select-coop/sound/0A_waluigi_attacked.aiff b/mods/character-select-coop/sound/0A_waluigi_attacked.aiff new file mode 100644 index 000000000..eea71e9ca Binary files /dev/null and b/mods/character-select-coop/sound/0A_waluigi_attacked.aiff differ diff --git a/mods/character-select-coop/sound/0A_waluigi_mama_mia.aiff b/mods/character-select-coop/sound/0A_waluigi_mama_mia.aiff new file mode 100644 index 000000000..7d5b3594d Binary files /dev/null and b/mods/character-select-coop/sound/0A_waluigi_mama_mia.aiff differ diff --git a/mods/character-select-coop/sound/0B_waluigi_okey_dokey.aiff b/mods/character-select-coop/sound/0B_waluigi_okey_dokey.aiff new file mode 100644 index 000000000..d020e3c9a Binary files /dev/null and b/mods/character-select-coop/sound/0B_waluigi_okey_dokey.aiff differ diff --git a/mods/character-select-coop/sound/0B_waluigi_ooof.aiff b/mods/character-select-coop/sound/0B_waluigi_ooof.aiff new file mode 100644 index 000000000..258e4d1a2 Binary files /dev/null and b/mods/character-select-coop/sound/0B_waluigi_ooof.aiff differ diff --git a/mods/character-select-coop/sound/0C_waluigi_drowning.aiff b/mods/character-select-coop/sound/0C_waluigi_drowning.aiff new file mode 100644 index 000000000..40a5f31ed Binary files /dev/null and b/mods/character-select-coop/sound/0C_waluigi_drowning.aiff differ diff --git a/mods/character-select-coop/sound/0C_waluigi_here_we_go.aiff b/mods/character-select-coop/sound/0C_waluigi_here_we_go.aiff new file mode 100644 index 000000000..32fb36905 Binary files /dev/null and b/mods/character-select-coop/sound/0C_waluigi_here_we_go.aiff differ diff --git a/mods/character-select-coop/sound/0D_waluigi_thank_you_playing_my_game.aiff b/mods/character-select-coop/sound/0D_waluigi_thank_you_playing_my_game.aiff new file mode 100644 index 000000000..f014b950b Binary files /dev/null and b/mods/character-select-coop/sound/0D_waluigi_thank_you_playing_my_game.aiff differ diff --git a/mods/character-select-coop/sound/0D_waluigi_yawning.aiff b/mods/character-select-coop/sound/0D_waluigi_yawning.aiff new file mode 100644 index 000000000..ecabd0d4c Binary files /dev/null and b/mods/character-select-coop/sound/0D_waluigi_yawning.aiff differ diff --git a/mods/character-select-coop/sound/0E_waluigi_snoring1.aiff b/mods/character-select-coop/sound/0E_waluigi_snoring1.aiff new file mode 100644 index 000000000..069878bf1 Binary files /dev/null and b/mods/character-select-coop/sound/0E_waluigi_snoring1.aiff differ diff --git a/mods/character-select-coop/sound/0F_waluigi_snoring2.aiff b/mods/character-select-coop/sound/0F_waluigi_snoring2.aiff new file mode 100644 index 000000000..a57f3c8cb Binary files /dev/null and b/mods/character-select-coop/sound/0F_waluigi_snoring2.aiff differ diff --git a/mods/character-select-coop/sound/10_waluigi_doh.aiff b/mods/character-select-coop/sound/10_waluigi_doh.aiff new file mode 100644 index 000000000..94f22e3be Binary files /dev/null and b/mods/character-select-coop/sound/10_waluigi_doh.aiff differ diff --git a/mods/character-select-coop/sound/11_waluigi_game_over.aiff b/mods/character-select-coop/sound/11_waluigi_game_over.aiff new file mode 100644 index 000000000..bd70bc2dc Binary files /dev/null and b/mods/character-select-coop/sound/11_waluigi_game_over.aiff differ diff --git a/mods/character-select-coop/sound/12_waluigi_hello.aiff b/mods/character-select-coop/sound/12_waluigi_hello.aiff new file mode 100644 index 000000000..e3defaf7d Binary files /dev/null and b/mods/character-select-coop/sound/12_waluigi_hello.aiff differ diff --git a/mods/character-select-coop/sound/13_waluigi_press_start_to_play.aiff b/mods/character-select-coop/sound/13_waluigi_press_start_to_play.aiff new file mode 100644 index 000000000..5d8aebd3c Binary files /dev/null and b/mods/character-select-coop/sound/13_waluigi_press_start_to_play.aiff differ diff --git a/mods/character-select-coop/sound/14_waluigi_twirl_bounce.aiff b/mods/character-select-coop/sound/14_waluigi_twirl_bounce.aiff new file mode 100644 index 000000000..a0a60e296 Binary files /dev/null and b/mods/character-select-coop/sound/14_waluigi_twirl_bounce.aiff differ diff --git a/mods/character-select-coop/sound/15_waluigi_snoring3.aiff b/mods/character-select-coop/sound/15_waluigi_snoring3.aiff new file mode 100644 index 000000000..04c5a4390 Binary files /dev/null and b/mods/character-select-coop/sound/15_waluigi_snoring3.aiff differ diff --git a/mods/character-select-coop/sound/16_waluigi_so_longa_bowser.aiff b/mods/character-select-coop/sound/16_waluigi_so_longa_bowser.aiff new file mode 100644 index 000000000..e9ef5989f Binary files /dev/null and b/mods/character-select-coop/sound/16_waluigi_so_longa_bowser.aiff differ diff --git a/mods/character-select-coop/sound/17_waluigi_tired.aiff b/mods/character-select-coop/sound/17_waluigi_tired.aiff new file mode 100644 index 000000000..9c61ce7b5 Binary files /dev/null and b/mods/character-select-coop/sound/17_waluigi_tired.aiff differ diff --git a/mods/character-select-coop/sound/18_waluigi_waha.aiff b/mods/character-select-coop/sound/18_waluigi_waha.aiff new file mode 100644 index 000000000..397c7c0ce Binary files /dev/null and b/mods/character-select-coop/sound/18_waluigi_waha.aiff differ diff --git a/mods/character-select-coop/sound/19_waluigi_yippee.aiff b/mods/character-select-coop/sound/19_waluigi_yippee.aiff new file mode 100644 index 000000000..26a1883e3 Binary files /dev/null and b/mods/character-select-coop/sound/19_waluigi_yippee.aiff differ diff --git a/mods/character-select-coop/sound/1A_waluigi_lets_a_go.aiff b/mods/character-select-coop/sound/1A_waluigi_lets_a_go.aiff new file mode 100644 index 000000000..38d5d2193 Binary files /dev/null and b/mods/character-select-coop/sound/1A_waluigi_lets_a_go.aiff differ diff --git a/mods/character-select-coop/sound/char_select_dial_wind.ogg b/mods/character-select-coop/sound/char_select_dial_wind.ogg new file mode 100644 index 000000000..624c841c0 Binary files /dev/null and b/mods/character-select-coop/sound/char_select_dial_wind.ogg differ diff --git a/mods/character-select-coop/sound/char_select_menu_theme.ogg b/mods/character-select-coop/sound/char_select_menu_theme.ogg new file mode 100644 index 000000000..4de7bd194 Binary files /dev/null and b/mods/character-select-coop/sound/char_select_menu_theme.ogg differ 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 deleted file mode 100644 index 08c151266..000000000 Binary files a/mods/character-select-coop/textures/char-select-luigi-meter-left.tex and /dev/null differ diff --git a/mods/character-select-coop/textures/char-select-luigi-meter-right.tex b/mods/character-select-coop/textures/char-select-luigi-meter-right.tex deleted file mode 100644 index 5fabcaab5..000000000 Binary files a/mods/character-select-coop/textures/char-select-luigi-meter-right.tex and /dev/null differ diff --git a/mods/character-select-coop/textures/char-select-text.tex b/mods/character-select-coop/textures/char-select-text.tex deleted file mode 100644 index f679a2db4..000000000 Binary files a/mods/character-select-coop/textures/char-select-text.tex and /dev/null differ diff --git a/mods/character-select-coop/textures/char-select-toad-meter-left.tex b/mods/character-select-coop/textures/char-select-toad-meter-left.tex deleted file mode 100644 index b2dcc45c9..000000000 Binary files a/mods/character-select-coop/textures/char-select-toad-meter-left.tex and /dev/null differ 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 deleted file mode 100644 index b796d4495..000000000 Binary files a/mods/character-select-coop/textures/char-select-toad-meter-right.tex and /dev/null differ diff --git a/mods/character-select-coop/textures/char-select-triangle.tex b/mods/character-select-coop/textures/char-select-triangle.tex deleted file mode 100644 index 339ea23de..000000000 Binary files a/mods/character-select-coop/textures/char-select-triangle.tex and /dev/null differ diff --git a/mods/character-select-coop/textures/char-select-waluigi-meter-left.tex b/mods/character-select-coop/textures/char-select-waluigi-meter-left.tex deleted file mode 100644 index 800402e81..000000000 Binary files a/mods/character-select-coop/textures/char-select-waluigi-meter-left.tex and /dev/null differ diff --git a/mods/character-select-coop/textures/char-select-waluigi-meter-right.tex b/mods/character-select-coop/textures/char-select-waluigi-meter-right.tex deleted file mode 100644 index a6dff0e79..000000000 Binary files a/mods/character-select-coop/textures/char-select-waluigi-meter-right.tex and /dev/null differ 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 deleted file mode 100644 index c36242673..000000000 Binary files a/mods/character-select-coop/textures/char-select-wario-meter-left.tex and /dev/null differ diff --git a/mods/character-select-coop/textures/char-select-wario-meter-right.tex b/mods/character-select-coop/textures/char-select-wario-meter-right.tex deleted file mode 100644 index 41e0f7119..000000000 Binary files a/mods/character-select-coop/textures/char-select-wario-meter-right.tex and /dev/null differ diff --git a/mods/character-select-coop/textures/char_select_album_back.tex b/mods/character-select-coop/textures/char_select_album_back.tex new file mode 100644 index 000000000..4294d3bb3 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_album_back.tex differ diff --git a/mods/character-select-coop/textures/char_select_album_front.tex b/mods/character-select-coop/textures/char_select_album_front.tex new file mode 100644 index 000000000..36d5d728a Binary files /dev/null and b/mods/character-select-coop/textures/char_select_album_front.tex differ diff --git a/mods/character-select-coop/textures/char_select_album_overlay.tex b/mods/character-select-coop/textures/char_select_album_overlay.tex new file mode 100644 index 000000000..40a4c8fa6 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_album_overlay.tex differ diff --git a/mods/character-select-coop/textures/char_select_category.tex b/mods/character-select-coop/textures/char_select_category.tex new file mode 100644 index 000000000..bdfdc1380 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_category.tex differ diff --git a/mods/character-select-coop/textures/char_select_caution_tape.tex b/mods/character-select-coop/textures/char_select_caution_tape.tex new file mode 100644 index 000000000..e4ec0292a Binary files /dev/null and b/mods/character-select-coop/textures/char_select_caution_tape.tex differ diff --git a/mods/character-select-coop/textures/char_select_cd_layer1.tex b/mods/character-select-coop/textures/char_select_cd_layer1.tex new file mode 100644 index 000000000..a4ef216aa Binary files /dev/null and b/mods/character-select-coop/textures/char_select_cd_layer1.tex differ diff --git a/mods/character-select-coop/textures/char_select_cd_layer2.tex b/mods/character-select-coop/textures/char_select_cd_layer2.tex new file mode 100644 index 000000000..5366e59b2 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_cd_layer2.tex differ diff --git a/mods/character-select-coop/textures/char_select_cd_layer3.tex b/mods/character-select-coop/textures/char_select_cd_layer3.tex new file mode 100644 index 000000000..0c063241f Binary files /dev/null and b/mods/character-select-coop/textures/char_select_cd_layer3.tex differ diff --git a/mods/character-select-coop/textures/char_select_cd_layer4.tex b/mods/character-select-coop/textures/char_select_cd_layer4.tex new file mode 100644 index 000000000..546654433 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_cd_layer4.tex differ 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 similarity index 98% rename from mods/character-select-coop/textures/char-select-custom-course-bottom.tex rename to mods/character-select-coop/textures/char_select_custom_course_bottom.tex index 05ed93274..a947596f2 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-course-bottom.tex and b/mods/character-select-coop/textures/char_select_custom_course_bottom.tex differ diff --git a/mods/character-select-coop/textures/char-select-custom-course-top.tex b/mods/character-select-coop/textures/char_select_custom_course_top.tex similarity index 99% rename from mods/character-select-coop/textures/char-select-custom-course-top.tex rename to mods/character-select-coop/textures/char_select_custom_course_top.tex index 259fc4f16..4e0a07de0 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-course-top.tex and b/mods/character-select-coop/textures/char_select_custom_course_top.tex differ 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 similarity index 97% rename from mods/character-select-coop/textures/char-select-custom-meter-left.tex rename to mods/character-select-coop/textures/char_select_custom_meter_left.tex index 228d3d0d5..2e6fe7821 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-meter-left.tex and b/mods/character-select-coop/textures/char_select_custom_meter_left.tex differ 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 similarity index 96% rename from mods/character-select-coop/textures/char-select-custom-meter-pie1.tex rename to mods/character-select-coop/textures/char_select_custom_meter_pie1.tex index a835772fc..6e1925084 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-meter-pie1.tex and b/mods/character-select-coop/textures/char_select_custom_meter_pie1.tex differ 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 similarity index 96% rename from mods/character-select-coop/textures/char-select-custom-meter-pie2.tex rename to mods/character-select-coop/textures/char_select_custom_meter_pie2.tex index bcd8e25b5..7dd6de86d 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-meter-pie2.tex and b/mods/character-select-coop/textures/char_select_custom_meter_pie2.tex differ diff --git a/mods/character-select-coop/textures/char-select-custom-meter-pie3.tex b/mods/character-select-coop/textures/char_select_custom_meter_pie3.tex similarity index 96% rename from mods/character-select-coop/textures/char-select-custom-meter-pie3.tex rename to mods/character-select-coop/textures/char_select_custom_meter_pie3.tex index 18e45d7b9..1309ea3e9 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-meter-pie3.tex and b/mods/character-select-coop/textures/char_select_custom_meter_pie3.tex differ diff --git a/mods/character-select-coop/textures/char-select-custom-meter-pie4.tex b/mods/character-select-coop/textures/char_select_custom_meter_pie4.tex similarity index 96% rename from mods/character-select-coop/textures/char-select-custom-meter-pie4.tex rename to mods/character-select-coop/textures/char_select_custom_meter_pie4.tex index 3fd474be7..86ffca8cb 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-meter-pie4.tex and b/mods/character-select-coop/textures/char_select_custom_meter_pie4.tex differ diff --git a/mods/character-select-coop/textures/char-select-custom-meter-pie5.tex b/mods/character-select-coop/textures/char_select_custom_meter_pie5.tex similarity index 96% rename from mods/character-select-coop/textures/char-select-custom-meter-pie5.tex rename to mods/character-select-coop/textures/char_select_custom_meter_pie5.tex index 3fb01c880..4cd145b57 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-meter-pie5.tex and b/mods/character-select-coop/textures/char_select_custom_meter_pie5.tex differ diff --git a/mods/character-select-coop/textures/char-select-custom-meter-pie6.tex b/mods/character-select-coop/textures/char_select_custom_meter_pie6.tex similarity index 96% rename from mods/character-select-coop/textures/char-select-custom-meter-pie6.tex rename to mods/character-select-coop/textures/char_select_custom_meter_pie6.tex index fbf2f59d5..c20718be8 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-meter-pie6.tex and b/mods/character-select-coop/textures/char_select_custom_meter_pie6.tex differ 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 similarity index 97% rename from mods/character-select-coop/textures/char-select-custom-meter-pie7.tex rename to mods/character-select-coop/textures/char_select_custom_meter_pie7.tex index 2c9e6c634..b9eab15fb 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-meter-pie7.tex and b/mods/character-select-coop/textures/char_select_custom_meter_pie7.tex differ 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 similarity index 97% rename from mods/character-select-coop/textures/char-select-custom-meter-pie8.tex rename to mods/character-select-coop/textures/char_select_custom_meter_pie8.tex index 07acd535b..ecb1b59d6 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-meter-pie8.tex and b/mods/character-select-coop/textures/char_select_custom_meter_pie8.tex differ 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 similarity index 97% rename from mods/character-select-coop/textures/char-select-custom-meter-right.tex rename to mods/character-select-coop/textures/char_select_custom_meter_right.tex index 94047be19..ce552f94d 100644 Binary files a/mods/character-select-coop/textures/char-select-custom-meter-right.tex and b/mods/character-select-coop/textures/char_select_custom_meter_right.tex differ diff --git a/mods/character-select-coop/textures/char_select_font_brick.tex b/mods/character-select-coop/textures/char_select_font_brick.tex new file mode 100644 index 000000000..ec9dfa3b1 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_font_brick.tex differ diff --git a/mods/character-select-coop/textures/char_select_font_characteristic.tex b/mods/character-select-coop/textures/char_select_font_characteristic.tex new file mode 100644 index 000000000..f4f785bcf Binary files /dev/null and b/mods/character-select-coop/textures/char_select_font_characteristic.tex differ diff --git a/mods/character-select-coop/textures/char_select_gear.tex b/mods/character-select-coop/textures/char_select_gear.tex new file mode 100644 index 000000000..fac9453fa Binary files /dev/null and b/mods/character-select-coop/textures/char_select_gear.tex differ diff --git a/mods/character-select-coop/textures/char_select_graffiti_default.tex b/mods/character-select-coop/textures/char_select_graffiti_default.tex new file mode 100644 index 000000000..4c153abfc Binary files /dev/null and b/mods/character-select-coop/textures/char_select_graffiti_default.tex differ diff --git a/mods/character-select-coop/textures/char_select_graffiti_luigi.tex b/mods/character-select-coop/textures/char_select_graffiti_luigi.tex new file mode 100644 index 000000000..95683dba7 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_graffiti_luigi.tex differ diff --git a/mods/character-select-coop/textures/char_select_graffiti_mario.tex b/mods/character-select-coop/textures/char_select_graffiti_mario.tex new file mode 100644 index 000000000..3aa877572 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_graffiti_mario.tex differ diff --git a/mods/character-select-coop/textures/char_select_graffiti_toad.tex b/mods/character-select-coop/textures/char_select_graffiti_toad.tex new file mode 100644 index 000000000..aaa4eadd2 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_graffiti_toad.tex differ diff --git a/mods/character-select-coop/textures/char_select_graffiti_waluigi.tex b/mods/character-select-coop/textures/char_select_graffiti_waluigi.tex new file mode 100644 index 000000000..d616c1956 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_graffiti_waluigi.tex differ diff --git a/mods/character-select-coop/textures/char_select_graffiti_wario.tex b/mods/character-select-coop/textures/char_select_graffiti_wario.tex new file mode 100644 index 000000000..6f65b8869 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_graffiti_wario.tex differ diff --git a/mods/character-select-coop/textures/char_select_icon_signs.tex b/mods/character-select-coop/textures/char_select_icon_signs.tex new file mode 100644 index 000000000..2a61eb5a6 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_icon_signs.tex differ diff --git a/mods/character-select-coop/textures/char_select_list_button.tex b/mods/character-select-coop/textures/char_select_list_button.tex new file mode 100644 index 000000000..620ee55d9 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_list_button.tex differ diff --git a/mods/character-select-coop/textures/char_select_logo.tex b/mods/character-select-coop/textures/char_select_logo.tex new file mode 100644 index 000000000..045b3d9d3 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_logo.tex differ 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 000000000..5cad15deb Binary files /dev/null and b/mods/character-select-coop/textures/char_select_luigi_meter_left.tex differ diff --git a/mods/character-select-coop/textures/char_select_luigi_meter_right.tex b/mods/character-select-coop/textures/char_select_luigi_meter_right.tex new file mode 100644 index 000000000..0b0b3d242 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_luigi_meter_right.tex differ diff --git a/mods/character-select-coop/textures/char_select_nameplate.tex b/mods/character-select-coop/textures/char_select_nameplate.tex new file mode 100644 index 000000000..9e5c9cdb3 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_nameplate.tex differ diff --git a/mods/character-select-coop/textures/char_select_options_tv.tex b/mods/character-select-coop/textures/char_select_options_tv.tex new file mode 100644 index 000000000..b2f0e8b8c Binary files /dev/null and b/mods/character-select-coop/textures/char_select_options_tv.tex differ diff --git a/mods/character-select-coop/textures/char_select_palette_bucket.tex b/mods/character-select-coop/textures/char_select_palette_bucket.tex new file mode 100644 index 000000000..431685d07 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_palette_bucket.tex differ diff --git a/mods/character-select-coop/textures/char_select_record.tex b/mods/character-select-coop/textures/char_select_record.tex new file mode 100644 index 000000000..9ed0c0976 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_record.tex differ diff --git a/mods/character-select-coop/textures/char_select_toad_meter_left.tex b/mods/character-select-coop/textures/char_select_toad_meter_left.tex new file mode 100644 index 000000000..3b12f4560 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_toad_meter_left.tex differ 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 000000000..5934bc310 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_toad_meter_right.tex differ diff --git a/mods/character-select-coop/textures/char_select_wall_left.tex b/mods/character-select-coop/textures/char_select_wall_left.tex new file mode 100644 index 000000000..502ea34b9 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_wall_left.tex differ diff --git a/mods/character-select-coop/textures/char_select_wall_right.tex b/mods/character-select-coop/textures/char_select_wall_right.tex new file mode 100644 index 000000000..e5e557e56 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_wall_right.tex differ diff --git a/mods/character-select-coop/textures/char_select_waluigi_meter_left.tex b/mods/character-select-coop/textures/char_select_waluigi_meter_left.tex new file mode 100644 index 000000000..2b07ec117 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_waluigi_meter_left.tex differ diff --git a/mods/character-select-coop/textures/char_select_waluigi_meter_right.tex b/mods/character-select-coop/textures/char_select_waluigi_meter_right.tex new file mode 100644 index 000000000..27daf6c44 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_waluigi_meter_right.tex differ 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 000000000..636030a33 Binary files /dev/null and b/mods/character-select-coop/textures/char_select_wario_meter_left.tex differ diff --git a/mods/character-select-coop/textures/char_select_wario_meter_right.tex b/mods/character-select-coop/textures/char_select_wario_meter_right.tex new file mode 100644 index 000000000..e07d6f95d Binary files /dev/null and b/mods/character-select-coop/textures/char_select_wario_meter_right.tex differ diff --git a/mods/character-select-coop/voice.lua b/mods/character-select-coop/voice.lua new file mode 100644 index 000000000..5f9f9be1c --- /dev/null +++ b/mods/character-select-coop/voice.lua @@ -0,0 +1,385 @@ +if incompatibleClient then return 0 end + +local TYPE_TABLE = "table" +local TYPE_USERDATA = "userdata" +local TYPE_STRING = "string" + +local SLEEP_TALK_SNORES = 8 +local STARTING_SNORE = 46 +local SLEEP_TALK_START = STARTING_SNORE + 49 +local SLEEP_TALK_END = SLEEP_TALK_START + SLEEP_TALK_SNORES +local stallTimer = 0 +local stallSayLine = 5 + +characterVoices = { + [E_MODEL_WALUIGI] = { + [CHAR_SOUND_OKEY_DOKEY] = audio_sample_load('0B_waluigi_okey_dokey.aiff'), + [CHAR_SOUND_LETS_A_GO] = audio_sample_load('1A_waluigi_lets_a_go.aiff'), + [CHAR_SOUND_GAME_OVER] = audio_sample_load('11_waluigi_game_over.aiff'), + [CHAR_SOUND_PUNCH_YAH] = audio_sample_load('08_waluigi_punch_yah.aiff'), + [CHAR_SOUND_PUNCH_WAH] = audio_sample_load('01_waluigi_jump_wah.aiff'), + [CHAR_SOUND_PUNCH_HOO] = audio_sample_load('09_waluigi_punch_hoo.aiff'), + [CHAR_SOUND_YAH_WAH_HOO] = {audio_sample_load('00_waluigi_jump_hoo.aiff'), audio_sample_load('01_waluigi_jump_wah.aiff'), audio_sample_load('02_waluigi_yah.aiff')}, + [CHAR_SOUND_HOOHOO] = audio_sample_load('01_waluigi_hoohoo.aiff'), + [CHAR_SOUND_YAHOO_WAHA_YIPPEE] = {audio_sample_load('04_waluigi_yahoo.aiff'), audio_sample_load('18_waluigi_waha.aiff'), audio_sample_load('19_waluigi_yippee.aiff')}, + [CHAR_SOUND_UH] = audio_sample_load('05_waluigi_uh.aiff'), + [CHAR_SOUND_UH2] = audio_sample_load('05_waluigi_uh2.aiff'), + [CHAR_SOUND_UH2_2] = audio_sample_load('05_waluigi_uh2.aiff'), + [CHAR_SOUND_DOH] = audio_sample_load('10_waluigi_doh.aiff'), + [CHAR_SOUND_OOOF] = audio_sample_load('0B_waluigi_ooof.aiff'), + [CHAR_SOUND_OOOF2] = audio_sample_load('0B_waluigi_ooof.aiff'), + [CHAR_SOUND_HAHA] = audio_sample_load('03_waluigi_haha.aiff'), + [CHAR_SOUND_HAHA_2] = audio_sample_load('03_waluigi_haha.aiff'), + [CHAR_SOUND_YAHOO] = audio_sample_load('04_waluigi_yahoo.aiff'), + [CHAR_SOUND_DOH] = audio_sample_load('10_waluigi_doh.aiff'), + [CHAR_SOUND_WHOA] = audio_sample_load('08_waluigi_whoa.aiff'), + [CHAR_SOUND_EEUH] = audio_sample_load('09_waluigi_eeuh.aiff'), + [CHAR_SOUND_WAAAOOOW] = audio_sample_load('00_waluigi_waaaooow.aiff'), + [CHAR_SOUND_TWIRL_BOUNCE] = audio_sample_load('14_waluigi_twirl_bounce.aiff'), + [CHAR_SOUND_GROUND_POUND_WAH] = audio_sample_load('01_waluigi_jump_wah.aiff'), + [CHAR_SOUND_WAH2] = audio_sample_load('07_waluigi_wah2.aiff'), + [CHAR_SOUND_HRMM] = audio_sample_load('06_waluigi_hrmm.aiff'), + [CHAR_SOUND_HERE_WE_GO] = audio_sample_load('0C_waluigi_here_we_go.aiff'), + [CHAR_SOUND_SO_LONGA_BOWSER] = audio_sample_load('16_waluigi_so_longa_bowser.aiff'), + -- DAMAGE + [CHAR_SOUND_ATTACKED] = audio_sample_load('0A_waluigi_attacked.aiff'), + [CHAR_SOUND_PANTING] = audio_sample_load('02_waluigi_panting.aiff'), + [CHAR_SOUND_PANTING_COLD] = audio_sample_load('02_waluigi_panting.aiff'), + [CHAR_SOUND_ON_FIRE] = audio_sample_load('04_waluigi_on_fire.aiff'), + -- SLEEP SOUNDS + [CHAR_SOUND_IMA_TIRED] = audio_sample_load('17_waluigi_tired.aiff'), + [CHAR_SOUND_YAWNING] = audio_sample_load('0D_waluigi_yawning.aiff'), + [CHAR_SOUND_SNORING1] = audio_sample_load('0E_waluigi_snoring1.aiff'), + [CHAR_SOUND_SNORING2] = audio_sample_load('0F_waluigi_snoring2.aiff'), + [CHAR_SOUND_SNORING3] = audio_sample_load('15_waluigi_snoring3.aiff'), + -- COUGHING + [CHAR_SOUND_COUGHING1] = audio_sample_load('06_waluigi_coughing.aiff'), + [CHAR_SOUND_COUGHING2] = audio_sample_load('06_waluigi_coughing.aiff'), + [CHAR_SOUND_COUGHING3] = audio_sample_load('06_waluigi_coughing.aiff'), + -- DEATH + [CHAR_SOUND_DYING] = audio_sample_load('03_waluigi_dying.aiff'), + [CHAR_SOUND_DROWNING] = audio_sample_load('0C_waluigi_drowning.aiff'), + [CHAR_SOUND_MAMA_MIA] = audio_sample_load('0A_waluigi_mama_mia.aiff') + } +} + +local levelReverbs = { + [LEVEL_NONE] = { 0x00, 0x00, 0x00 }, + [LEVEL_UNKNOWN_1] = { 0x00, 0x00, 0x00 }, + [LEVEL_UNKNOWN_2] = { 0x00, 0x00, 0x00 }, + [LEVEL_UNKNOWN_3] = { 0x00, 0x00, 0x00 }, + [LEVEL_BBH] = { 0x28, 0x28, 0x28 }, + [LEVEL_CCM] = { 0x10, 0x38, 0x38 }, + [LEVEL_CASTLE] = { 0x20, 0x20, 0x30 }, + [LEVEL_HMC] = { 0x28, 0x28, 0x28 }, + [LEVEL_SSL] = { 0x08, 0x30, 0x30 }, + [LEVEL_BOB] = { 0x08, 0x08, 0x08 }, + [LEVEL_SL] = { 0x10, 0x28, 0x28 }, + [LEVEL_WDW] = { 0x10, 0x18, 0x18 }, + [LEVEL_JRB] = { 0x10, 0x18, 0x18 }, + [LEVEL_THI] = { 0x0c, 0x0c, 0x20 }, + [LEVEL_TTC] = { 0x18, 0x18, 0x18 }, + [LEVEL_RR] = { 0x20, 0x20, 0x20 }, + [LEVEL_CASTLE_GROUNDS] = { 0x08, 0x08, 0x08 }, + [LEVEL_BITDW] = { 0x28, 0x28, 0x28 }, + [LEVEL_VCUTM] = { 0x28, 0x28, 0x28 }, + [LEVEL_BITFS] = { 0x28, 0x28, 0x28 }, + [LEVEL_SA] = { 0x10, 0x10, 0x10 }, + [LEVEL_BITS] = { 0x28, 0x28, 0x28 }, + [LEVEL_LLL] = { 0x08, 0x30, 0x30 }, + [LEVEL_DDD] = { 0x10, 0x20, 0x20 }, + [LEVEL_WF] = { 0x08, 0x08, 0x08 }, + [LEVEL_ENDING] = { 0x00, 0x00, 0x00 }, + [LEVEL_CASTLE_COURTYARD] = { 0x08, 0x08, 0x08 }, + [LEVEL_PSS] = { 0x28, 0x28, 0x28 }, + [LEVEL_COTMC] = { 0x28, 0x28, 0x28 }, + [LEVEL_TOTWC] = { 0x20, 0x20, 0x20 }, + [LEVEL_BOWSER_1] = { 0x40, 0x40, 0x40 }, + [LEVEL_WMOTR] = { 0x28, 0x28, 0x28 }, + [LEVEL_UNKNOWN_32] = { 0x70, 0x00, 0x00 }, + [LEVEL_BOWSER_2] = { 0x40, 0x40, 0x40 }, + [LEVEL_BOWSER_3] = { 0x40, 0x40, 0x40 }, + [LEVEL_UNKNOWN_35] = { 0x00, 0x00, 0x00 }, + [LEVEL_TTM] = { 0x08, 0x08, 0x08 }, + [LEVEL_UNKNOWN_37] = { 0x00, 0x00, 0x00 }, + [LEVEL_UNKNOWN_38] = { 0x00, 0x00, 0x00 }, +} + +local stalledAudio = {} + +---@param sample ModAudio +---@param pos Vec3f +---@param baseVolume number +---@param reverbAmount number (0 to 1, where 1 = full echo effect) +local function play_sound_with_reverb(sample, pos, baseVolume, reverbAmount) + if is_game_paused() or optionTable[optionTableRef.localVoices].toggle == 0 then return end + -- Play the original sample + audio_sample_play(sample, pos, baseVolume) + + -- Define simple fake reverb delays and volume reductions + local echoDelays = { 0.1, 0.2, 0.35, 0.5 } + local echoVolumes = { + baseVolume * reverbAmount * 0.6, + baseVolume * reverbAmount * 0.4, + baseVolume * reverbAmount * 0.25, + baseVolume * reverbAmount * 0.15, + } + + for i = 1, #echoDelays do + table.insert(stalledAudio, { + path = sample.filepath, + frame = (get_global_timer() + math.floor(echoDelays[i]*30)), + sample = sample, + pos = pos, + volume = echoVolumes[i] + }) + end +end + + +---@param sample ModAudio +local function stop_sound_with_reverb(sample) + audio_sample_stop(sample) + if #stalledAudio > 0 then + for i = #stalledAudio, 1, -1 do + if stalledAudio[i] ~= nil and stalledAudio[i].path == sample.filepath then + audio_sample_stop(stalledAudio[i].sample) + table.remove(stalledAudio, i) + end + end + end +end + +local function stop_all_custom_character_sounds() + -- run through each player + for i = 0, MAX_PLAYERS - 1 do + local m = gMarioStates[i] + -- get the voice table, if there is one + local voiceTable = character_get_voice(m) + if voiceTable ~= nil then + -- run through each sample + for sound in pairs(voiceTable) do + -- if the sample is found, try to stop it + if voiceTable[sound] ~= nil and type(voiceTable[sound]) ~= "string" then + -- if there's no pointer then it must be a sound clip table + if voiceTable[sound]._pointer == nil then + for voice in pairs(voiceTable[sound]) do + if type(voiceTable[sound][voice]) == "string" then + break + end + stop_sound_with_reverb(voiceTable[sound][voice]) + end + else + stop_sound_with_reverb(voiceTable[sound]) + end + end + end + end + end +end + +local playerSample = {} +for i = 0, MAX_PLAYERS - 1 do + playerSample[i] = nil +end + +local characterAddonSounds = { + [CHAR_SOUND_PUNCH_YAH] = {sound = SOUND_ACTION_THROW, pitch = 1.1}, + [CHAR_SOUND_PUNCH_WAH] = {sound = SOUND_ACTION_THROW, pitch = 1.0}, + [CHAR_SOUND_PUNCH_HOO] = {sound = SOUND_ACTION_THROW, pitch = 0.9}, +} + +---@param m MarioState +---@param sound CharacterSound +---@param pos Vec3f? +function custom_character_sound(m, sound, pos) + local np = gNetworkPlayers[m.playerIndex] + local voiceTable = character_get_voice(m) + local voiceToggle = optionTable[optionTableRef.localVoices].toggle + local voiceOff = (voiceToggle == 0 or (voiceToggle == 2 and m.playerIndex ~= 0)) + if m.playerIndex == 0 then + if not startup_init_stall() then + return NO_SOUND + end + end + local index = m.playerIndex + if playerSample[index] ~= nil and type(playerSample[index]) ~= TYPE_STRING then + stop_sound_with_reverb(playerSample[index]) + end + + -- Add punch "woosh" since NO_SOUND removes it + if characterAddonSounds[sound] and (voiceTable ~= nil or voiceOff) then + local soundInfo = characterAddonSounds[sound] + play_sound_with_freq_scale(soundInfo.sound, m.marioObj.header.gfx.cameraToObject, soundInfo.pitch); + end + + -- Voice Toggle + if voiceOff then return NO_SOUND end + + -- Vanilla Voicelines + if voiceTable == nil then return end + + -- Load the appropriate sample + local voice = character_get_voice(m)[sound] + if voice == nil then return NO_SOUND end + if type(voice) == TYPE_TABLE then + if #voice > 0 then + playerSample[index] = voice[math.random(1, #voice)] + else + return NO_SOUND + end + else + playerSample[index] = voice + end + + -- Play the sample + -- Volume based on sound type + local baseVolume = 1.0 + if sound == CHAR_SOUND_SNORING1 or sound == CHAR_SOUND_SNORING2 or sound == CHAR_SOUND_SNORING3 then + baseVolume = 0.5 + end + + local position = pos or m.pos + local reverbAmount = 0x08 + if levelReverbs[np.currLevelNum] ~= nil and levelReverbs[np.currLevelNum][np.currAreaIndex] ~= nil then + reverbAmount = levelReverbs[np.currLevelNum][np.currAreaIndex]/127 + elseif smlua_level_util_get_info(np.currLevelNum) ~= nil then + local levelInfo = smlua_level_util_get_info(np.currLevelNum) + levelReverbs[np.currLevelNum] = {} + levelReverbs[np.currLevelNum][1] = levelInfo.echoLevel1 or reverbAmount + levelReverbs[np.currLevelNum][2] = levelInfo.echoLevel2 or reverbAmount + levelReverbs[np.currLevelNum][3] = levelInfo.echoLevel3 or reverbAmount + reverbAmount = levelReverbs[np.currLevelNum][np.currAreaIndex]/127 + else + reverbAmount = levelReverbs[np.currLevelNum][1]/127 + end + + play_sound_with_reverb(playerSample[index], position, baseVolume, reverbAmount) + + return NO_SOUND +end + +---@param m MarioState +function custom_character_snore(m) + if is_game_paused() or optionTable[optionTableRef.localVoices].toggle == 0 or (optionTable[optionTableRef.localVoices].toggle == 2 and m.playerIndex ~= 0) then + -- Remove echo lines that should have played while paused + if #stalledAudio > 0 then + for i = 1, #stalledAudio do + if stalledAudio[i] ~= nil and stalledAudio[i].frame <= get_global_timer() then + table.remove(stalledAudio, i) + end + end + end + return + end + + -- Putting echo stuffs in snore since it's on update + if #stalledAudio > 0 then + for i = 1, #stalledAudio do + if stalledAudio[i] ~= nil and stalledAudio[i].frame <= get_global_timer() then + local voice = stalledAudio[i] + audio_sample_play(voice.sample, voice.pos, voice.volume) + table.remove(stalledAudio, i) + end + end + end + + if m.action ~= ACT_SLEEPING then + return + elseif m.actionState ~= 2 or (m.flags & MARIO_MARIO_SOUND_PLAYED) == 0 then + return + end + + -- get the voice table + local voiceTable = character_get_voice(m) + -- Check nil table for vanilla voices + if voiceTable == nil then return end + -- Check empty table for no sound + if voiceTable == nil then return NO_SOUND end + + local snoreTable = voiceTable[CHAR_SOUND_SNORING3] + if snoreTable == nil or snoreTable._pointer ~= nil then + snoreTable = {} + for i = CHAR_SOUND_SNORING1, CHAR_SOUND_SNORING3 do + if voiceTable[i] ~= nil then + table.insert(snoreTable, voiceTable[i]) + end + end + end + + local animFrame = m.marioObj.header.gfx.animInfo.animFrame + if snoreTable ~= nil and #snoreTable >= 2 then + if animFrame == 2 and m.actionTimer < SLEEP_TALK_START then + custom_character_sound(m, snoreTable[2]) + elseif animFrame == 25 then + if #snoreTable >= 3 then + m.actionTimer = m.actionTimer + 1 + if m.actionTimer >= SLEEP_TALK_END then + m.actionTimer = STARTING_SNORE + end + if m.actionTimer == SLEEP_TALK_START then + play_character_sound(m, CHAR_SOUND_SNORING3) + elseif m.actionTimer < SLEEP_TALK_START then + play_character_sound(m, CHAR_SOUND_SNORING1) + end + else + play_character_sound(m, CHAR_SOUND_SNORING1) + end + end + elseif animFrame == 2 then + play_character_sound(m, CHAR_SOUND_SNORING2) + + elseif animFrame == 25 then + play_character_sound(m, CHAR_SOUND_SNORING1) + end +end + +local function update() + if is_game_paused() then + stop_all_custom_character_sounds() + end +end + +hook_event(HOOK_UPDATE, update) +hook_event(HOOK_ON_LEVEL_INIT, stop_all_custom_character_sounds) + +function config_character_sounds() + log_to_console_once("'config_character_sounds' is deprecated, and functionality is now baked into `character_add_voice`", CONSOLE_MESSAGE_WARNING) +end + +-- Join sound +introLine = false +local function mario_update(m) + if m.playerIndex ~= 0 then return end + if startup_init_stall() and not introLine then + if m.action ~= ACT_INTRO_CUTSCENE then + play_character_sound(m, CHAR_SOUND_OKEY_DOKEY) + end + introLine = true + end + + custom_character_snore(m) +end + +hook_event(HOOK_CHARACTER_SOUND, custom_character_sound) +cs_hook_mario_update(mario_update) + +-- Peach Line Replacements +---@param soundbits integer +---@param pos Vec3f +local function on_play_sound(soundbits,pos) + local endpeachsoundtable = {[SOUND_PEACH_MARIO] = true,[SOUND_PEACH_POWER_OF_THE_STARS] = true,[SOUND_PEACH_THANKS_TO_YOU] = true, [SOUND_PEACH_THANK_YOU_MARIO] = true,[SOUND_PEACH_SOMETHING_SPECIAL] = true,[SOUND_PEACH_BAKE_A_CAKE] = true,[SOUND_PEACH_FOR_MARIO] = true,[SOUND_PEACH_MARIO2] = true} + local m = gMarioStates[0] + if endpeachsoundtable[soundbits] and (character_get_voice(m) ~= nil) and (character_get_voice(m)[soundbits] ~= nil) then --ending peach cutscene sounds + custom_character_sound(m,soundbits,pos) + return NO_SOUND + elseif (soundbits == SOUND_PEACH_DEAR_MARIO) and (character_get_voice(m) ~= nil) and (character_get_voice(m)[soundbits] ~= nil) then --introduction peach sounds + custom_character_sound(m,soundbits,pos) + return NO_SOUND + elseif (soundbits == SOUND_MENU_THANK_YOU_PLAYING_MY_GAME) and (character_get_voice(m) ~= nil) and (character_get_voice(m)[soundbits] ~= nil) then --cake screen thank you for playing my game voice + custom_character_sound(m,soundbits,pos) + return NO_SOUND + end +end + +hook_event(HOOK_ON_PLAY_SOUND, on_play_sound) diff --git a/mods/character-select-coop/o-api.lua b/mods/character-select-coop/z-api.lua similarity index 52% rename from mods/character-select-coop/o-api.lua rename to mods/character-select-coop/z-api.lua index b939f5447..77f7df648 100644 --- a/mods/character-select-coop/o-api.lua +++ b/mods/character-select-coop/z-api.lua @@ -1,48 +1,15 @@ if incompatibleClient then return 0 end --- localize functions to improve performance - o-api.lua -local table_insert,djui_hud_measure_text,smlua_model_util_get_id,type,tonumber = table.insert,djui_hud_measure_text,smlua_model_util_get_id,type,tonumber - ---- @class CharacterTable ---- @field public name string ---- @field public saveName string ---- @field public description table ---- @field public credit string ---- @field public color Color ---- @field public model ModelExtendedId|integer ---- @field public forceChar CharacterType ---- @field public lifeIcon TextureInfo ---- @field public camScale integer - -local characterVoices = {} -local saveNameTable = {} - --- Here for functions below api ----@ignore -local function placeholder() end - ----@ignore -local function split_text_into_lines(text) - local words = {} - for word in text:gmatch("%S+") do - table_insert(words, word) - end - - local lines = {} - local currentLine = "" - for i, word in ipairs(words) do - local measuredWidth = djui_hud_measure_text(currentLine .. " " .. word)*0.3 - if measuredWidth <= 100 then - currentLine = currentLine .. " " .. word - else - table_insert(lines, currentLine) - currentLine = word - end - end - table_insert(lines, currentLine) -- add the last line - - return lines -end +---@class CharacterTable +---@field public name string +---@field public saveName string +---@field public description table +---@field public credit string +---@field public color Color +---@field public model ModelExtendedId|integer +---@field public baseChar CharacterType +---@field public lifeIcon TextureInfo +---@field public camScale integer local TYPE_INTEGER = "number" local TYPE_STRING = "string" @@ -59,90 +26,111 @@ local TYPE_FUNCTION = "function" ---@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 ----@param color Color|string|nil `{r, g, b}` ----@param modelInfo ModelExtendedId|integer|nil Use `smlua_model_util_get_id` ----@param forceChar CharacterType|nil Character Type, such as `CT_MARIO` ----@param lifeIcon TextureInfo|string|nil Use get_texture_info ----@param camScale integer|nil Zooms the camera based on a multiplier (Default `1`) +---@param name string? `"Custom Model"` +---@param description string|table? `{"string"}` +---@param credit string? `"You!"`, Credit the creators +---@param color Color|string? `{r, g, b}` +---@param modelInfo ModelExtendedId|integer? Use `smlua_model_util_get_id` +---@param baseChar CharacterType? Character Type, such as `CT_MARIO` +---@param lifeIcon TextureInfo|string? Use get_texture_info +---@param camScale integer? Zooms the camera based on a multiplier (Default `1`) ---@return integer --The index of the character in the character table -local function character_add(name, description, credit, color, modelInfo, forceChar, lifeIcon, camScale) - if type(description) == TYPE_STRING then - description = split_text_into_lines(description) +local function character_add(name, description, credit, color, modelInfo, baseChar, lifeIcon, camScale) + name = type(name) == TYPE_STRING and name or "Untitled" + credit = type(credit) == TYPE_STRING and credit or "Unknown" + if type(description) == TYPE_TABLE then + local table = description + description = "" + for i = 1, #table do + description = description .. table[i] .. (i ~= #table and " " or "") + end end if color ~= nil and type(color) == TYPE_STRING then color = {r = tonumber(color:sub(1,2), 16), g = tonumber(color:sub(3,4), 16), b = tonumber(color:sub(5,6), 16) } end - if lifeIcon ~= nil and type(lifeIcon) == TYPE_STRING then + if lifeIcon and type(lifeIcon) == TYPE_STRING then lifeIcon = lifeIcon:sub(1,1) end - local addedModel = (modelInfo and modelInfo ~= E_MODEL_ERROR_MODEL) and modelInfo or E_MODEL_ARMATURE + + local addedModel = (modelInfo and modelInfo ~= E_MODEL_ERROR_MODEL) and modelInfo or E_MODEL_ERROR_MODEL local charNum = #characterTable + 1 - table_insert(characterTable, { - saveName = type(name) == TYPE_STRING and string_space_to_underscore(name) or "Untitled", + + if name and type(name) == TYPE_STRING and not _G["CT_"..name:upper():gsub(" ", "_")] then + local charNum = charNum ---@type CharacterType + define_valid_global("CT_"..name:upper():gsub(" ", "_"), charNum) + end + + table.insert(characterTable, { + saveName = type(name) == TYPE_STRING and string_space_to_underscore(name.."_"..credit) or "Untitled", + nickname = type(name) == TYPE_STRING and name or "Untitled", currAlt = 1, hasMoveset = false, - locked = false, + locked = LOCKED_NEVER, category = "All", ogNum = charNum, + playtime = 0, + autoDialog = true, + replaceModels = {}, [1] = { - name = type(name) == TYPE_STRING and name or "Untitled", - description = type(description) == TYPE_TABLE and description or {"No description has been provided"}, - credit = type(credit) == TYPE_STRING and credit or "Unknown", + name = name, + description = type(description) == TYPE_STRING and description or "No description has been provided", + credit = credit, color = type(color) == TYPE_TABLE and color or {r = 255, g = 255, b = 255}, model = addedModel, ogModel = addedModel, - forceChar = forceChar and forceChar or CT_MARIO, + baseChar = baseChar and baseChar or CT_MARIO, lifeIcon = (type(lifeIcon) == TYPE_TABLE or type(lifeIcon) == TYPE_TEX_INFO or type(lifeIcon) == TYPE_STRING) and lifeIcon or "?", starIcon = gTextures.star, camScale = type(camScale) == TYPE_INTEGER and camScale or 1, - healthTexture = nil, + healthMeter = nil, }, }) - saveNameTable[charNum] = characterTable[charNum].saveName characterMovesets[charNum] = {} + characterDialog[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"}` ----@param credit string|nil `"You!"`, Credit the creators ----@param color Color|string|nil `{r, g, b}` ----@param modelInfo ModelExtendedId|integer|nil Use `smlua_model_util_get_id` ----@param forceChar CharacterType|nil Character Type, such as `CT_MARIO` ----@param lifeIcon TextureInfo|string|nil Use get_texture_info ----@param camScale integer|nil Zooms the camera based on a multiplier (Default `1`) ----@return integer --The index of the costume in the character's table -local function character_add_costume(charNum, name, description, credit, color, modelInfo, forceChar, lifeIcon, camScale) - if tonumber(charNum) == nil or charNum > #characterTable or charNum < 0 then return end - if type(description) == TYPE_STRING then - description = split_text_into_lines(description) +---@param name string? `"Custom Model"` +---@param description table|string? `{"string"}` +---@param credit string? `"You!"`, Credit the creators +---@param color Color|string? `{r, g, b}` +---@param modelInfo ModelExtendedId|integer? Use `smlua_model_util_get_id` +---@param baseChar CharacterType? Character Type, such as `CT_MARIO` +---@param lifeIcon TextureInfo|string? Use get_texture_info +---@param camScale integer? Zooms the camera based on a multiplier (Default `1`) +---@return integer? --The index of the costume in the character's table +local function character_add_costume(charNum, name, description, credit, color, modelInfo, baseChar, lifeIcon, camScale) + if not tonumber(charNum) or charNum > #characterTable or charNum < 0 then return end + if description ~= nil and type(description) == TYPE_TABLE then + local table = description + description = "" + for i = 1, #table do + description = description .. table[i] .. (i ~= #table and " " or "") + end end - if type(color) == TYPE_STRING then + if color ~= nil and type(color) == TYPE_STRING then color = {r = tonumber(color:sub(1,2), 16), g = tonumber(color:sub(3,4), 16), b = tonumber(color:sub(5,6), 16) } end - if lifeIcon ~= nil and type(lifeIcon) == TYPE_STRING then + if lifeIcon and type(lifeIcon) == TYPE_STRING then lifeIcon = lifeIcon:sub(1,1) end - local addedModel = (modelInfo and modelInfo ~= E_MODEL_ERROR_MODEL) and modelInfo or tableCache.model local tableCache = characterTable[charNum][1] - table_insert(characterTable[charNum], { + local addedModel = (modelInfo and modelInfo ~= E_MODEL_ERROR_MODEL) and modelInfo or tableCache.model + table.insert(characterTable[charNum], { name = type(name) == TYPE_STRING and name or tableCache.name, - description = type(description) == TYPE_TABLE and description or tableCache.description, + description = type(description) == TYPE_STRING and description or tableCache.description, credit = type(credit) == TYPE_STRING and credit or tableCache.credit, color = type(color) == TYPE_TABLE and color or tableCache.color, model = addedModel, ogModel = addedModel, - forceChar = type(forceChar) == TYPE_INTEGER and forceChar or tableCache.forceChar, + baseChar = type(baseChar) == TYPE_INTEGER and baseChar or tableCache.baseChar, lifeIcon = (type(lifeIcon) == TYPE_TABLE or type(lifeIcon) == TYPE_TEX_INFO or type(lifeIcon) == TYPE_STRING) and lifeIcon or tableCache.lifeIcon, starIcon = tableCache.starIcon, -- Done to prevent it getting lost in the sauce camScale = type(camScale) == TYPE_INTEGER and camScale or tableCache.camScale, - healthTexture = tableCache.healthTexture, + healthMeter = tableCache.healthMeter, }) return #characterTable[charNum] end @@ -151,39 +139,42 @@ end ---@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"` ----@param description table|string|nil `{"string"}` ----@param credit string|nil `"You!"`, Credit the creators ----@param color Color|string|nil `{r, g, b}` ----@param modelInfo ModelExtendedId|integer|nil Use `smlua_model_util_get_id` ----@param forceChar CharacterType|nil Character Type, such as `CT_MARIO` ----@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_costume(charNum, charAlt, name, description, credit, color, modelInfo, forceChar, lifeIcon, camScale) +---@param name string? `"Custom Model"` +---@param description table|string? `{"string"}` +---@param credit string? `"You!"`, Credit the creators +---@param color Color|string? `{r, g, b}` +---@param modelInfo ModelExtendedId|integer? Use `smlua_model_util_get_id` +---@param baseChar CharacterType? Character Type, such as `CT_MARIO` +---@param lifeIcon TextureInfo|string? Use get_texture_info +---@param camScale integer? Zooms the camera based on a multiplier (Default `1`) +local function character_edit_costume(charNum, charAlt, name, description, credit, color, modelInfo, baseChar, lifeIcon, camScale) if tonumber(charNum) == nil or charNum > #characterTable or charNum < 0 then return end - if type(description) == TYPE_STRING then - description = split_text_into_lines(description) + if description ~= nil and type(description) == TYPE_TABLE then + local table = description + description = "" + for i = 1, #table do + description = description .. table[i] .. (i ~= #table and " " or "") + end end - if type(color) == TYPE_STRING then + if color ~= nil and type(color) == TYPE_STRING then color = {r = tonumber(color:sub(1,2), 16), g = tonumber(color:sub(3,4), 16), b = tonumber(color:sub(5,6), 16) } end - if lifeIcon ~= nil and type(lifeIcon) == TYPE_STRING then + if lifeIcon and type(lifeIcon) == TYPE_STRING then lifeIcon = lifeIcon:sub(1,1) end local tableCache = characterTable[charNum][charAlt] characterTable[charNum][charAlt] = characterTable[charNum][charAlt] and { name = type(name) == TYPE_STRING and name or tableCache.name, - saveName = saveNameTable[charNum], - description = type(description) == TYPE_TABLE and description or tableCache.description, + description = type(description) == TYPE_STRING and description or tableCache.description, credit = type(credit) == TYPE_STRING and credit or tableCache.credit, color = type(color) == TYPE_TABLE and color or tableCache.color, model = (modelInfo and modelInfo ~= E_MODEL_ERROR_MODEL) and modelInfo or tableCache.model, ogModel = tableCache.ogModel, - forceChar = type(forceChar) == TYPE_INTEGER and forceChar or tableCache.forceChar, + baseChar = type(baseChar) == TYPE_INTEGER and baseChar or tableCache.baseChar, lifeIcon = (type(lifeIcon) == TYPE_TABLE or type(lifeIcon) == TYPE_TEX_INFO or type(lifeIcon) == TYPE_STRING) and lifeIcon or tableCache.lifeIcon, starIcon = tableCache.starIcon, -- Done to prevent it getting lost in the sauce camScale = type(camScale) == TYPE_INTEGER and camScale or tableCache.camScale, - healthTexture = tableCache.healthTexture, + healthMeter = tableCache.healthMeter, } or nil if modelInfo and characterColorPresets[modelInfo] and tableCache.model and characterColorPresets[tableCache.model] and #characterColorPresets[modelInfo] == #characterColorPresets[tableCache.model] then @@ -194,16 +185,37 @@ 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"}` ----@param credit string|nil `"You!"`, Credit the creators ----@param color Color|string|nil `{r, g, b}` ----@param modelInfo ModelExtendedId|integer|nil Use `smlua_model_util_get_id` ----@param forceChar CharacterType|nil Character Type, such as `CT_MARIO` ----@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, characterTable[charNum] and characterTable[charNum].currAlt or 1, name, description, credit, color, modelInfo, forceChar, lifeIcon, camScale) +---@param name string? `"Custom Model"` +---@param description table|string? `{"string"}` +---@param credit string? `"You!"`, Credit the creators +---@param color Color|string? `{r, g, b}` +---@param modelInfo ModelExtendedId|integer? Use `smlua_model_util_get_id` +---@param baseChar CharacterType? Character Type, such as `CT_MARIO` +---@param lifeIcon TextureInfo|string? Use get_texture_info +---@param camScale integer? Zooms the camera based on a multiplier (Default `1`) +local function character_edit(charNum, name, description, credit, color, modelInfo, baseChar, lifeIcon, camScale) + character_edit_costume(charNum, characterTable[charNum] and characterTable[charNum].currAlt or 1, name, description, credit, color, modelInfo, baseChar, lifeIcon, camScale) +end + +---@description A function to set a Character's Nickname, used for Dialog Replacement +---@added 1.16 +---@param charNum integer The number/table position of the Character you want to nickname +---@param nickname string The Character's new nickname +---@param autoSetDialog boolean Wheather dialog is automatically set (Defaults to `true`) +local function character_set_nickname(charNum, nickname, autoSetDialog) + if autoSetDialog == nil then autoSetDialog = true end + if characterTable[charNum] == nil or type(nickname) == TYPE_STRING then + characterTable[charNum].nickname = nickname + characterTable[charNum].autoDialog = autoSetDialog + end +end + + +---@description A function to get a Character's Nickname, used for Dialog Replacement +---@added 1.16 +---@param charNum integer The number/table position of the Character you want to get the nickname of +local function character_get_nickname(charNum) + return characterTable[charNum] ~= nil and characterTable[charNum].nickname end ---@description A function that adds a voice table to a character @@ -244,7 +256,47 @@ end ---@note } ---@note ``` local function character_add_voice(modelInfo, clips) - characterVoices[modelInfo] = type(clips) == TYPE_TABLE and clips or nil + --hook_event(HOOK_ON_MODS_LOADED, function () + local voiceTable = {} + -- Check nil table for vanilla voices + if clips == nil then return end + -- Check empty table for no sound + if clips == nil then return NO_SOUND end + + -- Load samples that haven't been loaded + for voice, sound in pairs(clips) do + if sound then + if type(sound) == TYPE_STRING then + local load = audio_sample_load(sound) + if load ~= nil then + voiceTable[voice] = load + end + elseif type(sound) == TYPE_TABLE then + -- load RNG/Table Samples + voiceTable[voice] = {} + for i, subsound in pairs(sound) do + if type(subsound) == TYPE_STRING then + local load = audio_sample_load(subsound) + if load ~= nil then + voiceTable[voice][i] = load + end + end + end + end + end + end + + characterVoices[modelInfo] = voiceTable + --end) +end +hook_event(HOOK_ON_MODS_LOADED, character_add_voice) + +---@description A function that gets the current character's voice table +---@added 1.5 +---@param model integer|MarioState Can use Model and/or MarioState +function character_get_voice(model) + local model = (type(model) == TYPE_INTEGER) and model or gCSPlayers[model.playerIndex].modelId + return characterVoices[model] end ---@description A function that adds a caps table to a character @@ -265,7 +317,7 @@ 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 +---@param modelInfo ModelExtendedId|integer? 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] @@ -275,45 +327,75 @@ end ---@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) -local function character_add_costume_health_meter(charNum, charAlt, healthTexture) +---@param healthMeter table|function? A Table with your Character's Health Textures (Table Shown in character_add_health_meter) or Rendering Function +local function character_add_costume_health_meter(charNum, charAlt, healthMeter) 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].healthTexture = type(healthTexture) == TYPE_TABLE and healthTexture or nil + if healthMeter == nil then + return + elseif type(healthMeter) == TYPE_FUNCTION then + characterTable[charNum][charAlt].healthMeter = healthMeter + elseif type(healthMeter) == TYPE_TABLE then + characterTable[charNum][charAlt].healthMeter = { + label = { + left = is_texture_valid(healthMeter.label.left) and healthMeter.label.left or defaultMeterInfo.label.left, + right = is_texture_valid(healthMeter.label.right) and healthMeter.label.right or defaultMeterInfo.label.right, + }, + pie = { + is_texture_valid(healthMeter.pie[1]) and healthMeter.pie[1] or defaultMeterInfo.pie[1], + is_texture_valid(healthMeter.pie[2]) and healthMeter.pie[2] or defaultMeterInfo.pie[2], + is_texture_valid(healthMeter.pie[3]) and healthMeter.pie[3] or defaultMeterInfo.pie[3], + is_texture_valid(healthMeter.pie[4]) and healthMeter.pie[4] or defaultMeterInfo.pie[4], + is_texture_valid(healthMeter.pie[5]) and healthMeter.pie[5] or defaultMeterInfo.pie[5], + is_texture_valid(healthMeter.pie[6]) and healthMeter.pie[6] or defaultMeterInfo.pie[6], + is_texture_valid(healthMeter.pie[7]) and healthMeter.pie[7] or defaultMeterInfo.pie[7], + is_texture_valid(healthMeter.pie[8]) and healthMeter.pie[8] or defaultMeterInfo.pie[8], + } + } + end 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) +---@param healthMeter table|function? A Table with your Character's Health Textures (Table Shown Below) or Rendering Function ---@note ```lua ---@note local HEALTH_METER_CHAR = { ---@note label = { ----@note left = get_texture_info("hp-back-left"), ----@note right = get_texture_info("hp-back-right"), +---@note left = get_texture_info("char_hp_pie_left"), +---@note right = get_texture_info("char_hp_pie_right"), ---@note }, ---@note pie = { ----@note [1] = get_texture_info("hp-pie-1"), ----@note [2] = get_texture_info("hp-pie-2"), ----@note [3] = get_texture_info("hp-pie-3"), ----@note [4] = get_texture_info("hp-pie-4"), ----@note [5] = get_texture_info("hp-pie-5"), ----@note [6] = get_texture_info("hp-pie-6"), ----@note [7] = get_texture_info("hp-pie-7"), ----@note [8] = get_texture_info("hp-pie-8"), +---@note [1] = get_texture_info("char_hp_pie_1"), +---@note [2] = get_texture_info("char_hp_pie_2"), +---@note [3] = get_texture_info("char_hp_pie_3"), +---@note [4] = get_texture_info("char_hp_pie_4"), +---@note [5] = get_texture_info("char_hp_pie_5"), +---@note [6] = get_texture_info("char_hp_pie_6"), +---@note [7] = get_texture_info("char_hp_pie_7"), +---@note [8] = get_texture_info("char_hp_pie_8"), ---@note } ---@note } +---@note +---@note -- or -- +---@note +---@note local function char_meter_render (localIndex, health, prevX, prevY, prevScaleX, prevScaleY, x, y, scaleX, scaleY) +---@note local squares = health >> 8 +---@note for i = 1, squares do +---@note djui_hud_render_rect(x + (i * 17), y, 16, 16) +---@note end +---@note end ---@note ``` -local function character_add_health_meter(charNum, healthTexture) - character_add_costume_health_meter(charNum, 1, healthTexture) +local function character_add_health_meter(charNum, healthMeter) + character_add_costume_health_meter(charNum, 1, healthMeter) end ---@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) +---@param courseTexture table? A Table with your Character's Health Textures (Table Shown in character_add_course) +local function character_add_costume_course_texture(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 @@ -322,27 +404,46 @@ end ---@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) +---@param courseTexture table? 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 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) +local function character_add_course_texture(charNum, courseTexture) + character_add_costume_course_texture(charNum, 1, courseTexture) +end + +-- Here because the model replacement feature is unstable +local bhvAllowReplace = { + [id_bhvEndToad] = true, + [id_bhvBeginningPeach] = true, + [id_bhvEndPeach] = true, + --[id_bhvGoomba] = true, + [id_bhvCelebrationStar] = true, +} + +---@param charNum ModelExtendedId|integer Player Model ID +---@param bhvId BehaviorId|integer Behavior ID of the type of objects you want to replace +---@param replaceModel ModelExtendedId|integer|function? Model ID +local function character_add_model_replacement(charNum, bhvId, replaceModel) + if not bhvAllowReplace[bhvId] then + log_to_console_once("Using `character_add_model_replacement` on untested behaviors such as '" .. get_behavior_name_from_id(bhvId) .. "' may be unstable!", CONSOLE_MESSAGE_WARNING) + end + characterTable[charNum].replaceModels[bhvId] = replaceModel 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() +---@param modelInfo ModelExtendedId|integer Player Model ID +---@param starModel ModelExtendedId|integer Custom Star Model ID +---@param starIcon TextureInfo? Custom Star Texture local function character_add_celebration_star(modelInfo, starModel, starIcon) - characterCelebrationStar[modelInfo] = starModel - for i = 2, #characterTable do + for i = 0, #characterTable do for a = 1, #characterTable[i] do if characterTable[i][a].model == modelInfo then + character_add_model_replacement(i, id_bhvCelebrationStar, starModel) characterTable[i][a].starIcon = type(starIcon) == TYPE_TABLE and starIcon or gTextures.star return end @@ -351,11 +452,44 @@ local function character_add_celebration_star(modelInfo, starModel, starIcon) return false end +---@description A function that adds a peach model to a character for the opening letter and ending cutscene.Can also change peach's letter for the character +---@added 1.16 +---@param modelInfo ModelExtendedId|integer Model Information Received from smlua_model_util_get_id() +---@param peachmodelstart ModelExtendedId? Model Information Received from smlua_model_util_get_id() the model used for peach in the opening if left blank will use default peach model +---@param peachmodelend ModelExtendedId? Model Information Received from smlua_model_util_get_id() the model used for peach in the ending if left blank will use default peach model +---@param peachletterleft TextureInfo? left side of the texture to replace peach's letter texture in the intro +---@param peachletterright TextureInfo? right side of the texture to replace peach's letter texture in the intro +---@param peachlettersig TextureInfo? texture to replace peach's letter texture in the intro +local function character_add_peach_custom(modelInfo, peachmodelstart, peachmodelend, peachletterleft, peachletterright, peachlettersig) + character_add_model_replacement(character_get_number_from_model(modelInfo), id_bhvBeginningPeach, peachmodelstart) + character_add_model_replacement(character_get_number_from_model(modelInfo), id_bhvEndPeach, peachmodelend) + if (peachletterleft ~= nil) and (peachletterright ~= nil) and (peachlettersig ~= nil) then + characterpeachletter[modelInfo] = {left = peachletterleft, right = peachletterright, sig = peachlettersig} + end +end + +---@description A function that sets the toad models during the ending cutscene +---@added 1.16 +---@param modelInfo ModelExtendedId|integer Model Information Received from smlua_model_util_get_id() +---@param toadModelRight ModelExtendedId Model Information Received from smlua_model_util_get_id(), the model used for the right toad in the ending if left blank said toad will use the default npc toad model +---@param toadModelLeft ModelExtendedId Model Information Received from smlua_model_util_get_id(), the model used for the left toad in the ending if left blank said toad will use the default npc toad model +local function character_add_ending_toad_model(modelInfo, toadModelRight, toadModelLeft) + local settingRightToad = false + character_add_model_replacement(character_get_number_from_model(modelInfo), id_bhvEndToad, function (o) + -- Only difference between the two objects is positions + settingRightToad = not settingRightToad + if settingRightToad then + return toadModelRight + end + return toadModelLeft + end) +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 +---@param paletteName string? ---@note ```lua ---@note local PALETTE_CHAR = { ---@note [PANTS] = {r = 0x00, g = 0x00, b = 0xff}, @@ -369,6 +503,13 @@ end ---@note ``` ---@note Strings can also be used rather than RGB tables, ex. `[PANTS] = "0000ff"` local function character_add_palette_preset(modelInfo, paletteTable, paletteName) + if paletteName == nil then + if characterColorPresets[modelInfo] == nil then + paletteName = "Default" + else + paletteName = "Alt " .. tostring(#characterColorPresets[modelInfo]) + end + end local paletteTableOut = { name = paletteName, } @@ -382,9 +523,9 @@ local function character_add_palette_preset(modelInfo, paletteTable, paletteName paletteTableOut[i].b = tonumber(color:sub(5,6), 16) and tonumber(color:sub(5,6), 16) or defaultColors[i].b end if type(color) == TYPE_TABLE then - paletteTableOut[i].r = (type(color) == TYPE_TABLE and color.r ~= nil) and color.r or defaultColors[i].r - paletteTableOut[i].g = (type(color) == TYPE_TABLE and color.g ~= nil) and color.g or defaultColors[i].g - paletteTableOut[i].b = (type(color) == TYPE_TABLE and color.b ~= nil) and color.b or defaultColors[i].b + paletteTableOut[i].r = (type(color) == TYPE_TABLE and color.r) and color.r or defaultColors[i].r + paletteTableOut[i].g = (type(color) == TYPE_TABLE and color.g) and color.g or defaultColors[i].g + paletteTableOut[i].b = (type(color) == TYPE_TABLE and color.b) and color.b or defaultColors[i].b end end if characterColorPresets[modelInfo] == nil then @@ -392,15 +533,21 @@ local function character_add_palette_preset(modelInfo, paletteTable, paletteName currPalette = 1, } end - table_insert(characterColorPresets[modelInfo], paletteTableOut) + 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 +---@param animTable? table +---@param eyeTable? table +---@param handTable? table +local function character_add_animations(modelInfo, animTable, eyeTable, handTable) + characterAnims[modelInfo] = { + anims = type(animTable) == TYPE_TABLE and animTable or nil, + eyes = type(eyeTable) == TYPE_TABLE and eyeTable or nil, + hands = type(handTable) == TYPE_TABLE and handTable or nil, + } end ---@description A function that gets any animation table from a model @@ -412,8 +559,8 @@ end ---@description A function that gets a character's full Character Select Table ---@added 1 ----@param tablePos integer|nil ----@param charAlt integer|nil +---@param tablePos integer? +---@param charAlt integer? ---@return CharacterTable local function character_get_current_table(tablePos, charAlt) tablePos = tablePos and tablePos or currChar @@ -430,9 +577,10 @@ end ---@description A function that gets the current character's table position in CS ---@added 1 ---- @param localIndex integer|nil ---- @return integer|nil +---@param localIndex integer? The local player index you want to get the character number from, Default is `0` +---@return integer? local function character_get_current_number(localIndex) + if not startup_init_stall() then return end if localIndex == nil or localIndex == 0 then return currChar else @@ -447,8 +595,8 @@ end ---@description A function that gets the current costumes's table position in CS ---@added 1.12 ----@param localIndex integer|nil ----@return integer|nil +---@param localIndex integer? +---@return integer? local function character_get_current_costume(localIndex) if localIndex == nil or localIndex == 0 then return characterTable[currChar].currAlt @@ -462,27 +610,30 @@ local function character_get_current_costume(localIndex) end end ----@description A function that sets the current character based only table position +---@description A function that sets the current character based only table position with an optional second argument for setting a specific costume ---@added 1.9 ----@param charNum integer|nil -local function character_set_current_number(charNum) +---@param charNum integer The number/table position of the Character you want the local player to become +---@param charAlt integer? The number/table position of a costume in the corresponding character's costume table to switch to. If nil will use the 1st costume +local function character_set_current_number(charNum, charAlt) if type(charNum) ~= TYPE_INTEGER or characterTable[charNum] == nil then return end - currChar = charNum + if charAlt == nil then charAlt = 1 end + charAlt = math.clamp(charAlt, 1, #characterTable[charNum]) + force_set_character(charNum, charAlt) charBeingSet = true end ---@description A function that gets the current character's palette data ---@added 1.12 ---- @return table|nil +---@return table? local function character_get_current_palette() local model = characterTable[currChar][characterTable[currChar].currAlt].model - return characterColorPresets[model][gCSPlayers[0].presetPalette] + return characterColorPresets[model] ~= nil and characterColorPresets[model][gCSPlayers[0].presetPalette] or nil end ---@description A function that gets the current character's palette number ---@added 1.12 ---- @param localIndex integer|nil ---- @return integer|nil +---@param localIndex integer? +---@return integer? local function character_get_current_palette_number(localIndex) if localIndex == nil then localIndex = 0 end return gCSPlayers[localIndex].presetPalette @@ -491,9 +642,10 @@ 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) +---@return integer? +function character_get_number_from_string(name) if type(name) ~= TYPE_STRING then return nil end - for i = 2, #characterTable do + for i = 0, #characterTable do for a = 1, #characterTable[i] do if characterTable[i][a].name == name or characterTable[i][a].name == string_space_to_underscore(name) then return i @@ -503,11 +655,19 @@ 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] +---@description A function that searches for a character's table posision based on model +---@added 1.16 +---@param model integer|ModelExtendedId +---@return integer? +function character_get_number_from_model(model) + if type(model) ~= TYPE_INTEGER then return nil end + for i = 0, #characterTable do + for a = 1, #characterTable[i] do + if characterTable[i][a].model == model or characterTable[i][a].ogModel == model then + return i + end + end + end end -- Located in n-hud.lua @@ -574,24 +734,39 @@ end ---@description A function that renders a persons health meter texture table ---@added 1.12 ---@param localIndex integer +---@param health integer ---@param x integer ---@param y integer ---@param scaleX integer ---@param scaleY integer ---@forcedoc character_render_health_meter +---@description A function that renders a persons health meter texture table, with interpolation +---@added 1.16 +---@param localIndex integer +---@param health integer +---@param prevX integer +---@param prevY integer +---@param prevScaleX integer +---@param prevScaleY integer +---@param x integer +---@param y integer +---@param scaleX integer +---@param scaleY integer +---@forcedoc character_render_health_meter_interpolated + ---@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 +---@param charNum integer? The number of the Character you want to Lock +---@param unlockCondition function|boolean? The condition for if the character stays locked +---@param notify boolean? 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 charNum == nil or charNum > #characterTable or charNum < CT_MAX then return end if unlockCondition == nil then unlockCondition = false end if notify == nil then notify = true end - characterTable[charNum].locked = true + characterTable[charNum].locked = LOCKED_TRUE if currChar == charNum then - currChar = 1 + force_set_character() end characterUnlock[charNum] = { check = unlockCondition, @@ -601,28 +776,59 @@ end ---@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 +---@param charNum integer The number of the Character you want to set the category for +---@param categoryName string The Category Name (Will create a new category if category does not exist) +---@param forceIcon boolean Forces the icon to be used as a category icon +local function character_set_category(charNum, categoryName, forceIcon) + if not charNum then return end + if not categoryName then return end + categoryName = string_underscore_to_space(categoryName) + local foundCategory = nil for i = 1, #characterCategories do - if characterCategories[i] == category then - foundCategory = true + if characterCategories[i].name == categoryName then + foundCategory = characterCategories[i] end end - if not foundCategory then - table_insert(characterCategories, category) + if not foundCategory then + table.insert(characterCategories, {name = categoryName, icon1 = nil, icon2 = nil}) + foundCategory = characterCategories[#characterCategories] end - characterTable[charNum].category = characterTable[charNum].category .. "_" .. category + if forceIcon then + if not foundCategory.icon1 then + foundCategory.icon1 = charNum + elseif not foundCategory.icon2 then + foundCategory.icon2 = charNum + end + end + characterTable[charNum].category = characterTable[charNum].category .. "_" .. categoryName +end + +---@description A function that replaces dialog if you are playing as a specific character +---@added 1.16 +---@param charNum integer The number of the Character you want to replace dislog for +---@param dialogId integer|DialogId The ID of the dialog you want to replace +---@param unused integer Unused Dialog Variable +---@param linesPerBox integer Lines of text that appear in a single dialog +---@param leftOffset integer Dialog Box Posistion relitive to the left side of the screen +---@param width integer Verticle Position on screen (Dispite Variable Name) +---@param text string Dialog to be replaced with +local function character_replace_dialog(charNum, dialogId, unused, linesPerBox, leftOffset, width, text) + if modded == nil then modded = true end + characterDialog[charNum][dialogId] = { + unused = unused, + linesPerBox = linesPerBox, + leftOffset = leftOffset, + width = width, + text = text, + } end ---@header ---@forcedoc Menu_Functions ----@description A function that sets the big "Character Select" texture in the Character Select Menu +---@description (Deprecated) A function that sets the big "Character Select" texture in the Character Select Menu ---@added 1.7 ----@param texture TextureInfo|nil +---@param texture TextureInfo? ---@forcedoc header_set_texture ---@description A function that returns the version string @@ -662,7 +868,7 @@ end ---@description A function that forces they Character Select Menu state ---@added 1.8 ----@param bool boolean|nil Sets if the menu is open +---@param bool boolean? Sets if the menu is open local function set_menu_open(bool) if bool == nil then bool = true end menu = bool @@ -702,44 +908,64 @@ end ---@added 1 ---@return boolean local function is_options_open() - return options + return options ~= nil end ----@description A function that adds a line of credit to the CS Options' Credit section +---@description A function that adds credits to the CS Options' Credits 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 - if modName == creditTable[i].packName then - table_insert(creditTable[i], {creditTo = creditTo, creditFor = creditFor}) - return - end +---@param creditee string The person you want to Credit +---@param credit string What the Person helped with +---@overload fun(modName: string, credits: string[][]) +local function credit_add(modName, creditee, credit) + local credits + for i = 2, #creditTable do + if modName == creditTable[i].packName then + credits = creditTable[i] end end - local i = #creditTable + 1 - creditTable[i] = { - packName = modName - } - table_insert(creditTable[i], {creditTo = creditTo, creditFor = creditFor}) + if not credits then + credits = { packName = modName } + table.insert(creditTable, credits) + end + + if type(creditee) == "table" then + for _, credit in ipairs(creditee) do + table.insert(credits, { creditee = credit[1], credit = credit[2] }) + end + else table.insert(credits, { creditee = creditee, credit = credit }) end 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 not network_is_server() then return end if bool == nil then bool = true end - stopPalettes = bool + gGlobalSyncTable.charSelectRestrictPalettes = bool and 2 or 0 end ---@description A function that sets if movesets are restricted (Default `false`) ---@added 1.10 ---@param bool boolean local function restrict_movesets(bool) + if not network_is_server() then return end if bool == nil then bool = true end - stopMovesets = bool + gGlobalSyncTable.charSelectRestrictMovesets = bool and 2 or optionTable[optionTableRef.restrictMovesets].toggle +end + +---@description A function that checks if palettes are restricted +---@added 1.15 +---@return boolean +local function are_palettes_restricted() + return gGlobalSyncTable.charSelectRestrictPalettes > 0 +end + +---@description A function that checks if movesets are restricted +---@added 1.15 +---@return boolean +local function are_movesets_restricted() + return gGlobalSyncTable.charSelectRestrictMovesets > 0 end ---@description A table that contains the local mario's controller before Character Select's menu cancels them @@ -759,17 +985,18 @@ local controller = { ---@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`) +---@param toggleDefault number? The default number that the option toggles to (Defaults to `0`) +---@param toggleMax number? The max number the option can be toggled to (Defaults to `1`) +---@param toggleNames table? A table of strings, each entry being for a toggle's name `{"Off", "On"}` +---@param description table? A table of strings, each entry being a new line `{"This toggle allows your", "character to feel everything."}` +---@param save boolean? 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) - table_insert(optionTable, { + table.insert(optionTable, { name = type(name) == TYPE_STRING and name or "Unknown Toggle", + category = OPTION_API, toggle = nil, -- Set as nil for Failsafe to Catch toggleSaveName = save and saveName or nil, toggleDefault = type(toggleDefault) == TYPE_INTEGER and toggleDefault or 0, @@ -784,7 +1011,7 @@ end ---@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 +---@return table? local function get_option(tableNum) if type(tableNum) ~= TYPE_INTEGER then return nil end return optionTable[tableNum] @@ -793,11 +1020,8 @@ end ---@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 +---@return number? +---@forcedoc get_options_status ---@description A function that sets an option's status from the Character Select Options Menu ---@added 1.9 @@ -816,10 +1040,12 @@ end ---@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 +---@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 such as `"Luigi"`. +function dialog_set_replace_name(name) + DEFAULT_DIALOG_NAME = name +end ----@description A function that sets the preset palette for a network player forcefully +---@description A function that sets the preset palette for a network player forcefully their current Preset Palette ---@added 1.11 ---@param np NetworkPlayer ---@forcedoc update_preset_palette @@ -855,7 +1081,7 @@ end ---@param func function local function hook_allow_menu_open(func) if type(func) ~= TYPE_FUNCTION then return end - table_insert(allowMenu, func) + 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) @@ -864,20 +1090,29 @@ end local function hook_render_in_menu(func, underText) if type(func) ~= TYPE_FUNCTION then return end if underText then - table_insert(renderInMenuTable.back, func) + table.insert(hookTableRenderInMenu.back, func) else - table_insert(renderInMenuTable.front, func) + table.insert(hookTableRenderInMenu.front, func) end end +---@description A function that runs the inputted function when the character is changed +---@added 1.15 +---@param func function +---@note Function gives `currChar` and `prevChar` as function inputs +local function hook_on_character_change(func) + if type(func) ~= TYPE_FUNCTION then return end + table.insert(hookTableOnCharacterChange, func) +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 +---@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 charNum integer +---@param hookEventType LuaHookedEventType|integer The hook event tied to a specific character. Supports the following hooks: `HOOK_MARIO_UPDATE`, `HOOK_BEFORE_MARIO_UPDATE`, `HOOK_BEFORE_PHYS_STEP`, `HOOK_ALLOW_PVP_ATTACK`, `HOOK_ON_PVP_ATTACK`, `HOOK_ON_INTERACT`, `HOOK_ALLOW_INTERACT`, `HOOK_ON_SET_MARIO_ACTION`, `HOOK_BEFORE_SET_MARIO_ACTION`, `HOOK_ON_DEATH`, `HOOK_ON_HUD_RENDER`, `HOOK_ON_HUD_RENDER_BEHIND`, `HOOK_ON_LEVEL_INIT`, `HOOK_ON_SYNC_VALID`, `HOOK_ON_OBJECT_RENDER`, `HOOK_ALLOW_FORCE_WATER_ACTION`, `HOOK_MARIO_OVERRIDE_FLOOR_CLASS` ` ---@param func function local function character_hook_moveset(charNum, hookEventType, func) if charNum > #characterTable then return end @@ -893,6 +1128,51 @@ local function character_get_moveset(charNum) return characterMovesets[charNum] end +---@description A function that returns if the character number is of a character that is included with CoopDX +---@added 1.15.1 +---@param charNum integer? The character number you want to check, Default is the local character +---@note Function was made in preperation for v1.16, in which the Base Cast are individual characters rather than Costumes of each other. +---@forcedoc character_is_vanilla + +---@description A function that adds an instrument track to a specific character +---@added 1.16 +---@param charNum integer The character number you want to add instruments for +---@param loadedAudio ModAudio The loaded instrumental audio file +---@note Original Song is `.ogg` File Format, `Mono` Channel, `G# Major Key`, `82` BPM, `93.659` Seconds Long, and is set to a sample rate of `22050`. If these requirements are not met then the song will not properly play, or incorrectly fit with the base theme. +local function character_add_menu_instrumental(charNum, loadedAudio) + audio_stream_set_looping(loadedAudio, true) + audio_stream_set_loop_points(loadedAudio, 0, 93.659*22050) + characterInstrumentals[charNum] = { + audio = loadedAudio, + volume = 0, + targetVolume = 0, + } +end + +---@description A function that adds graffiti art to the background of the menu +---@added 1.16 +---@param charNum integer +---@param texture TextureInfo +local function character_add_graffiti(charNum, texture) + characterGraffiti[charNum] = texture +end + +---@description A function that adds graffiti art to the background of the menu +---@added 1.16 +---@param charNum integer +local function character_get_graffiti(charNum) + return characterGraffiti[charNum] and characterGraffiti[charNum] or TEX_GRAFFITI_DEFAULT +end + +---@description A function that runs when Character Select Resets it's save data +---@added 1.16 +---@param func function +---@note Function gives `currChar` and `prevChar` as function inputs +local function hook_on_save_data_reset(func) + if type(func) ~= TYPE_FUNCTION then return end + table.insert(hookTableOnReset, func) +end + _G.charSelectExists = true _G.charSelect = { -- Character Functions -- @@ -900,14 +1180,19 @@ _G.charSelect = { character_add_costume = character_add_costume, character_edit = character_edit, character_edit_costume = character_edit_costume, + character_set_nickname = character_set_nickname, + character_get_nickname = character_get_nickname, character_add_voice = character_add_voice, character_add_caps = character_add_caps, character_get_caps = character_get_caps, + character_add_model_replacement = character_add_model_replacement, character_add_celebration_star = character_add_celebration_star, + character_add_peach_custom = character_add_peach_custom, + character_add_ending_toad_model = character_add_ending_toad_model, character_add_health_meter = character_add_health_meter, character_add_costume_health_meter = character_add_costume_health_meter, - character_add_course_texture = character_add_course, - character_add_costume_course_texture = character_add_costume_course, + character_add_course_texture = character_add_course_texture, + character_add_costume_course_texture = character_add_costume_course_texture, character_add_palette_preset = character_add_palette_preset, character_add_animations = character_add_animations, character_get_animations = character_get_animations, @@ -920,6 +1205,7 @@ _G.charSelect = { character_get_current_palette = character_get_current_palette, character_get_current_palette_number = character_get_current_palette_number, character_get_number_from_string = character_get_number_from_string, + character_get_number_from_model = character_get_number_from_model, character_get_voice = character_get_voice, character_get_life_icon = life_icon_from_local_index, -- Function located in n-hud.lua character_render_life_icon = render_life_icon_from_local_index, -- Function located in n-hud.lua @@ -929,17 +1215,27 @@ _G.charSelect = { character_render_star_icon_interpolated = render_star_icon_from_local_index_interpolated, -- Function located in n-hud.lua 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_render_health_meter_interpolated = render_health_meter_from_local_index_interpolated, -- Function located in n-hud.lua character_set_locked = character_set_locked, character_set_category = character_set_category, + character_replace_dialog = character_replace_dialog, character_get_moveset = character_get_moveset, + character_is_vanilla = character_is_vanilla, -- Function located in main.lua + character_add_menu_instrumental = character_add_menu_instrumental, + character_add_graffiti = character_add_graffiti, + character_get_graffiti = character_get_graffiti, + -- Located in voice.lua + voice = { + sound = custom_character_sound, + snore = custom_character_snore, + }, -- Hud Element Functions -- - 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 + hud_hide_element = hud_hide_element, -- Function located in hud.lua + hud_show_element = hud_show_element, -- Function located in hud.lua + hud_get_element = hud_get_element, -- Function located in hud.lua -- Menu Functions -- - header_set_texture = header_set_texture, -- Function located in main.lua version_get = version_get, version_get_full = version_get_full, is_menu_open = is_menu_open, @@ -953,10 +1249,12 @@ _G.charSelect = { credit_add = credit_add, restrict_palettes = restrict_palettes, restrict_movesets = restrict_movesets, + are_palettes_restricted = are_palettes_restricted, + are_movesets_restricted = are_movesets_restricted, -- Misc -- dialog_set_replace_name = dialog_set_replace_name, -- Function located in dialog.lua - update_preset_palette = placeholder, -- Function located in z-palettes.lua + update_preset_palette = update_preset_palette, -- Function located in palettes.lua -- Tables & Variables -- optionTableRef = optionTableRef, @@ -968,22 +1266,24 @@ _G.charSelect = { -- 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 + hook_on_character_change = hook_on_character_change, + hook_on_save_data_reset = hook_on_save_data_reset, + config_character_sounds = config_character_sounds, -- Function located in voice.lua character_hook_moveset = character_hook_moveset, } -- Replace base functions local obj_set_model_extended_original = obj_set_model_extended --- Replace obj_set_model_extended to error for mario models +-- Replace obj_set_model_extended to warn 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) + log_to_console_once("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 +_G.obj_set_model_extended = obj_set_model_extended diff --git a/mods/character-select-coop/z-palettes.lua b/mods/character-select-coop/z-palettes.lua deleted file mode 100644 index 2300dd070..000000000 --- a/mods/character-select-coop/z-palettes.lua +++ /dev/null @@ -1,153 +0,0 @@ -if incompatibleClient then return 0 end - --- localize functions to improve performance - z-palettes.lua -local network_player_set_override_palette_color,network_player_reset_override_palette = network_player_set_override_palette_color,network_player_reset_override_palette - - -characterColorPresets = { - [E_MODEL_MARIO] = { - currPalette = 0, - [1] = { - [PANTS] = { r = 0x00, g = 0x00, b = 0xff }, - [SHIRT] = { r = 0xff, g = 0x00, b = 0x00 }, - [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, - [SHOES] = { r = 0x72, g = 0x1c, b = 0x0e }, - [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, - [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, - [CAP] = { r = 0xff, g = 0x00, b = 0x00 }, - [EMBLEM] = { r = 0xff, g = 0x00, b = 0x00 }, - }, - }, - [E_MODEL_LUIGI] = { - currPalette = 0, - [1] = { - [PANTS] = { r = 0x00, g = 0x00, b = 0xff }, - [SHIRT] = { r = 0x00, g = 0xff, b = 0x00 }, - [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, - [SHOES] = { r = 0x72, g = 0x1c, b = 0x0e }, - [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, - [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, - [CAP] = { r = 0x00, g = 0xff, b = 0x00 }, - [EMBLEM] = { r = 0x00, g = 0xff, b = 0x00 }, - }, - }, - [E_MODEL_TOAD_PLAYER] = { - currPalette = 0, - [1] = { - [PANTS] = { r = 0xff, g = 0xff, b = 0xff }, - [SHIRT] = { r = 0x4c, g = 0x2c, b = 0xd3 }, - [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, - [SHOES] = { r = 0x68, g = 0x40, b = 0x1b }, - [HAIR] = { r = 0x73, g = 0x06, b = 0x00 }, - [SKIN] = { r = 0xfe, g = 0xd5, b = 0xa1 }, - [CAP] = { r = 0xff, g = 0x00, b = 0x00 }, - [EMBLEM] = { r = 0xff, g = 0x00, b = 0x00 }, - }, - }, - [E_MODEL_WALUIGI] = { - currPalette = 0, - [1] = { - [PANTS] = { r = 0x16, g = 0x16, b = 0x27 }, - [SHIRT] = { r = 0x61, g = 0x26, b = 0xb0 }, - [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, - [SHOES] = { r = 0xfe, g = 0x76, b = 0x00 }, - [HAIR] = { r = 0x73, g = 0x53, b = 0x00 }, - [SHOES] = { r = 0xfe, g = 0x76, b = 0x00 }, - [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, - [CAP] = { r = 0x61, g = 0x26, b = 0xb0 }, - [EMBLEM] = { r = 0xff, g = 0xde, b = 0x00 }, - }, - }, - [E_MODEL_WARIO] = { - currPalette = 0, - [1] = { - [PANTS] = { r = 0x7f, g = 0x20, b = 0x7a }, - [SHIRT] = { r = 0xff, g = 0xbd, b = 0x00 }, - [GLOVES] = { r = 0xff, g = 0xff, b = 0xff }, - [SHOES] = { r = 0x0e, g = 0x72, b = 0x1c }, - [HAIR] = { r = 0x73, g = 0x53, b = 0x00 }, - [SHOES] = { r = 0x0e, g = 0x72, b = 0x1c }, - [SKIN] = { r = 0xfe, g = 0xc1, b = 0x79 }, - [CAP] = { r = 0xff, g = 0xbd, b = 0x00 }, - [EMBLEM] = { r = 0x00, g = 0x00, b = 0xff }, - }, - } -} - -local paletteLoop = #characterColorPresets[E_MODEL_MARIO][1] - -local function network_player_set_full_override_palette(networkPlayer, colorTable) - if colorTable == nil then return end - for i = 0, paletteLoop do - network_player_set_override_palette_color(networkPlayer, i, colorTable[i]) - end -end - ---- @param np NetworkPlayer -local function update_preset_palette(np) - local p = gCSPlayers[np.localIndex] - local modelId = p.modelId - if np.connected and gCSPlayers[0].presetPalette > 0 and characterColorPresets[modelId] and not stopPalettes then - network_player_set_full_override_palette(np, characterColorPresets[modelId][p.presetPalette]) - end -end - --- API funcs -_G.charSelect.update_preset_palette = update_preset_palette - -local stallTimer = 5 - -local prevPresetPalette = {} -local prevModel = {} - -local function mario_update(m) - local np = gNetworkPlayers[m.playerIndex] - local p = gCSPlayers[m.playerIndex] - local currAlt = characterTable[currChar].currAlt - - if m.playerIndex == 0 and not p.isUpdating then - p.isUpdating = true - for i = 1, MAX_PLAYERS - 1 do - prevPresetPalette[i] = gCSPlayers[i].presetPalette - prevModel[i] = gCSPlayers[i].modelId - end - end - - if m.playerIndex == 0 then - if not stopPalettes then - gCSPlayers[0].presetPalette = characterColorPresets[gCSPlayers[0].modelId] ~= nil and characterColorPresets[gCSPlayers[0].modelId].currPalette or 0 - end - - if stallTimer > 0 then - stallTimer = stallTimer - 1 - end - end - - if np.connected then - if p.presetPalette == nil or characterColorPresets[p.modelId] == nil then - if p.presetPalette == nil then - prevPresetPalette[m.playerIndex] = 0 - end - p.presetPalette = 0 - end - - if (prevPresetPalette[m.playerIndex] ~= p.presetPalette or prevModel[m.playerIndex] ~= p.modelId) then - if p.presetPalette == 0 or not characterColorPresets[p.modelId] then - network_player_reset_override_palette(np) - end - end - - prevPresetPalette[m.playerIndex] = p.presetPalette - prevModel[m.playerIndex] = p.modelId - - if p.presetPalette > 0 and characterColorPresets[p.modelId] and not stopPalettes then - network_player_set_full_override_palette(np, characterColorPresets[p.modelId][p.presetPalette]) - end - else - if p.isUpdating then - p.isUpdating = false - end - end -end - -hook_event(HOOK_MARIO_UPDATE, mario_update) diff --git a/mods/character-select-coop/z-voice.lua b/mods/character-select-coop/z-voice.lua deleted file mode 100644 index 8a9c353cb..000000000 --- a/mods/character-select-coop/z-voice.lua +++ /dev/null @@ -1,223 +0,0 @@ -if incompatibleClient then return 0 end - --- localize functions to improve performance - z-voice.lua -local type,audio_sample_stop,audio_sample_load,math_random,audio_sample_play,is_game_paused,table_insert,play_character_sound = type,audio_sample_stop,audio_sample_load,math.random,audio_sample_play,is_game_paused,table.insert,play_character_sound - --- rewritten custom voice system for Character Select --- by Agent X - --- will need some revising in the future, but this will do for now. - -local SLEEP_TALK_SNORES = 8 -local STARTING_SNORE = 46 -local SLEEP_TALK_START = STARTING_SNORE + 49 -local SLEEP_TALK_END = SLEEP_TALK_START + SLEEP_TALK_SNORES -local stallTimer = 0 -local stallSayLine = 5 - -local TYPE_TABLE = "table" -local TYPE_USERDATA = "userdata" -local TYPE_STRING = "string" -local function check_sound_exists(sound) - if sound == nil then return false end - local soundType = type(sound) - if soundType == TYPE_USERDATA and sound._pointer ~= nil then - return true - elseif soundType == TYPE_STRING then - sound = "sound/"..sound - return (mod_file_exists(sound)) - end - return false -end - -local function stop_all_custom_character_sounds() - -- run through each player - for i = 0, MAX_PLAYERS - 1 do - local m = gMarioStates[i] - -- get the voice table, if there is one - local voiceTable = character_get_voice(m) - if voiceTable ~= nil then - -- run through each sample - for sound in pairs(voiceTable) do - -- if the sample is found, try to stop it - if voiceTable[sound] ~= nil and type(voiceTable[sound]) ~= "string" then - -- if there's no pointer then it must be a sound clip table - if voiceTable[sound]._pointer == nil then - for voice in pairs(voiceTable[sound]) do - if type(voiceTable[sound][voice]) == "string" then - break - end - audio_sample_stop(voiceTable[sound][voice]) - end - else - audio_sample_stop(voiceTable[sound]) - end - end - end - end - end -end - ---[[local function stop_custom_character_sound(m, sound) - local voiceTable = character_get_voice(m) - -- if there's no pointer then it must be a sound clip table - if type(voiceTable[sound]) == "string" then return end - if voiceTable[sound]._pointer == nil then - for voice in pairs(voiceTable[sound]) do - if type(voiceTable[voice]) == "string" then - break - end - audio_sample_stop(voiceTable[sound][voice]) - end - else - audio_sample_stop(voiceTable[sound]) - end -end]] - -local playerSample = {} -for i = 0, MAX_PLAYERS - 1 do - playerSample[i] = nil -end - ---- @param m MarioState ---- @param sound CharacterSound -local function custom_character_sound(m, sound) - if m.playerIndex == 0 then - if stallTimer < stallSayLine then - return NO_SOUND - end - end - local index = m.playerIndex - if check_sound_exists(playerSample[index]) and type(playerSample[index]) ~= TYPE_STRING then - audio_sample_stop(playerSample[index]) - end - if optionTable[optionTableRef.localVoices].toggle == 0 then return NO_SOUND end - - -- get the voice table - local voiceTable = character_get_voice(m) - if voiceTable == nil then return end - -- load samples that haven't been loaded - for voice, name in pairs(voiceTable) do - if check_sound_exists(voiceTable[voice]) and type(voiceTable[voice]) == "string" then - local load = audio_sample_load(name) - if load ~= nil then - voiceTable[voice] = load - end - end - end - - -- get the sample to play - local voice = voiceTable[sound] - if voice == nil then return NO_SOUND end - playerSample[index] = voice - -- if there's no pointer then it must be a sound clip table - if voice._pointer == nil and type(voice) ~= TYPE_STRING then - -- run through each sample and load in any samples that haven't been loaded - for i, name in pairs(voice) do - if check_sound_exists(voice[i]) and type(voice[i]) == "string" then - local load = audio_sample_load(name) - if load ~= nil then - voice[i] = load - end - end - end - if #voice ~= 0 then - -- choose a random sample - playerSample[index] = voice[math_random(#voice)] - end - end - - -- Play the sample - if check_sound_exists(playerSample[index]) then - if sound == CHAR_SOUND_SNORING1 or sound == CHAR_SOUND_SNORING2 or sound == CHAR_SOUND_SNORING3 then - audio_sample_play(playerSample[index], m.pos, 0.5) - else - audio_sample_play(playerSample[index], m.pos, 1.0) - end - return NO_SOUND - end -end - ---- @param m MarioState -local function custom_character_snore(m) - if is_game_paused() or optionTable[optionTableRef.localVoices].toggle == 0 then return end - - if m.action ~= ACT_SLEEPING then - return - elseif m.actionState ~= 2 or (m.flags & MARIO_MARIO_SOUND_PLAYED) == 0 then - return - end - - local voice = character_get_voice(m) - if voice == nil then return end - local snoreTable = voice[CHAR_SOUND_SNORING3] - if snoreTable == nil or snoreTable._pointer ~= nil then - snoreTable = {} - for i = CHAR_SOUND_SNORING1, CHAR_SOUND_SNORING3 do - if voice[i] ~= nil then - table_insert(snoreTable, voice[i]) - end - end - end - - local animFrame = m.marioObj.header.gfx.animInfo.animFrame - if snoreTable ~= nil and #snoreTable >= 2 then - if animFrame == 2 and m.actionTimer < SLEEP_TALK_START then - custom_character_sound(m, snoreTable[2]) - elseif animFrame == 25 then - if #snoreTable >= 3 then - m.actionTimer = m.actionTimer + 1 - if m.actionTimer >= SLEEP_TALK_END then - m.actionTimer = STARTING_SNORE - end - if m.actionTimer == SLEEP_TALK_START then - play_character_sound(m, CHAR_SOUND_SNORING3) - elseif m.actionTimer < SLEEP_TALK_START then - play_character_sound(m, CHAR_SOUND_SNORING1) - end - else - play_character_sound(m, CHAR_SOUND_SNORING1) - end - end - elseif animFrame == 2 then - play_character_sound(m, CHAR_SOUND_SNORING2) - - elseif animFrame == 25 then - play_character_sound(m, CHAR_SOUND_SNORING1) - end -end - -local function update() - if is_game_paused() then - stop_all_custom_character_sounds() - end -end - -hook_event(HOOK_UPDATE, update) -hook_event(HOOK_ON_LEVEL_INIT, stop_all_custom_character_sounds) - -_G.charSelect.voice = { - sound = custom_character_sound, - snore = custom_character_snore, -} - --- 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) - cs_hook_mario_update(custom_character_snore) -end -_G.charSelect.config_character_sounds = config_character_sounds - --- Join sound -local function mario_update(m) - if m.playerIndex ~= 0 then return end - if stallTimer == stallSayLine then - play_character_sound(m, CHAR_SOUND_OKEY_DOKEY) - stallTimer = stallTimer + 1 - elseif stallTimer < stallSayLine then - stallTimer = stallTimer + 1 - end -end ---hook_event(HOOK_MARIO_UPDATE, mario_update) -cs_hook_mario_update(mario_update) \ No newline at end of file