local LD = require("design.LevelDesignLibrary")
local EC = require("design.Encounter")
local timers = require("level.timer")
local monitors = require("level.MonitorLibrary")
local TUT = require("game.GlobalTutorials")
local uiCalls = require("ui.uicalls")
local CCOS = require("camera.camera_oneshot")
local CSL = require("camera.shakelibrary")
local player, son, thisLevel, sonPuppeteer, SandBowlMarker, Stn430NonSonCombatState
local C_FORCE_FEEDBACK_RUMBLE = {
  EffectName = "FFB_HEAVY_ATTACK",
  Duration = 1
}
local Encounter01, Encounter02, Encounter03, Encounter04, EncountersComplete
local bFallingDeathEnabled = false
local bElevatorRideStarted = false
local bElevatorRideCompleted = false
local bElevatorCollapsed = false
local FallingDeathMonitor, FirstWaveMonitor, SecondWaveMonitor, ThirdWaveMonitor, FourthWaveMonitor, ReachedTopMonitor, ResetPlatformMonitor, FloorGaugeMonitor
local Time_Attack_Started = false
local ecTimer, timeRemaining
local ec_TimeRequirement = 95
local warnTime_1, warnTime_2, ResStoneLockTimer
local WarnVal_1 = ec_TimeRequirement / 2
local WarnVal_2 = ec_TimeRequirement * 0.85
local ResStoneLockout = ec_TimeRequirement - 15
local WhirlFX_Full, WhirlFX_Mid, WhirlFX_Low, WhirlFX_Low_Bowl, FallingDeathVolume, PlatformCollision, bStartBtrDone
local guessCount = 0
local currentGuessInput, runeObject1Value, runeObject2Value, runeObject3Value, runeObject4Value
local rune1CorrectValue = 3
local rune2CorrectValue = 3
local rune3CorrectValue = 2
local rune4CorrectValue = 2
local rune1Correct = false
local rune2Correct = false
local rune3Correct = false
local rune4Correct = false
local bSequenceCorrect = false
local animTimer_0, animTimer_1, animTimer_2, animTimer_3, animTimer_4, disintegrationTimer
local disintegrationPhase = 1
local t0 = 0
local t1 = 0
local t2 = 0
local t3 = 0
local t4 = 0
local t5 = 0
local t6 = 0
local crack1, crack2, crack3, crack4, crack5, DMC_Col, Elevator, animTimerCrack_1, animTimerCrack_2, animTimerCrack_3, animTimerCrack_4, animTimerCrack_5
local numRunesIdentified = 0
local SandBowl_Puzzle, SandBowl_Continuous, bowlLiquid_C1, bowlLiquid_C2, bowlLiquid_P1, bowlLiquid_P2, Top_CA_TurretCO, EEE_BowlCollapse
local kratosOnPlatform = false
local hasPlayed_stn_MagicElevator_SandBowl_answer = false
local isAttemptingToSolve = false
local puzzleSolved = false
local roomComplete = false
local bPlatformCollapsed = false
local bFinaleTimer
local vibrateCount = 0
local playerIsDyingFromCollapse = false
local handleFinalShake, handleFinalRumble, camOneShot_FrameAroundRuneBowl, camOneShot_QuestionStarted, runeTable, FlipperTable
local elevatorSequenceStates = {
  StartCrashed = {
    StartAnimFrame = 0,
    EndAnimFrame = 0,
    PlayRate = 0,
    OnAnimDone = nil
  },
  RiseToIdle = {
    StartAnimFrame = 0,
    EndAnimFrame = 90,
    PlayRate = 1,
    OnAnimDone = "FormElevatorCompleted"
  },
  Idle = {
    StartAnimFrame = 90,
    EndAnimFrame = 300,
    PlayRate = 0.25,
    OnAnimDone = nil
  },
  RiseToDeathZone = {
    StartAnimFrame = 300,
    EndAnimFrame = 1000,
    PlayRate = 3,
    OnAnimDone = "RiseToEncounter01"
  },
  Encounter01 = {
    StartAnimFrame = 1000,
    EndAnimFrame = 1379,
    PlayRate = 2,
    OnAnimDone = "FirstWave",
    StoreCheckpoint = true
  },
  Encounter02 = {
    StartAnimFrame = 1379,
    EndAnimFrame = 1750,
    PlayRate = 1.5,
    OnAnimDone = "SecondWave",
    StoreCheckpoint = true
  },
  Encounter03 = {
    StartAnimFrame = 1750,
    EndAnimFrame = 2000,
    PlayRate = 1.5,
    OnAnimDone = "ThirdWave",
    StoreCheckpoint = true
  },
  Encounter04 = {
    StartAnimFrame = 2000,
    EndAnimFrame = 2200,
    PlayRate = 2,
    OnAnimDone = "FourthWave",
    StoreCheckpoint = true
  },
  RiseToTop = {
    StartAnimFrame = 2200,
    EndAnimFrame = 2450,
    PlayRate = 1,
    OnAnimDone = "ReachedTop"
  },
  RiseToNextState = {EndAnimFrame = 0, PlayRate = 3}
}
local currentElevatorState, nextElevatorState
function OnScriptLoaded(level)
  player = game.Player:FindPlayer()
  son = game.AI.FindSon()
  thisLevel = level
  SandBowlMarker = GameObjects.MarkerSandBowlInteractPos
  FallingDeathVolume = GameObjects.IC_DeathPit
  PlatformCollision = GameObjects.IC
  GameObjects.DeathSweep:Hide()
  crack1 = GameObjects.crack1
  crack2 = GameObjects.crack2
  crack3 = GameObjects.crack3
  crack4 = GameObjects.crack4
  crack5 = GameObjects.crack5
  DMC_Col = GameObjects.DMC_Col
  Elevator = GameObjects.StoneMasonElevator.Child
  SandBowl_Puzzle = GameObjects.soninteract_sandbowl_puzzle
  SandBowl_Continuous = GameObjects.soninteract_sandbowl_continuous
  SoundInit()
  bowlLiquid_C1 = SandBowl_Continuous:FindSingleGOByName("mesh_inactivestate_liquid")
  bowlLiquid_C2 = SandBowl_Continuous:FindSingleGOByName("mesh_deadstate_liquid")
  bowlLiquid_P1 = SandBowl_Puzzle:FindSingleGOByName("mesh_inactivestate_liquid")
  bowlLiquid_P2 = SandBowl_Puzzle:FindSingleGOByName("mesh_deadstate_liquid")
  WhirlFX_Low = GameObjects.rising_platform_group.Child:FindSingleGOByName("ElevatorWhirlFX_Low")
  WhirlFX_Low_Bowl = GameObjects.rising_platform_group.Child:FindSingleGOByName("ElevatorBowlLowFx_Isolate")
  WhirlFX_Mid = GameObjects.rising_platform_group.Child:FindSingleGOByName("ElevatorWhirlFX_Mid")
  WhirlFX_Full = GameObjects.rising_platform_group.Child:FindSingleGOByName("ElevatorWhirlFX")
  EEE_BowlCollapse = GameObjects.rising_platform_group.Child:FindSingleGOByName("EEE_BowlCollapse")
  Top_CA_TurretCO = GameObjects.rising_platform_group.Child:FindSingleGOByName("CA_Combat_Turret_CommndOnly_Stn430")
  GameObjects.RuneBreakFx_C1:Hide()
  GameObjects.RuneBreakFx_C2:Hide()
  GameObjects.RuneBreakFx_C3:Hide()
  GameObjects.RuneBreakFx_C4:Hide()
  GameObjects.EZ_BTR_PlayJump:HideEntityVolume()
end
function OnFirstStart(level)
  GameObjects.CrawlThrough_baseMesh:Hide()
  FallingDeathVolume:Hide()
  GameObjects.IC_Fanatics:HideCollision()
  GameObjects.ScriptControlled_IC_TubeCollision:ShowCollision()
  GameObjects.ScriptControlled_IC_PitEdges:ShowCollision()
  GameObjects.TraversePathExit:HideTraversePath()
  crack1:Hide()
  crack2:Hide()
  crack3:Hide()
  crack4:Hide()
  crack5:Hide()
  DMC_Col:HideCollision()
  GameObjects.RuneLight_1:Hide()
  GameObjects.RuneBreakFx_1:Hide()
  GameObjects.RuneLight_2:Hide()
  GameObjects.RuneBreakFx_2:Hide()
  GameObjects.RuneLight_3:Hide()
  GameObjects.RuneBreakFx_3:Hide()
  GameObjects.RuneLight_4:Hide()
  GameObjects.RuneBreakFx_4:Hide()
  GameObjects.RuneLight_4:Hide()
  GameObjects.BowlFall_IC_Coll:Hide()
  GameObjects.Elevator_IC_Coll:Hide()
  currentElevatorState = "StartCrashed"
end
function OnSaveCheckpoint(level)
  return {
    puzzleSolved = puzzleSolved,
    roomComplete = roomComplete,
    currentElevatorState = currentElevatorState,
    EncountersComplete = EncountersComplete,
    bElevatorRideStarted = bElevatorRideStarted,
    kratosOnPlatform = kratosOnPlatform
  }
end
function OnRestoreCheckpoint(level, savedInfo)
  puzzleSolved = savedInfo.puzzleSolved
  roomComplete = savedInfo.roomComplete
  currentElevatorState = savedInfo.currentElevatorState or "StartCrashed"
  if savedInfo.EncountersComplete then
    EncountersComplete = savedInfo.EncountersComplete
  end
  bElevatorRideStarted = savedInfo.bElevatorRideStarted or false
  kratosOnPlatform = savedInfo.kratosOnPlatform or false
