Skip to content

Instantly share code, notes, and snippets.

@marysiamzawka
Last active December 3, 2024 12:49
Show Gist options
  • Save marysiamzawka/003d1518fd5e1463c86f165ca02e5896 to your computer and use it in GitHub Desktop.
Save marysiamzawka/003d1518fd5e1463c86f165ca02e5896 to your computer and use it in GitHub Desktop.
MariomodXT RC1
-- name: MariomodXT
-- description: On-screen timer for full game runs with splits and reset functionality\nby Mr. Mary
_G.mxt_version = "RC1"
mQuake_aa = 12
startTime = get_global_timer()
storedTime = 100
resetPresses = 0
secondWarning = {
false,
false
}
runDone = false
finalTime = 0
levels = {
{9, "BOB"}, --BOB (no bother splitting here)
{24, "WF"}, --WF
{12, "JRB"}, --JRB
{5, "CCM"}, --CCM
{17, "BitDW"}, --BITDW
{27, "PSS"}, --PSS
{20, "SA"}, --SA
{29, "Wing Cap"}, --Wing Cap
{4, "BBH"}, --BBH
{7, "HMC"}, --HMC
{22, "LLL"}, --LLL
{8, "SSL"}, --SSL
{23, "DDD"}, --DDD
{19, "BitFS"}, --BITFS
{28, "Metal Cap"}, --Metal Cap
{18, "Vanish Cap"}, --Vanish Cap
{10, "SL"}, --SL
{11, "WDW"}, --WDW
{36, "TTM"}, --TTM
{13, "THI"}, --THI
{14, "TTC"}, --TTC
{15, "RR"}, --RR
{21, "BitS"}, --BITS
{31, "WMOTR"} --WMOTR
}
splits = {}
for i = 1, #levels do
splits[levels[i][1]] = {}
splits[levels[i][1]][1] = false
end
entered = {}
enteredString = ""
pbStats = {0, {}}
deviatedRoute = false
newBest = false
settings = {
inputViewer = false
}
local function initSplits()
if not mod_storage_load_bool("initSetupDone") then
djui_popup_create("First time setup...", 1)
for i = 1, #levels do
splits[levels[i][1]][3] = 0
mod_storage_save_number("besttime_" .. tostring(levels[i]), splits[levels[i][1]][3])
mod_storage_save_number("level_" .. tostring(i), 0)
end
mod_storage_save_bool("initSetupDone", true)
else
--djui_popup_create("Not first time, loading best times", 1)
for i = 1, #levels do
splits[levels[i][1]][3] = mod_storage_load_number("besttime_" .. tostring(levels[i][1]))
end
end
if mod_storage_load_bool("pbRecorded") then
pbStats[1] = mod_storage_load_number("bestTime")
levelOrder = mod_storage_load("levelOrder")
for i = 1, #levels do
table.insert(pbStats[2], mod_storage_load_number("level_" .. tostring(i)))
end
--pbStats[2] = deserializeInt(mod_storage_load_number("levelOrder_1"), mod_storage_load_number("levelOrder_2"), mod_storage_load_number("levelOrder_3") , mod_storage_load_number("levelOrder_4"), mod_storage_load_number("levelAmount"))
end
end
initSplits()
local function printTimer(time_string)
-- set text and scale
local text = time_string
local scale = 1.5
-- render to native screen space, with the MENU font
djui_hud_set_resolution(RESOLUTION_DJUI)
djui_hud_set_font(FONT_NORMAL)
-- get width of screen and text
local screenWidth = djui_hud_get_screen_width()
local width = djui_hud_measure_text(text) * scale
-- get height of screen and text
local screenHeight = djui_hud_get_screen_height()
local height = 64 * scale
-- set location
local x = 0
local y = (screenHeight / 2) + (height / 2)
-- set color and render
djui_hud_set_color(0, 0, 0, 95)
djui_hud_render_rect(x, y, width + 10, height / 2)
djui_hud_set_color(231, 229, 50, 255)
djui_hud_print_text(text, x, y, scale)
end
local function resetPopupWarnings()
for i = 1, 2 do
secondWarning[i] = false
end
end
local function resetCurrentSplits()
for i = 1, #levels do
splits[levels[i][1]][1] = false
splits[levels[i][1]][2] = nil
splits[levels[i][1]][3] = mod_storage_load_number("besttime_" .. tostring(levels[i][1]))
end
entered = {}
end
local function formatTime(currentTime, signed)
local isNegative = currentTime < 0
currentTime = math.abs(currentTime) -- Work with the absolute value for calculations
local totalSeconds = currentTime / 30
local minutes = math.floor(totalSeconds / 60)
local seconds = math.floor(totalSeconds % 60)
local milliseconds = math.floor((totalSeconds % 1) * 1000)
local formattedTime
if minutes < 10 then
formattedTime = string.format("%d:%02d.%03d", minutes, seconds, milliseconds)
else
formattedTime = string.format("%02d:%02d.%03d", minutes, seconds, milliseconds)
end
-- Add a sign only if `signed` is true
if signed then
if isNegative then
formattedTime = "-" .. formattedTime
else
formattedTime = "+" .. formattedTime
end
end
return formattedTime
end
local function nukeSave()
local saveSlot = get_current_save_file_num() - 1
save_file_erase(saveSlot)
save_file_erase_current_backup_save()
save_file_reload(saveSlot)
warp_to_level(LEVEL_CASTLE_GROUNDS,1,0)
gFirstPersonCamera.pitch = 0
startTime = get_global_timer()
--djui_popup_create("I am DarkViperAU and the run is dead", 1)
resetPresses = 0
storedTime = 100
runDone = false
finalTime = 0
deviatedRoute = false
newBest = false
resetPopupWarnings()
resetCurrentSplits()
initSplits()
end
local function nukeTimes()
for i = 1, #levels do
splits[levels[i][1]][3] = 0
end
end
local function reset(m)
if (m.controller.buttonPressed & U_JPAD) ~= 0 then
resetPresses = resetPresses + 1
if resetPresses == 1 then
djui_popup_create("Resetting in 3 seconds...", 1)
storedTime = get_global_timer()
elseif resetPresses == 2 then
djui_popup_create("Reset cancelled!", 1)
resetPresses = 0
resetPopupWarnings()
end
end
if resetPresses == 1 then
if get_global_timer() - storedTime == 30 and not secondWarning[1] then
djui_popup_create("Resetting in 2 seconds...", 1)
secondWarning[1] = true
elseif get_global_timer() - storedTime == 60 and not secondWarning[2] then
djui_popup_create("Resetting in 1 second...", 1)
secondWarning[2] = true
elseif get_global_timer() - storedTime > 90 then
nukeSave()
m.health = 0x0880
m.numLives = 4
end
end
end
local function trackSplit()
currentLevel = gNetworkPlayers[0].currLevelNum
if not runDone then
for i = 1, #levels do
if levels[i][1] == currentLevel then
if splits[currentLevel][1] == false then
splitTime = get_global_timer() - startTime
splits[currentLevel][2] = splitTime
bestTime = splits[currentLevel][3]
deltaTime = splitTime - bestTime
table.insert(entered, currentLevel)
splitString = formatTime(splitTime, false)
expected = entered[#entered] == pbStats[2][#entered]
print("entered now " .. tostring(entered[#entered]))
print("entered in PB " .. tostring(pbStats[2][#entered]))
if bestTime == 0 then
if pbStats[1] == 0 then
print("No best time on record")
splits[currentLevel][3] = splitTime
splitString = "Entering " .. levels[i][2] .. " at " .. splitString
else
splitString = "Entering " .. levels[i][2] .. " at " .. splitString
if not deviatedRoute then
djui_popup_create("\\#FE0000\\Route deviation - ignoring best times", 1)
deviatedRoute = true
nukeTimes()
end
print("Route deviation on split")
end
elseif expected then
color = "\\#FFFFFF\\"
if deltaTime > 0 then
color = "\\#FE0000\\"
elseif deltaTime < 0 then
color = "\\#21A212\\"
end
splitString = "Entering " .. levels[i][2] .. " at " .. splitString .. " (" .. color .. formatTime(deltaTime, true) .. "\\#FFFFFF\\)"
print("Best time on record")
else
splitString = "Entering " .. levels[i][2] .. " at " .. splitString
djui_popup_create("\\#FE0000\\Route deviation - ignoring best times", 1)
deviatedRoute = true
nukeTimes()
print("Route deviation on split")
end
splits[currentLevel][1] = true
djui_popup_create(splitString, 1)
for i, value in ipairs(entered) do
print(i, value)
end
end
end
end
end
end
local function calcCenter(string, scale)
string_width = djui_hud_measure_text(string) * scale
return djui_hud_get_screen_width() / 2 - string_width / 2
end
local function calcRightAlign(string, scale, x)
string_width = djui_hud_measure_text(string) * scale
return x - string_width
end
local function showStats()
djui_hud_set_resolution(RESOLUTION_DJUI)
djui_hud_set_font(FONT_NORMAL)
local screenWidth = djui_hud_get_screen_width()
local screenHeight = djui_hud_get_screen_height()
local scale = screenWidth * 0.0022
djui_hud_set_color(0, 0, 0, 191)
djui_hud_render_rect(screenWidth / 3, screenHeight * 0.07 , screenWidth / 3, screenHeight - screenHeight * 0.14)
djui_hud_set_color(231, 229, 50, 255)
if newBest then
djui_hud_print_text("New record!", calcCenter("New record!", scale), screenHeight * 0.1, scale)
else
djui_hud_print_text("Run complete!", calcCenter("Run complete!", scale), screenHeight * 0.1, scale)
end
djui_hud_print_text(tostring(formatTime(finalTime, false)), calcCenter(tostring(formatTime(finalTime, false)), scale), screenHeight - (screenHeight * 0.1) * 2, scale)
split_ypos = screenHeight * 0.24
previousID = nil
for _, enteredID in ipairs(entered) do
for _, level in ipairs(levels) do
if level[1] == enteredID then
time = formatTime(splits[enteredID][2], false)
djui_hud_set_color(231, 229, 50, 255)
djui_hud_print_text(level[2] .. " entry", screenWidth / 3 + screenWidth * 0.01, split_ypos, scale / 4)
djui_hud_print_text(time, calcRightAlign(time, scale / 4, screenWidth - (screenWidth / 3 + screenWidth * 0.01)), split_ypos, scale / 4)
if pbStats[1] ~= 0 and not deviatedRoute then
time2 = formatTime(splits[enteredID][2] - splits[enteredID][3], true)
if previousID == nil then
segmentCurrent = splits[enteredID][2]
segmentPrevious = splits[enteredID][3]
else
segmentCurrent = splits[enteredID][2] - splits[previousID][2]
segmentPrevious = splits[enteredID][3] - splits[previousID][3]
end
if segmentCurrent < segmentPrevious then
djui_hud_set_color(33, 162, 18, 255)
elseif segmentCurrent > segmentPrevious then
djui_hud_set_color(254, 0, 0, 255)
end
djui_hud_print_text(time2, calcRightAlign(time2, scale / 4, screenWidth - (screenWidth / 3 + screenWidth * 0.01)) - screenWidth * 0.08, split_ypos, scale / 4)
end
split_ypos = split_ypos + screenHeight * 0.0242
previousID = enteredID
break
end
end
end
time = formatTime(finalTime, false)
djui_hud_set_color(231, 229, 50, 255)
djui_hud_print_text("Grand Star", screenWidth / 3 + screenWidth * 0.01, split_ypos, scale / 4)
djui_hud_print_text(time, calcRightAlign(time, scale / 4, screenWidth - (screenWidth / 3 + screenWidth * 0.01)), split_ypos, scale / 4)
if pbStats[1] ~= 0 and not deviatedRoute then
time2 = formatTime(finalTime - pbStats[1], true)
segmentCurrent = finalTime - splits[previousID][2]
segmentPrevious = finalTime - splits[previousID][3]
if segmentCurrent < segmentPrevious then
djui_hud_set_color(33, 162, 18, 255)
elseif segmentCurrent > segmentPrevious then
djui_hud_set_color(254, 0, 0, 255)
end
djui_hud_print_text(time2, calcRightAlign(time2, scale / 4, screenWidth - (screenWidth / 3 + screenWidth * 0.01)) - screenWidth * 0.08, split_ypos, scale / 4)
end
end
local function saveRun(msg)
callFromChat = msg and (runDone and deviatedRoute)
if (not msg) or (callFromChat) then
mod_storage_save_bool("pbRecorded", true)
--[[ for i = 1, 4 do
mod_storage_save_number("levelOrder_" .. tostring(i), serializeInt(entered, i))
end ]]
for i = 1, #entered do
mod_storage_save_number("level_" .. tostring(i), entered[i])
end
mod_storage_save_number("levelAmount", #entered)
mod_storage_save_number("bestTime", finalTime)
for i = 1, #levels do
if splits[levels[i][1]][2] then
mod_storage_save_number("besttime_" .. tostring(levels[i][1]), splits[levels[i][1]][2])
end
end
djui_popup_create("Run saved!", 1)
if msg then
return true
end
end
if msg and (not callFromChat) then
djui_chat_message_create("This command works only after a run!")
return true
end
end
local function starAction(_, _, i)
--if i == INTERACT_STAR_OR_KEY and gMarioStates[0].numStars == 2 then
if i == INTERACT_STAR_OR_KEY and gNetworkPlayers[0].currLevelNum == 34 then
runDone = true
finalTime = get_global_timer() - startTime
enteredString = tostring(entered[1])
for i = 2, #entered do
enteredString = enteredString .. " " .. tostring(entered[i])
end
play_course_clear()
if pbStats[1] ~= 0 and pbStats[1] > finalTime then
newBest = true
print("set newbest flag")
end
if (not deviatedRoute) or (not #entered == #pbStats[2]) then
if pbStats[1] == 0 or pbStats[1] > finalTime then
saveRun()
print("saveable run")
end
else
djui_popup_create("\\#FE0000\\Route deviation - to save, type /mxt_save_run", 1)
end
end
end
local function drawTimer()
if not runDone then
printTimer(tostring(formatTime(get_global_timer() - startTime, false)))
else
printTimer(tostring(formatTime(finalTime), false))
showStats()
end
end
local function printTime(msg)
djui_chat_message_create(formatTime(pbStats[1], false))
return true
end
hook_event(HOOK_ON_INTERACT, starAction)
hook_event(HOOK_MARIO_UPDATE, reset)
hook_event(HOOK_ON_LEVEL_INIT, trackSplit)
hook_event(HOOK_ON_HUD_RENDER, drawTimer)
--hook_chat_command("bowser3", " - wipe the current savefile and reset to Castle Grounds", bowser3)
hook_chat_command("mxt_save_run", " - save currently finished run", saveRun)
hook_chat_command("mxt_best_time", " - print best recorded time", printTime)
djui_popup_create("MariomodXT v" .. mxt_version .. " loaded!", 1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment