Make default mods a little smaller by removing Flood

This commit is contained in:
Agent X 2023-12-23 11:30:18 -05:00
parent 5fb6757382
commit 52fab98176
14 changed files with 0 additions and 1283 deletions

View File

@ -1,102 +0,0 @@
unsupported = false
FLOOD_WATER = 0
FLOOD_LAVA = 1
FLOOD_SAND = 2
FLOOD_MUD = 3
FLOOD_BONUS_LEVELS = 0
FLOOD_LEVEL_COUNT = 0
LEVEL_LOBBY = LEVEL_CASTLE_GROUNDS
LEVEL_CTT = LEVEL_SA
GAME_VANILLA = 0
GAME_STAR_ROAD = 1
game = GAME_VANILLA
--- @class FloodLevel
--- @field public name string
--- @field public goalPos Vec3f
--- @field public speed number
--- @field public area integer
--- @field public type integer
--- @field public time integer
--- @field public customStartPos Vec3f
--- @type FloodLevel[]
gLevels = {}
gMapRotation = {}
-- localize functions to improve performance
local table_insert,djui_popup_create = table.insert,djui_popup_create
local function flood_define_level(bonus, level, name, goalPos, speed, area, type, customStartPos)
gLevels[level] = { name = name, goalPos = goalPos, speed = speed, area = area, type = type, time = 0, customStartPos = customStartPos }
table_insert(gMapRotation, level)
if bonus then FLOOD_BONUS_LEVELS = FLOOD_BONUS_LEVELS + 1 end
FLOOD_LEVEL_COUNT = FLOOD_LEVEL_COUNT + 1
end
_G.flood_define_level = flood_define_level
local function flood_load_vanilla_levels()
game = GAME_VANILLA
-- bonus level name goal position speed area type custom start pos
flood_define_level(false, LEVEL_BOB, "bob", { x = 3304, y = 4242, z = -4603, a = 0x0000 }, 2.5, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_WF, "wf", { x = 414, y = 5325, z = -20, a = 0x0000 }, 4.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_CCM, "ccm", { x = -478, y = 3471, z = -964, a = 0x0000 }, 5.0, 1, FLOOD_WATER, { x = 3336, y = -3800, z = 0, a = 0x0000 })
flood_define_level(false, LEVEL_BITDW, "bitdw", { x = 6772, y = 2867, z = 0, a = -0x4000 }, 4.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_BBH, "bbh", { x = 655, y = 3277, z = 244, a = 0x8000 }, 3.5, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_HMC, "hmc", { x = -4163, y = 2355, z = -2544, a = 0x0000 }, 5.0, 1, FLOOD_WATER, { x = -3538, y = -3979, z = 3568, a = 0x8000 })
flood_define_level(false, LEVEL_LLL, "lll", { x = 2523, y = 3591, z = -898, a = -0x8000 }, 3.5, 2, FLOOD_LAVA, nil)
flood_define_level(false, LEVEL_SSL, "ssl", { x = 512, y = 4815, z = -551, a = 0x0000 }, 3.0, 2, FLOOD_SAND, nil)
flood_define_level(false, LEVEL_WDW, "wdw", { x = 1467, y = 4096, z = 93, a = -0x4000 }, 4.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_TTM, "ttm", { x = 1053, y = 2309, z = 305, a = 0x0000 }, 3.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_THI, "thi", { x = 1037, y = 4060, z = -2091, a = 0x0000 }, 4.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_TTC, "ttc", { x = 2208, y = 7051, z = 2217, a = 0x0000 }, 4.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_BITS, "bits", { x = 369, y = 6552, z = -6000, a = 0x0000 }, 4.5, 1, FLOOD_LAVA, nil)
flood_define_level(false, LEVEL_CTT, "ctt", { x = 0, y = 700, z = 0, a = 0x0000 }, 5.0, 1, FLOOD_LAVA, nil)
flood_define_level(true, LEVEL_SL, "sl", { x = 40, y = 4864, z = 240, a = 0x0000 }, 3.0, 1, FLOOD_WATER, nil)
flood_define_level(true, LEVEL_RR, "rr", { x = 0, y = 3468, z = -2335, a = 0x0000 }, 3.0, 1, FLOOD_WATER, nil)
flood_define_level(true, LEVEL_CASTLE_GROUNDS, "castle_grounds", { x = 0, y = 7583, z = -4015, a = 0x0000 }, 7.0, 1, FLOOD_WATER, nil)
end
local function flood_load_star_road_levels()
game = GAME_STAR_ROAD
-- bonus level name goal position speed area type custom start pos
flood_define_level(false, LEVEL_BOB, "bob", { x = 5364, y = 1875, z = 2251, a = 0x0000 }, 3.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_WF, "wf", { x = 208, y = 2448, z = -2080, a = 0x4000 }, 5.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_JRB, "jrb", { x = -4672, y = 3541, z = -3619, a = -0x4000 }, 4.0, 1, FLOOD_WATER, { x = 2316, y = -448, z = -5150, a = 0x0000 })
flood_define_level(false, LEVEL_CCM, "ccm", { x = 5709, y = 3501, z = -2141, a = -0x4000 }, 3.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_PSS, "pss", { x = -3415, y = 4573, z = 2678, a = 0x0000 }, 3.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_BITDW, "bitdw", { x = 455, y = 2324, z = 0, a = -0x4000 }, 3.0, 1, FLOOD_MUD, nil)
flood_define_level(false, LEVEL_BBH, "bbh", { x = 4376, y = 2632, z = -4542, a = 0x0000 }, 3.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_LLL, "lll", { x = 4348, y = 4638, z = 3877, a = -0x4000 }, 7.0, 1, FLOOD_SAND, nil)
flood_define_level(false, LEVEL_SL, "sl", { x = 4543, y = 3709, z = 3311, a = 0x8000 }, 2.5, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_WDW, "wdw", { x = -3342, y = 2603, z = 845, a = 0x4000 }, 4.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_TTM, "ttm", { x = 1033, y = 4813, z = -6320, a = 0x8000 }, 2.0, 1, FLOOD_WATER, nil)
flood_define_level(false, LEVEL_TTC, "ttc", { x = 1405, y = 3425, z = -3463, a = 0x8000 }, 4.0, 1, FLOOD_LAVA, nil)
flood_define_level(false, LEVEL_RR, "rr", { x = 5052, y = 11056, z = 413, a = -0x4000 }, 4.0, 1, FLOOD_WATER, { x = 3923, y = -3283, z = -1323, a = 0x8000 })
flood_define_level(true, LEVEL_CASTLE_GROUNDS, "castle_grounds", { x = -8455, y = 2746, z = 2876, a = 0x8000 }, 15.0, 1, FLOOD_WATER, { x = -1644, y = -614, z = -1524, a = -0x4000 })
end
-- load romhack levels
for mod in pairs(gActiveMods) do
if gActiveMods[mod].incompatible ~= nil and gActiveMods[mod].incompatible:find("romhack") then
if gActiveMods[mod].relativePath == "star-road" then
flood_load_star_road_levels()
else
unsupported = true
djui_popup_create("\\#ff0000\\This rom hack is not supported with Flood.", 2)
end
break
end
end
if not unsupported and game == GAME_VANILLA then
flood_load_vanilla_levels()
end

View File

@ -1,166 +0,0 @@
moveset = false
cheats = false
for mod in pairs(gActiveMods) do
if gActiveMods[mod].name:find("Object Spawner") then
cheats = true
end
end
if gServerSettings.enableCheats ~= 0 then
cheats = true
end
for i in pairs(gActiveMods) do
if (gActiveMods[i].incompatible ~= nil and gActiveMods[i].incompatible:find("moveset")) or gActiveMods[i].name:find("Squishy's Server") or (gActiveMods[i].name:find("Pasta") and gActiveMods[i].name:find("Castle")) then
moveset = true
end
end
-- localize functions to improve performance
local math_floor,is_player_active,table_insert,is_game_paused,djui_hud_set_color = math.floor,is_player_active,table.insert,is_game_paused,djui_hud_set_color
rom_hack_cam_set_collisions(false)
-- Rounds up or down depending on the decimal position of `x`.
--- @param x number
--- @return integer
function math_round(x)
return if_then_else(x - math.floor(x) >= 0.5, math.ceil(x), math.floor(x))
end
-- Recieves a value of any type and converts it into a boolean.
function tobool(v)
local type = type(v)
if type == "boolean" then
return v
elseif type == "number" then
return v == 1
elseif type == "string" then
return v == "true"
elseif type == "table" or type == "function" or type == "thread" or type == "userdata" then
return true
end
return false
end
function switch(param, case_table)
local case = case_table[param]
if case then return case() end
local def = case_table['default']
return def and def() or nil
end
--- @param m MarioState
function active_player(m)
local np = gNetworkPlayers[m.playerIndex]
if m.playerIndex == 0 then
return 1
end
if not np.connected then
return 0
end
if np.currCourseNum ~= gNetworkPlayers[0].currCourseNum then
return 0
end
if np.currActNum ~= gNetworkPlayers[0].currActNum then
return 0
end
if np.currLevelNum ~= gNetworkPlayers[0].currLevelNum then
return 0
end
if np.currAreaIndex ~= gNetworkPlayers[0].currAreaIndex then
return 0
end
return is_player_active(m)
end
function if_then_else(cond, ifTrue, ifFalse)
if cond then return ifTrue end
return ifFalse
end
function string_without_hex(name)
local s = ''
local inSlash = false
for i = 1, #name do
local c = name:sub(i,i)
if c == '\\' then
inSlash = not inSlash
elseif not inSlash then
s = s .. c
end
end
return s
end
function on_or_off(value)
if value then return "\\#00ff00\\ON" end
return "\\#ff0000\\OFF"
end
function split(s)
local result = {}
for match in (s):gmatch(string.format("[^%s]+", " ")) do
table.insert(result, match)
end
return result
end
function djui_hud_set_adjusted_color(r, g, b, a)
local multiplier = 1
if is_game_paused() then multiplier = 0.5 end
djui_hud_set_color(r * multiplier, g * multiplier, b * multiplier, a)
end
function SEQUENCE_ARGS(priority, seqId)
return ((priority << 8) | seqId)
end
--- @param m MarioState
function mario_set_full_health(m)
m.health = 0x880
m.healCounter = 0
m.hurtCounter = 0
end
local levelToCourse = {
[LEVEL_NONE] = COURSE_NONE,
[LEVEL_BOB] = COURSE_BOB,
[LEVEL_WF] = COURSE_WF,
[LEVEL_JRB] = COURSE_JRB,
[LEVEL_CCM] = COURSE_CCM,
[LEVEL_BBH] = COURSE_BBH,
[LEVEL_HMC] = COURSE_HMC,
[LEVEL_LLL] = COURSE_LLL,
[LEVEL_SSL] = COURSE_SSL,
[LEVEL_DDD] = COURSE_DDD,
[LEVEL_SL] = COURSE_SL,
[LEVEL_WDW] = COURSE_WDW,
[LEVEL_TTM] = COURSE_TTM,
[LEVEL_THI] = COURSE_THI,
[LEVEL_TTC] = COURSE_TTC,
[LEVEL_RR] = COURSE_RR,
[LEVEL_BITDW] = COURSE_BITDW,
[LEVEL_BITFS] = COURSE_BITFS,
[LEVEL_BITS] = COURSE_BITS,
[LEVEL_PSS] = COURSE_PSS,
[LEVEL_COTMC] = COURSE_COTMC,
[LEVEL_TOTWC] = COURSE_TOTWC,
[LEVEL_VCUTM] = COURSE_VCUTM,
[LEVEL_WMOTR] = COURSE_WMOTR,
[LEVEL_SA] = COURSE_SA,
[LEVEL_ENDING] = COURSE_CAKE_END,
}
function level_to_course(level)
return levelToCourse[level] or COURSE_NONE
end
function timestamp(seconds)
seconds = seconds / 30
local minutes = math.floor(seconds / 60)
local milliseconds = math.floor((seconds - math.floor(seconds)) * 1000)
seconds = math.floor(seconds) % 60
return string.format("%d:%02d:%03d", minutes, seconds, milliseconds)
end

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,642 +0,0 @@
-- name: Flood
-- incompatible: gamemode
-- description: Flood v2.4.5\nBy \\#ec7731\\Agent X\\#dcdcdc\\\n\nThis mod adds a flood escape gamemode\nto sm64ex-coop, you must escape the flood and reach the top of the level before everything is flooded.
if unsupported then return end
local ROUND_STATE_INACTIVE = 0
ROUND_STATE_ACTIVE = 1
local ROUND_COOLDOWN = 600
local SPEEDRUN_MODE_OFF = 0
local SPEEDRUN_MODE_PROGRESS = 1
local SPEEDRUN_MODE_RESTART = 2
local TEX_FLOOD_FLAG = get_texture_info("flood_flag")
gGlobalSyncTable.roundState = ROUND_STATE_INACTIVE
gGlobalSyncTable.timer = ROUND_COOLDOWN
gGlobalSyncTable.level = LEVEL_BOB
gGlobalSyncTable.waterLevel = -20000
gGlobalSyncTable.speedMultiplier = 1
local sFlagIconPrevPos = { x = 0, y = 0 }
local globalTimer = 0
local listedSurvivors = false
local speedrunner = 0
-- localize functions to improve performance
local network_player_connected_count,init_single_mario,warp_to_level,play_sound,network_is_server,network_get_player_text_color_string,djui_chat_message_create,disable_time_stop,network_player_set_description,set_mario_action,obj_get_first_with_behavior_id,obj_check_hitbox_overlap,spawn_mist_particles,vec3f_dist,play_race_fanfare,play_music,djui_hud_set_resolution,djui_hud_get_screen_height,djui_hud_get_screen_width,djui_hud_render_rect,djui_hud_set_font,djui_hud_world_pos_to_screen_pos,clampf,math_floor,djui_hud_measure_text,djui_hud_print_text,hud_render_power_meter,hud_get_value,save_file_erase_current_backup_save,save_file_set_flags,save_file_set_using_backup_slot,find_floor_height,spawn_non_sync_object,set_environment_region,vec3f_set,vec3f_copy,math_random,set_ttc_speed_setting,get_level_name,hud_hide,smlua_text_utils_secret_star_replace,smlua_audio_utils_replace_sequence = network_player_connected_count,init_single_mario,warp_to_level,play_sound,network_is_server,network_get_player_text_color_string,djui_chat_message_create,disable_time_stop,network_player_set_description,set_mario_action,obj_get_first_with_behavior_id,obj_check_hitbox_overlap,spawn_mist_particles,vec3f_dist,play_race_fanfare,play_music,djui_hud_set_resolution,djui_hud_get_screen_height,djui_hud_get_screen_width,djui_hud_render_rect,djui_hud_set_font,djui_hud_world_pos_to_screen_pos,clampf,math.floor,djui_hud_measure_text,djui_hud_print_text,hud_render_power_meter,hud_get_value,save_file_erase_current_backup_save,save_file_set_flags,save_file_set_using_backup_slot,find_floor_height,spawn_non_sync_object,set_environment_region,vec3f_set,vec3f_copy,math.random,set_ttc_speed_setting,get_level_name,hud_hide,smlua_text_utils_secret_star_replace,smlua_audio_utils_replace_sequence
function speedrun_mode(mode)
if mode == nil then
return speedrunner > 0 and network_player_connected_count() == 1
else
return speedrunner == mode and network_player_connected_count() == 1
end
end
-- runs serverside
local function round_start()
gGlobalSyncTable.roundState = ROUND_STATE_ACTIVE
gGlobalSyncTable.timer = if_then_else(gGlobalSyncTable.level == LEVEL_CTT or (gGlobalSyncTable.level == LEVEL_RR and game == GAME_STAR_ROAD), 730, 100)
end
-- runs serverside
local function round_end()
gGlobalSyncTable.roundState = ROUND_STATE_INACTIVE
gGlobalSyncTable.timer = ROUND_COOLDOWN
gGlobalSyncTable.waterLevel = -20000
end
local function get_dest_act()
if game ~= GAME_STAR_ROAD then
return if_then_else(gNetworkPlayers[0].currLevelNum == LEVEL_CASTLE_GROUNDS, 99, 6)
else
if gNetworkPlayers[0].currLevelNum == LEVEL_CASTLE_GROUNDS then
return 99
end
return if_then_else(gNetworkPlayers[0].currLevelNum == LEVEL_BBH, 1, 6)
end
end
local function get_modifiers_string()
if not cheats and not moveset then return "" end
local modifiers = " ("
if moveset then
modifiers = modifiers .. "Moveset"
else
modifiers = modifiers .. "No moveset"
end
if cheats then
modifiers = modifiers .. ", cheats"
end
modifiers = modifiers .. ")"
return modifiers
end
function level_restart()
round_start()
init_single_mario(gMarioStates[0])
mario_set_full_health(gMarioStates[0])
gLevels[gGlobalSyncTable.level].time = 0
warp_to_level(gGlobalSyncTable.level, gLevels[gGlobalSyncTable.level].area, get_dest_act())
end
local function server_update()
if gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then
if gNetworkPlayers[0].currLevelNum == gGlobalSyncTable.level then
gGlobalSyncTable.waterLevel = gGlobalSyncTable.waterLevel + gLevels[gGlobalSyncTable.level].speed * gGlobalSyncTable.speedMultiplier
local active = 0
for i = 0, (MAX_PLAYERS - 1) do
local m = gMarioStates[i]
if active_player(m) ~= 0 and m.health > 0xFF and not gPlayerSyncTable[i].finished then
active = active + 1
end
end
if active == 0 then
local dead = 0
for i = 0, (MAX_PLAYERS) - 1 do
if active_player(gMarioStates[i]) ~= 0 and gMarioStates[i].health <= 0xFF then
dead = dead + 1
end
end
if dead == network_player_connected_count() or (speedrun_mode() and gNetworkPlayers[0].currLevelNum ~= LEVEL_CTT) then
gGlobalSyncTable.timer = 0
end
if gGlobalSyncTable.timer > 0 then
gGlobalSyncTable.timer = gGlobalSyncTable.timer - 1
else
round_end()
if not speedrun_mode() or speedrun_mode(SPEEDRUN_MODE_PROGRESS) then
-- move to the next level
local finished = 0
for i = 0, (MAX_PLAYERS - 1) do
if active_player(gMarioStates[i]) ~= 0 and gPlayerSyncTable[i].finished then
finished = finished + 1
end
end
if finished ~= 0 then
-- calculate position
local position = 1
for k, v in pairs(gMapRotation) do
if gGlobalSyncTable.level == v then
position = k
end
end
position = position + 1
if position > FLOOD_LEVEL_COUNT - FLOOD_BONUS_LEVELS then
position = 1
end
gGlobalSyncTable.level = gMapRotation[position]
end
end
end
end
end
else
if network_player_connected_count() > 1 then
if gGlobalSyncTable.timer > 0 then
gGlobalSyncTable.timer = gGlobalSyncTable.timer - 1
if gGlobalSyncTable.timer == 30 or gGlobalSyncTable.timer == 60 or gGlobalSyncTable.timer == 90 then
play_sound(SOUND_MENU_CHANGE_SELECT, gMarioStates[0].marioObj.header.gfx.cameraToObject)
elseif gGlobalSyncTable.timer == 11 then
play_sound(SOUND_GENERAL_RACE_GUN_SHOT, gMarioStates[0].marioObj.header.gfx.cameraToObject)
end
else
round_start()
end
end
end
end
local function update()
if network_is_server() then server_update() end
gServerSettings.playerInteractions = PLAYER_INTERACTIONS_NONE
if gGlobalSyncTable.roundState == ROUND_STATE_INACTIVE then
if gNetworkPlayers[0].currLevelNum ~= LEVEL_LOBBY or gNetworkPlayers[0].currActNum ~= 0 then
if speedrun_mode() then
level_restart()
end
warp_to_level(LEVEL_LOBBY, 1, 0)
if not listedSurvivors and globalTimer > 5 then
listedSurvivors = true
local finished = 0
local string = "Survivors:"
for i = 0, (MAX_PLAYERS - 1) do
if gNetworkPlayers[i].connected and gPlayerSyncTable[i].finished then
string = string .. "\n" .. network_get_player_text_color_string(i) .. gNetworkPlayers[i].name
finished = finished + 1
end
end
if finished == 0 then
string = string .. "\n\\#ff0000\\None"
end
djui_chat_message_create(string)
end
end
elseif gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then
local act = get_dest_act()
if gNetworkPlayers[0].currLevelNum ~= gGlobalSyncTable.level or gNetworkPlayers[0].currActNum ~= act then
listedSurvivors = false
mario_set_full_health(gMarioStates[0])
gLevels[gGlobalSyncTable.level].time = 0
gPlayerSyncTable[0].finished = false
warp_to_level(gGlobalSyncTable.level, gLevels[gGlobalSyncTable.level].area, act)
end
end
-- stops the star spawn cutscenes from happening
local m = gMarioStates[0]
if m.area ~= nil and m.area.camera ~= nil and (m.area.camera.cutscene == CUTSCENE_STAR_SPAWN or m.area.camera.cutscene == CUTSCENE_RED_COIN_STAR_SPAWN) then
m.area.camera.cutscene = 0
m.freeze = 0
disable_time_stop()
end
globalTimer = globalTimer + 1
end
--- @param m MarioState
local function mario_update(m)
if not gNetworkPlayers[m.playerIndex].connected then return end
if m.health > 0xFF then
network_player_set_description(gNetworkPlayers[m.playerIndex], "Alive", 75, 255, 75, 255)
else
network_player_set_description(gNetworkPlayers[m.playerIndex], "Dead", 255, 75, 75, 255)
end
if m.playerIndex ~= 0 then return end
-- action specific modifications
if m.action == ACT_STEEP_JUMP then
m.action = ACT_JUMP
elseif m.action == ACT_JUMBO_STAR_CUTSCENE then
m.flags = m.flags | MARIO_WING_CAP
end
-- disable instant warps
if m.floor ~= nil and (m.floor.type == SURFACE_WARP or (m.floor.type >= SURFACE_PAINTING_WARP_D3 and m.floor.type <= SURFACE_PAINTING_WARP_FC) or (m.floor.type >= SURFACE_INSTANT_WARP_1B and m.floor.type <= SURFACE_INSTANT_WARP_1E)) then
m.floor.type = SURFACE_DEFAULT
end
-- disable insta kills
if m.floor ~= nil and (m.floor.type == SURFACE_INSTANT_QUICKSAND or m.floor.type == SURFACE_INSTANT_MOVING_QUICKSAND) then
m.floor.type = SURFACE_BURNING
end
-- disable damage in lobby
if gGlobalSyncTable.roundState == ROUND_STATE_INACTIVE then
mario_set_full_health(m)
m.peakHeight = m.pos.y
return
end
-- dialog boxes
if (m.action == ACT_SPAWN_NO_SPIN_AIRBORNE or m.action == ACT_SPAWN_NO_SPIN_LANDING or m.action == ACT_SPAWN_SPIN_AIRBORNE or m.action == ACT_SPAWN_SPIN_LANDING) and m.pos.y < m.floorHeight + 10 then
set_mario_action(m, ACT_FREEFALL, 0)
end
-- manage CTT
if gNetworkPlayers[0].currLevelNum == LEVEL_CTT then
m.peakHeight = m.pos.y
local star = obj_get_first_with_behavior_id(id_bhvFinalStar)
if star ~= nil and obj_check_hitbox_overlap(m.marioObj, star) and m.action ~= ACT_JUMBO_STAR_CUTSCENE then
spawn_mist_particles()
set_mario_action(m, ACT_JUMBO_STAR_CUTSCENE, 0)
end
if m.action == ACT_JUMBO_STAR_CUTSCENE and m.actionTimer >= 499 then
set_mario_spectator(m)
end
end
-- check if the player has reached the end of the level
if gNetworkPlayers[0].currLevelNum == gGlobalSyncTable.level and not gPlayerSyncTable[0].finished and ((gNetworkPlayers[0].currLevelNum ~= LEVEL_CTT and m.pos.y == m.floorHeight)
or (gNetworkPlayers[0].currLevelNum == LEVEL_CTT and m.action == ACT_JUMBO_STAR_CUTSCENE) or (m.action & ACT_FLAG_ON_POLE) ~= 0)
and vec3f_dist(m.pos, gLevels[gGlobalSyncTable.level].goalPos) < 600 then
gPlayerSyncTable[0].finished = true
local string = ""
if gNetworkPlayers[0].currLevelNum ~= LEVEL_CTT and not (game == GAME_STAR_ROAD and gNetworkPlayers[0].currLevelNum == LEVEL_RR) then
string = string .. "\\#00ff00\\You escaped the flood!\n"
play_race_fanfare()
else
string = string .. "\\#00ff00\\You escaped the \\#ffff00\\final\\#00ff00\\ flood! Congratulations!\n"
play_music(0, SEQUENCE_ARGS(8, SEQ_EVENT_CUTSCENE_VICTORY), 0)
end
string = string .. "\\#ffffff\\Time: " .. string.format("%.3f", gLevels[gGlobalSyncTable.level].time / 30) .. get_modifiers_string()
djui_chat_message_create(string)
end
-- update spectator if finished, manage other things if not
if gPlayerSyncTable[0].finished then
mario_set_full_health(m)
if network_player_connected_count() > 1 and m.action ~= ACT_JUMBO_STAR_CUTSCENE then
set_mario_spectator(m)
end
else
if m.pos.y + 40 < gGlobalSyncTable.waterLevel then
m.health = m.health - 30
end
if m.action == ACT_QUICKSAND_DEATH then
m.health = 0xFF
end
if m.health <= 0xFF then
if network_player_connected_count() > 1 then
m.area.camera.cutscene = 0
set_mario_spectator(m)
end
else
gLevels[gGlobalSyncTable.level].time = gLevels[gGlobalSyncTable.level].time + 1
end
end
end
local function on_hud_render()
local water = obj_get_first_with_behavior_id(id_bhvWater)
if gNetworkPlayers[0].currLevelNum == gGlobalSyncTable.level and water ~= nil then
djui_hud_set_resolution(RESOLUTION_DJUI)
if gLakituState.pos.y < gGlobalSyncTable.waterLevel - 10 then
switch(water.oAnimState, {
[FLOOD_WATER] = function()
djui_hud_set_adjusted_color(0, 20, 200, 120)
end,
[FLOOD_LAVA] = function()
djui_hud_set_adjusted_color(200, 0, 0, 220)
end,
[FLOOD_SAND] = function()
djui_hud_set_adjusted_color(254, 193, 121, 220)
end,
[FLOOD_MUD] = function()
djui_hud_set_adjusted_color(74, 123, 0, 220)
end
})
djui_hud_render_rect(0, 0, djui_hud_get_screen_width(), djui_hud_get_screen_height())
end
end
djui_hud_set_resolution(RESOLUTION_N64)
djui_hud_set_font(FONT_TINY)
local level = gLevels[gNetworkPlayers[0].currLevelNum]
if level ~= nil and level.name ~= "ctt" then
local out = { x = 0, y = 0, z = 0 }
djui_hud_world_pos_to_screen_pos(level.goalPos, out)
local dX = clampf(out.x - 5, 0, djui_hud_get_screen_width() - 19.2)
local dY = clampf(out.y - 20, 0, djui_hud_get_screen_height() - 19.2)
djui_hud_set_adjusted_color(255, 255, 255, 200)
djui_hud_render_texture_interpolated(TEX_FLOOD_FLAG, sFlagIconPrevPos.x, sFlagIconPrevPos.y, 0.15, 0.15, dX, dY, 0.15, 0.15)
sFlagIconPrevPos.x = dX
sFlagIconPrevPos.y = dY
end
local text = if_then_else(gGlobalSyncTable.roundState == ROUND_STATE_INACTIVE, "Type '/flood start' to start a round", "0.000 seconds" .. get_modifiers_string())
if gNetworkPlayers[0].currAreaSyncValid then
if gGlobalSyncTable.roundState == ROUND_STATE_INACTIVE then
text = if_then_else(network_player_connected_count() > 1, "Round starts in " .. tostring(math_floor(gGlobalSyncTable.timer / 30)), "Type '/flood start' to start a round")
elseif gNetworkPlayers[0].currLevelNum == gGlobalSyncTable.level then
text = tostring(string.format("%.3f", gLevels[gGlobalSyncTable.level].time / 30)) .. " seconds" .. get_modifiers_string()
end
end
local scale = 1
local width = djui_hud_measure_text(text) * scale
local x = (djui_hud_get_screen_width() - width) * 0.5
djui_hud_set_adjusted_color(0, 0, 0, 128)
djui_hud_render_rect(x - 6, 0, width + 12, 16)
djui_hud_set_adjusted_color(255, 255, 255, 255)
djui_hud_print_text(text, x, 0, scale)
hud_render_power_meter(gMarioStates[0].health, djui_hud_get_screen_width() - 64, 0, 64, 64)
djui_hud_set_font(FONT_HUD)
djui_hud_render_texture(gTextures.coin, 5, 5, 1, 1)
djui_hud_print_text(">", 21, 5, 1)
djui_hud_print_text(tostring(hud_get_value(HUD_DISPLAY_COINS)), 37, 5, 1)
if gGlobalSyncTable.speedMultiplier ~= 1 then
djui_hud_print_text(string.format("%.2fx", gGlobalSyncTable.speedMultiplier), 5, 24, 1)
end
end
local function on_level_init()
-- reset save
save_file_erase_current_backup_save()
if gNetworkPlayers[0].currLevelNum ~= LEVEL_CASTLE_GROUNDS then
save_file_set_flags(SAVE_FLAG_HAVE_VANISH_CAP)
save_file_set_flags(SAVE_FLAG_HAVE_WING_CAP)
end
save_file_set_using_backup_slot(true)
if gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then
if network_is_server() then
local start = gLevels[gGlobalSyncTable.level].customStartPos
if start ~= nil then
gGlobalSyncTable.waterLevel = find_floor_height(start.x, start.y, start.z) - 1200
else
-- only sub areas have a weird issue where this function appears to always return the floor lower limit on level init
gGlobalSyncTable.waterLevel = if_then_else(gLevels[gGlobalSyncTable.level].area == 1, find_floor_height(gMarioStates[0].pos.x, gMarioStates[0].pos.y, gMarioStates[0].pos.z), gMarioStates[0].pos.y) - 1200
end
end
if game == GAME_VANILLA then
if gNetworkPlayers[0].currLevelNum == LEVEL_BITS then
spawn_non_sync_object(
id_bhvCustomStaticObject,
E_MODEL_CTT,
10000, -2000, -40000,
function(o) obj_scale(o, 0.5) end
)
elseif gNetworkPlayers[0].currLevelNum == LEVEL_WDW then
set_environment_region(1, -20000)
end
end
spawn_non_sync_object(
id_bhvWater,
E_MODEL_FLOOD,
0, gGlobalSyncTable.waterLevel, 0,
nil
)
end
local pos = gLevels[gNetworkPlayers[0].currLevelNum].goalPos
if pos == nil then return end
if gNetworkPlayers[0].currLevelNum == LEVEL_CTT then
spawn_non_sync_object(
id_bhvFinalStar,
E_MODEL_STAR,
pos.x, pos.y, pos.z,
nil
)
else
spawn_non_sync_object(
id_bhvFloodFlag,
E_MODEL_KOOPA_FLAG,
pos.x, pos.y, pos.z,
--- @param o Object
function(o)
o.oFaceAnglePitch = 0
o.oFaceAngleYaw = pos.a
o.oFaceAngleRoll = 0
end
)
end
end
-- dynos warps mario back to castle grounds facing the wrong way, likely something from the title screen
local function on_warp()
--- @type MarioState
local m = gMarioStates[0]
if gNetworkPlayers[0].currLevelNum == LEVEL_CASTLE_GROUNDS then
if game == GAME_VANILLA then
m.faceAngle.y = m.faceAngle.y + 0x8000
elseif game == GAME_STAR_ROAD then
if gGlobalSyncTable.roundState == ROUND_STATE_INACTIVE then
vec3f_set(m.pos, -6797, 1830, 2710)
m.faceAngle.y = 0x6000
else
vec3f_set(m.pos, -1644, -614, -1524)
m.faceAngle.y = -0x4000
end
end
if gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then
play_music(0, SEQUENCE_ARGS(4, SEQ_LEVEL_BOSS_KOOPA_FINAL), 0)
end
elseif gLevels[gGlobalSyncTable.level].customStartPos ~= nil then
local start = gLevels[gGlobalSyncTable.level].customStartPos
vec3f_copy(m.pos, start)
set_mario_action(m, ACT_SPAWN_SPIN_AIRBORNE, 0)
m.faceAngle.y = start.a
end
end
local function on_player_connected()
if network_is_server() and gGlobalSyncTable.roundState == ROUND_STATE_INACTIVE then gGlobalSyncTable.timer = ROUND_COOLDOWN end
end
local function on_start_command(msg)
if msg == "?" then
djui_chat_message_create("/flood \\#00ffff\\start\\#ffff00\\ [random|1-" .. FLOOD_LEVEL_COUNT .. "]\\#ffffff\\\nSets the level to a random one or a specific one, you can also leave it empty for normal progression.")
return true
end
if msg == "random" then
gGlobalSyncTable.level = gLevels[math_random(1, FLOOD_LEVEL_COUNT)]
else
local override = tonumber(msg)
if override ~= nil then
override = clamp(math_floor(override), 1, FLOOD_LEVEL_COUNT)
gGlobalSyncTable.level = gMapRotation[override]
else
for k, v in pairs(gLevels) do
if msg ~= nil and msg:lower() == v.name then
gGlobalSyncTable.level = k
end
end
end
end
if gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then
network_send(true, { restart = true })
level_restart()
else
round_start()
end
return true
end
local function on_speed_command(msg)
local speed = tonumber(msg)
if speed ~= nil then
speed = clampf(speed, 0, 10)
djui_chat_message_create("Water speed set to " .. speed)
gGlobalSyncTable.speedMultiplier = speed
return true
end
djui_chat_message_create("/flood \\#00ffff\\speed\\#ffff00\\ [number]\\#ffffff\\\nSets the speed multiplier of the flood")
return true
end
local function on_ttc_speed_command(msg)
if gGlobalSyncTable.roundState ~= ROUND_STATE_INACTIVE then
djui_chat_message_create("\\#ff0000\\You can only change the TTC speed before the round starts!")
return true
end
msg = msg:lower()
if msg == "fast" then
set_ttc_speed_setting(TTC_SPEED_FAST)
djui_chat_message_create("TTC speed set to fast")
return true
elseif msg == "slow" then
set_ttc_speed_setting(TTC_SPEED_SLOW)
djui_chat_message_create("TTC speed set to slow")
return true
elseif msg == "random" then
set_ttc_speed_setting(TTC_SPEED_RANDOM)
djui_chat_message_create("TTC speed set to random")
return true
elseif msg == "stopped" then
set_ttc_speed_setting(TTC_SPEED_STOPPED)
djui_chat_message_create("TTC speed stopped")
return true
end
djui_chat_message_create("/flood \\#00ffff\\ttc-speed\\#ffff00\\ [fast|slow|random|stopped]\\#ffffff\\\nChanges the speed of TTC")
return true
end
local function on_speedrun_command(msg)
msg = msg:lower()
if msg == "off" then
djui_chat_message_create("Speedrun mode status: \\#ff0000\\OFF")
speedrunner = SPEEDRUN_MODE_OFF
return true
elseif msg == "progress" then
djui_chat_message_create("Speedrun mode status: \\#00ff00\\Progress Level")
speedrunner = SPEEDRUN_MODE_PROGRESS
return true
elseif msg == "restart" then
djui_chat_message_create("Speedrun mode status: \\#00ff00\\Restart Level")
speedrunner = SPEEDRUN_MODE_RESTART
return true
end
djui_chat_message_create("/flood \\#00ffff\\speedrun\\#ffff00\\ [off|progress|restart]\\#ffffff\\\nTo make adjustments to singleplayer Flood helpful for speedrunners")
return true
end
local function on_scoreboard_command()
djui_chat_message_create("Times:")
local modifiers = get_modifiers_string()
local total = 0
for i = 1, FLOOD_LEVEL_COUNT do
local level = gMapRotation[i]
djui_chat_message_create(get_level_name(level_to_course(level), level, 1) .. " - " .. timestamp(gLevels[level].time) .. modifiers)
total = total + gLevels[level].time
end
djui_chat_message_create("Total Time: " .. timestamp(total))
return true
end
local function on_flood_command(msg)
local args = split(msg)
if args[1] == "start" then
return on_start_command(args[2])
elseif args[1] == "speed" then
return on_speed_command(args[2])
elseif args[1] == "ttc-speed" then
return on_ttc_speed_command(args[2])
elseif args[1] == "speedrun" then
return on_speedrun_command(args[2])
elseif args[1] == "scoreboard" then
return on_scoreboard_command()
end
djui_chat_message_create("/flood \\#00ffff\\[start|speed|ttc-speed|speedrun|scoreboard]")
return true
end
gServerSettings.skipIntro = 1
gServerSettings.stayInLevelAfterStar = 2
gLevelValues.entryLevel = LEVEL_LOBBY
gLevelValues.floorLowerLimit = -20000
gLevelValues.floorLowerLimitMisc = -20000 + 1000
gLevelValues.floorLowerLimitShadow = -20000 + 1000.0
gLevelValues.fixCollisionBugs = 1
gLevelValues.fixCollisionBugsRoundedCorners = 0
hud_hide()
if game == GAME_VANILLA then
set_ttc_speed_setting(TTC_SPEED_SLOW)
smlua_text_utils_secret_star_replace(COURSE_SA, " Climb The Tower Flood")
smlua_audio_utils_replace_sequence(SEQ_LEVEL_BOSS_KOOPA_FINAL, 37, 60, "00_pinball_custom")
end
hook_event(HOOK_UPDATE, update)
hook_event(HOOK_MARIO_UPDATE, mario_update)
hook_event(HOOK_ON_HUD_RENDER, on_hud_render)
hook_event(HOOK_ON_LEVEL_INIT, on_level_init)
hook_event(HOOK_ON_WARP, on_warp)
hook_event(HOOK_ON_PLAYER_CONNECTED, on_player_connected)
if network_is_server() then
hook_chat_command("flood", "\\#00ffff\\[start|speed|ttc-speed|speedrun|scoreboard]", on_flood_command)
end
for i = 0, (MAX_PLAYERS - 1) do
gPlayerSyncTable[i].finished = false
end