end
function OnStart(level)
  if not roomComplete then
    SetupFlippables()
    SetupEncounters()
    animTimer_0 = timers.StartLevelTimer(t0, ElevatorDegrading0)
    animTimer_0:Reset()
    animTimer_1 = timers.StartLevelTimer(t1, ElevatorDegrading1)
    animTimer_1:Reset()
    animTimer_2 = timers.StartLevelTimer(t2, ElevatorDegrading2)
    animTimer_2:Reset()
    animTimer_3 = timers.StartLevelTimer(t3, ElevatorDegrading3)
    animTimer_3:Reset()
    animTimer_4 = timers.StartLevelTimer(t4, ElevatorDegrading4)
    animTimer_4:Reset()
    animTimerCrack_1 = timers.StartLevelTimer(3, HideCrack1)
    animTimerCrack_1:Reset()
    animTimerCrack_2 = timers.StartLevelTimer(2.5, HideCrack2)
    animTimerCrack_2:Reset()
    animTimerCrack_3 = timers.StartLevelTimer(2, HideCrack3)
    animTimerCrack_3:Reset()
    animTimerCrack_4 = timers.StartLevelTimer(1.5, HideCrack4)
    animTimerCrack_4:Reset()
    animTimerCrack_5 = timers.StartLevelTimer(1, HideCrack5)
    animTimerCrack_5:Reset()
    if puzzleSolved and not roomComplete then
      if bElevatorRideStarted and kratosOnPlatform then
        if not EncountersComplete.Encounter01 then
          SetRiseState("Encounter01", true)
          LD.ShowFX(WhirlFX_Low)
          LD.ShowFX(WhirlFX_Low_Bowl)
          AudioElevatorLiftLP()
        elseif not EncountersComplete.Encounter02 then
          SetRiseState("Encounter02", true)
          LD.ShowFX(WhirlFX_Low)
          LD.ShowFX(WhirlFX_Low_Bowl)
          AudioElevatorLiftLP()
        elseif not EncountersComplete.Encounter03 then
          SetRiseState("Encounter03", true)
          LD.ShowFX(WhirlFX_Low)
          LD.ShowFX(WhirlFX_Low_Bowl)
          AudioElevatorLiftLP()
        elseif not EncountersComplete.Encounter04 then
          SetRiseState("Encounter04", true)
          LD.ShowFX(WhirlFX_Low)
          LD.ShowFX(WhirlFX_Low_Bowl)
          AudioElevatorLiftLP()
        end
      else
        SetRiseState("Idle", true)
        AudioElevatorActiveIdleLP()
      end
      EnableSonRuneRead()
    end
  end
end
function Stn210_EntryNav_Disable()
  local Stn210 = game.FindLevel("Stn210_LoadingDoors")
  Stn210:CallScript("Stn430_EntryNav_Disable")
  print("!!!disable remotely")
end
function EnableDoggyDoor()
  if not puzzleSolved then
    GameObjects.EZ_CA_Stn430_LookAtSB:Hide()
    GameObjects.CA_ObserveFar_Forward_SB_Stn430.LuaObjectScript.Interrupt()
    GameObjects.CA_ObserveFar_Forward_SB_Stn430.LuaObjectScript.Disable()
    GameObjects.CA_Observe_Down_Stn430_Edge.LuaObjectScript.Disable()
    GameObjects.CA_LookUnderObject_Forward_Stn430_DoggyDoor.LuaObjectScript.Enable()
    GameObjects.CrawlThrough_GroundLevel.Child.Child.LuaObjectScript.Enable()
  end
end
function EnableSonRuneRead()
  if puzzleSolved then
    GameObjects.BowlFall_IC_Coll:Hide()
    SandBowl_Continuous.LuaObjectScript.SetQuestionGiven()
    SandBowl_Continuous.LuaObjectScript.Enable()
  else
    GameObjects.CA_Puzzled_Stn430_SandbowlGoto.LuaObjectScript.Enable()
  end
end
function FirstArrivalBowl()
  GameObjects.CA_Puzzled_Stn430_SandbowlGoto.LuaObjectScript.Interrupt()
  GameObjects.CA_Puzzled_Stn430_SandbowlGoto.LuaObjectScript.Disable()
  SandBowl_Puzzle.LuaObjectScript.Enable()
end
function Stn210_LockLoadingDoors()
  local Stn210 = game.FindLevel("Stn210_LoadingDoors")
  if Stn210 ~= nil then
    Stn210:CallScript("LockDoor_Stn430")
  end
end
local callbackState_Continuous = "No Relevant State"
function OnSandbowlSolveStart_Cont()
  callbackState_Continuous = "OnSandbowlSolveStart"
  if kratosOnPlatform and not bElevatorRideCompleted then
    timers.StartLevelTimer(1, function()
      Rise()
      LD.HideFX(WhirlFX_Low)
      LD.HideFX(WhirlFX_Low_Bowl)
    end)
  end
end
local callbackState = "No Relevant State"
local askedQuestion = false
function OnSandbowlArrive()
  callbackState = "OnSandbowlArrive"
  son:CallScript("OnStandGround", true)
  if askedQuestion and not puzzleSolved then
    SandBowl_Puzzle.LuaObjectScript.SetRuneDiscovered(true)
  end
end
function OnSandbowlQuestionStart()
  callbackState = "OnSandbowlQuestionStart"
  game.Audio.PlayBanter("stn_MagicElevator_SandBowl_Arrive", function()
    SandBowl_Puzzle.LuaObjectScript.Enable()
    bStartBtrDone = true
  end)
  timers.StartLevelTimer(4, function()
    GameObjects.IC_SpinnerCovers:Hide()
  end)
  timers.StartLevelTimer(3, function()
    GameObjects.SpinnerPanels:PlayAnimToEnd(2)
    PlaySpinnerPanelOpen()
    GameObjects.SpinnerPanels:OnAnimDone(thisLevel, "StopSpinnerPanelOpen")
  end)
  CameraLookAt_QuestionStarted()
end
function OnSandbowlQuestionComplete()
  callbackState = "OnSandbowlQuestionComplete"
  askedQuestion = true
  if bStartBtrDone == true then
    timers.StartLevelTimer(1, function()
      SandBowl_Puzzle.LuaObjectScript.Enable()
    end)
  end
end
function OnSandbowlSolveStart()
  game.Audio.PlayBanter("stn_MagicElevator_Check")
  RuneCheck()
  isAttemptingToSolve = true
  callbackState = "OnSandbowlSolveStart"
  GameObjects.flippers_stn430_v1:FindSingleGOByName("FlipperModule").LuaObjectScript.DisableRotation()
  GameObjects.flippers_stn430_v2:FindSingleGOByName("FlipperModule").LuaObjectScript.DisableRotation()
  GameObjects.flippers_stn430_v3:FindSingleGOByName("FlipperModule").LuaObjectScript.DisableRotation()
  GameObjects.flippers_stn430_v4:FindSingleGOByName("FlipperModule").LuaObjectScript.DisableRotation()
  GameObjects.IC_SpinnerCovers:Show()
  GameObjects.SpinnerPanels:PlayAnimToEnd(-20)
  PlaySpinnerPanelClose()
  if bSequenceCorrect then
    timers.StartLevelTimer(2.5, SonInteractWithSandBowlCorrect)
  else
    timers.StartLevelTimer(1.5, SonInteractWithSandBowlIncorrect)
  end
end
function OnSandbowlSolveComplete()
  callbackState = "OnSandbowlSolveComplete"
  if not bElevatorRideCompleted then
    if bSequenceCorrect and not puzzleSolved then
      puzzleSolved = true
      SandBowl_Puzzle.LuaObjectScript.Disable()
      SandBowl_Puzzle.LuaObjectScript.HideSandBowl()
      SandBowl_Continuous.LuaObjectScript.ShowSandBowl()
      SandBowl_Continuous.LuaObjectScript.SetQuestionGiven()
      SandBowl_Continuous.LuaObjectScript.Enable()
      son:CallScript("OnStandGround", false)
    else
      timers.StartLevelTimer(2, function()
        SandBowl_Puzzle.LuaObjectScript.Reset()
        SandBowl_Puzzle.LuaObjectScript.SetQuestionGiven()
        SandBowl_Puzzle.LuaObjectScript.Enable()
      end)
    end
  end
  isAttemptingToSolve = false
end
function SetRiseState(state, jump)
  if state and elevatorSequenceStates[state] then
    nextElevatorState = state
    EnterNextRiseState(jump)
  end
end
function EnterNextRiseState(jump)
  local state = elevatorSequenceStates[nextElevatorState]
  if jump then
    GameObjects.rising_platform:JumpAnimToFrame(state.StartAnimFrame)
    GameObjects.rising_platform:PauseAnim()
    return
  end
  if state.StartAnimFrame > GameObjects.rising_platform.AnimFrame then
    elevatorSequenceStates.RiseToNextState.EndAnimFrame = state.StartAnimFrame
    state = elevatorSequenceStates.RiseToNextState
    currentElevatorState = "RiseToNextState"
    GameObjects.rising_platform:PlayAnimationToFrame(state.EndAnimFrame, state.PlayRate)
    GameObjects.rising_platform:OnAnimationDone(thisLevel, "Callback_RiseToNextState", {Force = true})
    return
  end
  currentElevatorState = nextElevatorState
  if state.EndAnimFrame > 0 and GameObjects.rising_platform.AnimFrame < state.EndAnimFrame then
    GameObjects.rising_platform:PlayAnimationToFrame(state.EndAnimFrame, state.PlayRate)
    if state.OnAnimDone then
      GameObjects.rising_platform:OnAnimationDone(thisLevel, state.OnAnimDone, {Force = true})
    end
  end
  if state.OnEnter then
    state.OnEnter()
  end
  if state.StoreCheckpoint then
    if string.match(currentElevatorState, "Encounter0") then
      StoreEncounterBookmark()
    else
      game.World.StoreCheckpoint({
        OverrideObject = GameObjects.CO_OnPlatform.Child
      })
    end
  end
end
function StoreEncounterBookmark()
  local bookmarkName = ""
  if currentElevatorState == "Encounter01" then
    bookmarkName = "14_Stonemason_053_MagicElevator_Encounter01"
  elseif currentElevatorState == "Encounter02" then
    bookmarkName = "14_Stonemason_054_MagicElevator_Encounter02"
  elseif currentElevatorState == "Encounter03" then
    bookmarkName = "14_Stonemason_055_MagicElevator_Encounter03"
  elseif currentElevatorState == "Encounter04" then
    bookmarkName = "14_Stonemason_056_MagicElevator_Encounter04"
  end
  local bookmarks = require("design.Bookmarks")
  local tableEntry = bookmarks["BOOKMARK_" .. bookmarkName]
  tableEntry.OverrideObject = GameObjects.CO_OnPlatform.Child
  game.World.StoreCheckpointAndBookmark(tableEntry)
end
function Callback_RiseToNextState()
  SetRiseState(nextElevatorState)
end
function FormElevator()
  timers.StartLevelTimer(7, function()
    LD.ShowFX(GameObjects.ElevatorImbueFinalFx)
  end)
  timers.StartLevelTimer(10.25, function()
    LD.ShowFX(GameObjects.ElevatorActivateFx)
  end)
  timers.StartLevelTimer(12.5, function()
    LD.ShowFX(WhirlFX_Full)
  end)
  timers.StartLevelTimer(16.5, function()
    LD.HideFX(WhirlFX_Full)
  end)
  timers.StartLevelTimer(16, function()
    LD.ShowFX(WhirlFX_Low)
    LD.ShowFX(WhirlFX_Low_Bowl)
  end)
  timers.StartLevelTimer(6.5, function()
    CSL.PlayShake("FSE_SHAKE_TREMORS_LEVEL_0", 2, 0.2, 0.3)
  end)
  timers.StartLevelTimer(6.5, function()
    CSL.PlayShake("FFB_GENERIC_RUMBLE_LOW", 2, 0.2, 0.3)
  end)
  timers.StartLevelTimer(6.5, function()
    AudioElevatorStart()
  end)
  timers.StartLevelTimer(10.3, function()
    CSL.PlayShake("FSE_shake_AxeThrow_Whoosh", 0.4, 0, 0.3)
  end)
  timers.StartLevelTimer(10.7, function()
    CSL.PlayShake("FSE_shake_AxeThrow_Whoosh", 0.4, 0, 0.3)
  end)
  timers.StartLevelTimer(8.5, function()
    CSL.PlayShake("FFB_GENERIC_RUMBLE_MEDIUM", 2.5, 0, 0.3)
  end)
  timers.StartLevelTimer(11.3, function()
    CSL.PlayShake("FSE_SWAY_CATCH", 1.14, 0.2, 0.3)
  end)
  timers.StartLevelTimer(11.3, function()
    CSL.PlayShake("FFB_THROW_HEAVY", 1.14, 0, 0.5)
  end)
  timers.StartLevelTimer(11.5, function()
    timers.StartLevelTimer(1, function()
      GameObjects.ScriptControlled_IC_Pit:HideCollision()
    end)
    SetRiseState("RiseToIdle")
    SetElevatorState("Idle")
    timers.StartLevelTimer(1.89, function()
      CSL.PlayShake("FSE_SHAKE_SWITCH_CLUNK", 1.14, 0, 0.8)
    end)
    timers.StartLevelTimer(1.89, function()
      CSL.PlayShake("FFB_GENERIC_RUMBLE_EXTREME", 0.8, 0, 2.3)
    end)
    ElevatorMusic()
  end)
end
function FormElevatorCompleted()
  timers.StartLevelTimer(1, function()
    game.Audio.PlayBanter("stn_MagicElevator_PlatformRestored")
  end)
  GameObjects.rising_platform:ClearAllAnimCallbacks()
  SetRiseState("Idle")
  GameObjects.ScriptControlled_IC_PitEdges:HideCollision()
  GameObjects.ScriptControlled_IC_TubeCollision:HideCollision()
  timers.StartLevelTimer(1, function()
    BOOKMARK_14_Stonemason_052_MagicElevator_PuzzleComplete()
  end)
  AudioElevatorActiveIdleLP()
end
function BOOKMARK_14_Stonemason_052_MagicElevator_PuzzleComplete()
  local bookmarks = require("design.Bookmarks")
  local tableEntry = bookmarks["BOOKMARK_" .. "14_Stonemason_052_MagicElevator_PuzzleComplete"]
  tableEntry.OverrideObject = GameObjects.CO_PuzzleComplete
  game.World.StoreCheckpointAndBookmark(tableEntry)
end
function RiseToEncounter01()
  SetRiseState("Encounter01")
end
function KratosOnPlatform()
  kratosOnPlatform = true
  GameObjects.ScriptControlled_IC_TubeCollision:ShowCollision()
  GameObjects.Elevator_IC_Coll:Show()
  SandBowl_Continuous.LuaObjectScript.SetRuneDiscovered()
  timers.StartLevelTimer(0.1, SandBowl_Continuous.LuaObjectScript.Enable())
end
function DisengageSon()
  SandBowl_Continuous.LuaObjectScript.SonAbortSandbowl()
  AudioElevatorLiftStop()
  AudioElevatorActiveIdleLP()
end
function ReachedTop()
  bElevatorRideCompleted = true
  StopShake_Degrading()
  AudioElevatorLiftStop()
  AudioElevatorActiveIdleLP()
  AudioElevatorDegradingStage3()
  ShakeElevator()
  local hammerFallWad = game.FindLevel("Stn400_HammerBase")
  if hammerFallWad then
    local hammerFallCineObj = hammerFallWad:FindSingleGameObject("Cine_HammerFall_Group")
    hammerFallCineObj:CallScript("SetupHammerForPush")
  end
  timers.StartLevelTimer(1.5, function()
    GameObjects.BowlFall_IC_Coll:Show()
    SetElevatorState("BowlCollapse")
    bowlLiquid_C1:Hide()
    bowlLiquid_C2:Hide()
    bowlLiquid_P1:Hide()
    bowlLiquid_P2:Hide()
    GiveFinaleHudHealthBar()
    FinalDisintegration()
    timers.StartLevelTimer(1, function()
      LD.HideFX(WhirlFX_Full)
    end)
    LD.ShowFX(WhirlFX_Low)
    LD.HideFX(WhirlFX_Low_Bowl)
  end)
end
function FinalDisintegration()
  t4 = 30
  animTimer_4 = timers.StartLevelTimer(t4, ElevatorDegrading4)
end
function Rise()
  timers.StartLevelTimer(1, function()
    LD.ShowFX(WhirlFX_Full)
  end)
  local riseRate = 2
  if bElevatorRideStarted == false then
    game.Audio.PlayBanter("stn_MagicElevator_OnPlatform")
    timers.StartLevelTimer(3, function()
      game.Audio.PlayBanter("stn_MagicElevator_FirstAscent")
    end)
    timers.StartLevelTimer(8, function()
      game.Audio.PlayBanter("stn_MagicElevator_HowIsThisPossible")
    end)
    timers.StartLevelTimer(1, function()
      SandBowlMarker:PlayAnimToEnd()
    end)
    timers.StartLevelTimer(3, function()
      AudioElevatorLiftLP()
      AudioElevatorActiveIdleLPStop()
      SetRiseState("RiseToDeathZone")
    end)
    PlayShake_Rising(3, 45)
    bElevatorRideStarted = true
  else
    PlatformDisintegrationStop()
    SetElevatorState("Idle")
    timers.StartLevelTimer(1.5, function()
      LD.HideFX(WhirlFX_Mid)
    end)
    timers.StartLevelTimer(1.5, function()
      LD.HideFX(WhirlFX_Low)
    end)
    if not EncountersComplete.Encounter01 then
      SetRiseState("Encounter01")
    elseif not EncountersComplete.Encounter02 then
      SetRiseState("Encounter02")
      PlayShake_Rising(0, 15)
      game.Audio.PlayBanter("stn_MagicElevator_SecondAscent")
    elseif not EncountersComplete.Encounter03 then
      SetRiseState("Encounter03")
      PlayShake_Rising(0, 10)
      game.Audio.PlayBanter("stn_MagicElevator_ThirdAscent")
    elseif not EncountersComplete.Encounter04 then
      SetRiseState("Encounter04")
      PlayShake_Rising(0, 18)
      game.Audio.PlayBanter("stn_MagicElevator_FourthAscent")
    end
    AudioElevatorLiftLP()
    AudioElevatorActiveIdleLPStop()
    PlatformHideCracks()
  end
end
function ShakeElevator()
  SetElevatorState("Shake")
  AudioElevatorLiftStop()
end
function ShakeElevatorStage_0()
  PlayShake_Degrading(0, 1.2)
  AudioElevatorLiftStop()
  CSL.PlayShake("FFB_GENERIC_RUMBLE_MEDIUM", 1.14, 0, 0.5)
end
function ShakeElevatorStage_1()
  PlayShake_Degrading(0, 2.8)
  SetElevatorState("State1")
  AudioElevatorLiftStop()
  CSL.PlayShake("FFB_GENERIC_RUMBLE_MEDIUM", 1.8, 0, 0.5)
end
function ShakeElevatorStage_2()
  PlayShake_Degrading(0, 4)
  SetElevatorState("State2")
  AudioElevatorLiftStop()
  CSL.PlayShake("FFB_GENERIC_RUMBLE_STRONG", 2, 0, 0.8)
end
function ShakeElevatorStage_3()
  SetElevatorState("State3")
  PlayShake_Degrading(0, 30)
  AudioElevatorDescend()
  CSL.PlayShake("FFB_GENERIC_RUMBLE_EXTREME", 3.6, 0, 1.5)
end
function EnableFallingDeathZone()
  FallingDeathVolume:Show()
end
function CollapseRunePlatform()
  if not bElevatorCollapsed then
    bElevatorCollapsed = true
    StopShake_Degrading()
    StopShake_ReachedTop()
    CSL.PlayShake("FFB_GIANT")
    timers.StartLevelTimer(0.2, function()
      CSL.PlayShake("FFB_GENERIC_RUMBLE_EXTREME", 1.8, 0.3, 0.8)
    end)
    GameObjects.TraversePathExit:HideTraversePath()
    GameObjects.DeathSweep:Show()
    GameObjects.DeathSweep:PlayAnimToEnd(0.25)
    GameObjects.rising_platform:PlayAnimToEnd(-10)
    SetElevatorState("Collapse")
    AudioElevatorImpactDrop()
    AudioElevatorShake()
    AudioElevatorStopDegradingStages()
    ElevatorMusicFail()
    RemoveHudHealthBar()
    timers.StartLevelTimer(3, function()
      LD.HideFX(WhirlFX_Low)
    end)
  end
end
function OnPlayerDeathFromFall()
  if bElevatorCollapsed and not playerIsDyingFromCollapse then
    uiCalls.UI_Event_Fade_To_Black(0.1)
    playerIsDyingFromCollapse = true
  end
end
function SetElevatorState(state)
  Elevator.LuaObjectScript.SetElevatorState(state)
end
local flippablesAndChildren = {}
function SetupFlippables()
  flippablesAndChildren = {
    {
      GameObjects.flippers_stn430_v1,
      GameObjects.WallTombRuneCube_v1
    },
    {
      GameObjects.flippers_stn430_v2,
      GameObjects.WallTombRuneCube_v2
    },
    {
      GameObjects.flippers_stn430_v3,
      GameObjects.WallTombRuneCube_v3
    },
    {
      GameObjects.flippers_stn430_v4,
      GameObjects.WallTombRuneCube_v4
    }
  }
  for _, v in ipairs(flippablesAndChildren) do
    if v[2].Parent ~= v[1]:FindSingleGOByName("ccwObject") then
      v[1]:FindSingleGOByName("ccwObject"):AddChild(v[2])
    end
  end
  GetRuneValues()
  SetupFlippableHitCallbacks()
