From 229664da6e072e6cb85bcd3435bca83e78a2f3e3 Mon Sep 17 00:00:00 2001 From: Blockyyy <88585273+Blockyyy@users.noreply.github.com> Date: Sat, 29 Apr 2023 06:01:55 +0200 Subject: [PATCH] massive Hide and Seek overhaul (#364) - Seekers only go faster in water - No more Act Select - Pause exits only allowed 30 seconds after entering a level - Dying no longer makes you seeker unless next to a seeker - Picks random seeker at the end of a round instead of last seeker - staying too long in a cannon shoots you out - can't trigger text or dialog - Defaults to hit to tag instead of touch to tag - no levels are banned - Anti camp removed - Much more optimized - Probably other stuff i cannot remember --- mods/hide-and-seek.lua | 603 +++++++++++++++-------------------------- 1 file changed, 223 insertions(+), 380 deletions(-) diff --git a/mods/hide-and-seek.lua b/mods/hide-and-seek.lua index 6dc6cb89..cbbda90b 100644 --- a/mods/hide-and-seek.lua +++ b/mods/hide-and-seek.lua @@ -1,61 +1,70 @@ --- name: Hide and Seek +-- name: \\#5feb7a\\Hide and Seek -- incompatible: gamemode --- 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, and are given boosted speed\n\and jump height.\n\nHiders are given no enhancements, and\n\become a Seeker upon dying.\n\nEnjoy! :D\n\nConcept by: Super Keeberghrh - --- globally sync enabled state -gGlobalSyncTable.hideAndSeek = true - +-- 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 -- keep track of round info -ROUND_STATE_WAIT = 0 -ROUND_STATE_ACTIVE = 1 -ROUND_STATE_SEEKERS_WIN = 2 -ROUND_STATE_HIDERS_WIN = 3 -ROUND_STATE_UNKNOWN_END = 4 -gGlobalSyncTable.touchTag = true -gGlobalSyncTable.campingTimer = false -- enable/disable camping timer -gGlobalSyncTable.hiderCaps = true + +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 gGlobalSyncTable.seekerCaps = false gGlobalSyncTable.banKoopaShell = true -gGlobalSyncTable.banRR = true -gGlobalSyncTable.roundState = ROUND_STATE_WAIT -- current round state gGlobalSyncTable.displayTimer = 0 -- the displayed timer -sRoundTimer = 0 -- the server's round timer -sRoundStartTimeout = 15 * 30 -- fifteen seconds -sRoundEndTimeout = 3 * 60 * 30 -- three minutes +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 --- server keeps track of last player turned seeker -sLastSeekerIndex = 0 - --- keep track of distance moved recently (camping detection) -sLastPos = {} -sLastPos.x = 0 -sLastPos.y = 0 -sLastPos.z = 0 -sDistanceMoved = 0 -sDistanceTimer = 0 -sDistanceTimeout = 10 * 30 -- ten seconds - --- flashing 'keep moving' index -sFlashingIndex = 0 +-- flashing text index +local sFlashingIndex = 0 -- pu prevention local puX = 0 local puZ = 0 -function server_update(m) +-- 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() -- increment timer sRoundTimer = sRoundTimer + 1 - gGlobalSyncTable.displayTimer = math.floor(sRoundTimer / 30) + gGlobalSyncTable.displayTimer = math_floor(sRoundTimer / 30) -- figure out state of the game local hasSeeker = false local hasHider = false local activePlayers = {} local connectedCount = 0 - for i=0,(MAX_PLAYERS-1) do + for i = 0, (MAX_PLAYERS-1) do if gNetworkPlayers[i].connected then connectedCount = connectedCount + 1 - table.insert(activePlayers, gPlayerSyncTable[i]) + table_insert(activePlayers, gPlayerSyncTable[i]) if gPlayerSyncTable[i].seeking then hasSeeker = true else @@ -99,15 +108,7 @@ function server_update(m) end hasSeeker = false - -- set seeker to last one turned into seeker - local np = gNetworkPlayers[sLastSeekerIndex] - if np.connected then - local s = gPlayerSyncTable[sLastSeekerIndex] - s.seeking = true - hasSeeker = true - end - - -- pick random seeker if last turned to seeker is invalid + -- pick random seeker if not hasSeeker then local randNum = math.random(#activePlayers) local s = activePlayers[randNum] @@ -119,87 +120,76 @@ function server_update(m) sRoundTimer = 0 gGlobalSyncTable.displayTimer = 0 - end end -function camping_detection(m) - -- this code only runs for the local player - local s = gPlayerSyncTable[m.playerIndex] +local function update() + pauseExitTimer = pauseExitTimer + 1 - -- track how far the local player has moved recently - sDistanceMoved = sDistanceMoved - 0.25 + vec3f_dist(sLastPos, m.pos) * 0.02 - vec3f_copy(sLastPos, m.pos) - - -- clamp between 0 to 100 - if sDistanceMoved < 0 then sDistanceMoved = 0 end - if sDistanceMoved > 100 then sDistanceMoved = 100 end - - if obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then - sDistanceMoved = 0 + if pauseExitTimer >= 900 and not canLeave then + canLeave = true end - - -- if player hasn't moved enough, start a timer - if sDistanceMoved < 10 and not s.seeking then - sDistanceTimer = sDistanceTimer + 1 - end - - -- if the player has moved enough, reset the timer - if sDistanceMoved > 25 then - sDistanceTimer = 0 - end - - -- inform the player that they need to move, or make them a seeker - if sDistanceTimer > sDistanceTimeout then - s.seeking = true - end - - -- make sound - if sDistanceTimer > 0 and sDistanceTimer % 30 == 1 then - play_sound(SOUND_MENU_CAMERA_BUZZ, m.marioObj.header.gfx.cameraToObject) - end -end - -function update() - -- check gamemode enabled state - if not gGlobalSyncTable.hideAndSeek then - return - end - -- only allow the server to figure out the seeker if network_is_server() then - server_update(gMarioStates[0]) - end - - -- check if local player is camping - if gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then - if gGlobalSyncTable.campingTimer or obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then - camping_detection(gMarioStates[0]) - else - sDistanceTimer = 0 - end - else - sDistanceTimer = 0 + server_update() end end -function mario_update(m) - -- check gamemode enabled state - if not gGlobalSyncTable.hideAndSeek then - return - end +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 + local m = gMarioStates[0] + local a = gMarioStates[i] + + 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 + end + end +end + +local cannonTimer = 0 +--- @param m MarioState +local function mario_update(m) if (m.flags & MARIO_VANISH_CAP) ~= 0 then - m.flags = m.flags & ~MARIO_VANISH_CAP --Always Remove Vanish Cap Cuz Broken + m.flags = m.flags & ~MARIO_VANISH_CAP --Always Remove Vanish Cap stop_cap_music() end -- this code runs for all players local s = gPlayerSyncTable[m.playerIndex] - -- if the local player died, make them a seeker - if m.playerIndex == 0 and m.health <= 0x110 then - s.seeking = true + 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 end -- remove caps @@ -217,71 +207,55 @@ function mario_update(m) end end - -- warp players out of banned levels + -- warp to the beninging if m.playerIndex == 0 then - if gNetworkPlayers[m.playerIndex].currLevelNum == LEVEL_RR and gGlobalSyncTable.banRR then - warp_to_castle(LEVEL_RR) - end - - if gNetworkPlayers[m.playerIndex].currLevelNum == LEVEL_BOWSER_1 then - warp_to_castle(LEVEL_BITDW) - end - - if gNetworkPlayers[m.playerIndex].currLevelNum == LEVEL_BOWSER_2 then - warp_to_castle(LEVEL_BITFS) - end - - if gNetworkPlayers[m.playerIndex].currLevelNum == LEVEL_BOWSER_3 then - warp_to_castle(LEVEL_BITS) - end - if gPlayerSyncTable[m.playerIndex].seeking and gGlobalSyncTable.displayTimer == 0 and gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then warp_to_level(gLevelValues.entryLevel, 1, 0) + warp_to_start_level() end end -- display all seekers as metal if s.seeking then - m.marioBodyState.modelState = MODEL_STATE_METAL - - m.health = 0x880 + m.marioBodyState.modelState = m.marioBodyState.modelState | MODEL_STATE_METAL end - + -- pu prevention if m.pos.x >= 0 then - puX = math.floor((8192 + m.pos.x) / 65536) + puX = math_floor((8192 + m.pos.x) / 65536) else - puX = math.ceil((-8192 + m.pos.x) / 65536) + puX = math_ceil((-8192 + m.pos.x) / 65536) end - if m.pos.z >= 0 then - puZ = math.floor((8192 + m.pos.z) / 65536) + puZ = math_floor((8192 + m.pos.z) / 65536) else - puZ = math.ceil((-8192 + m.pos.z) / 65536) + puZ = math_ceil((-8192 + m.pos.z) / 65536) end - - if (puX ~= 0) or (puZ ~= 0) then + if puX ~= 0 or puZ ~= 0 then s.seeking = true + warp_restart_level() end end -function mario_before_phys_step(m) +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 + end +end + +--- @param m MarioState +local function before_phys_step(m) -- prevent physics from being altered when bubbled - if m.action == ACT_BUBBLED then - return - end - - -- check gamemode enabled state - if not gGlobalSyncTable.hideAndSeek then - return - end - local s = gPlayerSyncTable[m.playerIndex] + if m.action == ACT_BUBBLED or s.seeking then return end + -- only make seekers faster - if not s.seeking then - return - end local hScale = 1.0 local vScale = 1.0 @@ -293,23 +267,9 @@ function mario_before_phys_step(m) vScale = vScale * 1.05 end end - - -- faster ground movement - if (m.action & ACT_FLAG_MOVING) ~= 0 then - hScale = hScale * 1.19 - end - - m.vel.x = m.vel.x * hScale - m.vel.y = m.vel.y * vScale - m.vel.z = m.vel.z * hScale end -function on_pvp_attack(attacker, victim) - -- check gamemode enabled state - if not gGlobalSyncTable.hideAndSeek then - return - end - +local function on_pvp_attack(attacker, victim) -- this code runs when a player attacks another player local sAttacker = gPlayerSyncTable[attacker.playerIndex] local sVictim = gPlayerSyncTable[victim.playerIndex] @@ -325,98 +285,66 @@ function on_pvp_attack(attacker, victim) end end -function on_player_connected(m) +--- @param m MarioState +local function on_player_connected(m) -- start out as a seeker local s = gPlayerSyncTable[m.playerIndex] s.seeking = true network_player_set_description(gNetworkPlayers[m.playerIndex], "seeker", 255, 64, 64, 255) end -function hud_top_render() - -- check gamemode enabled state - if not gGlobalSyncTable.hideAndSeek then - return - end - +local function hud_top_render() local seconds = 0 - local text = '' + local text = "" if gGlobalSyncTable.roundState == ROUND_STATE_WAIT then seconds = 60 - text = 'waiting for players' + text = "waiting for players" elseif gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then - seconds = math.floor(sRoundEndTimeout / 30 - gGlobalSyncTable.displayTimer) + seconds = math_floor(sRoundEndTimeout / 30 - gGlobalSyncTable.displayTimer) if seconds < 0 then seconds = 0 end - text = 'seekers have ' .. seconds .. ' seconds' + text = "seekers have " .. seconds .. " seconds" else - seconds = math.floor(sRoundStartTimeout / 30 - gGlobalSyncTable.displayTimer) + seconds = math_floor(sRoundStartTimeout / 30 - gGlobalSyncTable.displayTimer) if seconds < 0 then seconds = 0 end - text = 'next round in ' .. seconds .. ' seconds' + text = "next round in " .. seconds .. " seconds" end - local scale = 0.50 + local scale = 0.5 -- get width of screen and text local screenWidth = djui_hud_get_screen_width() local width = djui_hud_measure_text(text) * scale - local x = (screenWidth - width) / 2.0 + local x = (screenWidth - width) * 0.5 local y = 0 local background = 0.0 if seconds < 60 and gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then - background = (math.sin(sFlashingIndex / 10.0) * 0.5 + 0.5) * 1.0 + background = (math.sin(sFlashingIndex * 0.1) * 0.5 + 0.5) * 1 background = background * background background = background * background end -- render top - djui_hud_set_color(255 * background, 0, 0, 128); - djui_hud_render_rect(x - 6, y, width + 12, 16); + djui_hud_set_color(255 * background, 0, 0, 128) + djui_hud_render_rect(x - 6, y, width + 12, 16) - djui_hud_set_color(255, 255, 255, 255); - djui_hud_print_text(text, x, y, scale); + djui_hud_set_color(255, 255, 255, 255) + djui_hud_print_text(text, x, y, scale) end -function hud_bottom_render() - local seconds = math.floor((sDistanceTimeout - sDistanceTimer) / 30) - if seconds < 0 then seconds = 0 end - if sDistanceTimer < 1 then return end - - local text = 'Keep moving! (' .. seconds .. ')' - local scale = 0.50 - - -- 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 x = (screenWidth - width) / 2.0 - local y = screenHeight - 16 - - local background = (math.sin(sFlashingIndex / 10.0) * 0.5 + 0.5) * 1.0 - background = background * background - background = background * background - - -- render top - djui_hud_set_color(255 * background, 0, 0, 128); - djui_hud_render_rect(x - 6, y, width + 12, 16); - - djui_hud_set_color(255, 255, 255, 255); - djui_hud_print_text(text, x, y, scale); -end - -function hud_center_render() +local function hud_center_render() if gGlobalSyncTable.displayTimer > 3 then return end -- set text - local text = '' + local text = "" if gGlobalSyncTable.roundState == ROUND_STATE_SEEKERS_WIN then - text = 'Seekers Win!' + text = "Seekers Win!" elseif gGlobalSyncTable.roundState == ROUND_STATE_HIDERS_WIN then - text = 'Hiders Win!' + text = "Hiders Win!" elseif gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then - text = 'Go!' + text = "Go!" else return end @@ -430,203 +358,114 @@ function hud_center_render() local width = djui_hud_measure_text(text) * scale local height = 32 * scale - local x = (screenWidth - width) / 2.0 - local y = (screenHeight - height) / 2.0 + local x = (screenWidth - width) * 0.5 + local y = (screenHeight - height) * 0.5 -- render - djui_hud_set_color(0, 0, 0, 128); - djui_hud_render_rect(x - 6 * scale, y, width + 12 * scale, height); + djui_hud_set_color(0, 0, 0, 128) + djui_hud_render_rect(x - 6 * scale, y, width + 12 * scale, height) - djui_hud_set_color(255, 255, 255, 255); - djui_hud_print_text(text, x, y, scale); + djui_hud_set_color(255, 255, 255, 255) + djui_hud_print_text(text, x, y, scale) end -function on_hud_render() +local function on_hud_render() -- 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_bottom_render() hud_center_render() sFlashingIndex = sFlashingIndex + 1 end -function on_hide_and_seek_command(msg) - if msg == 'on' then - djui_chat_message_create('Hide-and-seek mod: enabled') - gGlobalSyncTable.hideAndSeek = true - gGlobalSyncTable.roundState = ROUND_STATE_WAIT - sRoundTimer = 0 - for i=0,(MAX_PLAYERS-1) do - gPlayerSyncTable[i].seeking = true - end - sLastSeekerIndex = 0 - - return true - elseif msg == 'off' then - djui_chat_message_create('Hide-and-seek mod: disabled') - gGlobalSyncTable.hideAndSeek = false - return true - end - - return false +local function on_touch_tag_command() + gGlobalSyncTable.touchTag = not gGlobalSyncTable.touchTag + djui_chat_message_create("Touch tag: " .. on_or_off(gGlobalSyncTable.touchTag)) + return true end -function on_anti_camp_command(msg) - if msg == 'on' then - djui_chat_message_create('Anti-camping timer: enabled') - gGlobalSyncTable.campingTimer = true - return true - elseif msg == 'off' then - djui_chat_message_create('Anti-camping timer: disabled') - gGlobalSyncTable.campingTimer = false - return true - end - - return false +local function on_hider_cap_command() + gGlobalSyncTable.hiderCaps = not gGlobalSyncTable.hiderCaps + djui_chat_message_create("Hider Caps: " .. on_or_off(gGlobalSyncTable.hiderCaps)) + return true end -function on_touch_tag_command(msg) - if msg == 'on' then - djui_chat_message_create('Touch tag: enabled') - gGlobalSyncTable.touchTag = true - return true - elseif msg == 'off' then - djui_chat_message_create('Touch tag: disabled') - gGlobalSyncTable.touchTag = false - return true - end - - return false +local function on_seeker_cap_command() + gGlobalSyncTable.seekerCaps = not gGlobalSyncTable.seekerCaps + djui_chat_message_create("Seeker Caps: " .. on_or_off(gGlobalSyncTable.seekerCaps)) + return true end -function on_hider_cap_command(msg) - if msg == 'on' then - djui_chat_message_create('Hider Caps: enabled') - gGlobalSyncTable.hiderCaps = false - return true - elseif msg == 'off' then - djui_chat_message_create('Hider Caps: disabled') - gGlobalSyncTable.hiderCaps = true - return true - end - - return false +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 end -function on_seeker_cap_command(msg) - if msg == 'on' then - djui_chat_message_create('Seeker Caps: enabled') - gGlobalSyncTable.seekerCaps = false - return true - elseif msg == 'off' then - djui_chat_message_create('Seeker Caps: disabled') - gGlobalSyncTable.seekerCaps = true - return true - end - - return false -end - -function on_koopa_shell_command(msg) - if msg == 'on' then - djui_chat_message_create('Koopa Shell: enabled') - gGlobalSyncTable.banKoopaShell = false - return true - elseif msg == 'off' then - djui_chat_message_create('Koopa Shell: disabled') - gGlobalSyncTable.banKoopaShell = true - return true - end - - return false -end - -function on_ban_rr_command(msg) - if msg == 'on' then - djui_chat_message_create('Ban RR: enabled') - gGlobalSyncTable.banRR = true - return true - elseif msg == 'off' then - djui_chat_message_create('Ban RR: disabled') - gGlobalSyncTable.banRR = false - return true - end - - return false -end - -function on_pause_exit(exitToCastle) +local function level_init() local s = gPlayerSyncTable[0] - if not s.seeking then - for i=1,(MAX_PLAYERS-1) do - if gNetworkPlayers[i].connected and gNetworkPlayers[i].currLevelNum == gNetworkPlayers[0].currLevelNum and gNetworkPlayers[i].currActNum == gNetworkPlayers[0].currActNum and gNetworkPlayers[i].currAreaIndex == gNetworkPlayers[0].currAreaIndex and gPlayerSyncTable[i].seeking then - local m = gMarioStates[0] - local a = gMarioStates[i] - if dist_between_objects(m.marioObj, a.marioObj) <= 4000 then - return false - end - end - end - end + pauseExitTimer = 0 + canLeave = false + + if s.seeking then canLeave = true end end -function allow_pvp_attack(m1, m2) - local s1 = gPlayerSyncTable[m1.playerIndex] - local s2 = gPlayerSyncTable[m2.playerIndex] - if s1.seeking == s2.seeking then +local function on_pause_exit() + local s = gPlayerSyncTable[0] + + if not canLeave and not s.seeking then + djui_popup_create(tostring(math_floor(30 - pauseExitTimer / 30)).." Seconds until you can leave!", 2) return false end - return true end ----------------------- -- network callbacks -- ----------------------- -function on_round_state_changed(tag, oldVal, newVal) +local function on_round_state_changed() local rs = gGlobalSyncTable.roundState - if rs == ROUND_STATE_WAIT then - -- nothing - elseif rs == ROUND_STATE_ACTIVE then + if rs == ROUND_STATE_ACTIVE then play_character_sound(gMarioStates[0], CHAR_SOUND_HERE_WE_GO) elseif rs == ROUND_STATE_SEEKERS_WIN then play_sound(SOUND_MENU_CLICK_CHANGE_VIEW, gMarioStates[0].marioObj.header.gfx.cameraToObject) - elseif rs == ROUND_STATE_HIDERS_WIN then + elseif rs == ROUND_STATE_HIDERS_WIN then play_sound(SOUND_MENU_CLICK_CHANGE_VIEW, gMarioStates[0].marioObj.header.gfx.cameraToObject) - elseif rs == ROUND_STATE_UNKNOWN_END then - -- nothing end end - -function on_seeking_changed(tag, oldVal, newVal) +local function on_seeking_changed(tag, oldVal, newVal) local m = gMarioStates[tag] - local np = gNetworkPlayers[tag] + local npT = gNetworkPlayers[tag] -- 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) - djui_popup_create(playerColor .. np.name .. '\\#ffa0a0\\ is now a seeker', 2) - if gGlobalSyncTable.roundState == ROUND_STATE_ACTIVE then - sLastSeekerIndex = m.playerIndex - end + djui_popup_create(playerColor .. npT.name .. "\\#ffa0a0\\ is now a seeker", 2) sRoundTimer = 32 end if newVal then - network_player_set_description(np, "seeker", 255, 64, 64, 255) + network_player_set_description(npT, "seeker", 255, 64, 64, 255) else - network_player_set_description(np, "hider", 128, 128, 128, 255) + network_player_set_description(npT, "hider", 128, 128, 128, 255) end end -function on_interact(m, obj, intee) +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 + end + + return false +end + +local function on_interact(m, obj, intee) if intee == INTERACT_PLAYER then if not gGlobalSyncTable.touchTag then @@ -647,50 +486,54 @@ function on_interact(m, obj, intee) end end -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 - end - - return false -end - -function allow_interact(m, obj, intee) +local function allow_interact(_, _, intee) if intee == INTERACT_KOOPA_SHELL and gGlobalSyncTable.banKoopaShell then return false end end +function allow_pvp_attack(m1, m2) + local s1 = gPlayerSyncTable[m1.playerIndex] + local s2 = gPlayerSyncTable[m2.playerIndex] + if s1.seeking == s2.seeking then + return false + end + return true +end + +gLevelValues.disableActs = true + ----------- -- hooks -- ----------- hook_event(HOOK_UPDATE, update) +hook_event(HOOK_ON_SCREEN_TRANSITION, screen_transition) +hook_event(HOOK_BEFORE_SET_MARIO_ACTION, before_set_mario_action) hook_event(HOOK_MARIO_UPDATE, mario_update) -hook_event(HOOK_BEFORE_PHYS_STEP, mario_before_phys_step) +hook_event(HOOK_BEFORE_PHYS_STEP, before_phys_step) +hook_event(HOOK_ALLOW_PVP_ATTACK, allow_pvp_attack) hook_event(HOOK_ON_PVP_ATTACK, on_pvp_attack) hook_event(HOOK_ON_PLAYER_CONNECTED, on_player_connected) hook_event(HOOK_ON_HUD_RENDER, on_hud_render) -hook_event(HOOK_ON_PAUSE_EXIT, on_pause_exit) -hook_event(HOOK_ALLOW_PVP_ATTACK, allow_pvp_attack) +hook_event(HOOK_ON_LEVEL_INIT, level_init) +hook_event(HOOK_ON_PAUSE_EXIT, on_pause_exit) -- timer hook_event(HOOK_ON_INTERACT, on_interact) hook_event(HOOK_ALLOW_INTERACT, allow_interact) +hook_event(HOOK_USE_ACT_SELECT, function () return false end) if network_is_server() then - hook_chat_command('hide-and-seek', "[on|off] turn hide-and-seek on or off", on_hide_and_seek_command) - hook_chat_command('touch-to-tag', "[on|off] turn touch tag on or off", on_touch_tag_command) - hook_chat_command('hiders-caps', "[on|off] turn caps for hiders on or off", on_hider_cap_command) - hook_chat_command('seekers-caps', "[on|off] turn caps for seekers on or off", on_seeker_cap_command) - hook_chat_command('anti-camp', "[on|off] turn the anti-camp timer on or off", on_anti_camp_command) - hook_chat_command('koopa-shell', "[on|off] Turn the koopa shell on or off", on_koopa_shell_command) - hook_chat_command('ban-rr', "[on|off] Turn Banning RR on or off", on_ban_rr_command) + 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) end -- call functions when certain sync table values change -hook_on_sync_table_change(gGlobalSyncTable, 'roundState', 0, on_round_state_changed) -for i=0,(MAX_PLAYERS-1) do +hook_on_sync_table_change(gGlobalSyncTable, "roundState", 0, on_round_state_changed) + +for i = 0, (MAX_PLAYERS - 1) do gPlayerSyncTable[i].seeking = true - hook_on_sync_table_change(gPlayerSyncTable[i], 'seeking', i, on_seeking_changed) + hook_on_sync_table_change(gPlayerSyncTable[i], "seeking", i, on_seeking_changed) network_player_set_description(gNetworkPlayers[i], "seeker", 255, 64, 64, 255) end -