2023-04-29 04:08:53 +00:00
-- name: Hide and Seek
2022-02-03 04:28:24 +00:00
-- incompatible: gamemode
2023-04-29 04:01:55 +00:00
-- description: A simple hide-and-seek gamemode for\nCo-op.\n\nThe game is split into two teams:\n\nHiders and Seekers. The goal is for all\n\Hiders to be converted into a Seeker within a certain timeframe.\n\nAll Seekers appear as a metal character.\n\nEnjoy! :D\n\nConcept by: Super Keeberghrh
2022-02-17 02:27:52 +00:00
-- keep track of round info
2023-04-29 04:01:55 +00:00
local ROUND_STATE_WAIT = 0
local ROUND_STATE_ACTIVE = 1
local ROUND_STATE_SEEKERS_WIN = 2
local ROUND_STATE_HIDERS_WIN = 3
local ROUND_STATE_UNKNOWN_END = 4
gGlobalSyncTable.roundState = ROUND_STATE_WAIT -- current round state
gGlobalSyncTable.touchTag = false
gGlobalSyncTable.hiderCaps = false
2022-05-22 04:17:00 +00:00
gGlobalSyncTable.seekerCaps = false
2022-09-13 02:58:37 +00:00
gGlobalSyncTable.banKoopaShell = true
2022-02-17 02:27:52 +00:00
gGlobalSyncTable.displayTimer = 0 -- the displayed timer
2023-04-29 04:01:55 +00:00
local sRoundTimer = 0 -- the server's round timer
local sRoundStartTimeout = 15 * 30 -- fifteen seconds
local sRoundEndTimeout = 3 * 60 * 30 -- three minutes
local pauseExitTimer = 0
local canLeave = false
2022-02-03 04:28:24 +00:00
2023-04-29 04:01:55 +00:00
-- flashing text index
local sFlashingIndex = 0
2022-02-04 03:06:21 +00:00
2022-08-11 08:24:21 +00:00
-- pu prevention
local puX = 0
local puZ = 0
2023-04-29 04:01:55 +00:00
-- avoid repetion
local np = gNetworkPlayers [ 0 ]
--localize functions to improve performance
local
hook_chat_command , network_player_set_description , hook_on_sync_table_change , network_is_server ,
hook_event , djui_popup_create , network_get_player_text_color_string , play_sound ,
play_character_sound , djui_chat_message_create , djui_hud_set_resolution , djui_hud_set_font ,
djui_hud_set_color , djui_hud_render_rect , djui_hud_print_text , djui_hud_get_screen_width , djui_hud_get_screen_height ,
djui_hud_measure_text , tostring , warp_to_level , warp_to_start_level , stop_cap_music , dist_between_objects ,
math_floor , math_ceil , table_insert , set_camera_mode
=
hook_chat_command , network_player_set_description , hook_on_sync_table_change , network_is_server ,
hook_event , djui_popup_create , network_get_player_text_color_string , play_sound ,
play_character_sound , djui_chat_message_create , djui_hud_set_resolution , djui_hud_set_font ,
djui_hud_set_color , djui_hud_render_rect , djui_hud_print_text , djui_hud_get_screen_width , djui_hud_get_screen_height ,
djui_hud_measure_text , tostring , warp_to_level , warp_to_start_level , stop_cap_music , dist_between_objects ,
math.floor , math.ceil , table.insert , set_camera_mode
local function on_or_off ( value )
if value then return " enabled " end
return " disabled "
end
local function server_update ( )
2022-02-17 02:27:52 +00:00
-- increment timer
sRoundTimer = sRoundTimer + 1
2023-04-29 04:01:55 +00:00
gGlobalSyncTable.displayTimer = math_floor ( sRoundTimer / 30 )
2022-02-17 02:27:52 +00:00
2022-02-03 04:28:24 +00:00
-- figure out state of the game
local hasSeeker = false
local hasHider = false
local activePlayers = { }
2022-02-04 03:50:27 +00:00
local connectedCount = 0
2023-04-29 04:01:55 +00:00
for i = 0 , ( MAX_PLAYERS - 1 ) do
2022-02-03 04:28:24 +00:00
if gNetworkPlayers [ i ] . connected then
2022-02-04 03:50:27 +00:00
connectedCount = connectedCount + 1
2023-04-29 04:01:55 +00:00
table_insert ( activePlayers , gPlayerSyncTable [ i ] )
2022-02-03 04:28:24 +00:00
if gPlayerSyncTable [ i ] . seeking then
hasSeeker = true
else
hasHider = true
end
end
end
2022-02-04 03:50:27 +00:00
-- only change state if there are 2+ players
if connectedCount < 2 then
2022-02-17 02:27:52 +00:00
gGlobalSyncTable.roundState = ROUND_STATE_WAIT
2022-02-04 03:50:27 +00:00
return
2022-02-17 02:27:52 +00:00
elseif gGlobalSyncTable.roundState == ROUND_STATE_WAIT then
gGlobalSyncTable.roundState = ROUND_STATE_UNKNOWN_END
sRoundTimer = 0
gGlobalSyncTable.displayTimer = 0
2022-02-04 03:50:27 +00:00
end
2022-02-04 08:15:14 +00:00
-- check to see if the round should end
2022-02-17 02:27:52 +00:00
if gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then
if not hasHider or not hasSeeker or sRoundTimer > sRoundEndTimeout then
2022-02-04 08:15:28 +00:00
if not hasHider then
2022-02-17 02:27:52 +00:00
gGlobalSyncTable.roundState = ROUND_STATE_SEEKERS_WIN
elseif sRoundTimer > sRoundEndTimeout then
gGlobalSyncTable.roundState = ROUND_STATE_HIDERS_WIN
2022-02-04 08:15:28 +00:00
else
2022-02-17 02:27:52 +00:00
gGlobalSyncTable.roundState = ROUND_STATE_UNKNOWN_END
2022-02-04 08:15:28 +00:00
end
2022-02-17 02:27:52 +00:00
sRoundTimer = 0
gGlobalSyncTable.displayTimer = 0
2022-02-04 08:14:38 +00:00
else
return
end
2022-02-03 04:28:24 +00:00
end
2022-02-17 02:27:52 +00:00
-- start round
if sRoundTimer >= sRoundStartTimeout then
2022-02-03 04:28:24 +00:00
-- reset seekers
2022-02-05 23:05:18 +00:00
for i = 0 , ( MAX_PLAYERS - 1 ) do
gPlayerSyncTable [ i ] . seeking = false
2022-02-03 04:28:24 +00:00
end
2022-02-05 23:05:18 +00:00
hasSeeker = false
2022-02-03 04:28:24 +00:00
2023-04-29 04:01:55 +00:00
-- pick random seeker
2022-02-03 04:28:24 +00:00
if not hasSeeker then
2022-05-22 04:17:00 +00:00
local randNum = math.random ( # activePlayers )
local s = activePlayers [ randNum ]
2022-02-03 04:28:24 +00:00
s.seeking = true
end
2022-02-04 03:06:21 +00:00
2022-02-17 02:27:52 +00:00
-- set round state
gGlobalSyncTable.roundState = ROUND_STATE_ACTIVE
sRoundTimer = 0
gGlobalSyncTable.displayTimer = 0
2022-05-10 06:11:12 +00:00
2022-02-03 04:28:24 +00:00
end
end
2023-04-29 04:01:55 +00:00
local function update ( )
pauseExitTimer = pauseExitTimer + 1
2022-02-04 08:15:14 +00:00
2023-04-29 04:01:55 +00:00
if pauseExitTimer >= 900 and not canLeave then
canLeave = true
2022-02-04 08:15:14 +00:00
end
2023-04-29 04:01:55 +00:00
-- only allow the server to figure out the seeker
if network_is_server ( ) then
server_update ( )
2022-02-17 02:10:06 +00:00
end
2022-02-04 03:06:21 +00:00
end
2022-02-03 04:28:24 +00:00
2023-04-29 04:01:55 +00:00
local function screen_transition ( trans )
-- if the local player died next to a seeker, make them a seeker
local s = gPlayerSyncTable [ 0 ]
if not s.seeking then
for i = 1 , ( MAX_PLAYERS - 1 ) do
if gNetworkPlayers [ i ] . connected and gNetworkPlayers [ i ] . currLevelNum == np.currLevelNum and
gNetworkPlayers [ i ] . currActNum == np.currActNum and gNetworkPlayers [ i ] . currAreaIndex == np.currAreaIndex
and gPlayerSyncTable [ i ] . seeking then
2022-02-03 04:28:24 +00:00
2023-04-29 04:01:55 +00:00
local m = gMarioStates [ 0 ]
local a = gMarioStates [ i ]
2022-02-04 08:15:14 +00:00
2023-04-29 04:01:55 +00:00
if trans == WARP_TRANSITION_FADE_INTO_BOWSER or ( m.floor . type == SURFACE_DEATH_PLANE and m.pos . y <= m.floorHeight + 2048 ) then
if dist_between_objects ( m.marioObj , a.marioObj ) <= 4000 and m.playerIndex == 0 then
s.seeking = true
end
end
end
2022-03-26 06:16:56 +00:00
end
2022-02-05 20:22:41 +00:00
end
2022-02-03 04:28:24 +00:00
end
2023-04-29 04:01:55 +00:00
local cannonTimer = 0
--- @param m MarioState
local function mario_update ( m )
2022-05-22 04:17:00 +00:00
if ( m.flags & MARIO_VANISH_CAP ) ~= 0 then
2023-04-29 04:01:55 +00:00
m.flags = m.flags & ~ MARIO_VANISH_CAP --Always Remove Vanish Cap
2022-05-22 04:17:00 +00:00
stop_cap_music ( )
end
2022-05-10 06:11:12 +00:00
2022-02-03 04:28:24 +00:00
-- this code runs for all players
local s = gPlayerSyncTable [ m.playerIndex ]
2023-04-29 04:01:55 +00:00
if m.playerIndex == 0 and m.action == ACT_IN_CANNON and m.actionState == 2 then
cannonTimer = cannonTimer + 1
if cannonTimer >= 150 then
m.forwardVel = 100 * coss ( m.faceAngle . x )
m.vel . y = 100 * sins ( m.faceAngle . x )
m.pos . x = m.pos . x + 120 * coss ( m.faceAngle . x ) * sins ( m.faceAngle . y )
m.pos . y = m.pos . y + 120 * sins ( m.faceAngle . x )
m.pos . z = m.pos . z + 120 * coss ( m.faceAngle . x ) * coss ( m.faceAngle . y )
play_sound ( SOUND_ACTION_FLYING_FAST , m.marioObj . header.gfx . cameraToObject )
play_sound ( SOUND_OBJ_POUNDING_CANNON , m.marioObj . header.gfx . cameraToObject )
m.marioObj . header.gfx . node.flags = m.marioObj . header.gfx . node.flags | GRAPH_RENDER_ACTIVE
set_camera_mode ( m.area . camera , m.area . camera.defMode , 1 )
set_mario_action ( m , ACT_SHOT_FROM_CANNON , 0 )
queue_rumble_data_mario ( m , 60 , 70 )
m.usedObj . oAction = 2
cannonTimer = 0
end
2022-02-04 03:06:21 +00:00
end
2022-08-11 08:24:21 +00:00
-- remove caps
2022-05-22 04:17:00 +00:00
if m.playerIndex == 0 or gGlobalSyncTable.roundState ~= ROUND_STATE_ACTIVE then
if gGlobalSyncTable.seekerCaps and gPlayerSyncTable [ m.playerIndex ] . seeking then
2022-08-11 08:24:21 +00:00
m.flags = m.flags & ~ MARIO_WING_CAP -- remove wing cap if seeking
m.flags = m.flags & ~ MARIO_METAL_CAP -- remove metal cap if seeking
2022-05-22 04:17:00 +00:00
stop_cap_music ( )
m.capTimer = 0
elseif gGlobalSyncTable.hiderCaps and not gPlayerSyncTable [ m.playerIndex ] . seeking then
2022-08-11 08:24:21 +00:00
m.flags = m.flags & ~ MARIO_WING_CAP -- remove wing cap if hiding
m.flags = m.flags & ~ MARIO_METAL_CAP -- remove metal cap if hiding
2022-05-22 04:17:00 +00:00
stop_cap_music ( )
m.capTimer = 0
end
2022-05-10 06:11:12 +00:00
end
2023-04-29 04:01:55 +00:00
-- warp to the beninging
2022-08-11 08:24:21 +00:00
if m.playerIndex == 0 then
if gPlayerSyncTable [ m.playerIndex ] . seeking and gGlobalSyncTable.displayTimer == 0 and gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then
warp_to_level ( gLevelValues.entryLevel , 1 , 0 )
2023-04-29 04:01:55 +00:00
warp_to_start_level ( )
2022-08-11 08:24:21 +00:00
end
end
2022-05-22 04:17:00 +00:00
2022-02-03 04:28:24 +00:00
-- display all seekers as metal
if s.seeking then
2023-04-29 04:01:55 +00:00
m.marioBodyState . modelState = m.marioBodyState . modelState | MODEL_STATE_METAL
2022-02-03 04:28:24 +00:00
end
2023-04-29 04:01:55 +00:00
2022-08-11 08:24:21 +00:00
-- pu prevention
if m.pos . x >= 0 then
2023-04-29 04:01:55 +00:00
puX = math_floor ( ( 8192 + m.pos . x ) / 65536 )
2022-08-11 08:24:21 +00:00
else
2023-04-29 04:01:55 +00:00
puX = math_ceil ( ( - 8192 + m.pos . x ) / 65536 )
2022-08-11 08:24:21 +00:00
end
if m.pos . z >= 0 then
2023-04-29 04:01:55 +00:00
puZ = math_floor ( ( 8192 + m.pos . z ) / 65536 )
2022-08-11 08:24:21 +00:00
else
2023-04-29 04:01:55 +00:00
puZ = math_ceil ( ( - 8192 + m.pos . z ) / 65536 )
2022-08-11 08:24:21 +00:00
end
2023-04-29 04:01:55 +00:00
if puX ~= 0 or puZ ~= 0 then
2022-08-11 08:24:21 +00:00
s.seeking = true
2023-04-29 04:01:55 +00:00
warp_restart_level ( )
2022-08-11 08:24:21 +00:00
end
2022-02-03 04:28:24 +00:00
end
2023-04-29 04:01:55 +00:00
function before_set_mario_action ( m , action )
if m.playerIndex == 0 then
if action == ACT_WAITING_FOR_DIALOG or action == ACT_READING_SIGN or action == ACT_READING_AUTOMATIC_DIALOG or action == ACT_READING_NPC_DIALOG or action == ACT_JUMBO_STAR_CUTSCENE then
return 1
elseif action == ACT_EXIT_LAND_SAVE_DIALOG then
set_camera_mode ( m.area . camera , m.area . camera.defMode , 1 )
return ACT_IDLE
end
2022-02-04 03:50:27 +00:00
end
2023-04-29 04:01:55 +00:00
end
2022-02-04 03:50:27 +00:00
2023-04-29 04:01:55 +00:00
--- @param m MarioState
local function before_phys_step ( m )
-- prevent physics from being altered when bubbled
2022-02-03 04:28:24 +00:00
local s = gPlayerSyncTable [ m.playerIndex ]
2023-04-29 04:01:55 +00:00
if m.action == ACT_BUBBLED or s.seeking then return end
2022-02-03 04:28:24 +00:00
-- only make seekers faster
local hScale = 1.0
local vScale = 1.0
-- make swimming seekers 5% faster
if ( m.action & ACT_FLAG_SWIMMING ) ~= 0 then
hScale = hScale * 1.05
if m.action ~= ACT_WATER_PLUNGE then
vScale = vScale * 1.05
end
end
end
2023-04-29 04:01:55 +00:00
local function on_pvp_attack ( attacker , victim )
2022-02-03 04:28:24 +00:00
-- this code runs when a player attacks another player
local sAttacker = gPlayerSyncTable [ attacker.playerIndex ]
local sVictim = gPlayerSyncTable [ victim.playerIndex ]
-- only consider local player
if victim.playerIndex ~= 0 then
return
end
-- make victim a seeker
if sAttacker.seeking and not sVictim.seeking then
sVictim.seeking = true
end
end
2023-04-29 04:01:55 +00:00
--- @param m MarioState
local function on_player_connected ( m )
2022-05-22 04:17:00 +00:00
-- start out as a seeker
2022-02-03 04:28:24 +00:00
local s = gPlayerSyncTable [ m.playerIndex ]
2022-02-17 02:27:52 +00:00
s.seeking = true
2022-02-17 06:30:17 +00:00
network_player_set_description ( gNetworkPlayers [ m.playerIndex ] , " seeker " , 255 , 64 , 64 , 255 )
2022-02-03 04:28:24 +00:00
end
2023-04-29 04:01:55 +00:00
local function hud_top_render ( )
2022-02-17 02:10:06 +00:00
local seconds = 0
2023-04-29 04:01:55 +00:00
local text = " "
2022-02-17 02:10:06 +00:00
2022-02-17 02:27:52 +00:00
if gGlobalSyncTable.roundState == ROUND_STATE_WAIT then
2022-02-17 02:10:06 +00:00
seconds = 60
2023-04-29 04:01:55 +00:00
text = " waiting for players "
2022-02-17 02:27:52 +00:00
elseif gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then
2023-04-29 04:01:55 +00:00
seconds = math_floor ( sRoundEndTimeout / 30 - gGlobalSyncTable.displayTimer )
2022-02-17 02:27:52 +00:00
if seconds < 0 then seconds = 0 end
2023-04-29 04:01:55 +00:00
text = " seekers have " .. seconds .. " seconds "
2022-02-17 02:10:06 +00:00
else
2023-04-29 04:01:55 +00:00
seconds = math_floor ( sRoundStartTimeout / 30 - gGlobalSyncTable.displayTimer )
2022-02-17 02:27:52 +00:00
if seconds < 0 then seconds = 0 end
2023-04-29 04:01:55 +00:00
text = " next round in " .. seconds .. " seconds "
2022-02-17 02:10:06 +00:00
end
2023-04-29 04:01:55 +00:00
local scale = 0.5
2022-02-17 02:10:06 +00:00
-- get width of screen and text
local screenWidth = djui_hud_get_screen_width ( )
local width = djui_hud_measure_text ( text ) * scale
2023-04-29 04:01:55 +00:00
local x = ( screenWidth - width ) * 0.5
2022-02-17 02:10:06 +00:00
local y = 0
local background = 0.0
2022-02-17 02:27:52 +00:00
if seconds < 60 and gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then
2023-04-29 04:01:55 +00:00
background = ( math.sin ( sFlashingIndex * 0.1 ) * 0.5 + 0.5 ) * 1
2022-02-17 02:10:06 +00:00
background = background * background
background = background * background
end
-- render top
2023-04-29 04:01:55 +00:00
djui_hud_set_color ( 255 * background , 0 , 0 , 128 )
djui_hud_render_rect ( x - 6 , y , width + 12 , 16 )
2022-02-17 02:10:06 +00:00
2023-04-29 04:01:55 +00:00
djui_hud_set_color ( 255 , 255 , 255 , 255 )
djui_hud_print_text ( text , x , y , scale )
2022-02-17 02:10:06 +00:00
end
2023-04-29 04:01:55 +00:00
local function hud_center_render ( )
2022-02-17 02:27:52 +00:00
if gGlobalSyncTable.displayTimer > 3 then return end
2022-02-17 02:10:06 +00:00
-- set text
2023-04-29 04:01:55 +00:00
local text = " "
2022-02-17 02:27:52 +00:00
if gGlobalSyncTable.roundState == ROUND_STATE_SEEKERS_WIN then
2023-04-29 04:01:55 +00:00
text = " Seekers Win! "
2022-02-17 02:27:52 +00:00
elseif gGlobalSyncTable.roundState == ROUND_STATE_HIDERS_WIN then
2023-04-29 04:01:55 +00:00
text = " Hiders Win! "
2022-02-17 02:27:52 +00:00
elseif gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then
2023-04-29 04:01:55 +00:00
text = " Go! "
2022-02-17 02:10:06 +00:00
else
return
end
-- set scale
2022-02-17 02:27:52 +00:00
local scale = 1
2022-02-17 02:10:06 +00:00
-- get width of screen and text
local screenWidth = djui_hud_get_screen_width ( )
local screenHeight = djui_hud_get_screen_height ( )
local width = djui_hud_measure_text ( text ) * scale
local height = 32 * scale
2023-04-29 04:01:55 +00:00
local x = ( screenWidth - width ) * 0.5
local y = ( screenHeight - height ) * 0.5
2022-02-17 02:10:06 +00:00
-- render
2023-04-29 04:01:55 +00:00
djui_hud_set_color ( 0 , 0 , 0 , 128 )
djui_hud_render_rect ( x - 6 * scale , y , width + 12 * scale , height )
2022-02-17 02:10:06 +00:00
2023-04-29 04:01:55 +00:00
djui_hud_set_color ( 255 , 255 , 255 , 255 )
djui_hud_print_text ( text , x , y , scale )
2022-02-17 02:10:06 +00:00
end
2023-04-29 04:01:55 +00:00
local function on_hud_render ( )
2022-02-17 02:10:06 +00:00
-- render to N64 screen space, with the HUD font
djui_hud_set_resolution ( RESOLUTION_N64 )
djui_hud_set_font ( FONT_NORMAL )
hud_top_render ( )
hud_center_render ( )
sFlashingIndex = sFlashingIndex + 1
end
2023-04-29 04:01:55 +00:00
local function on_touch_tag_command ( )
gGlobalSyncTable.touchTag = not gGlobalSyncTable.touchTag
djui_chat_message_create ( " Touch tag: " .. on_or_off ( gGlobalSyncTable.touchTag ) )
return true
2022-03-26 06:16:56 +00:00
end
2023-04-29 04:01:55 +00:00
local function on_hider_cap_command ( )
gGlobalSyncTable.hiderCaps = not gGlobalSyncTable.hiderCaps
djui_chat_message_create ( " Hider Caps: " .. on_or_off ( gGlobalSyncTable.hiderCaps ) )
return true
2022-05-22 04:17:00 +00:00
end
2023-04-29 04:01:55 +00:00
local function on_seeker_cap_command ( )
gGlobalSyncTable.seekerCaps = not gGlobalSyncTable.seekerCaps
djui_chat_message_create ( " Seeker Caps: " .. on_or_off ( gGlobalSyncTable.seekerCaps ) )
return true
2022-05-22 04:17:00 +00:00
end
2023-04-29 04:01:55 +00:00
local function on_koopa_shell_command ( )
gGlobalSyncTable.banKoopaShell = not gGlobalSyncTable.banKoopaShell
djui_chat_message_create ( " Koopa Shells: " .. on_or_off ( not gGlobalSyncTable.seekerCaps ) )
return true
2022-09-13 02:58:37 +00:00
end
2023-04-29 04:01:55 +00:00
local function level_init ( )
local s = gPlayerSyncTable [ 0 ]
2022-09-13 02:58:37 +00:00
2023-04-29 04:01:55 +00:00
pauseExitTimer = 0
canLeave = false
2022-09-13 02:58:37 +00:00
2023-04-29 04:01:55 +00:00
if s.seeking then canLeave = true end
2022-05-22 04:17:00 +00:00
end
2023-04-29 04:01:55 +00:00
local function on_pause_exit ( )
2022-03-26 06:10:43 +00:00
local s = gPlayerSyncTable [ 0 ]
2022-09-13 02:58:37 +00:00
2023-04-29 04:01:55 +00:00
if not canLeave and not s.seeking then
djui_popup_create ( tostring ( math_floor ( 30 - pauseExitTimer / 30 ) ) .. " Seconds until you can leave! " , 2 )
2022-03-26 06:18:48 +00:00
return false
end
end
2022-02-04 08:15:14 +00:00
-----------------------
-- network callbacks --
-----------------------
2023-04-29 04:01:55 +00:00
local function on_round_state_changed ( )
2022-02-17 02:27:52 +00:00
local rs = gGlobalSyncTable.roundState
2022-02-04 08:15:14 +00:00
2023-04-29 04:01:55 +00:00
if rs == ROUND_STATE_ACTIVE then
2022-02-17 02:27:52 +00:00
play_character_sound ( gMarioStates [ 0 ] , CHAR_SOUND_HERE_WE_GO )
elseif rs == ROUND_STATE_SEEKERS_WIN then
2022-02-17 02:10:06 +00:00
play_sound ( SOUND_MENU_CLICK_CHANGE_VIEW , gMarioStates [ 0 ] . marioObj.header . gfx.cameraToObject )
2023-04-29 04:01:55 +00:00
elseif rs == ROUND_STATE_HIDERS_WIN then
2022-02-17 02:27:52 +00:00
play_sound ( SOUND_MENU_CLICK_CHANGE_VIEW , gMarioStates [ 0 ] . marioObj.header . gfx.cameraToObject )
2022-02-04 08:15:14 +00:00
end
end
2023-04-29 04:01:55 +00:00
local function on_seeking_changed ( tag , oldVal , newVal )
2022-02-04 08:15:14 +00:00
local m = gMarioStates [ tag ]
2023-04-29 04:01:55 +00:00
local npT = gNetworkPlayers [ tag ]
2022-02-04 08:15:14 +00:00
-- play sound and create popup if became a seeker
if newVal and not oldVal then
play_sound ( SOUND_OBJ_BOWSER_LAUGH , m.marioObj . header.gfx . cameraToObject )
playerColor = network_get_player_text_color_string ( m.playerIndex )
2023-04-29 04:01:55 +00:00
djui_popup_create ( playerColor .. npT.name .. " \\ #ffa0a0 \\ is now a seeker " , 2 )
2022-05-22 04:17:00 +00:00
sRoundTimer = 32
2022-02-04 08:15:14 +00:00
end
2022-02-17 06:30:17 +00:00
if newVal then
2023-04-29 04:01:55 +00:00
network_player_set_description ( npT , " seeker " , 255 , 64 , 64 , 255 )
2022-02-17 06:30:17 +00:00
else
2023-04-29 04:01:55 +00:00
network_player_set_description ( npT , " hider " , 128 , 128 , 128 , 255 )
end
end
local function check_touch_tag_allowed ( i )
if gMarioStates [ i ] . action ~= ACT_TELEPORT_FADE_IN and gMarioStates [ i ] . action ~= ACT_TELEPORT_FADE_OUT and gMarioStates [ i ] . action ~= ACT_PULLING_DOOR and gMarioStates [ i ] . action ~= ACT_PUSHING_DOOR and gMarioStates [ i ] . action ~= ACT_WARP_DOOR_SPAWN and gMarioStates [ i ] . action ~= ACT_ENTERING_STAR_DOOR and gMarioStates [ i ] . action ~= ACT_STAR_DANCE_EXIT and gMarioStates [ i ] . action ~= ACT_STAR_DANCE_NO_EXIT and gMarioStates [ i ] . action ~= ACT_STAR_DANCE_WATER and gMarioStates [ i ] . action ~= ACT_PANTING and gMarioStates [ i ] . action ~= ACT_UNINITIALIZED and gMarioStates [ i ] . action ~= ACT_WARP_DOOR_SPAWN then
return true
2022-02-17 06:30:17 +00:00
end
2023-04-29 04:01:55 +00:00
return false
2022-02-04 08:15:14 +00:00
end
2023-04-29 04:01:55 +00:00
local function on_interact ( m , obj , intee )
2022-05-10 06:11:12 +00:00
if intee == INTERACT_PLAYER then
2022-05-22 04:17:00 +00:00
if not gGlobalSyncTable.touchTag then
return
end
2022-05-10 06:11:12 +00:00
if m ~= gMarioStates [ 0 ] then
for i = 0 , ( MAX_PLAYERS - 1 ) do
2022-05-22 04:17:00 +00:00
if gNetworkPlayers [ i ] . connected and gNetworkPlayers [ i ] . currAreaSyncValid then
if gPlayerSyncTable [ m.playerIndex ] . seeking and not gPlayerSyncTable [ i ] . seeking and obj == gMarioStates [ i ] . marioObj and check_touch_tag_allowed ( i ) then
2022-05-10 06:11:12 +00:00
gPlayerSyncTable [ i ] . seeking = true
network_player_set_description ( gNetworkPlayers [ i ] , " seeker " , 255 , 64 , 64 , 255 )
end
end
end
end
end
end
2023-04-29 04:01:55 +00:00
local function allow_interact ( _ , _ , intee )
if intee == INTERACT_KOOPA_SHELL and gGlobalSyncTable.banKoopaShell then
return false
2022-05-22 04:17:00 +00:00
end
end
2023-04-29 04:01:55 +00:00
function allow_pvp_attack ( m1 , m2 )
local s1 = gPlayerSyncTable [ m1.playerIndex ]
local s2 = gPlayerSyncTable [ m2.playerIndex ]
if s1.seeking == s2.seeking then
2022-05-22 04:17:00 +00:00
return false
end
2023-04-29 04:01:55 +00:00
return true
2022-05-22 04:17:00 +00:00
end
2023-04-29 04:01:55 +00:00
gLevelValues.disableActs = true
2022-02-03 04:28:24 +00:00
-----------
-- hooks --
-----------
hook_event ( HOOK_UPDATE , update )
2023-04-29 04:01:55 +00:00
hook_event ( HOOK_ON_SCREEN_TRANSITION , screen_transition )
hook_event ( HOOK_BEFORE_SET_MARIO_ACTION , before_set_mario_action )
2022-02-03 04:28:24 +00:00
hook_event ( HOOK_MARIO_UPDATE , mario_update )
2023-04-29 04:01:55 +00:00
hook_event ( HOOK_BEFORE_PHYS_STEP , before_phys_step )
hook_event ( HOOK_ALLOW_PVP_ATTACK , allow_pvp_attack )
2022-02-03 04:28:24 +00:00
hook_event ( HOOK_ON_PVP_ATTACK , on_pvp_attack )
hook_event ( HOOK_ON_PLAYER_CONNECTED , on_player_connected )
2022-02-17 02:10:06 +00:00
hook_event ( HOOK_ON_HUD_RENDER , on_hud_render )
2023-04-29 04:01:55 +00:00
hook_event ( HOOK_ON_LEVEL_INIT , level_init )
hook_event ( HOOK_ON_PAUSE_EXIT , on_pause_exit ) -- timer
2022-05-10 06:11:12 +00:00
hook_event ( HOOK_ON_INTERACT , on_interact )
2022-05-22 04:17:00 +00:00
hook_event ( HOOK_ALLOW_INTERACT , allow_interact )
2023-04-29 04:01:55 +00:00
hook_event ( HOOK_USE_ACT_SELECT , function ( ) return false end )
2022-02-04 03:50:27 +00:00
2022-05-22 06:07:29 +00:00
if network_is_server ( ) then
2023-04-29 04:01:55 +00:00
hook_chat_command ( " touch-to-tag " , " turn touch tag on or off " , on_touch_tag_command )
hook_chat_command ( " hiders-caps " , " turn caps for hiders on or off " , on_hider_cap_command )
hook_chat_command ( " seekers-caps " , " turn caps for seekers on or off " , on_seeker_cap_command )
hook_chat_command ( " koopa-shell " , " Turn the koopa shell on or off " , on_koopa_shell_command )
2022-05-22 06:07:29 +00:00
end
2022-02-04 08:15:14 +00:00
-- call functions when certain sync table values change
2023-04-29 04:01:55 +00:00
hook_on_sync_table_change ( gGlobalSyncTable , " roundState " , 0 , on_round_state_changed )
for i = 0 , ( MAX_PLAYERS - 1 ) do
2022-02-17 02:10:06 +00:00
gPlayerSyncTable [ i ] . seeking = true
2023-04-29 04:01:55 +00:00
hook_on_sync_table_change ( gPlayerSyncTable [ i ] , " seeking " , i , on_seeking_changed )
2022-02-17 06:30:17 +00:00
network_player_set_description ( gNetworkPlayers [ i ] , " seeker " , 255 , 64 , 64 , 255 )
2022-02-04 08:15:14 +00:00
end
2023-05-03 07:51:50 +00:00
_G.HideAndSeek = {
is_player_seeker = function ( playerIndex )
return gPlayerSyncTable [ playerIndex ] . seeking
end ,
set_player_seeker = function ( playerIndex , seeking )
gPlayerSyncTable [ playerIndex ] . seeking = seeking
end ,
}