end
function RuneCheck()
  if not puzzleSolved and not isAttemptingToSolve then
    local previousSequenceCorrect = bSequenceCorrect
    if not hasPlayed_stn_MagicElevator_SandBowl_answer then
      hasPlayed_stn_MagicElevator_SandBowl_answer = true
    end
    GetRuneValues()
    rune1Correct = runeObject1Value == rune1CorrectValue
    rune2Correct = runeObject2Value == rune2CorrectValue
    rune3Correct = runeObject3Value == rune3CorrectValue
    rune4Correct = runeObject4Value == rune4CorrectValue
    bSequenceCorrect = rune1Correct and rune2Correct and rune3Correct and rune4Correct
  end
end
function GetRuneValues()
  runeObject1Value = GameObjects.flippers_stn430_v1:FindSingleGOByName("FlipperModule").LuaObjectScript.GetCurrentState()
  runeObject2Value = GameObjects.flippers_stn430_v2:FindSingleGOByName("FlipperModule").LuaObjectScript.GetCurrentState()
  runeObject3Value = GameObjects.flippers_stn430_v3:FindSingleGOByName("FlipperModule").LuaObjectScript.GetCurrentState()
  runeObject4Value = GameObjects.flippers_stn430_v4:FindSingleGOByName("FlipperModule").LuaObjectScript.GetCurrentState()
end
function SonInteractedWithSandBowl()
  GameObjects.CA_Observe_Forward_SandBowl.LuaObjectScript.Disable()
end
function SonInteractWithSandBowlIncorrect()
  BtrSeasonsCallout()
  timers.StartLevelTimer(5, function()
    HintBanterCheck()
  end)
  timers.StartLevelTimer(7, function()
    GameObjects.SpinnerPanels:PlayAnimToEnd(20)
    GameObjects.SpinnerPanels:OnAnimDone(thisLevel, "StopSpinnerPanelOpen")
    GameObjects.IC_SpinnerCovers:Hide()
    GameObjects.flippers_stn430_v1:FindSingleGOByName("FlipperModule").LuaObjectScript.EnableRotation()
    GameObjects.flippers_stn430_v2:FindSingleGOByName("FlipperModule").LuaObjectScript.EnableRotation()
    GameObjects.flippers_stn430_v3:FindSingleGOByName("FlipperModule").LuaObjectScript.EnableRotation()
    GameObjects.flippers_stn430_v4:FindSingleGOByName("FlipperModule").LuaObjectScript.EnableRotation()
  end)
end
function BtrSeasonsCallout()
  currentGuessInput = {
    runeObject1Value,
    runeObject2Value,
    runeObject3Value,
    runeObject4Value
  }
  local s1 = currentGuessInput[1]
  local s2 = currentGuessInput[2]
  local s3 = currentGuessInput[3]
  local s4 = currentGuessInput[4]
  timers.StartLevelTimer(0, function()
    if s1 == 1 then
      game.Audio.PlayBanter("stn_MagicElevator_Spring")
    elseif s1 == 2 then
      game.Audio.PlayBanter("stn_MagicElevator_Winter")
    elseif s1 == 3 then
      game.Audio.PlayBanter("stn_MagicElevator_Autumn")
    end
  end)
  timers.StartLevelTimer(1, function()
    if s2 == 1 then
      game.Audio.PlayBanter("stn_MagicElevator_Autumn")
    elseif s2 == 2 then
      game.Audio.PlayBanter("stn_MagicElevator_Spring")
    elseif s2 == 3 then
      game.Audio.PlayBanter("stn_MagicElevator_Summer")
    end
  end)
  timers.StartLevelTimer(2, function()
    if s3 == 1 then
      game.Audio.PlayBanter("stn_MagicElevator_Winter")
    elseif s3 == 2 then
      game.Audio.PlayBanter("stn_MagicElevator_Spring")
    elseif s3 == 3 then
      game.Audio.PlayBanter("stn_MagicElevator_Summer")
    end
  end)
  timers.StartLevelTimer(3, function()
    if s4 == 1 then
      game.Audio.PlayBanter("stn_MagicElevator_Summer")
    elseif s4 == 2 then
      game.Audio.PlayBanter("stn_MagicElevator_Winter")
    elseif s4 == 3 then
      game.Audio.PlayBanter("stn_MagicElevator_Autumn")
    end
  end)
end
function HintBanterCheck()
  currentGuessInput = {
    runeObject1Value,
    runeObject2Value,
    runeObject3Value,
    runeObject4Value
  }
  if currentGuessInput[1] == 2 and currentGuessInput[2] == 2 and currentGuessInput[3] == 3 and currentGuessInput[4] == 3 then
    timers.StartLevelTimer(5.5, function()
      game.Audio.PlayBanter("stn_MagicElevator_Hint1")
    end)
  else
    guessCount = guessCount + 1
    timers.StartLevelTimer(3, function()
      GiveHint()
    end)
  end
end
function GiveHint()
  if guessCount == 1 then
    game.Audio.PlayBanter("stn_MagicElevator_Hint1a_Wrong")
  elseif guessCount == 2 then
    game.Audio.PlayBanter("stn_MagicElevator_Hint2_Wrong")
  elseif guessCount == 3 then
    game.Audio.PlayBanter("stn_MagicElevator_Hint2")
  elseif guessCount == 4 then
    game.Audio.PlayBanter("stn_MagicElevator_Hint3")
  elseif guessCount == 5 then
    game.Audio.PlayBanter("stn_MagicElevator_Hint3_Wrong")
  elseif guessCount == 6 then
    game.Audio.PlayBanter("stn_MagicElevator_Hint4")
  elseif guessCount == 7 then
    game.Audio.PlayBanter("stn_MagicElevator_Hint4_Wrong")
  elseif 7 < guessCount then
    game.Audio.PlayBanter("stn_MagicElevator_FinalHintRepeat")
  end
end
function SonInteractWithSandBowlCorrect()
  game.Audio.PlayBanter("stn_MagicElevator_Solved")
  timers.StartLevelTimer(0.5, function()
    GameObjects.RuneLight_1:Show()
    GameObjects.RuneBreakFx_1:Show()
    AudioRuneSolved(4)
  end)
  timers.StartLevelTimer(1.2, function()
    GameObjects.RuneLight_2:Show()
    GameObjects.RuneBreakFx_2:Show()
    AudioRuneSolved(3)
  end)
  timers.StartLevelTimer(2, function()
    GameObjects.RuneLight_3:Show()
    GameObjects.RuneBreakFx_3:Show()
    AudioRuneSolved(2)
  end)
  timers.StartLevelTimer(2.8, function()
    GameObjects.RuneLight_4:Show()
    GameObjects.RuneBreakFx_4:Show()
    AudioRuneSolved(1)
  end)
  timers.StartLevelTimer(5.15, function()
    GameObjects.Rune_1:PlayAnimToEnd(3)
    GameObjects.RuneBreakFx_C1:Show()
    AudioRuneSolved(2)
    AudioRuneSolved(3)
  end)
  timers.StartLevelTimer(6.15, function()
    GameObjects.Rune_2:PlayAnimToEnd(3)
    GameObjects.RuneBreakFx_C2:Show()
    AudioRuneSolved(2)
    AudioRuneSolved(3)
  end)
  timers.StartLevelTimer(7.15, function()
    GameObjects.Rune_3:PlayAnimToEnd(3)
    GameObjects.RuneBreakFx_C3:Show()
    AudioRuneSolved(2)
    AudioRuneSolved(3)
  end)
  timers.StartLevelTimer(8.15, function()
    GameObjects.Rune_4:PlayAnimToEnd(3)
    GameObjects.RuneBreakFx_C4:Show()
    AudioRuneSolved(2)
    AudioRuneSolved(3)
  end)
  timers.StartLevelTimer(4.5, CameraLookAt_FrameAroundRuneBowl)
  timers.StartLevelTimer(10.5, FormElevator)
end
function Rumble_LeftRocks()
  timers.StartLevelTimer(0.41, function()
    CSL.PlayShake("FSE_SHAKE_SLAM_MEDIUM", 2, 0.2, 0.8)
  end)
  timers.StartLevelTimer(0.41, function()
    CSL.PlayShake("FFB_GENERIC_RUMBLE_MEDIUM", 2, 0.2, 0.8)
  end)
end
function Rumble_RightRocks()
  timers.StartLevelTimer(0.59, function()
    CSL.PlayShake("FSE_SHAKE_SLAM_MEDIUM", 2, 0, 0.8)
  end)
  timers.StartLevelTimer(0.59, function()
    CSL.PlayShake("FFB_GENERIC_RUMBLE_MEDIUM", 2, 0, 0.8)
  end)
end
function Rumble_MiddleRocks()
  timers.StartLevelTimer(0.84, function()
    CSL.PlayShake("FFB_SLAM", 1.8, 0, 0.69)
  end)
end
function VibrateCrystalLeft()
  GameObjects.BifrostVibrate_Fractured_L1.LuaObjectScript.Deactivate()
  local fanaticL = LD.FindSingleAIByMarker("FanaticL")
  if fanaticL and not fanaticL:IsDead() then
    fanaticL:ForceMove("BRA_Stn430PlatformDeathL")
  end
  if vibrateCount == 0 then
    Rumble_LeftRocks()
    vibrateCount = 1
    timers.StartLevelTimer(0.15, function()
      GameObjects.L_pillar_all:PlayAnimToEnd()
      AudioPlatformBreak(2)
    end)
  elseif vibrateCount == 1 then
    vibrateCount = 2
    StimDisableTurret()
    Rumble_LeftRocks()
    Rumble_MiddleRocks()
    timers.StartLevelTimer(0.15, function()
      GameObjects.L_pillar_all:PlayAnimToEnd()
      AudioPlatformBreak(2)
    end)
    timers.StartLevelTimer(0.7, function()
      GameObjects.M_pillar_all:PlayAnimToEnd()
      AudioPlatformBreak(1)
    end)
    timers.StartLevelTimer(2.5, function()
      GameObjects.TraversePathExit:ShowTraversePath()
      GameObjects.EZ_BTR_PlayJump:ShowEntityVolume()
    end)
    local fanatic = LD.FindSingleAIByMarker("FanaticM")
    if fanatic and not fanatic:IsDead() then
      fanatic:ForceMove("BRA_Stn430PlatformDeathM")
    end
    fanatic = LD.FindSingleAIByMarker("FanaticL")
    if fanatic and not fanatic:IsDead() then
      fanatic:ForceMove("BRA_Stn430PlatformDeathL")
    end
    fanatic = LD.FindSingleAIByMarker("FanaticR")
    if fanatic and not fanatic:IsDead() then
      fanatic:ForceMove("BRA_Stn430PlatformDeathR")
    end
    timers.StartLevelTimer(0.5, function()
      KillAllDraugr()
      son:CallScript("LuaHook_SetNextPostCombatTimerLength", 0.1)
    end)
    Encounter04:Stop()
    Encounter04:SetComplete()
  end
