2023-10-30 06:03:36 +01:00
-- name: Flood
-- incompatible: gamemode
2023-12-05 20:37:48 +01:00
-- 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.
2023-10-30 06:03:36 +01:00
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 ]
2023-12-05 20:37:48 +01:00
if active_player ( m ) ~= 0 and m.health > 0xFF and not gPlayerSyncTable [ i ] . finished then
2023-10-30 06:03:36 +01:00
active = active + 1
end
end
if active == 0 then
local dead = 0
for i = 0 , ( MAX_PLAYERS ) - 1 do
2023-12-05 20:37:48 +01:00
if active_player ( gMarioStates [ i ] ) ~= 0 and gMarioStates [ i ] . health <= 0xFF then
2023-10-30 06:03:36 +01:00
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
2023-12-05 20:37:48 +01:00
if m.health > 0xFF then
2023-10-30 06:03:36 +01:00
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
2023-12-05 20:37:48 +01:00
m.health = 0xFF
2023-10-30 06:03:36 +01:00
end
2023-12-05 20:37:48 +01:00
if m.health <= 0xFF then
2023-10-30 06:03:36 +01:00
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 )
2023-12-05 20:37:48 +01:00
djui_hud_print_text ( " > " , 21 , 5 , 1 )
2023-10-30 06:03:36 +01:00
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 \\ \n Sets 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 \\ \n Sets 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 \\ \n Changes 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 \\ \n To 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