View File

@ -1,210 +0,0 @@
if unsupported then return end
E_MODEL_FLOOD = smlua_model_util_get_id("flood_geo")
E_MODEL_CTT = smlua_model_util_get_id("ctt_geo") -- easter egg in the distance
E_MODEL_LAUNCHPAD = smlua_model_util_get_id("launchpad_geo")
local COL_LAUNCHPAD = smlua_collision_util_get("launchpad_collision")
-- localize functions to improve performance
local get_environment_region,set_environment_region,set_override_far,cur_obj_scale,cur_obj_init_animation,bhv_pole_base_loop,nearest_mario_state_to_object,play_mario_jump_sound,set_mario_action,spawn_non_sync_object,mario_set_forward_vel,vec3f_set,load_object_collision_model,obj_mark_for_deletion,network_is_server,obj_check_hitbox_overlap,obj_has_behavior_id = get_environment_region,set_environment_region,set_override_far,cur_obj_scale,cur_obj_init_animation,bhv_pole_base_loop,nearest_mario_state_to_object,play_mario_jump_sound,set_mario_action,spawn_non_sync_object,mario_set_forward_vel,vec3f_set,load_object_collision_model,obj_mark_for_deletion,network_is_server,obj_check_hitbox_overlap,obj_has_behavior_id
--- @param o Object
local function bhv_water_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.oAnimState = gLevels[gGlobalSyncTable.level].type
o.header.gfx.skipInViewCheck = true
o.oFaceAnglePitch = 0
o.oFaceAngleRoll = 0
end
--- @param o Object
local function bhv_water_loop(o)
o.oPosY = gGlobalSyncTable.waterLevel
if game == GAME_VANILLA and gGlobalSyncTable.level ~= LEVEL_SSL then
o.oFaceAngleYaw = o.oTimer * 5 * (gLevels[gNetworkPlayers[0].currLevelNum].speed or 1)
end
if game == GAME_VANILLA and gNetworkPlayers[0].currLevelNum ~= LEVEL_WDW and gNetworkPlayers[0].currLevelNum ~= LEVEL_HMC then
for i = 1, 3 do
if get_environment_region(i) < gGlobalSyncTable.waterLevel then
set_environment_region(i, -20000)
end
end
else
set_environment_region(1, -20000)
end
end
id_bhvWater = hook_behavior(nil, OBJ_LIST_SURFACE, true, bhv_water_init, bhv_water_loop)
--- @param o Object
local function bhv_custom_static_object_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.header.gfx.skipInViewCheck = true
set_override_far(50000)
end
id_bhvCustomStaticObject = hook_behavior(nil, OBJ_LIST_LEVEL, true, bhv_custom_static_object_init, nil)
--- @param o Object
local function bhv_final_star_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.hitboxRadius = 160
o.hitboxHeight = 100
cur_obj_scale(2)
end
--- @param o Object
local function bhv_final_star_loop(o)
o.oFaceAngleYaw = o.oFaceAngleYaw + 0x800
end
id_bhvFinalStar = hook_behavior(nil, OBJ_LIST_GENACTOR, true, bhv_final_star_init, bhv_final_star_loop)
--- @param o Object
local function bhv_flood_flag_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.oInteractType = INTERACT_POLE
o.hitboxRadius = 80
o.hitboxHeight = 700
o.oIntangibleTimer = 0
o.oAnimations = gObjectAnimations.koopa_flag_seg6_anims_06001028
cur_obj_init_animation(0)
end
--- @param o Object
local function bhv_flood_flag_loop(o)
bhv_pole_base_loop()
end
id_bhvFloodFlag = hook_behavior(nil, OBJ_LIST_POLELIKE, true, bhv_flood_flag_init, bhv_flood_flag_loop)
local function bhv_launchpad_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.oCollisionDistance = 500
o.collisionData = COL_LAUNCHPAD
obj_scale(o, 0.85)
end
local function bhv_launchpad_loop(o)
local m = nearest_mario_state_to_object(o)
if m.marioObj.platform == o then
play_mario_jump_sound(m)
if o.oBehParams2ndByte ~= 255 then
set_mario_action(m, ACT_TWIRLING, 0)
m.vel.y = o.oBehParams2ndByte
else
spawn_non_sync_object(
id_bhvWingCap,
E_MODEL_NONE,
m.pos.x + m.vel.x, m.pos.y + m.vel.y, m.pos.z + m.vel.z,
nil
)
set_mario_action(m, ACT_FLYING_TRIPLE_JUMP, 0)
mario_set_forward_vel(m, 100)
vec3f_set(m.angleVel, 0, 0, 0)
vec3f_set(m.faceAngle, 0, 0x4500, 0)
m.vel.y = 55
end
end
load_object_collision_model()
end
id_bhvLaunchpad = hook_behavior(nil, OBJ_LIST_SURFACE, true, bhv_launchpad_init, bhv_launchpad_loop)
--- @param o Object
local function obj_hide(o)
o.header.gfx.node.flags = o.header.gfx.node.flags | GRAPH_RENDER_INVISIBLE
end
--- @param o Object
local function obj_mark_for_deletion_on_sync(o)
if gNetworkPlayers[0].currAreaSyncValid then obj_mark_for_deletion(o) end
end
hook_behavior(id_bhvStar, OBJ_LIST_UNIMPORTANT, true, obj_hide, obj_mark_for_deletion_on_sync)
hook_behavior(id_bhvHoot, OBJ_LIST_UNIMPORTANT, true, obj_hide, obj_mark_for_deletion_on_sync)
hook_behavior(id_bhvWarpPipe, OBJ_LIST_UNIMPORTANT, true, obj_hide, obj_mark_for_deletion_on_sync)
hook_behavior(id_bhvFadingWarp, OBJ_LIST_UNIMPORTANT, true, obj_hide, obj_mark_for_deletion_on_sync)
hook_behavior(id_bhvBalconyBigBoo, OBJ_LIST_UNIMPORTANT, true, obj_hide, obj_mark_for_deletion_on_sync)
hook_behavior(id_bhvExclamationBox, OBJ_LIST_UNIMPORTANT, true, obj_hide, obj_mark_for_deletion_on_sync)
hook_behavior(id_bhvWaterLevelDiamond, OBJ_LIST_UNIMPORTANT, true, obj_hide, obj_mark_for_deletion_on_sync)
hook_behavior(id_bhvKoopaRaceEndpoint, OBJ_LIST_UNIMPORTANT, true, obj_hide, obj_mark_for_deletion_on_sync)
--- @param m MarioState
local function before_phys_step(m)
if m.playerIndex ~= 0 then return end
if m.pos.y + 40 < gGlobalSyncTable.waterLevel and gNetworkPlayers[m.playerIndex].currLevelNum == gGlobalSyncTable.level then
m.vel.y = m.vel.y + 2
m.peakHeight = m.pos.y
end
end
--- @param m MarioState
--- @param o Object
local function allow_interact(m, o)
if m.action == ACT_SPECTATOR or
(o.header.gfx.node.flags & GRAPH_RENDER_ACTIVE) == 0 or
o.oInteractType == INTERACT_WARP_DOOR or
o.oInteractType == INTERACT_WARP then
return false
end
return true
end
local function on_death()
local m = gMarioStates[0]
if m.floor.type == SURFACE_DEATH_PLANE or m.floor.type == SURFACE_VERTICAL_WIND then
m.health = 0xFF
end
return false
end
local function on_pause_exit()
if network_is_server() then
network_send(true, { restart = true })
level_restart()
end
return false
end
--- @param m MarioState
local function allow_hazard_surface(m)
if m.health <= 0xFF then return false end
return true
end
-- thanks Peachy
--- @param o Object
local function on_object_unload(o)
local m = gMarioStates[0]
if (o.header.gfx.node.flags & GRAPH_RENDER_INVISIBLE) == 0 and obj_has_behavior_id(o, id_bhv1Up) == 1 and obj_check_hitbox_overlap(o, m.marioObj) then
m.healCounter = 31
m.hurtCounter = 0
end
end
local function on_packet_receive(dataTable)
if dataTable.restart then level_restart() end
end
hook_event(HOOK_BEFORE_PHYS_STEP, before_phys_step)
hook_event(HOOK_ALLOW_INTERACT, allow_interact)
hook_event(HOOK_ON_DEATH, on_death)
hook_event(HOOK_ON_PAUSE_EXIT, on_pause_exit)
hook_event(HOOK_ALLOW_HAZARD_SURFACE, allow_hazard_surface)
hook_event(HOOK_ON_OBJECT_UNLOAD, on_object_unload)
hook_event(HOOK_ON_PACKET_RECEIVE, on_packet_receive)