end
function VibrateCrystalRight()
  GameObjects.BifrostVibrate_Fractured_R1.LuaObjectScript.Deactivate()
  local fanaticR = LD.FindSingleAIByMarker("FanaticR")
  if fanaticR and not fanaticR:IsDead() then
    fanaticR:ForceMove("BRA_Stn430PlatformDeathR")
  end
  if vibrateCount == 0 then
    Rumble_RightRocks()
    vibrateCount = 1
    timers.StartLevelTimer(0.15, function()
      GameObjects.R_pillar_all:PlayAnimToEnd()
      AudioPlatformBreak(3)
    end)
  elseif vibrateCount == 1 then
    vibrateCount = 2
    StimDisableTurret()
    Rumble_RightRocks()
    Rumble_MiddleRocks()
    timers.StartLevelTimer(0.15, function()
      GameObjects.R_pillar_all:PlayAnimToEnd()
      AudioPlatformBreak(3)
    end)
    timers.StartLevelTimer(0.7, function()
      GameObjects.M_pillar_all:PlayAnimToEnd()
      AudioPlatformBreak(1)
    end)
    timers.StartLevelTimer(2.5, function()
      GameObjects.TraversePathExit:ShowTraversePath()
      GameObjects.EZ_BTR_PlayJump:ShowEntityVolume()
    end)
    local fanatic = LD.FindSingleAIByMarker("FanaticM")
    if fanatic and not fanatic:IsDead() then
      fanatic:ForceMove("BRA_Stn430PlatformDeathM")
    end
    fanatic = LD.FindSingleAIByMarker("FanaticL")
    if fanatic and not fanatic:IsDead() then
      fanatic:ForceMove("BRA_Stn430PlatformDeathL")
    end
    fanatic = LD.FindSingleAIByMarker("FanaticR")
    if fanatic and not fanatic:IsDead() then
      fanatic:ForceMove("BRA_Stn430PlatformDeathR")
    end
    timers.StartLevelTimer(0.5, function()
      KillAllDraugr()
      son:CallScript("LuaHook_SetNextPostCombatTimerLength", 0.1)
    end)
    Encounter04:Stop()
    Encounter04:SetComplete()
  end
end
function BanterKratosJump()
  ElevatorMusicOff()
end
function BTR_PlayJump()
  game.Audio.PlayBanter("stn_MagicElevator_Jump")
end
function ReenableResStone()
  player:CallScript("LuaHook_DisableRevive", false)
  game.AI.FindSon():CallScript("ClearBehaviorContext")
end
function DisableCrackClimbToHammer()
  GameObjects.TraversePath2:HideTraversePath()
end
function Breakout01()
  local brk01 = GameObjects.tomb_door1.Child:GetBreakable()
  if brk01.Broken == false then
    brk01:Break()
  end
end
function Breakout02()
  local brk02 = GameObjects.tomb_door2.Child:GetBreakable()
  if brk02.Broken == false then
    brk02:Break()
  end
end
function Breakout03()
  local brk03 = GameObjects.tomb_door3.Child:GetBreakable()
  if brk03.Broken == false then
    brk03:Break()
  end
end
function Breakout201()
  local brk = GameObjects.tomb_door201
  brk:PlayAnimToEnd()
end
function Breakout202()
  local brk = GameObjects.tomb_door202
  brk:PlayAnimToEnd()
end
function Breakout203()
  local brk = GameObjects.tomb_door203
  brk:PlayAnimToEnd()
end
function Breakout204()
  local brk = GameObjects.tomb_door204
  brk:PlayAnimToEnd()
end
function HideCrack1()
  crack1:Hide()
end
function HideCrack2()
  crack2:Hide()
end
function HideCrack3()
  crack3:Hide()
end
function HideCrack4()
  crack4:Hide()
end
function HideCrack5()
  crack5:Hide()
end
function SetDisintegrationPhaseTimes(mT1, mT2, mT3, mT4)
  PlatformDisintegrationStop()
  crack1:Show()
  t1, t2, t3, t4 = mT1, mT2, mT3, mT4
  ElevatorDegrading0()
  animTimer_1 = timers.StartLevelTimer(mT1, ElevatorDegrading1)
  animTimer_2 = timers.StartLevelTimer(mT2, ElevatorDegrading2)
  animTimer_3 = timers.StartLevelTimer(mT3, ElevatorDegrading3)
  animTimer_4 = timers.StartLevelTimer(mT4, ElevatorDegrading4)
end
function PlatformDisintegrationStart()
  animTimer_0:Restart()
  animTimer_1:Restart()
  animTimer_2:Restart()
  animTimer_3:Restart()
  animTimer_4:Restart()
end
function PlatformDisintegrationStop()
  animTimer_0:Reset()
  animTimer_1:Reset()
  animTimer_2:Reset()
  animTimer_3:Reset()
  animTimer_4:Reset()
  AudioElevatorStopDegradingStages()
end
function PlatformHideCracks()
  animTimerCrack_1:Restart()
  animTimerCrack_2:Restart()
  animTimerCrack_3:Restart()
  animTimerCrack_4:Restart()
  animTimerCrack_5:Restart()
end
function ElevatorDegrading0()
  ShakeElevatorStage_0()
  AudioElevatorShake()
  AudioElevatorDegradingStage0()
end
function ElevatorDegrading1()
  crack1:Show()
  ShakeElevatorStage_1()
  AudioElevatorShake()
  AudioElevatorDegradingStage1()
end
function ElevatorDegrading2()
  ShakeElevatorStage_2()
  crack2:Show()
  AudioElevatorShake()
  AudioElevatorDegradingStage2()
end
function ElevatorDegrading3()
  ShakeElevatorStage_3()
  AudioElevatorShake()
  AudioElevatorDegradingStage3()
  crack3:Show()
end
function ElevatorDegrading4()
  PlayShake_FallingApart(0, 1.5)
  crack4:Show()
  PlatformCollision:HideCollision()
  CollapseRunePlatform()
end
function RoomComplete()
  roomComplete = true
  LD.CompleteQuest("Quest_StoneMason_Objective350")
  RemoveHudHealthBar()
end
function GiveHudHealthBar()
  uiCalls.EnableMechanicMeter("METER_StoneMasonElevator")
  player:PickupAcquire("StonemasonElevatorHealthBar")
  ecTimer = StartLevelTimer(ec_TimeRequirement)
  warnTime_1 = timers.StartLevelTimer(WarnVal_1, function()
    game.Audio.PlayBanter("stn_MagicElevator_LiftUp1")
    LD.ShowFX(WhirlFX_Mid)
    LD.HideFX(WhirlFX_Full)
  end)
  warnTime_2 = timers.StartLevelTimer(WarnVal_2, function()
    game.Audio.PlayBanter("stn_MagicElevator_LiftUp2")
    LD.ShowFX(WhirlFX_Low)
    LD.ShowFX(WhirlFX_Low_Bowl)
    LD.HideFX(WhirlFX_Mid)
  end)
  ResStoneLockTimer = timers.StartLevelTimer(ResStoneLockout, function()
    player:CallScript("LuaHook_DisableRevive", true)
  end)
  timers.StartLevelTimer(1, function()
    player:MeterSetValue("METER_StoneMasonElevator", ec_TimeRequirement)
    Time_Attack_Started = true
    ecTimer:Start()
  end)
end
function GiveFinaleHudHealthBar()
  player:PickupAcquire("StonemasonElevatorHealthBar")
  player:PickupActivate("StonemasonElevatorHealthBar")
  bFinaleTimer = true
  ec_TimeRequirement = 30
  ecTimer = StartLevelTimer(30)
  timers.StartLevelTimer(1, function()
    player:MeterSetValue("METER_StoneMasonElevator", ec_TimeRequirement)
    Time_Attack_Started = true
    ecTimer:Start()
  end)
end
function RemoveHudHealthBar()
  uiCalls.DisableMechanicMeter()
  if player:PickupIsAcquired("StonemasonElevatorHealthBar") then
    player:PickupRelinquish("StonemasonElevatorHealthBar")
    Time_Attack_Started = false
    ecTimer:Stop()
    ecTimer:Reset()
    if not bFinaleTimer then
      warnTime_1:Stop()
      warnTime_1:Reset()
      warnTime_2:Stop()
      warnTime_2:Reset()
      ResStoneLockTimer:Stop()
      ResStoneLockTimer:Reset()
    end
  end
