-- name: Hide and Seek \\#0ff\\Lite -- incompatible: gamemode -- description: A reimplementation of the original Hide and Seek mod which optimizes code and fixes bugs while retaining the original game design. -- pausable: false -- PACKETS local splashText = "" local splashTimer = 0 local function seeker_message(i) djui_popup_create(network_get_player_text_color_string(i) .. gNetworkPlayers[i].name .. "\\#ffa0a0\\ is now a seeker", 2) end local function packet_receive(data) if data.packet == "start" then play_character_sound(gMarioStates[0], CHAR_SOUND_HERE_WE_GO) splashText = "Begin!" splashTimer = 90 seeker_message(network_local_index_from_global(data.i)) if network_local_index_from_global(data.i) == 0 then warp_to_start_level() end end if data.packet == "tag" then play_sound(SOUND_OBJ_BOWSER_LAUGH, gMarioStates[0].marioObj.header.gfx.cameraToObject) seeker_message(network_local_index_from_global(data.i)) if network_is_server() then gGlobalSyncTable.timer = 180 end end if data.packet == "result" then play_sound(SOUND_MENU_CLICK_CHANGE_VIEW, gMarioStates[0].marioObj.header.gfx.cameraToObject) splashText = data.message splashTimer = 90 end end hook_event(HOOK_ON_PACKET_RECEIVE, packet_receive) local function send_packet(packet) packet_receive(packet) network_send(true, packet) end -- ENGINE gGlobalSyncTable.gameState = 1 gGlobalSyncTable.timer = 15 local frameTimer = 0 if network_is_server() then for i=0, MAX_PLAYERS-1 do gPlayerSyncTable[i].seeker = true end end local function end_round(splash) send_packet({packet="result", message=splash}) gGlobalSyncTable.gameState = 1 gGlobalSyncTable.timer = 15 end local function update() for i=0, MAX_PLAYERS-1 do if gPlayerSyncTable[i].seeker then network_player_set_description(gNetworkPlayers[i], "Seeker", 255, 128, 128, 255) else network_player_set_description(gNetworkPlayers[i], "Hider", 128, 128, 255, 255) end if network_is_server() and not gNetworkPlayers[i].connected then gPlayerSyncTable[i].seeker = true end end if network_is_server() then if network_player_connected_count() < 2 then gGlobalSyncTable.gameState = 0 gGlobalSyncTable.timer = 15 return elseif gGlobalSyncTable.gameState == 0 then gGlobalSyncTable.gameState = 1 end frameTimer = frameTimer + 1 if frameTimer >= 30 then gGlobalSyncTable.timer = gGlobalSyncTable.timer - 1 frameTimer = 0 end if gGlobalSyncTable.timer == 0 then if gGlobalSyncTable.gameState == 1 then gGlobalSyncTable.gameState = 2 gGlobalSyncTable.timer = 180 for i=0, MAX_PLAYERS-1 do gPlayerSyncTable[i].seeker = false end local rng = math.random(network_player_connected_count())-1 gPlayerSyncTable[rng].seeker = true send_packet({packet="start", i=rng}) elseif gGlobalSyncTable.gameState == 2 then end_round("Hiders Win!") end elseif gGlobalSyncTable.gameState == 2 then local noMoreHiders = true local noMoreSeekers = true for i=0, MAX_PLAYERS-1 do if not gPlayerSyncTable[i].seeker then noMoreHiders = false end if gPlayerSyncTable[i].seeker and gNetworkPlayers[i].connected then noMoreSeekers = false end end if noMoreHiders then end_round("Seekers Win!") end if noMoreSeekers then end_round("Forfeit...") end end end end hook_event(HOOK_UPDATE, update) -- ENFORCEMENTS gServerSettings.bubbleDeath = 0 gServerSettings.nametags = false gLevelValues.disableActs = true gBehaviorValues.ShowStarMilestones = false gBehaviorValues.ShowStarDialog = false gGlobalSyncTable.touch = false gGlobalSyncTable.bljs = false gGlobalSyncTable.shells = false gGlobalSyncTable.hiderCaps = true gGlobalSyncTable.seekerCaps = true local cannonTimer = 0 local exitTimer = 0 local antiInvincTimer = 0 local warpStallTimer = 0 local function disqualify(message) gPlayerSyncTable[0].seeker = true send_packet({packet="tag", i=network_global_index_from_local(0)}) djui_chat_message_create(message) end local function mario_update(m) -- Display Seekers as Metal if gPlayerSyncTable[m.playerIndex].seeker then m.marioBodyState.modelState = m.marioBodyState.modelState | MODEL_STATE_METAL end -- Only Execute the Following Code for Local Player if m.playerIndex ~= 0 then return end -- Enforce Camera Configs camera_config_enable_collisions(true) rom_hack_cam_set_collisions(1) camera_romhack_set_zoomed_in_dist(900) camera_romhack_set_zoomed_out_dist(1400) camera_romhack_set_zoomed_in_height(300) camera_romhack_set_zoomed_out_height(450) -- Disable Vanish Caps if m.flags & MARIO_VANISH_CAP ~= 0 then m.flags = m.flags & ~MARIO_VANISH_CAP stop_cap_music() end -- Enforce Wing/Metal Cap Toggles if (not gGlobalSyncTable.hiderCaps and not gPlayerSyncTable[0].seeker) or (not gGlobalSyncTable.seekerCaps and gPlayerSyncTable[0].seeker) then m.flags = m.flags & ~MARIO_WING_CAP m.flags = m.flags & ~MARIO_METAL_CAP stop_cap_music() end -- Enforce BLJ Toggle if not gGlobalSyncTable.bljs and (m.action == ACT_LONG_JUMP or m.action == ACT_LONG_JUMP_LAND) and m.forwardVel <= -55 then m.forwardVel = -55 end -- Exit Cooldown Timer if exitTimer > 0 then exitTimer = exitTimer - 1 end -- Invincibility Stall Fix if not gPlayerSyncTable[0].seeker and not gGlobalSyncTable.touch and gGlobalSyncTable.gameState == 2 and m.invincTimer > 0 then antiInvincTimer = antiInvincTimer + 1 if antiInvincTimer >= 300 then disqualify("\\#ffa0a0\\You are disqualified for abusing invincibility.") end else antiInvincTimer = 0 end -- Warp Stall Fix if warpStallTimer >= 300 then disqualify("\\#ffa0a0\\You are disqualified for using warps exceedingly.") warpStallTimer = 0 elseif warpStallTimer > 0 then warpStallTimer = warpStallTimer - 1 end -- Parallel Universe Fix if (m.pos.x > 0x7FFF or m.pos.x < -0x8000 or m.pos.z > 0x7FFF or m.pos.z < -0x8000) then warp_restart_level() if gGlobalSyncTable.gameState == 2 and not gPlayerSyncTable[0].seeker then disqualify("\\#ffa0a0\\You are disqualified for entering a parallel universe.") end end -- Cannon Timer if 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 else cannonTimer = 0 end end hook_event(HOOK_MARIO_UPDATE, mario_update) local function level_init() exitTimer = 900 end hook_event(HOOK_ON_LEVEL_INIT, level_init) local function on_pause_exit() if not gPlayerSyncTable[0].seeker and exitTimer > 0 then djui_popup_create(math.floor(exitTimer/30)+1 .." Seconds until you can leave!", 2) return false end end hook_event(HOOK_ON_PAUSE_EXIT, on_pause_exit) local function before_set_mario_action(m, action) -- Prevent NPC/Sign Interactions if m.playerIndex == 0 then if action == ACT_WAITING_FOR_DIALOG or action == ACT_READING_SIGN or action == ACT_READING_NPC_DIALOG then return 1 -- Prevent Course Clear Cutscene 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 hook_event(HOOK_BEFORE_SET_MARIO_ACTION, before_set_mario_action) local function on_dialog(id) -- Prevent Other Dialogs local m = gMarioStates[0] if m.action == ACT_READING_NPC_DIALOG and m.usedObj ~= nil then m.usedObj.oDialogState = 3 m.usedObj.oDialogResponse = 1 end return false end hook_event(HOOK_ON_DIALOG, on_dialog) -- HUD local breathe = 0 local function render_text(message, y, size) if gGlobalSyncTable.gameState == 2 and gGlobalSyncTable.timer <= 60 then djui_hud_set_color(64 + 64 * math.sin(breathe), 0, 0, 160) else djui_hud_set_color(0, 0, 0, 160) end djui_hud_render_rect(djui_hud_get_screen_width()/2-djui_hud_measure_text(message)*size/2-(4*size), y, djui_hud_measure_text(message)*size+(8*size), size*30) djui_hud_set_color(255, 255, 255, 255) djui_hud_print_text(message, djui_hud_get_screen_width()/2-djui_hud_measure_text(message)*size/2, y-4, size) end local function draw_hud() breathe = breathe + math.pi/7 if breathe >= math.pi*2 then breathe = 0 end local topMessage = "Waiting for Players..." if gGlobalSyncTable.gameState == 1 then topMessage = "Starting in " .. gGlobalSyncTable.timer elseif gGlobalSyncTable.gameState == 2 then topMessage = "Time: " .. gGlobalSyncTable.timer end render_text(topMessage, 0, 2) if gMarioStates[0].action == ACT_IN_CANNON and gMarioStates[0].actionState == 2 then render_text("Shooting in " .. (math.floor((150-cannonTimer)/30)+1), djui_hud_get_screen_height()-60, 2) end if splashTimer > 0 then render_text(splashText, 90, 4) splashTimer = splashTimer - 1 end end hook_event(HOOK_ON_HUD_RENDER, draw_hud) -- TAG HANDLING local function allow_pvp(a, v) if gPlayerSyncTable[a.playerIndex].seeker == gPlayerSyncTable[v.playerIndex].seeker then return false end return true end hook_event(HOOK_ALLOW_PVP_ATTACK, allow_pvp) local function on_pvp(a, v) if v.playerIndex ~= 0 then return end if gGlobalSyncTable.gameState == 2 and not gPlayerSyncTable[0].seeker then gPlayerSyncTable[0].seeker = true send_packet({packet="tag", i=network_global_index_from_local(0)}) end end hook_event(HOOK_ON_PVP_ATTACK, on_pvp) local function allow_interact(m, o, intee) if not gGlobalSyncTable.shells and intee == INTERACT_KOOPA_SHELL then return false end if gGlobalSyncTable.gameState == 2 and gGlobalSyncTable.touch and gPlayerSyncTable[0].seeker and m.playerIndex ~= 0 and intee == INTERACT_PLAYER then for i=0,(MAX_PLAYERS-1) do if gNetworkPlayers[i].connected and gNetworkPlayers[i].currAreaSyncValid and not gPlayerSyncTable[i].seeker and 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 gPlayerSyncTable[i].seeker = true send_packet({packet="tag", i=network_global_index_from_local(i)}) end end end end hook_event(HOOK_ALLOW_INTERACT, allow_interact) local function on_death() if gGlobalSyncTable.gameState == 2 and not gPlayerSyncTable[0].seeker then for i=1,(MAX_PLAYERS-1) do if gNetworkPlayers[i].connected and gPlayerSyncTable[i].seeker and gNetworkPlayers[i].currAreaSyncValid and gNetworkPlayers[0].currLevelNum == gNetworkPlayers[i].currLevelNum and gNetworkPlayers[0].currAreaIndex == gNetworkPlayers[i].currAreaIndex and dist_between_objects(gMarioStates[0].marioObj, gMarioStates[i].marioObj) <= 4000 then disqualify("\\#ffa0a0\\A seeker was nearby when you died.") end end end end hook_event(HOOK_ON_DEATH, on_death) local function on_warp() if not gPlayerSyncTable[0].seeker and not gGlobalSyncTable.touch and gGlobalSyncTable.gameState == 2 then warpStallTimer = warpStallTimer + 150 end end hook_event(HOOK_ON_WARP, on_warp) hook_event(HOOK_ON_INSTANT_WARP, on_warp) -- COMMANDS local function toggle_rule(rule, b) if b then djui_chat_message_create(rule .. " disabled.") else djui_chat_message_create(rule .. " enabled.") end return not b end local function command_touch() gGlobalSyncTable.touch = toggle_rule("Touch-to-Tag", gGlobalSyncTable.touch) return true end local function command_hider_caps() gGlobalSyncTable.hiderCaps = toggle_rule("Hider Wing/Metal Caps", gGlobalSyncTable.hiderCaps) return true end local function command_seeker_caps() gGlobalSyncTable.seekerCaps = toggle_rule("Seeker Wing/Metal Caps", gGlobalSyncTable.seekerCaps) return true end local function command_shells() gGlobalSyncTable.shells = toggle_rule("Shells", gGlobalSyncTable.shells) return true end local function command_bljs() gGlobalSyncTable.bljs = toggle_rule("BLJs", gGlobalSyncTable.bljs) return true end if network_is_server() then hook_chat_command("touch", " - Toggle Touch-to-Tag", command_touch) hook_chat_command("hider-caps", " - Toggle Wing/Metal Caps for Hiders", command_hider_caps) hook_chat_command("seeker-caps", " - Toggle Wing/Metal Caps for Seekers", command_seeker_caps) hook_chat_command("shells", " - Toggle Shells", command_shells) hook_chat_command("bljs", " - Toggle BLJs", command_bljs) end