642 lines
25 KiB
Lua
642 lines
25 KiB
Lua
-- name: Flood
|
|
-- incompatible: gamemode
|
|
-- description: Flood v2.4.2\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("x", 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 |