end
function SetupEncounters()
  if not EncountersComplete then
    EncountersComplete = {
      Encounter01 = false,
      Encounter02 = false,
      Encounter03 = false,
      Encounter04 = false
    }
  end
  if not EncountersComplete.Encounter01 then
    Encounter01 = EC.NewEncounter(thisLevel, "Elevator Encounter 1, Draugr Shield")
    Encounter01:AddWave({
      requiredWaveCompletion = 50,
      prioritizeOnScreenSpawners = true,
      enableSpawnersOnWaveComplete = false,
      powerLevel = 2,
      {
        markerID = "Draugr",
        spawners = "Draugr_S_N_SFA",
        spawnLocators = "W1_Loc_",
        useSpawnLocatorsOnly = true,
        disableSpawnerPostSpawn = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 1.4
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_S_N_SFA",
        spawnLocators = "W1_Loc_",
        useSpawnLocatorsOnly = true,
        disableSpawnerPostSpawn = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 2.7
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_S_N_SFA",
        spawnLocators = "W1_Loc_",
        useSpawnLocatorsOnly = true,
        disableSpawnerPostSpawn = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 3
      }
    })
    Encounter01:AddWave({
      prioritizeOnScreenSpawners = true,
      requireCompletionOfAllPriorWaves = true,
      powerLevel = 3,
      {
        markerID = "Draugr",
        spawners = "Draugr_N_SFA",
        spawnLocators = "W1_Loc_",
        useSpawnLocatorsOnly = true,
        disableSpawnerPostSpawn = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 1.2
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_N_SFA",
        spawnLocators = "W1_Loc_",
        useSpawnLocatorsOnly = true,
        disableSpawnerPostSpawn = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 2.5
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_N_SFA",
        spawnLocators = "W1_Loc_",
        useSpawnLocatorsOnly = true,
        disableSpawnerPostSpawn = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 2.1
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_N_SFA",
        spawnLocators = "W1_Loc_*",
        useSpawnLocatorsOnly = true,
        disableSpawnerPostSpawn = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 3.2
      }
    })
    Encounter01:AddWave({
      prioritizeOnScreenSpawners = true,
      {
        markerID = "Draugr",
        spawners = "SH_Draugr_N_SFG",
        spawnLocators = "Elevator_Loc_",
        useSpawnLocatorsOnly = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 1.2,
        powerLevel = 3
      },
      {
        markerID = "Draugr",
        spawners = "SH_Draugr_N_SFG",
        spawnLocators = "Elevator_Loc_",
        useSpawnLocatorsOnly = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 8.2,
        powerLevel = 3
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_S_N_SFG",
        spawnLocators = "Elevator_Loc_*",
        useSpawnLocatorsOnly = true,
        maxActive = 1,
        totalSpawns = 2,
        spawnCooldown = 2.1,
        powerLevel = 2
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_S_N_SFG",
        spawnLocators = "Elevator_Loc_*",
        useSpawnLocatorsOnly = true,
        maxActive = 1,
        totalSpawns = 2,
        spawnCooldown = 3.8,
        powerLevel = 3
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_S_N_SFG",
        spawnLocators = "Elevator_Loc_*",
        useSpawnLocatorsOnly = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 5.1,
        powerLevel = 3
      }
    })
    Encounter01:OnStart(function()
      game.Compass.SetDesignerForcedHide(true)
      GiveHudHealthBar()
    end)
    Encounter01:OnEnemySpawn(function(enemy)
      enemy:ForceMove("BRA_SetDropHealthFlag_On")
    end, {wave = 3, element = 1})
    Encounter01:OnEnemySpawn(function(enemy)
      enemy:ForceMove("BRA_SetDropHealthFlag_On")
    end, {wave = 3, element = 2})
    Encounter01:OnEnemySpawn(function(enemy)
      BreakNearestWall(enemy, "L1_WallTombCover")
    end)
    Encounter01:OnComplete(function()
      EncountersComplete.Encounter01 = true
      FirstWaveCompleted()
      RemoveHudHealthBar()
      PlatformDisintegrationStop()
    end)
  end
  if not EncountersComplete.Encounter02 then
    Encounter02 = EC.NewEncounter(thisLevel, "Elevator Encounter 2, Draugr Legs")
    Encounter02:AddWave({
      requiredWaveCompletion = 50,
      prioritizeOnScreenSpawners = true,
      {
        markerID = "Draugr",
        spawners = "Draugr_L_SFG",
        spawnLocators = "Elevator_Loc_",
        useSpawnLocatorsOnly = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 0.1,
        powerLevel = 3
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_L_SFG",
        spawnLocators = "Elevator_Loc_",
        useSpawnLocatorsOnly = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 0.8,
        powerLevel = 3
      }
    })
    Encounter02:AddWave({
      {
        markerID = "Draugr",
        spawners = "H_Draugr_N_SFG",
        spawnLocators = "Elevator_Loc_",
        useSpawnLocatorsOnly = true,
        maxActive = 1,
        totalSpawns = 2,
        initialSpawnCooldown = 0.2,
        initialSpawnAmount = 1,
        spawnCooldown = 2,
        powerLevel = 3
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_L_SFG",
        spawnLocators = "Elevator_Loc_",
        useSpawnLocatorsOnly = true,
        maxActive = 2,
        totalSpawns = 3,
        spawnCooldown = 2.8,
        powerLevel = 3
      },
      {
        markerID = "Draugr",
        spawners = "Draugr_PL_SFG",
        spawnLocators = "Elevator_Loc_",
        useSpawnLocatorsOnly = true,
        maxActive = 1,
        totalSpawns = 2,
        spawnCooldown = 5,
        powerLevel = 3
      }
    })
    Encounter02:AddWave({
      requireCompletionOfAllPriorWaves = true,
      {
        markerID = "Draugr",
        spawners = "Draugr_L_SFG",
        spawnLocators = "Elevator_Loc_",
        useSpawnLocatorsOnly = true,
        disableSpawnerPostSpawn = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 0.1,
        powerLevel = 4
      }
    })
    Encounter02:OnStart(function()
      GiveHudHealthBar()
    end)
    Encounter02:OnEnemySpawn(function()
      Encounter02:StartWave(3)
    end, {count = 3, wave = 2})
    Encounter02:OnEnemySpawn(function(enemy)
      enemy:ForceMove("BRA_SetDropHealthFlag_On")
    end)
    Encounter02:OnComplete(function()
      EncountersComplete.Encounter02 = true
      SecondWaveCompleted()
      RemoveHudHealthBar()
      PlatformDisintegrationStop()
    end)
  end
  if not EncountersComplete.Encounter03 then
    Encounter03 = EC.NewEncounter(thisLevel, "Elevator Encounter 3, Witch")
    Encounter03:AddWave({
      {
        markerID = "Draugr",
        spawners = "Flyer_S_SABU",
        spawnLocators = "Elevator_Loc_*",
        useSpawnLocatorsOnly = true,
        maxActive = 3,
        totalSpawns = 6,
        spawnCooldown = 1.2,
        powerLevel = 3
      }
    })
    Encounter03:AddWave({
      timeBeforeNextWave = 10,
      prioritizeOnScreenSpawners = true,
      enableSpawnersOnWaveComplete = false,
      {
        markerID = "Draugr",
        spawners = "Draugr_B_SFA",
        spawnLocators = "W2_Loc_*",
        disableSpawnerPostSpawn = true,
        useSpawnLocatorsOnly = true,
        maxActive = 2,
        totalSpawns = 2,
        spawnCooldown = 0.8,
        powerLevel = 3
      }
    })
    Encounter03:AddWave({
      {
        markerID = "Draugr",
        spawners = "Draugr_S_N_SFG",
        spawnLocators = "Elevator_Loc_*",
        useSpawnLocatorsOnly = true,
        maxActive = 4,
        totalSpawns = 9,
        spawnCooldown = 1.2,
        powerLevel = 2
      }
    })
    Encounter03:AddWave({
      requireCompletionOfAllPriorWaves = true,
      {
        markerID = "Draugr",
        spawners = "Witch_S_SFG",
        spawnLocators = "Elevator_Loc_",
        useSpawnLocatorsOnly = true,
        maxActive = 1,
        totalSpawns = 1,
        spawnCooldown = 0.85,
        powerLevel = 4
      },
      {
        markerID = "Draugr",
        spawners = "Flyer_S_SABU",
        spawnLocators = "Elevator_Loc_*",
        useSpawnLocatorsOnly = true,
        initialSpawnAmount = 1,
        initialSpawnCooldown = 5.1,
        maxActive = 2,
        totalSpawns = 4,
        spawnCooldown = 0.525,
        powerLevel = 3
      }
    })
    Encounter03:OnStart(function()
      GiveHudHealthBar()
    end)
    Encounter03:OnEnemySpawn(function(enemy)
      BreakNearestWall(enemy, "L2_WallTombCover")
    end, {wave = 2})
    Encounter03:OnEnemyDeath(function()
      Encounter03:StartWave(4)
    end, {wave = 3, count = 4})
    Encounter03:OnCombatStart(function()
      game.Audio.StartCheckpointedMusic("SND_MX_STN_hammer_climb_3")
    end)
    Encounter03:OnComplete(function()
      EncountersComplete.Encounter03 = true
      ThirdWaveCompleted()
      RemoveHudHealthBar()
      PlatformDisintegrationStop()
    end)
  end
  if not EncountersComplete.Encounter04 then
    if not bPlatformCollapsed then
      GameObjects.IC_Fanatics:ShowCollision()
      Encounter04 = EC.NewEncounter(thisLevel, "Encounter04")
      Encounter04:AddWave({
        powerLevel = 2,
        {
          spawners = "EnemySpawnerTopTurret02L",
          spawnLocators = "W4_Loc_02*",
          useSpawnLocatorsOnly = true,
          markerID = "FanaticL",
          maxActive = 1,
          totalSpawns = 1,
          spawnCooldown = 0.8
        },
        {
          spawners = "EnemySpawnerTopTurret02R",
          spawnLocators = "W4_Loc_01*",
          useSpawnLocatorsOnly = true,
          markerID = "FanaticR",
          maxActive = 1,
          totalSpawns = 1,
          spawnCooldown = 1.3
        }
      })
    else
      Encounter04 = EC.NewEncounter(thisLevel, "Encounter04")
      Encounter04:AddWave({
        {
          spawners = "EnemySpawnerTopTurret02L",
          maxActive = 1,
          totalSpawns = 1,
          spawnCooldown = 0.8,
          powerLevel = 2
        },
        {
          spawners = "EnemySpawnerTopTurret02R",
          maxActive = 1,
          totalSpawns = 1,
          spawnCooldown = 1.3,
          powerLevel = 2
        }
      })
    end
    Encounter04:OnComplete(function()
      GameObjects.IC_Fanatics:HideCollision()
      EncountersComplete.Encounter04 = true
      game.Compass.SetDesignerForcedHide(false)
    end)
    Encounter04:OnComplete(function()
      LD.UnlockBestiaryEntry_EndOfEncounter("Bestiary_Unlock_Revenant_Spawner")
    end)
    Encounter04:OnComplete(function()
      son:CallScript("LuaHook_SetNextPostCombatTimerLength", 0.15)
    end)
  end
end
function KillAllDraugr()
  local draugrs = LD.FindAllAIByMarker("Draugr")
  for _, d in pairs(draugrs) do
    if not d:IsDead() then
      d:ForceMove(GetRandomDraugrDeathMove())
    end
  end