View File

@ -1,163 +0,0 @@
if unsupported then return end
local MARIO_HEAD_POS = 120
local sPlayerFirstPerson = {
pos = { x = 0, y = 0, z = 0 },
freecam = camera_config_is_free_cam_enabled(),
pitch = 0,
yaw = 0,
fov = 70
}
-- localize functions to improve performance - spectator.lua
local camera_config_get_x_sensitivity,camera_config_get_y_sensitivity,camera_config_is_x_inverted,camera_config_is_y_inverted,is_game_paused,djui_hud_get_raw_mouse_y,clamp,djui_hud_get_raw_mouse_x,vec3f_copy,mario_drop_held_object,set_mario_animation,vec3f_set,vec3f_mul,djui_hud_set_mouse_locked,camera_freeze,maxf,camera_config_is_free_cam_enabled,set_override_near,set_override_fov,camera_unfreeze,camera_config_is_mouse_look_enabled,allocate_mario_action = camera_config_get_x_sensitivity,camera_config_get_y_sensitivity,camera_config_is_x_inverted,camera_config_is_y_inverted,is_game_paused,djui_hud_get_raw_mouse_y,clamp,djui_hud_get_raw_mouse_x,vec3f_copy,mario_drop_held_object,set_mario_animation,vec3f_set,vec3f_mul,djui_hud_set_mouse_locked,camera_freeze,maxf,camera_config_is_free_cam_enabled,set_override_near,set_override_fov,camera_unfreeze,camera_config_is_mouse_look_enabled,allocate_mario_action
--- @param m MarioState
local function update_fp_camera(m)
gLakituState.mode = CAMERA_MODE_FREE_ROAM
gLakituState.defMode = CAMERA_MODE_FREE_ROAM
local sensX = 0.3 * camera_config_get_x_sensitivity()
local sensY = 0.4 * camera_config_get_y_sensitivity()
local invX = if_then_else(camera_config_is_x_inverted(), 1, -1)
local invY = if_then_else(camera_config_is_y_inverted(), 1, -1)
if not is_game_paused() then
-- update pitch
sPlayerFirstPerson.pitch = sPlayerFirstPerson.pitch - sensY * (invY * m.controller.extStickY - 1.5 * djui_hud_get_raw_mouse_y())
sPlayerFirstPerson.pitch = clamp(sPlayerFirstPerson.pitch, -0x3F00, 0x3F00)
-- update yaw
if (m.controller.buttonPressed & L_TRIG) ~= 0 then
sPlayerFirstPerson.yaw = m.faceAngle.y + 0x8000
else
sPlayerFirstPerson.yaw = sPlayerFirstPerson.yaw + sensX * (invX * m.controller.extStickX - 1.5 * djui_hud_get_raw_mouse_x())
end
sPlayerFirstPerson.yaw = (sPlayerFirstPerson.yaw + 0x10000) % 0x10000
end
gLakituState.yaw = sPlayerFirstPerson.yaw
m.area.camera.yaw = sPlayerFirstPerson.yaw
-- update pos
gLakituState.pos.x = sPlayerFirstPerson.pos.x + coss(sPlayerFirstPerson.pitch) * sins(sPlayerFirstPerson.yaw)
gLakituState.pos.y = sPlayerFirstPerson.pos.y + sins(sPlayerFirstPerson.pitch) + MARIO_HEAD_POS
gLakituState.pos.z = sPlayerFirstPerson.pos.z + coss(sPlayerFirstPerson.pitch) * coss(sPlayerFirstPerson.yaw)
vec3f_copy(m.area.camera.pos, gLakituState.pos)
vec3f_copy(gLakituState.curPos, gLakituState.pos)
vec3f_copy(gLakituState.goalPos, gLakituState.pos)
-- update focus
gLakituState.focus.x = sPlayerFirstPerson.pos.x - 100 * coss(sPlayerFirstPerson.pitch) * sins(sPlayerFirstPerson.yaw)
gLakituState.focus.y = sPlayerFirstPerson.pos.y - 100 * sins(sPlayerFirstPerson.pitch) + MARIO_HEAD_POS
gLakituState.focus.z = sPlayerFirstPerson.pos.z - 100 * coss(sPlayerFirstPerson.pitch) * coss(sPlayerFirstPerson.yaw)
vec3f_copy(m.area.camera.focus, gLakituState.focus)
vec3f_copy(gLakituState.curFocus, gLakituState.focus)
vec3f_copy(gLakituState.goalFocus, gLakituState.focus)
-- set other values
gLakituState.posHSpeed = 0
gLakituState.posVSpeed = 0
gLakituState.focHSpeed = 0
gLakituState.focVSpeed = 0
end
--- @param m MarioState
function set_mario_spectator(m)
if m.action ~= ACT_SPECTATOR then
sPlayerFirstPerson.pos = { x = m.pos.x, y = if_then_else(m.health > 0xFF, m.pos.y, gGlobalSyncTable.waterLevel), z = m.pos.z }
end
m.action = ACT_SPECTATOR
end
--- @param m MarioState
local function act_spectator(m)
mario_drop_held_object(m)
m.squishTimer = 0
set_mario_animation(m, MARIO_ANIM_DROWNING_PART2)
m.marioBodyState.eyeState = MARIO_EYES_DEAD
m.faceAngle.x = 0
m.faceAngle.z = 0
if gPlayerSyncTable[m.playerIndex].finished then
m.marioObj.header.gfx.node.flags = m.marioObj.header.gfx.node.flags & ~GRAPH_RENDER_ACTIVE
local goalPos = gLevels[gGlobalSyncTable.level].goalPos
vec3f_set(m.pos, goalPos.x, goalPos.y + 600, goalPos.z)
mario_set_full_health(m)
else
m.pos.y = gGlobalSyncTable.waterLevel - 70
vec3f_copy(m.marioObj.header.gfx.pos, m.pos)
vec3f_copy(m.marioObj.header.gfx.angle, m.faceAngle)
m.marioObj.header.gfx.angle.y = 0
m.health = 0xFF
m.healCounter = 0
m.hurtCounter = 0
end
if m.playerIndex ~= 0 then return end
if not is_game_paused() then
local forward = { x = sins(m.faceAngle.y), y = 0, z = coss(m.faceAngle.y) }
local right = { x = sins(m.faceAngle.y - 0x4000), y = 0, z = coss(m.faceAngle.y - 0x4000) }
local dir = { x = forward.x * m.controller.stickY + right.x * m.controller.stickX, y = 0, z = forward.z * m.controller.stickY + right.z * m.controller.stickX }
local speed = if_then_else((m.controller.buttonDown & B_BUTTON) ~= 0, 2, 1)
dir = vec3f_mul(dir, speed)
sPlayerFirstPerson.pos.x = sPlayerFirstPerson.pos.x + dir.x
sPlayerFirstPerson.pos.z = sPlayerFirstPerson.pos.z + dir.z
if (m.input & INPUT_A_DOWN) ~= 0 then
sPlayerFirstPerson.pos.y = sPlayerFirstPerson.pos.y + (50 * speed)
end
if (m.input & INPUT_Z_DOWN) ~= 0 then
sPlayerFirstPerson.pos.y = sPlayerFirstPerson.pos.y - (50 * speed)
end
end
m.faceAngle.y = m.area.camera.yaw + 0x8000
djui_hud_set_mouse_locked(not is_game_paused())
camera_freeze()
update_fp_camera(m)
end
--- @param m MarioState
local function on_set_mario_action(m)
if m.action == ACT_VERTICAL_WIND then
m.vel.y = maxf(m.vel.y, 0)
end
if m.playerIndex ~= 0 then return end
if m.action == ACT_SPECTATOR then
sPlayerFirstPerson.freecam = camera_config_is_free_cam_enabled()
camera_freeze()
set_override_near(45)
set_override_fov(sPlayerFirstPerson.fov)
sPlayerFirstPerson.pitch = 0
sPlayerFirstPerson.yaw = m.faceAngle.y + 0x8000
else
if sPlayerFirstPerson.freecam then
gLakituState.mode = CAMERA_MODE_NEWCAM
gLakituState.defMode = CAMERA_MODE_NEWCAM
end
camera_unfreeze()
set_override_near(0)
set_override_fov(0)
sPlayerFirstPerson.pitch = 0
sPlayerFirstPerson.yaw = 0
if not camera_config_is_mouse_look_enabled() then
djui_hud_set_mouse_locked(false)
end
end
end
ACT_SPECTATOR = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_INVULNERABLE)
hook_event(HOOK_ON_SET_MARIO_ACTION, on_set_mario_action)
---@diagnostic disable-next-line: missing-parameter
hook_mario_action(ACT_SPECTATOR, act_spectator)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 952 B

Binary file not shown.