mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-10-30 08:01:01 +00:00
Add Character Select to built in mods
This commit is contained in:
parent
949a05fd14
commit
c3ea12ff8c
9 changed files with 1176 additions and 0 deletions
90
mods/character-select-coop/a-utils.lua
Normal file
90
mods/character-select-coop/a-utils.lua
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
----------------------
|
||||||
|
-- Global Functions --
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
local saveableCharacters = {
|
||||||
|
["1"] = true,
|
||||||
|
["2"] = true,
|
||||||
|
["3"] = true,
|
||||||
|
["4"] = true,
|
||||||
|
["5"] = true,
|
||||||
|
["6"] = true,
|
||||||
|
["7"] = true,
|
||||||
|
["8"] = true,
|
||||||
|
["9"] = true,
|
||||||
|
["0"] = true,
|
||||||
|
["a"] = true,
|
||||||
|
["b"] = true,
|
||||||
|
["c"] = true,
|
||||||
|
["d"] = true,
|
||||||
|
["e"] = true,
|
||||||
|
["f"] = true,
|
||||||
|
["g"] = true,
|
||||||
|
["h"] = true,
|
||||||
|
["i"] = true,
|
||||||
|
["j"] = true,
|
||||||
|
["k"] = true,
|
||||||
|
["l"] = true,
|
||||||
|
["m"] = true,
|
||||||
|
["n"] = true,
|
||||||
|
["o"] = true,
|
||||||
|
["p"] = true,
|
||||||
|
["q"] = true,
|
||||||
|
["r"] = true,
|
||||||
|
["s"] = true,
|
||||||
|
["t"] = true,
|
||||||
|
["u"] = true,
|
||||||
|
["v"] = true,
|
||||||
|
["w"] = true,
|
||||||
|
["x"] = true,
|
||||||
|
["y"] = true,
|
||||||
|
["z"] = true,
|
||||||
|
["_"] = true,
|
||||||
|
["-"] = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
function string_underscore_to_space(string)
|
||||||
|
local s = ''
|
||||||
|
for i = 1, #string do
|
||||||
|
local c = string:sub(i,i)
|
||||||
|
if c ~= '_' then
|
||||||
|
s = s .. c
|
||||||
|
else
|
||||||
|
s = s .. " "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
function string_space_to_underscore(string)
|
||||||
|
local s = ''
|
||||||
|
for i = 1, #string do
|
||||||
|
local c = string:sub(i,i)
|
||||||
|
if saveableCharacters[string.lower(c)] then
|
||||||
|
s = s .. c
|
||||||
|
else
|
||||||
|
s = s .. "_"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------
|
||||||
|
-- Global Variables --
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
modVersion = "1.5"
|
||||||
|
|
||||||
|
allowMenu = {}
|
||||||
|
|
||||||
|
menuColorTable = {
|
||||||
|
{r = 255, g = 50, b = 50 },
|
||||||
|
{r = 255, g = 100, b = 50 },
|
||||||
|
{r = 255, g = 255, b = 50 },
|
||||||
|
{r = 50, g = 255, b = 50 },
|
||||||
|
{r = 100, g = 100, b = 255},
|
||||||
|
{r = 251, g = 148, b = 220},
|
||||||
|
{r = 130, g = 25, b = 130},
|
||||||
|
{r = 255, g = 255, b = 255},
|
||||||
|
{r = 50, g = 50, b = 50 },
|
||||||
|
}
|
||||||
BIN
mods/character-select-coop/actors/armature_geo.bin
Normal file
BIN
mods/character-select-coop/actors/armature_geo.bin
Normal file
Binary file not shown.
788
mods/character-select-coop/main.lua
Normal file
788
mods/character-select-coop/main.lua
Normal file
|
|
@ -0,0 +1,788 @@
|
||||||
|
-- name: Character Select
|
||||||
|
-- description: A Library / API made to make adding and\nusing Custom Characters as simple as possible!\n\nCreated by:\\#008800\\ Squishy6094\n\\#dcdcdc\\Concepts by:\\#4496f5\\ AngelicMiracles\\#AAAAFF\\\n\nGithub:\nSquishy6094/character-select-coop
|
||||||
|
|
||||||
|
|
||||||
|
menu = false
|
||||||
|
options = false
|
||||||
|
|
||||||
|
currChar = 1
|
||||||
|
local currOption = 1
|
||||||
|
|
||||||
|
|
||||||
|
local TEX_HEADER = get_texture_info("char-select-text")
|
||||||
|
|
||||||
|
local TEXT_PREF_LOAD = "Default"
|
||||||
|
|
||||||
|
local ommActive = _G.OmmApi ~= nil
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Note: Do NOT add characters via the characterTable below,
|
||||||
|
We highly reccomend you create your own mod and use the
|
||||||
|
API to add characters, this ensures your pack is easy
|
||||||
|
to use for anyone and low on file space!
|
||||||
|
]]
|
||||||
|
characterTable = {
|
||||||
|
[1] = {
|
||||||
|
name = "Default",
|
||||||
|
description = {"The vanilla cast for sm64ex-coop!", "", "These Characters are swappable", "via the default Options Menu"},
|
||||||
|
credit = "Nintendo / Coop Team",
|
||||||
|
color = {r = 255, g = 50, b = 50},
|
||||||
|
model = nil,
|
||||||
|
forceChar = nil,
|
||||||
|
lifeIcon = gTextures.mario_head,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local optionTableRef = {
|
||||||
|
openInputs = 1,
|
||||||
|
menuColor = 2,
|
||||||
|
anims = 3,
|
||||||
|
inputLatency = 4,
|
||||||
|
localModels = 5,
|
||||||
|
prefToDefault = 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
optionTable = {
|
||||||
|
[optionTableRef.openInputs] = {
|
||||||
|
name = "Open Binds",
|
||||||
|
toggle = tonumber(mod_storage_load("MenuInput")),
|
||||||
|
toggleSaveName = "MenuInput",
|
||||||
|
toggleDefault = 0,
|
||||||
|
toggleMax = 2,
|
||||||
|
toggleNames = {"None", ommActive and "D-pad Down + R" or "D-pad Down", "Z (Pause Menu)"},
|
||||||
|
},
|
||||||
|
[optionTableRef.menuColor] = {
|
||||||
|
name = "Menu Color",
|
||||||
|
toggle = tonumber(mod_storage_load("MenuColor")),
|
||||||
|
toggleSaveName = "MenuColor",
|
||||||
|
toggleDefault = 0,
|
||||||
|
toggleMax = 9,
|
||||||
|
toggleNames = {"Auto", "Red", "Orange", "Yellow", "Green", "Blue", "Pink", "Purple", "White", "Black"},
|
||||||
|
},
|
||||||
|
[optionTableRef.anims] = {
|
||||||
|
name = "Animations",
|
||||||
|
toggle = tonumber(mod_storage_load("Anims")),
|
||||||
|
toggleSaveName = "Anims",
|
||||||
|
toggleDefault = 1,
|
||||||
|
toggleMax = 1,
|
||||||
|
},
|
||||||
|
[optionTableRef.inputLatency] = {
|
||||||
|
name = "Scroll Speed",
|
||||||
|
toggle = tonumber(mod_storage_load("Latency")),
|
||||||
|
toggleSaveName = "Latency",
|
||||||
|
toggleDefault = 1,
|
||||||
|
toggleMax = 2,
|
||||||
|
toggleNames = {"Slow", "Normal", "Fast"},
|
||||||
|
},
|
||||||
|
[optionTableRef.localModels] = {
|
||||||
|
name = "Locally Display Models",
|
||||||
|
toggle = tonumber(mod_storage_load("localModels")),
|
||||||
|
toggleSaveName = "localModels",
|
||||||
|
toggleDefault = 1,
|
||||||
|
toggleMax = 1,
|
||||||
|
},
|
||||||
|
[optionTableRef.prefToDefault] = {
|
||||||
|
name = "Set Preference to Default",
|
||||||
|
toggle = 0,
|
||||||
|
toggleDefault = 0,
|
||||||
|
toggleMax = 1,
|
||||||
|
toggleNames = {"", ""},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local defaultPlayerColors = {
|
||||||
|
[CT_MARIO] = {r = 255, g = 50, b = 50},
|
||||||
|
[CT_LUIGI] = {r = 50, g = 255, b = 50},
|
||||||
|
[CT_TOAD] = {r = 100, g = 100, b = 255},
|
||||||
|
[CT_WALUIGI] = {r = 130, g = 25, b = 130},
|
||||||
|
[CT_WARIO] = {r = 255, g = 255, b = 50},
|
||||||
|
}
|
||||||
|
|
||||||
|
local defaultIcons = {
|
||||||
|
[CT_MARIO] = gTextures.mario_head,
|
||||||
|
[CT_LUIGI] = gTextures.luigi_head,
|
||||||
|
[CT_TOAD] = gTextures.toad_head,
|
||||||
|
[CT_WALUIGI] = gTextures.waluigi_head,
|
||||||
|
[CT_WARIO] = gTextures.wario_head,
|
||||||
|
}
|
||||||
|
|
||||||
|
local latencyValueTable = {15, 10, 5}
|
||||||
|
|
||||||
|
local camera_freeze = camera_freeze
|
||||||
|
local camera_unfreeze = camera_unfreeze
|
||||||
|
local network_local_index_from_global = network_local_index_from_global
|
||||||
|
local obj_set_model_extended = obj_set_model_extended
|
||||||
|
local hud_hide = hud_hide
|
||||||
|
local hud_show = hud_show
|
||||||
|
local djui_chat_message_create = djui_chat_message_create
|
||||||
|
local djui_hud_set_resolution = djui_hud_set_resolution
|
||||||
|
local djui_hud_set_font = djui_hud_set_font
|
||||||
|
local djui_hud_set_color = djui_hud_set_color
|
||||||
|
local djui_hud_get_screen_width = djui_hud_get_screen_width
|
||||||
|
local djui_hud_render_rect = djui_hud_render_rect
|
||||||
|
local djui_hud_print_text = djui_hud_print_text
|
||||||
|
local djui_hud_render_texture = djui_hud_render_texture
|
||||||
|
local math_max = math.max
|
||||||
|
local math_min = math.min
|
||||||
|
local math_sin = math.sin
|
||||||
|
local math_random = math.random
|
||||||
|
local play_sound = play_sound
|
||||||
|
local mod_storage_save = mod_storage_save
|
||||||
|
local mod_storage_load = mod_storage_load
|
||||||
|
local string_lower = string.lower
|
||||||
|
|
||||||
|
---@param m MarioState
|
||||||
|
local function nullify_inputs(m)
|
||||||
|
local c = m.controller
|
||||||
|
_G.charSelect.controller = {
|
||||||
|
buttonDown = c.buttonDown,
|
||||||
|
buttonPressed = c.buttonPressed & ~_G.charSelect.controller.buttonDown,
|
||||||
|
extStickX = c.extStickX,
|
||||||
|
extStickY = c.extStickY,
|
||||||
|
rawStickX = c.rawStickX,
|
||||||
|
rawStickY = c.rawStickY,
|
||||||
|
stickMag = c.stickMag,
|
||||||
|
stickX = c.stickX,
|
||||||
|
stickY = c.stickY
|
||||||
|
}
|
||||||
|
c.buttonDown = 0
|
||||||
|
c.buttonPressed = 0
|
||||||
|
c.extStickX = 0
|
||||||
|
c.extStickY = 0
|
||||||
|
c.rawStickX = 0
|
||||||
|
c.rawStickY = 0
|
||||||
|
c.stickMag = 0
|
||||||
|
c.stickX = 0
|
||||||
|
c.stickY = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local function load_preferred_char()
|
||||||
|
if mod_storage_load("PrefChar") ~= nil and mod_storage_load("PrefChar") ~= "Default" then
|
||||||
|
for i = 2, #characterTable do
|
||||||
|
if characterTable[i].name == mod_storage_load("PrefChar") then
|
||||||
|
currChar = i
|
||||||
|
djui_popup_create('Character Select:\nYour Preferred Character\n"'..string_underscore_to_space(characterTable[i].name)..'"\nwas applied successfully!', 4)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif mod_storage_load("PrefChar") == nil then
|
||||||
|
mod_storage_save("PrefChar", "Default")
|
||||||
|
end
|
||||||
|
if #characterTable == 1 then
|
||||||
|
djui_popup_create("Character Select:\nNo Characters were Found", 2)
|
||||||
|
end
|
||||||
|
TEXT_PREF_LOAD = mod_storage_load("PrefChar")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function failsafe_options()
|
||||||
|
for i = 1, #optionTable do
|
||||||
|
if optionTable[i].toggle == nil then
|
||||||
|
optionTable[i].toggle = optionTable[i].toggleDefault
|
||||||
|
if optionTable[i].toggleSaveName ~= nil then
|
||||||
|
mod_storage_save(optionTable[i].toggleSaveName, tostring(optionTable[i].toggle))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if optionTable[i].toggleNames == nil then
|
||||||
|
optionTable[i].toggleNames = {"Off", "On"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if optionTable[optionTableRef.openInputs].toggle == 1 and ommActive then
|
||||||
|
djui_popup_create('Character Select:\nYour Open bind has changed to:\nD-pad Down + R\nDue to OMM Rebirth being active!', 4)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local hasOpenedMenu = false
|
||||||
|
|
||||||
|
local function idiot_proof_note()
|
||||||
|
if mod_storage_load("openedmenu") == nil then
|
||||||
|
if #characterTable > 1 then
|
||||||
|
djui_chat_message_create("Character Select is active and has "..(#characterTable - 1).." characters available!\nYou can use \\#ffff00\\/char-select \\#ffffff\\to open the menu!")
|
||||||
|
else
|
||||||
|
djui_chat_message_create("Character Select is active!\nYou can use \\#ffff00\\/char-select \\#ffffff\\to open the menu!")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
hasOpenedMenu = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
-- Model Handler --
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
local stallFrame = 0
|
||||||
|
local noLoop = false
|
||||||
|
|
||||||
|
-- Respecfully, GO FUCK YOURSELVES. I hate EVERY SINGLE ONE OF YOU. Your lives are NOTHING. You serve ZERO PURPOSE. You should kill yourselves, NOW!
|
||||||
|
local ignored_surfaces = {
|
||||||
|
SURFACE_BURNING, SURFACE_QUICKSAND, SURFACE_INSTANT_QUICKSAND, SURFACE_INSTANT_MOVING_QUICKSAND, SURFACE_DEEP_MOVING_QUICKSAND, SURFACE_INSTANT_QUICKSAND, SURFACE_DEEP_QUICKSAND, SURFACE_SHALLOW_MOVING_QUICKSAND,
|
||||||
|
SURFACE_SHALLOW_QUICKSAND, SURFACE_WARP, SURFACE_LOOK_UP_WARP, SURFACE_WOBBLING_WARP, SURFACE_INSTANT_WARP_1B, SURFACE_INSTANT_WARP_1C, SURFACE_INSTANT_WARP_1D, SURFACE_INSTANT_WARP_1E
|
||||||
|
}
|
||||||
|
-- Yes, floral gave me permission to use this table full of USELESS PIECES OF SHITS
|
||||||
|
|
||||||
|
--- @param m MarioState
|
||||||
|
local function mario_update(m)
|
||||||
|
if stallFrame == 1 then
|
||||||
|
load_preferred_char()
|
||||||
|
failsafe_options()
|
||||||
|
idiot_proof_note()
|
||||||
|
end
|
||||||
|
|
||||||
|
if stallFrame < 2 then
|
||||||
|
stallFrame = stallFrame + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if m.playerIndex == 0 and stallFrame > 1 then
|
||||||
|
characterTable[1].forceChar = gNetworkPlayers[m.playerIndex].modelIndex
|
||||||
|
if currChar == 1 then
|
||||||
|
characterTable[1].color = defaultPlayerColors[gNetworkPlayers[m.playerIndex].modelIndex]
|
||||||
|
characterTable[1].lifeIcon = defaultIcons[gNetworkPlayers[m.playerIndex].modelIndex]
|
||||||
|
end
|
||||||
|
if optionTable[optionTableRef.localModels].toggle > 0 then
|
||||||
|
gPlayerSyncTable[0].modelId = characterTable[currChar].model
|
||||||
|
gPlayerSyncTable[0].capModels = characterTable[currChar].capModels
|
||||||
|
if characterTable[currChar].forceChar ~= nil then
|
||||||
|
gNetworkPlayers[m.playerIndex].overrideModelIndex = characterTable[currChar].forceChar
|
||||||
|
end
|
||||||
|
else
|
||||||
|
gPlayerSyncTable[0].modelId = nil
|
||||||
|
gPlayerSyncTable[0].capModels = nil
|
||||||
|
gNetworkPlayers[m.playerIndex].overrideModelIndex = characterTable[1].forceChar
|
||||||
|
end
|
||||||
|
|
||||||
|
if menu then
|
||||||
|
for _, func in pairs(allowMenu) do
|
||||||
|
if not func() then
|
||||||
|
menu = false
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
camera_freeze()
|
||||||
|
hud_hide()
|
||||||
|
if _G.PersonalStarCounter then
|
||||||
|
_G.PersonalStarCounter.hide_star_counters(true)
|
||||||
|
end
|
||||||
|
local focusPos = {
|
||||||
|
x = m.pos.x,
|
||||||
|
y = m.pos.y + 120,
|
||||||
|
z = m.pos.z,
|
||||||
|
}
|
||||||
|
vec3f_copy(gLakituState.focus, focusPos)
|
||||||
|
gLakituState.pos.x = m.pos.x + sins(m.faceAngle.y) * 500
|
||||||
|
gLakituState.pos.y = m.pos.y + 100
|
||||||
|
gLakituState.pos.z = m.pos.z + coss(m.faceAngle.y) * 500
|
||||||
|
|
||||||
|
if m.forwardVel == 0 and m.pos.y == m.floorHeight and not ignored_surfaces[m.floor.type] and m.health > 255 then
|
||||||
|
set_mario_action(m, ACT_IDLE, 0)
|
||||||
|
set_mario_animation(m, MARIO_ANIM_STAR_DANCE)
|
||||||
|
end
|
||||||
|
noLoop = false
|
||||||
|
elseif not noLoop then
|
||||||
|
camera_unfreeze()
|
||||||
|
hud_show()
|
||||||
|
if _G.PersonalStarCounter then
|
||||||
|
_G.PersonalStarCounter.hide_star_counters(false)
|
||||||
|
end
|
||||||
|
noLoop = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--Set Pref to Default Check
|
||||||
|
if optionTable[optionTableRef.prefToDefault].toggle > 0 then
|
||||||
|
mod_storage_save("PrefChar", "Default")
|
||||||
|
TEXT_PREF_LOAD = "Default"
|
||||||
|
optionTable[optionTableRef.prefToDefault].toggle = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function set_model(o, model)
|
||||||
|
if obj_has_behavior_id(o, id_bhvMario) ~= 0 then
|
||||||
|
local i = network_local_index_from_global(o.globalPlayerIndex)
|
||||||
|
if gPlayerSyncTable[i].modelId ~= nil and obj_has_model_extended(o, gPlayerSyncTable[i].modelId) == 0 then
|
||||||
|
obj_set_model_extended(o, gPlayerSyncTable[i].modelId)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if get_object_list_from_behavior(o.behavior) == OBJ_LIST_LEVEL then
|
||||||
|
local i = network_local_index_from_global(o.globalPlayerIndex)
|
||||||
|
local capModels = gPlayerSyncTable[i].capModels
|
||||||
|
local capModel = nil
|
||||||
|
if capModels ~= nil then
|
||||||
|
if model == gMarioStates[i].character.capModelId then
|
||||||
|
capModel = capModels.normal
|
||||||
|
elseif model == gMarioStates[i].character.capWingModelId then
|
||||||
|
capModel = capModels.wing
|
||||||
|
elseif model == gMarioStates[i].character.capMetalModelId then
|
||||||
|
capModel = capModels.metal
|
||||||
|
elseif model == gMarioStates[i].character.capMetalWingModelId then
|
||||||
|
capModel = capModels.metalWing
|
||||||
|
end
|
||||||
|
if capModel ~= nil and obj_has_model_extended(o, capModel) == 0 then
|
||||||
|
obj_set_model_extended(o, capModel)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hook_event(HOOK_MARIO_UPDATE, mario_update)
|
||||||
|
hook_event(HOOK_OBJECT_SET_MODEL, set_model)
|
||||||
|
|
||||||
|
------------------
|
||||||
|
-- Menu Handler --
|
||||||
|
------------------
|
||||||
|
|
||||||
|
local buttonAnimTimer = 0
|
||||||
|
local buttonScroll = 0
|
||||||
|
local buttonScrollCap = 30
|
||||||
|
|
||||||
|
local optionAnimTimer = -200
|
||||||
|
local optionAnimTimerCap = optionAnimTimer
|
||||||
|
|
||||||
|
local inputStallTimer = 0
|
||||||
|
local inputStallTo = 15
|
||||||
|
|
||||||
|
local TEXT_OPTIONS_HEADER = "Menu Options"
|
||||||
|
local TEXT_RATIO_UNSUPPORTED = "Your Current Aspect-Ratio isn't Supported!"
|
||||||
|
local TEXT_DESCRIPTION = "Character Description:"
|
||||||
|
local TEXT_PREF_SAVE = "Press A to Set as Preferred Character"
|
||||||
|
local TEXT_PAUSE_Z_OPEN = "Z Button - Character Select"
|
||||||
|
local TEXT_PAUSE_CURR_CHAR = "Current Character: "
|
||||||
|
if math_random(100) == 64 then -- Easter Egg if you get lucky loading the mod >v<
|
||||||
|
TEXT_PAUSE_Z_OPEN = "Z - DynOS" -- Referencing the original sm64ex DynOS options
|
||||||
|
TEXT_PAUSE_CURR_CHAR = "Model: "
|
||||||
|
end
|
||||||
|
local TEXT_OPTIONS_OPEN = "Press START to open Options"
|
||||||
|
local TEXT_MENU_CLOSE = "Press B to Exit Menu"
|
||||||
|
local TEXT_OPTIONS_SELECT = "A - Select | B - Exit "
|
||||||
|
local TEXT_LOCAL_MODEL_OFF = "Locally Display Models is Off"
|
||||||
|
local TEXT_LOCAL_MODEL_OFF_OPTIONS = "You can turn it back on in the Options Menu"
|
||||||
|
|
||||||
|
local menuColor = characterTable[currChar].color
|
||||||
|
|
||||||
|
local function on_hud_render()
|
||||||
|
djui_hud_set_resolution(RESOLUTION_N64)
|
||||||
|
djui_hud_set_font(FONT_NORMAL)
|
||||||
|
|
||||||
|
local width = djui_hud_get_screen_width() + 1.4
|
||||||
|
local height = 240
|
||||||
|
local widthHalf = width*0.5
|
||||||
|
local heightHalf = height*0.5
|
||||||
|
local widthScale = math_max(width, 321.4)*0.00311332503
|
||||||
|
|
||||||
|
if menu then
|
||||||
|
if optionTable[optionTableRef.menuColor].toggle ~= 0 then
|
||||||
|
menuColor = menuColorTable[optionTable[optionTableRef.menuColor].toggle]
|
||||||
|
else
|
||||||
|
menuColor = characterTable[currChar].color
|
||||||
|
end
|
||||||
|
|
||||||
|
if optionTable[optionTableRef.localModels].toggle == 0 then
|
||||||
|
djui_hud_set_color(0, 0, 0, 200)
|
||||||
|
djui_hud_render_rect(0, 0, width, height)
|
||||||
|
djui_hud_set_color(255, 255, 255, 255)
|
||||||
|
djui_hud_print_text(TEXT_LOCAL_MODEL_OFF, widthHalf - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF)*0.15*widthScale, heightHalf, 0.3 * widthScale)
|
||||||
|
djui_hud_print_text(TEXT_LOCAL_MODEL_OFF_OPTIONS, widthHalf - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF_OPTIONS)*0.1*widthScale, heightHalf + 10*widthScale, 0.2*widthScale)
|
||||||
|
end
|
||||||
|
|
||||||
|
--Character Buttons
|
||||||
|
local x = 135 * widthScale * 0.8
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_render_rect(0, 0, x, height)
|
||||||
|
djui_hud_set_color(0, 0, 0, 255)
|
||||||
|
djui_hud_render_rect(2, 2, x - 4, height - 4)
|
||||||
|
|
||||||
|
if optionTable[optionTableRef.anims].toggle > 0 then
|
||||||
|
buttonAnimTimer = buttonAnimTimer + 1
|
||||||
|
end
|
||||||
|
if optionTable[optionTableRef.anims].toggle == 0 then
|
||||||
|
buttonScroll = 0
|
||||||
|
elseif buttonScroll > 0.1 or buttonScroll < -0.1 then
|
||||||
|
buttonScroll = buttonScroll*0.03*inputStallTo
|
||||||
|
end
|
||||||
|
|
||||||
|
local buttonColor = {}
|
||||||
|
for i = -1, 4 do
|
||||||
|
if characterTable[i + currChar] ~= nil then
|
||||||
|
buttonColor = characterTable[i + currChar].color
|
||||||
|
djui_hud_set_color(buttonColor.r, buttonColor.g, buttonColor.b, 255)
|
||||||
|
local buttonX = 20 * widthScale
|
||||||
|
if optionTable[optionTableRef.anims].toggle > 0 then
|
||||||
|
if i == 0 then buttonX = buttonX + math_sin(buttonAnimTimer*0.05)*2.5 + 5 end
|
||||||
|
else
|
||||||
|
if i == 0 then buttonX = buttonX + 10 end
|
||||||
|
end
|
||||||
|
local y = (i + 3) * 30 + buttonScroll
|
||||||
|
djui_hud_render_rect(buttonX, y, 70, 20)
|
||||||
|
djui_hud_set_color(0, 0, 0, 255)
|
||||||
|
djui_hud_render_rect(buttonX + 1, y + 1, 68, 18)
|
||||||
|
djui_hud_set_font(FONT_TINY)
|
||||||
|
djui_hud_set_color(buttonColor.r, buttonColor.g, buttonColor.b, 255)
|
||||||
|
djui_hud_print_text(string_underscore_to_space(characterTable[currChar + i].name), buttonX + 5, y + 5, 0.6)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_render_rect(0, height-2, x, 2)
|
||||||
|
|
||||||
|
-- Scroll Bar
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_render_rect(7 * widthScale, 55, 7, 180)
|
||||||
|
djui_hud_set_color(0, 0, 0, 255)
|
||||||
|
djui_hud_render_rect(7 * widthScale + 1, 56, 5, 178)
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_render_rect(7 * widthScale + 2, 57 + 176 * ((currChar - 1) / #characterTable) - (buttonScroll*0.03333333333)*(176/#characterTable), 3, 176/#characterTable)
|
||||||
|
|
||||||
|
|
||||||
|
--Character Description
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_render_rect(width - x, 0, x, height)
|
||||||
|
djui_hud_set_color(0, 0, 0, 255)
|
||||||
|
djui_hud_render_rect(width - x + 2, 2, x - 4, height - 4)
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_set_font(FONT_NORMAL)
|
||||||
|
|
||||||
|
local TEXT_NAME = string_underscore_to_space(characterTable[currChar].name)
|
||||||
|
local TEXT_CREDIT = "By: "..characterTable[currChar].credit
|
||||||
|
local TEXT_DESCRIPTION_TABLE = characterTable[currChar].description
|
||||||
|
local TEXT_PREF = 'Preferred Character: "'..string_underscore_to_space(TEXT_PREF_LOAD)..'"'
|
||||||
|
|
||||||
|
local textX = x * 0.5
|
||||||
|
djui_hud_print_text(TEXT_NAME, width - textX - djui_hud_measure_text(TEXT_NAME)*0.3, 55, 0.6)
|
||||||
|
djui_hud_set_font(FONT_TINY)
|
||||||
|
djui_hud_print_text(TEXT_CREDIT, width - textX - djui_hud_measure_text(TEXT_CREDIT)*0.3, 72, 0.6)
|
||||||
|
djui_hud_set_font(FONT_NORMAL)
|
||||||
|
djui_hud_print_text(TEXT_DESCRIPTION, width - textX - djui_hud_measure_text(TEXT_DESCRIPTION)*0.2, 85, 0.4)
|
||||||
|
for i = 1, #TEXT_DESCRIPTION_TABLE do
|
||||||
|
djui_hud_print_text(TEXT_DESCRIPTION_TABLE[i], width - textX - djui_hud_measure_text(TEXT_DESCRIPTION_TABLE[i])*0.15, 90 + i*9, 0.3)
|
||||||
|
end
|
||||||
|
djui_hud_print_text(TEXT_PREF, width - textX - djui_hud_measure_text(TEXT_PREF)*0.15, height - 20, 0.3)
|
||||||
|
djui_hud_print_text(TEXT_PREF_SAVE, width - textX - djui_hud_measure_text(TEXT_PREF_SAVE)*0.15, height - 30, 0.3)
|
||||||
|
|
||||||
|
--Character Select Header
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_render_rect(0, 0, width, 50)
|
||||||
|
djui_hud_set_color(0, 0, 0, 255)
|
||||||
|
djui_hud_render_rect(2, 2, width - 4, 46)
|
||||||
|
djui_hud_set_color(menuColor.r * 0.5 + 127, menuColor.g * 0.5 + 127, menuColor.b * 0.5 + 127, 255)
|
||||||
|
djui_hud_render_texture(TEX_HEADER, widthHalf - 128, 10, 1, 1)
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_set_font(FONT_TINY)
|
||||||
|
djui_hud_print_text("Version: "..modVersion, 5, 3, 0.5)
|
||||||
|
--Unsupported Res Warning
|
||||||
|
if width < 321.2 or width > 575 then
|
||||||
|
djui_hud_print_text(TEXT_RATIO_UNSUPPORTED, 5, 39, 0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
--Options display
|
||||||
|
if options or optionAnimTimer > optionAnimTimerCap then
|
||||||
|
djui_hud_set_color(menuColor.r * 0.25, menuColor.g * 0.25, menuColor.b * 0.25, 205 + math_max(-200, optionAnimTimer))
|
||||||
|
djui_hud_render_rect(0, 0, width, height)
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_render_rect(width*0.5 - 50 * widthScale, math.min(55 - optionAnimTimer, height - 25 * widthScale), 100 * widthScale, 200)
|
||||||
|
djui_hud_set_color(0, 0, 0, 255)
|
||||||
|
djui_hud_render_rect(width*0.5 - 50 * widthScale + 2, math.min(55 - optionAnimTimer + 2, height - 25 * widthScale + 2), 100 * widthScale - 4, 196)
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_render_rect(width*0.5 - 50 * widthScale, height - 2, 100 * widthScale, 2)
|
||||||
|
djui_hud_set_font(FONT_NORMAL)
|
||||||
|
djui_hud_set_color(menuColor.r * 0.5 + 127, menuColor.g * 0.5 + 127, menuColor.b * 0.5 + 127, 255)
|
||||||
|
djui_hud_print_text(TEXT_OPTIONS_HEADER, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_HEADER)*0.3*widthScale, 65 + optionAnimTimer * -1, 0.6*widthScale)
|
||||||
|
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
for i = 1, #optionTable do
|
||||||
|
local toggleName = optionTable[i].name
|
||||||
|
local scale = 0.5
|
||||||
|
local yOffset = 70 + 10 * math_min(widthScale, 1.8) + i * 9 * math_min(widthScale, 1.8) - optionAnimTimer
|
||||||
|
if i == currOption then
|
||||||
|
djui_hud_set_font(FONT_NORMAL)
|
||||||
|
scale = 0.3
|
||||||
|
yOffset = yOffset - 1
|
||||||
|
if optionTable[i].toggleNames[optionTable[i].toggle + 1] ~= "" then
|
||||||
|
toggleName = "> " .. toggleName .. " - " .. optionTable[i].toggleNames[optionTable[i].toggle + 1]
|
||||||
|
else
|
||||||
|
toggleName = "> " .. toggleName
|
||||||
|
end
|
||||||
|
else
|
||||||
|
djui_hud_set_font(FONT_TINY)
|
||||||
|
end
|
||||||
|
scale = scale * math_min(widthScale, 1.8)
|
||||||
|
djui_hud_print_text(toggleName, widthHalf - djui_hud_measure_text(toggleName)*scale*0.5, yOffset, scale)
|
||||||
|
end
|
||||||
|
|
||||||
|
djui_hud_set_font(FONT_TINY)
|
||||||
|
djui_hud_print_text(TEXT_OPTIONS_SELECT, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_SELECT)*0.3, height - 20 - optionAnimTimer, 0.6)
|
||||||
|
else
|
||||||
|
-- How to open options display
|
||||||
|
local widthScaleUnlimited = widthScale
|
||||||
|
local widthScale = math_min(widthScale, 1.42)
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_render_rect(widthHalf - 50 * widthScaleUnlimited, height - 25 * widthScale, 100 * widthScaleUnlimited, 26 * widthScale)
|
||||||
|
djui_hud_set_color(0, 0, 0, 255)
|
||||||
|
djui_hud_render_rect(widthHalf - 50 * widthScaleUnlimited + 2, height - 25 * widthScale + 2, 100 * widthScaleUnlimited - 4, 22 * widthScale)
|
||||||
|
djui_hud_set_color(menuColor.r, menuColor.g, menuColor.b, 255)
|
||||||
|
djui_hud_render_rect(widthHalf - 50 * widthScaleUnlimited, height - 2, 100 * widthScaleUnlimited, 2)
|
||||||
|
djui_hud_set_font(FONT_NORMAL)
|
||||||
|
djui_hud_print_text(TEXT_OPTIONS_OPEN, widthHalf - djui_hud_measure_text(TEXT_OPTIONS_OPEN)*0.175 * widthScale, height - 23 * widthScale + optionAnimTimer + 202, 0.35 * widthScale)
|
||||||
|
djui_hud_set_font(FONT_TINY)
|
||||||
|
djui_hud_print_text(TEXT_MENU_CLOSE, widthHalf - djui_hud_measure_text(TEXT_MENU_CLOSE)*0.25 * widthScale, height - 13 * widthScale + optionAnimTimer + 202, 0.5 * widthScale)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Anim logic
|
||||||
|
if options then
|
||||||
|
if optionTable[optionTableRef.anims].toggle > 0 then
|
||||||
|
if optionAnimTimer < -1 then
|
||||||
|
optionAnimTimer = optionAnimTimer/1.1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
optionAnimTimer = -1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if optionTable[optionTableRef.anims].toggle > 0 then
|
||||||
|
if optionAnimTimer > optionAnimTimerCap then
|
||||||
|
optionAnimTimer = optionAnimTimer*1.2
|
||||||
|
end
|
||||||
|
else
|
||||||
|
optionAnimTimer = optionAnimTimerCap
|
||||||
|
end
|
||||||
|
end
|
||||||
|
optionAnimTimer = math_max(optionAnimTimer, -200)
|
||||||
|
else
|
||||||
|
options = false
|
||||||
|
optionAnimTimer = optionAnimTimerCap
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Info / Z Open Bind on Pause Menu
|
||||||
|
if is_game_paused() and not djui_hud_is_pause_menu_created() and gMarioStates[0].action ~= ACT_EXIT_LAND_SAVE_DIALOG then
|
||||||
|
local currCharY = 0
|
||||||
|
djui_hud_set_resolution(RESOLUTION_DJUI)
|
||||||
|
if optionTable[optionTableRef.openInputs].toggle == 2 then
|
||||||
|
currCharY = 27
|
||||||
|
local width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_PAUSE_Z_OPEN)
|
||||||
|
djui_hud_set_font(FONT_NORMAL)
|
||||||
|
djui_hud_set_color(0, 0, 0, 255)
|
||||||
|
djui_hud_print_text(TEXT_PAUSE_Z_OPEN, width - 19, 17, 1)
|
||||||
|
djui_hud_set_color(255, 255, 255, 255)
|
||||||
|
djui_hud_print_text(TEXT_PAUSE_Z_OPEN, width - 20, 16, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
if optionTable[optionTableRef.localModels].toggle == 1 then
|
||||||
|
local charName = string_underscore_to_space(characterTable[currChar].name)
|
||||||
|
local TEXT_PAUSE_CURR_CHAR_WITH_NAME = TEXT_PAUSE_CURR_CHAR..charName
|
||||||
|
local width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_PAUSE_CURR_CHAR_WITH_NAME)
|
||||||
|
local charColor = characterTable[currChar].color
|
||||||
|
djui_hud_set_font(FONT_NORMAL)
|
||||||
|
djui_hud_set_color(0, 0, 0, 255)
|
||||||
|
djui_hud_print_text(TEXT_PAUSE_CURR_CHAR_WITH_NAME, width - 19, 17 + currCharY, 1)
|
||||||
|
djui_hud_set_color(255, 255, 255, 255)
|
||||||
|
djui_hud_print_text(TEXT_PAUSE_CURR_CHAR, width - 20, 16 + currCharY, 1)
|
||||||
|
djui_hud_set_color(charColor.r, charColor.g, charColor.b, 255)
|
||||||
|
djui_hud_print_text(charName, djui_hud_get_screen_width() - djui_hud_measure_text(charName) - 20, 16 + currCharY, 1)
|
||||||
|
else
|
||||||
|
local width = djui_hud_get_screen_width() - djui_hud_measure_text(TEXT_LOCAL_MODEL_OFF)
|
||||||
|
djui_hud_set_font(FONT_NORMAL)
|
||||||
|
djui_hud_set_color(0, 0, 0, 255)
|
||||||
|
djui_hud_print_text(TEXT_LOCAL_MODEL_OFF, width - 19, 17 + currCharY, 1)
|
||||||
|
djui_hud_set_color(255, 255, 255, 255)
|
||||||
|
djui_hud_print_text(TEXT_LOCAL_MODEL_OFF, width - 20, 16 + currCharY, 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Custom life icon rendering (Thanks LuigiGamer)
|
||||||
|
function on_life_counter_render()
|
||||||
|
if obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then return end
|
||||||
|
-- Rendering settings --
|
||||||
|
djui_hud_set_font(FONT_HUD)
|
||||||
|
djui_hud_set_resolution(RESOLUTION_N64)
|
||||||
|
djui_hud_set_color(255, 255, 255, 255);
|
||||||
|
|
||||||
|
-- Texture scale --
|
||||||
|
|
||||||
|
-- Texture position --
|
||||||
|
local x = 22
|
||||||
|
local y = 15
|
||||||
|
|
||||||
|
-- Texture Rendering --
|
||||||
|
if gNetworkPlayers[0].currActNum == 99 then return end
|
||||||
|
if not hud_is_hidden() then
|
||||||
|
local icon = characterTable[currChar].lifeIcon
|
||||||
|
djui_hud_render_texture(icon, x, y, 1/(icon.width/16), 1/(icon.height/16))
|
||||||
|
djui_hud_print_text("@", x + 16, y, 1)
|
||||||
|
djui_hud_print_text(tostring(gMarioStates[0].numLives), x + 32, y, 1)
|
||||||
|
hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) &~ HUD_DISPLAY_FLAG_LIVES) -- Hides the lives counter
|
||||||
|
else
|
||||||
|
hud_set_value(HUD_DISPLAY_FLAGS, hud_get_value(HUD_DISPLAY_FLAGS) | HUD_DISPLAY_FLAG_LIVES) -- Shows the lives counter, use this when you're no longer using a custom character
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function before_mario_update(m)
|
||||||
|
if m.playerIndex ~= 0 then return end
|
||||||
|
if inputStallTimer > 0 then inputStallTimer = inputStallTimer - 1 end
|
||||||
|
|
||||||
|
if menu and inputStallTo ~= latencyValueTable[optionTable[optionTableRef.inputLatency].toggle + 1] then
|
||||||
|
inputStallTo = latencyValueTable[optionTable[optionTableRef.inputLatency].toggle + 1]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Menu Inputs
|
||||||
|
if not menu and (m.controller.buttonDown & D_JPAD) ~= 0 and m.action ~= ACT_EXIT_LAND_SAVE_DIALOG and optionTable[optionTableRef.openInputs].toggle == 1 then
|
||||||
|
if ommActive then
|
||||||
|
if (m.controller.buttonDown & R_TRIG) ~= 0 then
|
||||||
|
menu = true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
menu = true
|
||||||
|
end
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
end
|
||||||
|
if is_game_paused() and m.action ~= ACT_EXIT_LAND_SAVE_DIALOG and (m.controller.buttonPressed & Z_TRIG) ~= 0 and optionTable[optionTableRef.openInputs].toggle == 2 then
|
||||||
|
menu = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local cameraToObject = gMarioStates[0].marioObj.header.gfx.cameraToObject
|
||||||
|
|
||||||
|
-- C-up Failsafe (Camera Softlocks)
|
||||||
|
if m.action == ACT_FIRST_PERSON or (m.prevAction == ACT_FIRST_PERSON and is_game_paused()) then
|
||||||
|
menu = false
|
||||||
|
elseif m.prevAction == ACT_FIRST_PERSON and not is_game_paused() then
|
||||||
|
m.prevAction = ACT_WALKING
|
||||||
|
end
|
||||||
|
|
||||||
|
if gNetworkPlayers[0].currActNum == 99 then
|
||||||
|
menu = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if menu and not options then
|
||||||
|
if inputStallTimer == 0 then
|
||||||
|
if (m.controller.buttonPressed & D_JPAD) ~= 0 then
|
||||||
|
currChar = currChar + 1
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
buttonScroll = buttonScrollCap
|
||||||
|
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||||
|
end
|
||||||
|
if (m.controller.buttonPressed & U_JPAD) ~= 0 then
|
||||||
|
currChar = currChar - 1
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
buttonScroll = -buttonScrollCap
|
||||||
|
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||||
|
end
|
||||||
|
if (m.controller.buttonPressed & D_CBUTTONS) ~= 0 then
|
||||||
|
currChar = currChar + 1
|
||||||
|
inputStallTimer = inputStallTo*0.6
|
||||||
|
buttonScroll = buttonScrollCap
|
||||||
|
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||||
|
end
|
||||||
|
if (m.controller.buttonPressed & U_CBUTTONS) ~= 0 then
|
||||||
|
currChar = currChar - 1
|
||||||
|
inputStallTimer = inputStallTo*0.6
|
||||||
|
buttonScroll = -buttonScrollCap
|
||||||
|
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||||
|
end
|
||||||
|
if m.controller.stickY < -60 then
|
||||||
|
currChar = currChar + 1
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
buttonScroll = buttonScrollCap
|
||||||
|
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||||
|
end
|
||||||
|
if m.controller.stickY > 60 then
|
||||||
|
currChar = currChar - 1
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
buttonScroll = -buttonScrollCap
|
||||||
|
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||||
|
end
|
||||||
|
if (m.controller.buttonPressed & A_BUTTON) ~= 0 then
|
||||||
|
if characterTable[currChar] ~= nil then
|
||||||
|
TEXT_PREF_LOAD = characterTable[currChar].name
|
||||||
|
mod_storage_save("PrefChar", TEXT_PREF_LOAD)
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
play_sound(SOUND_MENU_CLICK_FILE_SELECT, cameraToObject)
|
||||||
|
else
|
||||||
|
play_sound(SOUND_MENU_CAMERA_BUZZ, cameraToObject)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (m.controller.buttonPressed & B_BUTTON) ~= 0 then
|
||||||
|
menu = false
|
||||||
|
end
|
||||||
|
if (m.controller.buttonPressed & START_BUTTON) ~= 0 then
|
||||||
|
options = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if currChar > #characterTable then currChar = 1 end
|
||||||
|
if currChar < 1 then currChar = #characterTable end
|
||||||
|
nullify_inputs(m)
|
||||||
|
if is_game_paused() then
|
||||||
|
m.controller.buttonPressed = START_BUTTON
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Idiot Proof Check
|
||||||
|
if not hasOpenedMenu then
|
||||||
|
mod_storage_save("openedmenu", "youdidit")
|
||||||
|
hasOpenedMenu = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if options then
|
||||||
|
if inputStallTimer == 0 then
|
||||||
|
if (m.controller.buttonPressed & D_JPAD) ~= 0 then
|
||||||
|
currOption = currOption + 1
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||||
|
end
|
||||||
|
if (m.controller.buttonPressed & U_JPAD) ~= 0 then
|
||||||
|
currOption = currOption - 1
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||||
|
end
|
||||||
|
if m.controller.stickY < -60 then
|
||||||
|
currOption = currOption + 1
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||||
|
end
|
||||||
|
if m.controller.stickY > 60 then
|
||||||
|
currOption = currOption - 1
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, cameraToObject)
|
||||||
|
end
|
||||||
|
if (m.controller.buttonPressed & A_BUTTON) ~= 0 then
|
||||||
|
optionTable[currOption].toggle = optionTable[currOption].toggle + 1
|
||||||
|
if optionTable[currOption].toggle > optionTable[currOption].toggleMax then optionTable[currOption].toggle = 0 end
|
||||||
|
if optionTable[currOption].toggleSaveName ~= nil then
|
||||||
|
mod_storage_save(optionTable[currOption].toggleSaveName, tostring(optionTable[currOption].toggle))
|
||||||
|
end
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
play_sound(SOUND_MENU_CHANGE_SELECT, cameraToObject)
|
||||||
|
end
|
||||||
|
if (m.controller.buttonPressed & B_BUTTON) ~= 0 then
|
||||||
|
options = false
|
||||||
|
inputStallTimer = inputStallTo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if currOption > #optionTable then currOption = 1 end
|
||||||
|
if currOption < 1 then currOption = #optionTable end
|
||||||
|
nullify_inputs(m)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hook_event(HOOK_BEFORE_MARIO_UPDATE, before_mario_update)
|
||||||
|
hook_event(HOOK_ON_HUD_RENDER, on_hud_render)
|
||||||
|
hook_event(HOOK_ON_HUD_RENDER_BEHIND, on_life_counter_render)
|
||||||
|
|
||||||
|
--------------
|
||||||
|
-- Commands --
|
||||||
|
--------------
|
||||||
|
|
||||||
|
local function chat_command(msg)
|
||||||
|
if msg ~= "" then
|
||||||
|
msg = string_lower(msg)
|
||||||
|
for i = 1, #characterTable do
|
||||||
|
if msg == string_underscore_to_space(string_lower(characterTable[i].name)) then
|
||||||
|
currChar = i
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
djui_chat_message_create("Character Not Found")
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
menu = not menu
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hook_chat_command("char-select", "- Opens the Character Select Menu", chat_command)
|
||||||
147
mods/character-select-coop/o-api.lua
Normal file
147
mods/character-select-coop/o-api.lua
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
|
||||||
|
|
||||||
|
local characterVoices = {}
|
||||||
|
|
||||||
|
local TEX_UNKNOWN_CHAR = get_texture_info("unknown-icon")
|
||||||
|
|
||||||
|
local E_MODEL_ARMATURE = smlua_model_util_get_id("armature_geo")
|
||||||
|
|
||||||
|
local table_insert = table.insert
|
||||||
|
local type = type
|
||||||
|
|
||||||
|
---------
|
||||||
|
-- API --
|
||||||
|
---------
|
||||||
|
|
||||||
|
---@param name string|nil Underscores turn into Spaces
|
||||||
|
---@param description table|nil {"string"}
|
||||||
|
---@param credit string|nil
|
||||||
|
---@param color Color|nil {r, g, b}
|
||||||
|
---@param modelInfo ModelExtendedId|table|nil Use smlua_model_util_get_id()
|
||||||
|
---@param forceChar CharacterType|nil CT_MARIO, CT_LUIGI, CT_TOAD, CT_WALUIGI, CT_WARIO
|
||||||
|
---@param lifeIcon TextureInfo|nil Use get_texture_info()
|
||||||
|
---@return integer
|
||||||
|
local character_add = function(name, description, credit, color, modelInfo, forceChar, lifeIcon)
|
||||||
|
table_insert(characterTable, {
|
||||||
|
name = name and string_space_to_underscore(name) or "Untitled",
|
||||||
|
description = description and description or {"No description has been provided"},
|
||||||
|
credit = credit and credit or "Unknown",
|
||||||
|
color = color and color or menuColorTable[8],
|
||||||
|
model = modelInfo and (type(modelInfo) == "table" and modelInfo[1] or modelInfo) or E_MODEL_ARMATURE,
|
||||||
|
capModels = type(modelInfo) == "table" and modelInfo[2] or nil,
|
||||||
|
forceChar = forceChar and forceChar or CT_MARIO,
|
||||||
|
lifeIcon = lifeIcon and lifeIcon or TEX_UNKNOWN_CHAR,
|
||||||
|
})
|
||||||
|
return #characterTable
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param charNum integer Use _G.charSelect.character_get_number_from_string() or _G.charSelect.character_add()'s return value
|
||||||
|
---@param name string|nil Underscores turn into Spaces
|
||||||
|
---@param description table|nil {"string"}
|
||||||
|
---@param credit string|nil
|
||||||
|
---@param color Color|nil {r, g, b}
|
||||||
|
---@param modelInfo ModelExtendedId|integer|table|nil Use smlua_model_util_get_id()
|
||||||
|
---@param forceChar CharacterType|nil CT_MARIO, CT_LUIGI, CT_TOAD, CT_WALUIGI, CT_WARIO
|
||||||
|
---@param lifeIcon TextureInfo|nil Use get_texture_info()
|
||||||
|
local character_edit = function(charNum, name, description, credit, color, modelInfo, forceChar, lifeIcon)
|
||||||
|
characterTable[charNum] = characterTable[charNum] and {
|
||||||
|
name = name and string_space_to_underscore(name) or characterTable[charNum].name,
|
||||||
|
description = description and description or characterTable[charNum].description,
|
||||||
|
credit = credit and credit or characterTable[charNum].credit,
|
||||||
|
color = color and color or characterTable[charNum].color,
|
||||||
|
model = modelInfo and (type(modelInfo) == "table" and modelInfo[1] or modelInfo) or characterTable[charNum].model,
|
||||||
|
capModels = type(modelInfo) == "table" and modelInfo[2] or characterTable[charNum].capModels,
|
||||||
|
forceChar = forceChar and forceChar or characterTable[charNum].forceChar,
|
||||||
|
lifeIcon = lifeIcon and lifeIcon or characterTable[charNum].lifeIcon,
|
||||||
|
} or nil
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param modelInfo ModelExtendedId|integer
|
||||||
|
---@param clips table
|
||||||
|
local character_add_voice = function(modelInfo, clips)
|
||||||
|
characterVoices[modelInfo] = clips
|
||||||
|
end
|
||||||
|
|
||||||
|
---@return table
|
||||||
|
local character_get_current_table = function ()
|
||||||
|
return characterTable[currChar]
|
||||||
|
end
|
||||||
|
|
||||||
|
local character_get_current_model_number = function ()
|
||||||
|
return currChar
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param name string
|
||||||
|
local character_get_number_from_string = function (name)
|
||||||
|
for i = 2, #characterTable do
|
||||||
|
if characterTable[i].name == name or characterTable[i].name == string_space_to_underscore(name) then
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param m MarioState
|
||||||
|
local character_get_voice = function (m)
|
||||||
|
return characterVoices[gPlayerSyncTable[m.playerIndex].modelId]
|
||||||
|
end
|
||||||
|
|
||||||
|
local version_get = function ()
|
||||||
|
return modVersion
|
||||||
|
end
|
||||||
|
|
||||||
|
local is_menu_open = function ()
|
||||||
|
return menu
|
||||||
|
end
|
||||||
|
|
||||||
|
local hook_allow_menu_open = function (func)
|
||||||
|
table.insert(allowMenu, func)
|
||||||
|
end
|
||||||
|
|
||||||
|
local is_options_open = function ()
|
||||||
|
return options
|
||||||
|
end
|
||||||
|
|
||||||
|
local optionTableRef = {
|
||||||
|
openInputs = 1,
|
||||||
|
menuColor = 2,
|
||||||
|
anims = 3,
|
||||||
|
inputLatency = 4,
|
||||||
|
localModels = 5,
|
||||||
|
prefToDefault = 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
local controller = {
|
||||||
|
buttonDown = 0,
|
||||||
|
buttonPressed = 0,
|
||||||
|
extStickX = 0,
|
||||||
|
extStickY = 0,
|
||||||
|
rawStickX = 0,
|
||||||
|
rawStickY = 0,
|
||||||
|
stickMag = 0,
|
||||||
|
stickX = 0,
|
||||||
|
stickY = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
---@param tableNum integer
|
||||||
|
local get_status = function (tableNum)
|
||||||
|
return optionTable[tableNum].toggle
|
||||||
|
end
|
||||||
|
|
||||||
|
_G.charSelectExists = true -- Ace
|
||||||
|
_G.charSelect = {
|
||||||
|
character_add = character_add,
|
||||||
|
character_edit = character_edit,
|
||||||
|
character_add_voice = character_add_voice,
|
||||||
|
character_get_current_table = character_get_current_table,
|
||||||
|
character_get_current_model_number = character_get_current_model_number,
|
||||||
|
character_get_number_from_string = character_get_number_from_string,
|
||||||
|
character_get_voice = character_get_voice,
|
||||||
|
version_get = version_get,
|
||||||
|
is_menu_open = is_menu_open,
|
||||||
|
hook_allow_menu_open = hook_allow_menu_open,
|
||||||
|
is_options_open = is_options_open,
|
||||||
|
get_status = get_status,
|
||||||
|
optionTableRef = optionTableRef,
|
||||||
|
controller = controller,
|
||||||
|
}
|
||||||
BIN
mods/character-select-coop/textures/char-select-text.png
Normal file
BIN
mods/character-select-coop/textures/char-select-text.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 458 B |
BIN
mods/character-select-coop/textures/char-select-text.tex
Normal file
BIN
mods/character-select-coop/textures/char-select-text.tex
Normal file
Binary file not shown.
BIN
mods/character-select-coop/textures/unknown-icon.png
Normal file
BIN
mods/character-select-coop/textures/unknown-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 384 B |
BIN
mods/character-select-coop/textures/unknown-icon.tex
Normal file
BIN
mods/character-select-coop/textures/unknown-icon.tex
Normal file
Binary file not shown.
151
mods/character-select-coop/voice.lua
Normal file
151
mods/character-select-coop/voice.lua
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
for i = 0, MAX_PLAYERS -1, 1 do
|
||||||
|
gPlayerSyncTable[i].customVoice = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local voicecount = 0
|
||||||
|
|
||||||
|
local SLEEP_TALK_SNORES = 8
|
||||||
|
|
||||||
|
gCustomVoiceSamples = {}
|
||||||
|
gCustomVoiceSamplesBackup = {}
|
||||||
|
gCustomVoiceStream = nil
|
||||||
|
|
||||||
|
--- @param m MarioState
|
||||||
|
function stop_custom_character_sound(m, sound)
|
||||||
|
local voice_sample = gCustomVoiceSamples[m.playerIndex]
|
||||||
|
if voice_sample == false and gCustomVoiceSamplesBackup[m.playerIndex].loaded then
|
||||||
|
audio_sample_stop(gCustomVoiceSamplesBackup[m.playerIndex])
|
||||||
|
audio_sample_destroy(gCustomVoiceSamplesBackup[m.playerIndex])
|
||||||
|
voicecount = voicecount - 1
|
||||||
|
gCustomVoiceSamplesBackup[m.playerIndex] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if voice_sample == nil or type(voice_sample) == "boolean" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not voice_sample.loaded then
|
||||||
|
gCustomVoiceSamplesBackup[m.playerIndex] = true
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
audio_sample_stop(voice_sample)
|
||||||
|
if voice_sample.file.relativePath:match('^.+/(.+)$') == sound then
|
||||||
|
return voice_sample
|
||||||
|
end
|
||||||
|
audio_sample_destroy(voice_sample)
|
||||||
|
voicecount = voicecount - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param m MarioState
|
||||||
|
function play_custom_character_sound(m, voice)
|
||||||
|
local sound
|
||||||
|
if type(voice) == "table" then
|
||||||
|
sound = voice[math.random(#voice)]
|
||||||
|
else
|
||||||
|
sound = voice
|
||||||
|
end
|
||||||
|
if sound == nil then return 0 end
|
||||||
|
|
||||||
|
--Get current sample and stop it
|
||||||
|
local voice_sample = stop_custom_character_sound(m, sound)
|
||||||
|
|
||||||
|
if type(sound) ~= "string" then
|
||||||
|
return sound
|
||||||
|
end
|
||||||
|
|
||||||
|
if (m.area == nil or m.area.camera == nil) and m.playerIndex == 0 then
|
||||||
|
if gCustomVoiceStream ~= nil then
|
||||||
|
audio_stream_stop(gCustomVoiceStream)
|
||||||
|
audio_stream_destroy(gCustomVoiceStream)
|
||||||
|
end
|
||||||
|
gCustomVoiceStream = audio_stream_load(sound)
|
||||||
|
audio_stream_play(gCustomVoiceStream, true, 1)
|
||||||
|
else
|
||||||
|
if voice_sample == nil then
|
||||||
|
voice_sample = audio_sample_load(sound)
|
||||||
|
while not voice_sample.loaded do end
|
||||||
|
voicecount = voicecount + 1
|
||||||
|
end
|
||||||
|
audio_sample_play(voice_sample, m.pos, 1)
|
||||||
|
|
||||||
|
if gCustomVoiceSamplesBackup[m.playerIndex] ~= nil and not(gCustomVoiceSamples[m.playerIndex] == false) then
|
||||||
|
gCustomVoiceSamplesBackup[m.playerIndex] = voice_sample
|
||||||
|
else
|
||||||
|
gCustomVoiceSamples[m.playerIndex] = voice_sample
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param m MarioState
|
||||||
|
local function custom_character_sound(m, characterSound)
|
||||||
|
if is_game_paused() then return end
|
||||||
|
if characterSound == CHAR_SOUND_SNORING3 then return 0 end
|
||||||
|
if characterSound == CHAR_SOUND_HAHA and m.hurtCounter > 0 then return 0 end
|
||||||
|
|
||||||
|
local voice = _G.charSelect.character_get_voice(m)[characterSound]
|
||||||
|
if voice ~= nil then
|
||||||
|
return play_custom_character_sound(m, voice)
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local STARTING_SNORE = 46
|
||||||
|
local SLEEP_TALK_START = STARTING_SNORE + 49
|
||||||
|
local SLEEP_TALK_END = SLEEP_TALK_START + SLEEP_TALK_SNORES
|
||||||
|
|
||||||
|
--- @param m MarioState
|
||||||
|
local function custom_character_snore(m)
|
||||||
|
if is_game_paused() then return end
|
||||||
|
if gCustomVoiceSamplesBackup[m.playerIndex] ~= nil and not (gCustomVoiceSamples[m.playerIndex] == false) then
|
||||||
|
if gCustomVoiceSamples[m.playerIndex].loaded then
|
||||||
|
audio_sample_destroy(gCustomVoiceSamples[m.playerIndex])
|
||||||
|
voicecount = voicecount - 1
|
||||||
|
gCustomVoiceSamples[m.playerIndex] = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local SNORE3_TABLE = _G.charSelect.character_get_voice(m)[CHAR_SOUND_SNORING3]
|
||||||
|
|
||||||
|
if m.action ~= ACT_SLEEPING then
|
||||||
|
if m.isSnoring > 0 then
|
||||||
|
stop_custom_character_sound(m)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
|
||||||
|
elseif not (m.actionState == 2 and (m.flags & MARIO_MARIO_SOUND_PLAYED) ~= 0) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local animFrame = m.marioObj.header.gfx.animInfo.animFrame
|
||||||
|
|
||||||
|
if SNORE3_TABLE ~= nil and #SNORE3_TABLE >= 2 then
|
||||||
|
if animFrame == 2 and m.actionTimer < SLEEP_TALK_START then
|
||||||
|
play_custom_character_sound(m, SNORE3_TABLE[2])
|
||||||
|
elseif animFrame == 25 then
|
||||||
|
if #SNORE3_TABLE >= 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_custom_character_sound(m, SNORE3_TABLE[3])
|
||||||
|
elseif m.actionTimer < SLEEP_TALK_START then
|
||||||
|
play_custom_character_sound(m, SNORE3_TABLE[1])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
play_custom_character_sound(m, SNORE3_TABLE[1])
|
||||||
|
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
|
||||||
|
|
||||||
|
_G.charSelect.voice = {
|
||||||
|
sound = custom_character_sound,
|
||||||
|
snore = custom_character_snore,
|
||||||
|
}
|
||||||
|
gPlayerSyncTable[0].customVoice = true
|
||||||
Loading…
Add table
Reference in a new issue