end
function GetRandomDraugrDeathMove()
  local t = {
    "BRA_Stn430PlatformDeathL",
    "BRA_Stn430PlatformDeathM",
    "BRA_Stn430PlatformDeathR"
  }
  return t[math.random(1, #t)]
end
function FirstWave()
  Encounter01:Start()
  timers.StartLevelTimer(2.5, function()
    player:CallScript("LuaHook_DisableRevive", false)
    DisengageSon()
    ShakeElevator()
    AudioElevatorLiftStop()
    SetDisintegrationPhaseTimes(45, 60, 75, 96)
    game.Audio.PlayBanter("stn_MagicElevator_FirstStop")
  end)
end
function SecondWave()
  Encounter02:Start()
  DisengageSon()
  timers.StartLevelTimer(2.5, function()
    player:CallScript("LuaHook_DisableRevive", false)
    DisengageSon()
    ShakeElevator()
    AudioElevatorLiftStop()
    SetDisintegrationPhaseTimes(45, 60, 75, 96)
    game.Audio.PlayBanter("stn_MagicElevator_SecondStop")
  end)
end
function ThirdWave()
  Encounter03:Start()
  timers.StartLevelTimer(2.5, function()
    player:CallScript("LuaHook_DisableRevive", false)
    KillAllDraugr()
    DisengageSon()
    ShakeElevator()
    AudioElevatorLiftStop()
    SetDisintegrationPhaseTimes(45, 60, 75, 96)
    game.Audio.PlayBanter("stn_MagicElevator_ThirdStop")
  end)
end
function FirstWaveCompleted()
  EnableSonRuneRead()
  StopShake_Degrading()
  if bElevatorCollapsed == false then
    game.Audio.PlayBanter("stn_MagicElevator_FightDone1")
  end
end
function SecondWaveCompleted()
  EnableSonRuneRead()
  StopShake_Degrading()
  if bElevatorCollapsed == false then
    game.Audio.PlayBanter("stn_MagicElevator_FightDone2")
  end
end
function ThirdWaveCompleted()
  EnableSonRuneRead()
  StopShake_Degrading()
  if bElevatorCollapsed == false then
    game.Audio.PlayBanter("stn_MagicElevator_FightDone3")
  end
end
function FourthWave()
  SonCombat_Off()
  game.Audio.SetBanterFact("CreatureSpawnCooldown", true, 30)
  Encounter04:Start()
  player:CallScript("LuaHook_DisableRevive", true)
  timers.StartLevelTimer(1, function()
    GameObjects.icicle_rm_02_break.Child:PlayAnimToEnd()
    GameObjects.CrystalBlocker_Right:HideCollision()
  end)
  timers.StartLevelTimer(1.5, function()
    GameObjects.icicle_rm_02_break1.Child:PlayAnimToEnd()
    GameObjects.CrystalBlocker_Left:HideCollision()
  end)
  timers.StartLevelTimer(6.75, function()
    SandBowl_Continuous.LuaObjectScript.SonAbortSandbowl()
    PlayShake_ReachedTop()
  end)
  timers.StartLevelTimer(9, function()
    EEE_BowlCollapse.LuaObjectScript.Trigger()
  end)
  timers.StartLevelTimer(10, function()
    game.Audio.PlayBanter("stn_MagicElevator_HelWights")
  end)
  timers.StartLevelTimer(12, function()
    Top_CA_TurretCO.LuaObjectScript.Enable()
  end)
  timers.StartLevelTimer(11.5, function()
    SonCombat_On()
  end)
  timers.StartLevelTimer(1, function()
    CSL.PlayDefaultShake("ShakeRumbleSmall", 0.3, 0, 0)
  end)
  timers.StartLevelTimer(1.6, function()
    CSL.PlayDefaultShake("ShakeRumbleSmall", 0.3, 0, 0)
  end)
  timers.StartLevelTimer(1.9, function()
    CSL.PlayDefaultShake("CrumbleLower", 1, 0, 0.2)
  end)
  timers.StartLevelTimer(7, function()
    CSL.PlayShake("FSE_SWAY_CATCH", 1.14, 0.2, 0.3)
  end)
  timers.StartLevelTimer(7, function()
    CSL.PlayShake("FFB_THROW_HEAVY", 1.14, 0, 0.5)
  end)
  timers.StartLevelTimer(8.5, function()
    CSL.PlayDefaultShake("ShakeRumbleGiant", 2.5, 0, 0)
  end)
  timers.StartLevelTimer(9, function()
    CSL.PlayShake("FSE_SWAY_CATCH", 1.14, 0.2, 0.3)
  end)
  timers.StartLevelTimer(9.15, function()
    SetDriversForWarpAndPlayKratos()
  end)
  timers.StartLevelTimer(9, function()
    CSL.PlayShake("FFB_THROW_HEAVY", 1.14, 0, 0.5)
  end)
  timers.StartLevelTimer(11.37, function()
    CSL.PlayDefaultShake("ShakeRumbleGiant", 1.5, 0, 1.2)
  end)
  timers.StartLevelTimer(11, function()
    game.Audio.PlayBanter("stn_MagicElevator_BowlDrops")
  end)
  SetRiseState("RiseToTop")
end
function SonCombat_Off()
  Stn430NonSonCombatState = {
    AvailableForSync = true,
    AvailableForBanter = true,
    AvailableInLevel = true,
    AvailableForCombat = false
  }
  son:SetNewAvailabilityRequest("LevelDesignScript", Stn430NonSonCombatState)
end
function SonCombat_On()
  son:RemoveAvailabilityRequest("SonInteraction")
  son:RemoveAvailabilityRequest("LevelDesignScript", Stn430NonSonCombatState)
end
function StimDisableTurret()
  Top_CA_TurretCO.LuaObjectScript:Disable()
  timers.StartLevelTimer(1, function()
    GameObjects.EEE_Stn430_SecondImpact.LuaObjectScript.Trigger()
  end)
end
function CA_IdleBehavior_Stn430_Exit_CB()
  print("placeholder func")
end
function Start_End_Timer()
  local startDelay = 5
  ec_TimeRequirement = 30
  LD.CallFunctionAfterDelay(function()
    Time_Attack_Started = true
    ecTimer:Start()
  end, startDelay)
  local seconds = ec_TimeRequirement % 60
  local minutes = ec_TimeRequirement / 60
  local Time_Text = string.format("%02d : %02d", minutes, seconds)
  ecTimer = StartLevelTimer(30)
end
local bDebugEnabled = true
local kraElevatorStumble_Start_Fwd, kraElevatorStumble_Start_Position
function SetDriversForWarpAndPlayKratos()
  local rotationDriver = player:GetAnimDriver("harpoonReactRotationDriver")
  local translationDriver = player:GetAnimDriver("harpoonReactTranslationDriver")
  local elevatorStumbleWarpPoint
  local bestPosition = DetermineBestElevatorWarpPosition()
  if bestPosition ~= nil then
    elevatorStumbleWarpPoint = bestPosition
    kraElevatorStumble_Start_Fwd = elevatorStumbleWarpPoint:GetWorldForward()
    kraElevatorStumble_Start_Position = elevatorStumbleWarpPoint:GetWorldPosition()
    if rotationDriver ~= nil and translationDriver ~= nil then
      rotationDriver.ValueVec = kraElevatorStumble_Start_Fwd
      translationDriver.ValueVec = kraElevatorStumble_Start_Position
      player:TriggerMoveEvent("LE_StoneMason_ElevatorImpact_01")
    end
  end
end
function DetermineBestElevatorWarpPosition()
  local playerPosition
  if playerPosition == nil then
    playerPosition = player.WorldPosition
  end
  if game.World.IsInsideCameraZone(playerPosition, "CamZone_ElevatorWarp_010") then
    return GameObjects.markerElevator_goto_010
  elseif game.World.IsInsideCameraZone(playerPosition, "CamZone_ElevatorWarp_020") then
    return GameObjects.markerElevator_goto_020
  elseif game.World.IsInsideCameraZone(playerPosition, "CamZone_ElevatorWarp_030") then
    return GameObjects.markerElevator_goto_030
  elseif game.World.IsInsideCameraZone(playerPosition, "CamZone_ElevatorWarp_040") then
    return GameObjects.markerElevator_goto_040
  end
  return nil
end
function OnUpdate(level, obj)
  ShowDebugTable()
  if Time_Attack_Started then
    Elevator_Health_TickDown()
  end
  if camOneShot_FrameAroundRuneBowl ~= nil then
    camOneShot_FrameAroundRuneBowl:Update()
  end
  if camOneShot_QuestionStarted ~= nil then
    camOneShot_QuestionStarted:Update()
  end
end
function DebugEnable()
  bDebugEnabled = true
end
function DebugDisable()
  bDebugEnabled = false
end
function ShowDebugTable(x, y)
  if engine.IsDebug() and bDebugEnabled then
    local debugTable = {}
    debugTable.Y = y or 15
    debugTable.X = x or 50
    debugTable.Title = GameObjects.rising_platform:GetName()
    debugTable.TitleColor = engine.Vector.New(255, 0, 128)
    table.insert(debugTable, {
      "currentElevatorState: ",
      currentElevatorState
    })
    table.insert(debugTable, {
      "ElevatorAnimFrame: ",
      GameObjects.rising_platform.AnimFrame
    })
    table.insert(debugTable, {
      "CheckpointVars "
    })
    table.insert(debugTable, {
      "puzzleSolved: ",
      puzzleSolved
    })
    table.insert(debugTable, {
      "roomComplete: ",
      roomComplete
    })
    table.insert(debugTable, {
      "bElevatorRideStarted: ",
      bElevatorRideStarted
    })
    table.insert(debugTable, {
      "kratosOnPlatform: ",
      kratosOnPlatform
    })
    if currentElevatorState then
      for k, v in pairs(elevatorSequenceStates[currentElevatorState]) do
        table.insert(debugTable, {
          k .. ": ",
          v
        })
      end
      if elevatorSequenceStates[nextElevatorState] and currentElevatorState ~= nextElevatorState then
        table.insert(debugTable, {
          "nextElevatorState: ",
          nextElevatorState
        })
        for k, v in pairs(elevatorSequenceStates[nextElevatorState]) do
          table.insert(debugTable, {
            k .. ": ",
            v
          })
        end
      end
    end
    for k, v in pairs(EncountersComplete) do
      table.insert(debugTable, {
        k .. ":IsComplete: ",
        v
      })
    end
    table.insert(debugTable, {
      "SandBowlState_Continuous ",
      callbackState_Continuous
    })
    table.insert(debugTable, {
      "SandBowlState_Puzzle ",
      callbackState
    })
  end
end
function DestroyOneShot_FrameAroundRuneBowl()
  camOneShot_FrameAroundRuneBowl = nil
end
function CameraLookAt_FrameAroundRuneBowl()
  camOneShot_FrameAroundRuneBowl = CCOS.OneShotCamera.New("PLYR_NAR_ElevatorRuneBowl", 6.3)
  camOneShot_FrameAroundRuneBowl:SetCallback(DestroyOneShot_FrameAroundRuneBowl)
  camOneShot_FrameAroundRuneBowl:ActivateCineLock()
  camOneShot_FrameAroundRuneBowl:Start()
end
function DestroyOneShot_QuestionStarted()
  camOneShot_QuestionStarted = nil
end
function CameraLookAt_QuestionStarted()
  camOneShot_QuestionStarted = CCOS.OneShotCamera.New("PLYR_RuneRead_Focus", 6.9)
  camOneShot_QuestionStarted:SetCallback(DestroyOneShot_QuestionStarted)
  camOneShot_QuestionStarted:ActivateCineLock()
  camOneShot_QuestionStarted:Start()
end
function PlayShake_SlidingPanels(delay, length)
  timers.StartLevelTimer(delay, function()
    CSL.PlayShake("FSE_SHAKE_VERTICAL_SLIDING", length, 0, 0.3)
  end)
end
function PlayShake_Rising(delay, length)
  timers.StartLevelTimer(delay, function()
    CSL.PlayShake("FSE_SHAKE_ELEVATOR_RISING", length, 0.1, 2.3)
  end)
end
function PlayShake_Degrading(delay, length)
  timers.StartLevelTimer(delay, function()
    CSL.PlayDefaultShake("CrumbleMedium", length, 0.1, 2.3)
  end)
end
function PlayShake_FallingApart(delay, length)
  timers.StartLevelTimer(delay, function()
    CSL.PlayShake("FSE_SHAKE_TREMORS_LEVEL_3", length, 0.1, 2.3)
  end)
end
function PlayShake_ReachedTop()
  handleFinalShake = game.Blender.Start("FSE_SHAKE_TREMORS_LEVEL_3", {Weight = 0.42})
  handleFinalRumble = game.Blender.Start("FFB_LOOP_SMALL", {Weight = 0.42})
end
function StopShake_ReachedTop()
  if handleFinalShake then
    handleFinalShake:Stop()
  end
  if handleFinalRumble then
    handleFinalRumble:Stop()
  end
end
function StopShake_Degrading()
  game.Blender.Stop({
    Name = "FSE_SHAKE_TREMORS_LEVEL_2"
  })
  game.Blender.Stop({
    Name = "FFB_GENERIC_RUMBLE_MEDIUM"
  })
end
function Elevator_Health_TickDown()
  local newHealth = math.abs(ec_TimeRequirement - ecTimer.time)
  player:MeterSetValue("METER_StoneMasonElevator", newHealth)
  uiCalls.EnableMechanicMeter("METER_StoneMasonElevator")
end
function BreakNearestWall(enemy, tombcover)
  local allBreakableWalls = thisLevel:FindGameObjects(tombcover .. "*")
  local enemyPosition = enemy.WorldPosition
  local closestWall
  local closestDistance = 9999
  local maxDistance = 5
  for _, wall in pairs(allBreakableWalls) do
    if closestDistance > game.AIUtil.Distance(enemyPosition, wall.WorldPosition) then
      closestWall = wall
      closestDistance = game.AIUtil.Distance(enemyPosition, wall.WorldPosition)
    end
  end
  if maxDistance > closestDistance and closestWall then
    local breakable = closestWall.Child:GetBreakable()
    if not breakable.Broken then
      breakable:Break()
    end
  end
end
local SNDElevator
local SNDPillars = {}
local SNDSpinners
function SoundInit()
  SNDElevator = GameObjects.rising_platform_group.Child:FindSingleSoundEmitterByName("SNDElevator")
  SNDPillars[1] = GameObjects.M_pillar_all:FindSingleSoundEmitterByName("SNDPillarM")
  SNDPillars[2] = GameObjects.L_pillar_all:FindSingleSoundEmitterByName("SNDPillarL")
  SNDPillars[3] = GameObjects.R_pillar_all:FindSingleSoundEmitterByName("SNDPillarR")
  SNDSpinners = GameObjects.SpinnerPanels
end
function AudioElevatorStart()
  LD.PlaySound(SNDElevator, "SND_EVNT_Bowl_Lift_Sequence_Start")
end
function AudioElevatorActiveIdleLP()
  LD.PlaySound(SNDElevator, "SND_MECH_Bowl_Lift_Active_Idle_LP")
end
function AudioElevatorActiveIdleLPStop()
  LD.StopSound(SNDElevator, "SND_MECH_Bowl_Lift_Active_Idle_LP")
end
function AudioElevatorLiftLP()
  LD.PlaySound(SNDElevator, "SND_EVNT_Bowl_Lift_LP")
  AudioElevatorStopDownards()
end
function AudioElevatorLiftStop()
  LD.StopSound(SNDElevator, "SND_EVNT_Bowl_Lift_LP")
end
function AudioElevatorImpactDrop()
  LD.PlaySound(SNDElevator, "SND_EVNT_Bowl_Lift_Impact_Drop_Fall")
end
function AudioElevatorImpactStopUpwards()
  LD.StopSound(SNDElevator, "SND_EVNT_Bowl_Lift_LP")
  LD.PlaySound(SNDElevator, "SND_EVNT_Bowl_Lift_Impact_Stop_Upwards")
end
function AudioElevatorShake()
  LD.PlaySound(SNDElevator, "SND_MECH_Bowl_Lift_Shake")
end
function AudioElevatorDescend()
  AudioElevatorShake()
  LD.PlaySound(SNDElevator, "SND_MECH_Bowl_Lift_Rumble_LP")
end
function AudioElevatorStopDownards()
  LD.StopSound(SNDElevator, "SND_MECH_Bowl_Lift_Rumble_LP")
end
function AudioElevatorStopDegradingStages()
  LD.StopSound(SNDElevator, "SND_MECH_Bowl_Lift_Broken1_LP")
  LD.StopSound(SNDElevator, "SND_MECH_Bowl_Lift_Broken2_LP")
  LD.StopSound(SNDElevator, "SND_MECH_Bowl_Lift_Broken3_LP")
  LD.StopSound(SNDElevator, "SND_MECH_Bowl_Lift_Broken4_LP")
end
function AudioElevatorDegradingStage0()
  AudioElevatorStopDegradingStages()
  LD.PlaySound(SNDElevator, "SND_MECH_Bowl_Lift_Broken1_LP")
end
function AudioElevatorDegradingStage1()
  AudioElevatorStopDegradingStages()
  LD.PlaySound(SNDElevator, "SND_MECH_Bowl_Lift_Broken2_LP")
end
function AudioElevatorDegradingStage2()
  AudioElevatorStopDegradingStages()
  LD.PlaySound(SNDElevator, "SND_MECH_Bowl_Lift_Broken3_LP")
end
function AudioElevatorDegradingStage3()
  AudioElevatorStopDegradingStages()
  LD.PlaySound(SNDElevator, "SND_MECH_Bowl_Lift_Broken4_LP")
end
local bExitJumpStarted = false
function ElevatorMusic()
  game.Audio.StartCheckpointedMusic("SND_MX_STN_hammer_climb_in")
end
function ElevatorMusicOff(level)
  bExitJumpStarted = true
  game.Audio.StartMusic("SND_MX_STN_hammer_climb_out")
end
function ElevatorMusicFail()
  if not bExitJumpStarted then
    game.Audio.StartMusic("SND_MX_STN_hammer_elevator_fail")
  end
end
function AudioPlatformBreak(pillar)
  LD.PlaySound(SNDPillars[pillar], "SND_EVNT_Bowl_Lift_Enemy_Wall_Explo")
end
function PlaySpinnerPanelOpen()
  for i = 1, #SNDSpinners.SoundEmitters do
    LD.PlaySound(SNDSpinners.SoundEmitters[i], "SND_MECH_Bowl_Lift_Seasons_Cover_Open_LP")
  end
end
function StopSpinnerPanelOpen()
  for i = 1, #SNDSpinners.SoundEmitters do
    LD.StopSound(SNDSpinners.SoundEmitters[i], "SND_MECH_Bowl_Lift_Seasons_Cover_Open_LP")
  end
end
function PlaySpinnerPanelClose()
  for i = 1, #SNDSpinners.SoundEmitters do
    LD.PlaySound(SNDSpinners.SoundEmitters[i], "SND_MECH_Bowl_Lift_Seasons_Cover_Close")
  end
end
function SetupFlippableHitCallbacks()
  flippablesAndChildren[1][1]:FindSingleGOByName("FlipperModule").LuaObjectScript.RegisterOnRotateCallback(AudioRuneSpinSound1)
  flippablesAndChildren[2][1]:FindSingleGOByName("FlipperModule").LuaObjectScript.RegisterOnRotateCallback(AudioRuneSpinSound2)
  flippablesAndChildren[3][1]:FindSingleGOByName("FlipperModule").LuaObjectScript.RegisterOnRotateCallback(AudioRuneSpinSound3)
  flippablesAndChildren[4][1]:FindSingleGOByName("FlipperModule").LuaObjectScript.RegisterOnRotateCallback(AudioRuneSpinSound4)
end
function AudioRuneSpinSound1()
  LD.PlaySound(SNDSpinners.SoundEmitters[1], "SND_MECH_Bowl_Lift_Seasons_Puzzle_Turn")
end
function AudioRuneSpinSound2()
  LD.PlaySound(SNDSpinners.SoundEmitters[2], "SND_MECH_Bowl_Lift_Seasons_Puzzle_Turn")
end
function AudioRuneSpinSound3()
  LD.PlaySound(SNDSpinners.SoundEmitters[3], "SND_MECH_Bowl_Lift_Seasons_Puzzle_Turn")
end
function AudioRuneSpinSound4()
  LD.PlaySound(SNDSpinners.SoundEmitters[4], "SND_MECH_Bowl_Lift_Seasons_Puzzle_Turn")
end
function AudioRuneSolved(rune)
  LD.PlaySound(SNDSpinners.SoundEmitters[rune], "SND_MECH_Bowl_Lift_Seasons_Solve")
end
