local LD = require("design.LevelDesignLibrary")
local monitors = require("level.MonitorLibrary")
local uiCalls = require("ui.uicalls")
local CCOS = require("camera.camera_oneshot")
local player, sonPuppeteer, son, thisLevel, thisObj, realmControllerInteract
local triggerCinematic = false
local initiallySelectedRealm, fxScript
local animRate = 25
local bridgeRotating = false
local currentPressurePlate, loadZones, interactionOnStart, onRealmTravelStart, onRealmTravelComplete, cineInteractionTriggers, onSelectionChanged, realmSelectionChangedEvents, lockedRealmAttemptEvents, bridge
local miniTempleEndFrame = 60
local selectionRing, controllerPlatform, miniTemple_Rise, miniTemple_Rotation, rootCrystalHolder
local cineNumber_FirstInteract = 195
local cineNumber_TalismanAcquire = 512
local firstJotunheimAttempt = false
local realmUnlockedRevealOneshotCam
local jotReveal = false
local jotunheimFailRootsDestroyed = false
local jotunheimFailActive = false
local jotunheimFailActive_rootZoom = false
local realmPadColors = {
  Midgard = 11739076,
  Vanaheim = 11739076,
  Jotunheim = 16514882,
  Alfheim = 9362170,
  Helheim = 1102202,
  Svartalfheim = 2305742,
  Asgard = 16777215,
  Niflheim = 16318320,
  Muspelheim = 13380628
}
local state
local states = {
  STATE_INACTIVE = 0,
  STATE_REALM_SELECT = 1,
  STATE_REALM_TRAVEL = 2
}
local tutorialMarkers = {
  ROTATE_TABLE = "travelTutorial_Rotate",
  CONFIRM_SELECTION = "travelTutorial_Confirm",
  TAKE_BIFROST = "travelTutorial_TakeBifrost",
  TUTORIAL_ACTIVE = "travelTutorial_Active"
}
local pendingNewRealmUnlock
local narrativeLock = false
function OnScriptLoaded(level, obj)
  player = game.Player.FindPlayer()
  thisObj = obj
  thisLevel = level
  son = game.AI.FindSon()
  if obj:FindLuaTableAttribute("LoadZonesObject") ~= nil and obj:FindLuaTableAttribute("LoadZonesObject") ~= "" then
    loadZones = GameObjects[tostring(obj:FindLuaTableAttribute("LoadZonesObject"))]
  end
  fxScript = GameObjects.realmControllerFXSequencing.LuaObjectScript
  interactionOnStart = obj:FindLuaTableAttribute("Event_OnInteractStart")
  onRealmTravelStart = obj:FindLuaTableAttribute("Event_OnActivated")
  onRealmTravelComplete = obj:FindLuaTableAttribute("Event_OnTravelComplete")
  cineInteractionTriggers = obj:FindLuaTableAttribute("cineInteractionTriggers")
  onSelectionChanged = obj:FindLuaTableAttribute("Event_OnRotate")
  if interactionOnStart ~= nil then
    interactionOnStart = LD.ExtractCallbacksForEvent(level, obj, interactionOnStart)
  end
  if onRealmTravelStart ~= nil then
    onRealmTravelStart = LD.ExtractCallbacksForEvent(level, obj, onRealmTravelStart)
  end
  if onRealmTravelComplete ~= nil then
    onRealmTravelComplete = LD.ExtractCallbacksForEvent(level, obj, onRealmTravelComplete)
  end
  if cineInteractionTriggers then
    cineInteractionTriggers = LD.ExtractCallbacksForEvent(level, obj, cineInteractionTriggers)
  end
  if onSelectionChanged then
    onSelectionChanged = LD.ExtractCallbacksForEvent(level, obj, onSelectionChanged)
  end
  triggerCinematic = false
  selectionRing = obj:FindSingleGOByName("ringHorizontalAnim")
  controllerPlatform = GameObjects.hengeDisrupt00_P.Child
  miniTemple_Rise = GameObjects.templeReveal
  miniTemple_Rotation = miniTemple_Rise:FindSingleGOByName("miniModel")
  rootCrystalHolder = controllerPlatform:FindSingleGOByName("worldCrystalRaise00")
  realmControllerInteract = LD.CreateInteractZone_Standard_180(obj, "promptJoint")
  realmControllerInteract:SetTags("NotWhileSonInteracting")
  SetState(states.STATE_INACTIVE)
  SoundInit()
  game.SubObject.Sleep(obj)
end
function OnFirstPreStart(level, obj)
  controllerPlatform:StartAnim("envRealmTravelPlatformRotate360")
  SetBridgeAlignmentImmediate(LD.GetSelectedRealm())
end
function OnFirstStart(level, obj)
  local selRealm = LD.GetBridgePosition()
  miniTemple_Rise:JumpAnimToPercent(0)
  miniTemple_Rise:PauseAnim()
  miniTemple_Rotation:JumpAnimToFrame(LD.GetRealmFrame(selRealm))
  miniTemple_Rotation:PauseAnim()
  if selRealm ~= "Midgard" then
    currentPressurePlate = selRealm
  else
    currentPressurePlate = "Vanaheim"
  end
  SetRootBridgeFacing(selRealm)
  PauseAllMiniTowerAnims()
  ResetAllPressurePlates()
  GameObjects.ringVerticalAnim:JumpAnimToFrame(GameObjects.ringVerticalAnim.AnimLengthFrames)
  GameObjects.ringVerticalAnim:PauseAnim()
  rootCrystalHolder.LuaObjectScript.Reset()
  thisLevel:PauseGlobalMaterialAnimation("t_wt_root_a_jotundissolve", "wt_root_jotundissolve")
end
function OnStart(level, obj)
  HideAll_LoadZones()
  Show_SelectedLoadZone()
  HideAllMiniTowerFX()
  UnlockSelectedRealmDoor(true, false)
  SetRootBridgeFacing(currentPressurePlate)
  local completedCineNumber = LD.GetEntityVariable("CompletedCineNumber")
  local templeFlipped = LD.GetEntityVariable("CAL_TempleFlipped")
  if completedCineNumber <= 195 then
    miniTemple_Rotation:JumpAnimToFrame(LD.GetRealmInfo().frames.Vanaheim)
    selectionRing:JumpAnimToFrame(LD.GetRealmInfo().frames.Vanaheim)
    miniTemple_Rotation:PauseAnim()
    selectionRing:PauseAnim()
    GameObjects.freyaIntroDarken:Show()
    realmControllerInteract:SetXZRange(1.25)
  else
    GameObjects.freyaIntroDarken:Hide()
  end
  if not templeFlipped or templeFlipped and completedCineNumber >= cineNumber_TalismanAcquire then
    GameObjects.worldTreeBridge00_P.LuaObjectScript.Extend()
  else
    GameObjects.worldTreeBridge00_P.LuaObjectScript.Reset()
    fxScript.SetRoomState_TempleFlipped()
  end
  UpdateAvailableRealms_OnStart(completedCineNumber)
  miniTemple_Rise:OnAnimationDone(thisObj, "TempleRiseAnimDone", {Repeat = true, Force = true})
end
function OnUpdate(level, obj)
  UpdateCamera()
end
function UpdateAvailableRealms_OnRealmTravelStarted(destinationRealm)
  local completedCineNumber = game.Level.GetVariable("CompletedCineNumber")
  if destinationRealm == "Alfheim" then
    if completedCineNumber == 200 then
      LockTable()
    end
  elseif destinationRealm == "Jotunheim" and completedCineNumber == 570 then
    NarrativeLock("Jotunheim")
  end
  if 610 <= completedCineNumber then
    SetRealmDiscoveredOnTable("Jotunheim", false)
    LockRealm("Jotunheim")
  end
end
function NarrativeLock(forceRealm)
  narrativeLock = true
  UnlockRealm(forceRealm)
  if forceRealm ~= "Midgard" then
    LockRealm("Midgard")
  end
  for _, realm in pairs(LD.GetRealmInfo().names) do
    if realm ~= forceRealm then
      LockRealm(realm)
    end
  end
end
function NarrativeUnlock()
  narrativeLock = false
  if RealmIsDiscoveredOnTable("Midgard") == true then
    UnlockRealm("Midgard")
  end
  for _, realm in pairs(LD.GetRealmInfo().names) do
    if RealmIsDiscoveredOnTable(realm) == true then
      UnlockRealm(realm)
    end
  end
end
function JotunheimFailStateConditionsMet()
  local completedCineNumber = LD.GetEntityVariable("CompletedCineNumber")
  if jotunheimFailActive and 515 <= completedCineNumber and completedCineNumber < 570 then
    return true
  end
  return false
end
function LockRealm(realm)
  game.Level.SetVariable("CAL_RealmUnlocked_" .. realm, false)
  Event_RealmLocked(realm)
end
function UnlockRealm(realm)
  if RealmIsDiscoveredOnTable(realm) == false and realm ~= "Alfheim" and game.Level.GetVariable("CompletedCineNumber") ~= 570 then
    pendingNewRealmUnlock = realm
  end
  SetRealmDiscoveredOnTable(realm, true)
  game.Level.SetVariable("CAL_RealmUnlocked_" .. realm, true)
  Event_RealmUnlocked(realm)
end
function RealmIsUnlocked(realm)
  return game.Level.GetVariable("CAL_RealmUnlocked_" .. realm)
end
function RealmCanBeUnlocked(realm)
  if realm == "Midgard" or realm == "Vanaheim" or realm == "Svartalfheim" or realm == "Asgard" then
    return false
  end
  return true
end
function RealmIsDiscoveredOnTable(realm)
  if realm == "Midgard" then
    return true
  elseif realm == "Vanaheim" or realm == "Svartalfheim" or realm == "Asgard" then
    return nil
  end
  return LD.GetEntityVariable("CAL_RealmDiscovered_" .. realm)
end
function SetRealmDiscoveredOnTable(realm, value)
  if realm == "Vanaheim" or realm == "Svartalfheim" or realm == "Asgard" then
    return
  end
  LD.SetEntityVariable("CAL_RealmDiscovered_" .. realm, value)
end
function CreateSelectedRealmInfo()
  local realmInfo = {}
  local realmName = LD.GetSelectedRealm()
  local currentRealm = LD.GetCurrentRealm()
  local desc
  local status = 43019
  if realmName == "Midgard" then
    realmName = "Vanaheim"
  end
  local canBeUnlocked = RealmCanBeUnlocked(realmName)
  local isUnlocked = RealmIsUnlocked(realmName)
  if isUnlocked then
    status = 43019
    desc = nil
  elseif not canBeUnlocked then
    status = 20403
    desc = 20113
  elseif realmName == "Jotunheim" then
    local jotunheimFailTriggered = game.Level.GetVariable("_GBL_RealmTravel_JotunheimFailed")
    local cineNumber = game.Level.GetVariable("CompletedCineNumber")
    if cineNumber < 515 then
      status = 20403
      desc = 43210
    elseif cineNumber == 515 and jotunheimFailTriggered or 515 < cineNumber and cineNumber < 570 then
      status = 20117
      desc = 43211
    elseif 610 <= cineNumber then
      status = 20403
      desc = nil
    else
      status = 20117
      desc = 43038
    end
  elseif RealmIsDiscoveredOnTable(realmName) then
    status = 20117
    desc = 43038
  else
    status = 20117
    desc = 20114
  end
  realmInfo.Status = status
  realmInfo.Desc = desc
  realmInfo.CurrrentRealmName = currentRealm
  realmInfo.SelectedRealmName = realmName
  realmInfo.CanBeUnlocked = canBeUnlocked
  realmInfo.IsUnlocked = isUnlocked
  realmInfo.EnableChangeRealm = not IsExitingOrTravelling() and (not InTutorial() or player:HasMarker("travelTutorial_Rotate"))
  realmInfo.EnableConfirmRealm = not IsExitingOrTravelling() and (not InTutorial() or player:HasMarker("travelTutorial_Confirm"))
  realmInfo.EnableMidgardReturn = not IsExitingOrTravelling() and currentRealm ~= "Midgard" and game.Level.GetVariable("CAL_RealmUnlocked_Midgard")
  realmInfo.EnableExit = not IsExitingOrTravelling() and not InTutorial()
  return realmInfo
end
function IsExitingOrTravelling()
  return player:IsPlayingMove("MOV_TravelTableExit") or state == states.STATE_REALM_TRAVEL
end
function LuaHook_Intro_OnBifrostInsert()
  GameObjects.ringVerticalAnim:PlayAnimToEnd(-0.25)
  fxScript.LuaHook_Intro_OnBifrostInsert()
  GameObjects.FXCal130Freya:Hide()
end
function LuaHook_Intro_TableZoomStart()
  AnimateTempleRise(0.39)
  fxScript.LuaHook_Intro_TableZoomStart()
end
function LuaHook_Intro_TableZoomEnd()
  fxScript.LuaHook_Intro_TableZoomEnd()
end
function LuaHook_Intro_Door_Jotunheim_On()
  fxScript.LuaHook_Intro_Door_Jotunheim_On()
end
function LuaHook_Intro_Door_Vanaheim_On()
  fxScript.LuaHook_Intro_Door_Vanaheim_On()
end
function LuaHook_Intro_Door_Muspelheim_On()
  fxScript.LuaHook_Intro_Door_Muspelheim_On()
end
function LuaHook_Intro_Door_Niflheim_On()
  fxScript.LuaHook_Intro_Door_Niflheim_On()
end
function LuaHook_Intro_Door_Asgard_On()
  fxScript.LuaHook_Intro_Door_Asgard_On()
end
function LuaHook_Intro_Door_Svartalfheim_On()
  fxScript.LuaHook_Intro_Door_Svartalfheim_On()
end
function LuaHook_Intro_Door_Helheim_On()
  fxScript.LuaHook_Intro_Door_Helheim_On()
end
function LuaHook_Intro_Pool_Stars_On()
  fxScript.LuaHook_Intro_Pool_Stars_On()
end
function LuaHook_Intro_Doors_Off()
  fxScript.LuaHook_Intro_Doors_Off()
end
function LuaHook_Intro_Braziers_On()
  fxScript.LuaHook_Intro_Braziers_On()
end
function LuaHook_Intro_Root_Energy_Tendrils()
  fxScript.LuaHook_Intro_Root_Energy_Tendrils()
end
function LuaHook_Intro_Tree_Root_Energy_Tendrils()
  fxScript.LuaHook_Intro_Tree_Root_Energy_Tendrils()
end
function LuaHook_Intro_Tree_Branch_Energy_Tendrils()
  fxScript.LuaHook_Intro_Tree_Branch_Energy_Tendrils()
end
function LuaHook_Intro_MainLights_On()
  fxScript.LuaHook_Intro_MainLights_On()
end
function LuaHook_Intro_Tree_Top_Galaxy()
  fxScript.LuaHook_Intro_Tree_Top_Galaxy()
end
function LuaHook_Intro_Tree_Branch_Growth()
  fxScript.LuaHook_Intro_Tree_Branch_Growth()
end
function LuaHook_Intro_Tree_Root_Flowers()
  fxScript.LuaHook_Intro_Tree_Root_Flowers()
end
function LuaHook_Intro_ReturnToGameplay()
  LuaHook_OnEnterComplete()
  CheckRealmGemsOnEnter()
end
function LuaHook_OnBifrostInsert()
  GameObjects.CA_RT_Idle.LuaObjectScript.Enable()
  GameObjects.ringVerticalAnim:PlayAnimToEnd(-0.25)
  AnimateTempleRise()
  Event_OnBifrostInserted()
  if RealmIsUnlocked("Midgard") and LD.GetCurrentRealm() ~= "Midgard" then
    AddMarker("Midgard_Travel_Allowed")
  end
  if pendingNewRealmUnlock == nil then
    LD.CallFunctionAfterDelay(function()
      CheckRealmGemsOnEnter()
    end, 1.5)
  end
end
function AnimateTempleRise(rate)
  rate = rate or 1
  miniTemple_Rise:JumpAnimToFrame(0)
  miniTemple_Rise:PlayAnimToFrame(miniTempleEndFrame, rate)
  LD.CallFunctionAfterDelay(function()
    LD.AddControllerRumble({EffectName = "FFB_TINY", Duration = 2})
  end, 0.25)
end
function AnimateTempleFall(rate)
  rate = rate or -1
  rate = -1 * math.abs(rate)
  miniTemple_Rise:JumpAnimToFrame(miniTempleEndFrame)
  miniTemple_Rise:PlayAnimToEnd(rate)
  LD.CallFunctionAfterDelay(function()
    LD.AddControllerRumble({EffectName = "FFB_TINY", Duration = 2})
  end, 0.25)
  if state == states.STATE_REALM_TRAVEL then
    local travelRealm = LD.GetCurrentRealm()
    HideMiniTowerFX(travelRealm, 0)
    HideMiniTowerEmissive(travelRealm)
  end
end
function TempleRiseAnimDone()
  game.FX.StopEffect({EffectName = "FFB_SMALL"})
  if miniTemple_Rise.AnimFrame == miniTempleEndFrame then
    LD.AddControllerRumble({EffectName = "FFB_MEDIUM", Duration = 0.5})
  end
end
function LuaHook_OnEnterComplete()
  SetState(states.STATE_REALM_SELECT)
  EnableCameraUpdates()
end
function LuaHook_OnIdleStart()
  if pendingNewRealmUnlock ~= nil then
    LD.CallFunctionAfterDelay(function()
      player:TriggerMoveEvent("kLENewRealmUnlocked")
    end, 0.1)
  else
    UI_Open_RT_Menu()
    UpdateRealmSelectionInterface()
  end
end
function EnableCameraUpdates()
  if pendingNewRealmUnlock ~= nil then
    DisablePlayerInput()
  end
  game.SubObject.Wake(thisObj)
end
function JotunheimRevealActive()
  if jotReveal == false and LD.GetSelectedRealm() == "Jotunheim" and game.Level.GetVariable("CompletedCineNumber") == 515 then
    return true
  end
  return false
end
function LuaHook_OnBifrostRemove()
  fxScript.LuaHook_OnBifrostRemove()
  PlayNameOffSound()
  ResetPadColor()
  if state ~= states.STATE_REALM_TRAVEL then
    HideAllMiniTowerFX()
    GameObjects.ringVerticalAnim:PlayAnimToEnd()
    AnimateTempleFall()
    if not jotunheimFailActive then
      ResetTempleRiseAnim_PreviousSelection()
    end
  else
    HideAllMiniTowerFX(LD.GetCurrentRealm())
  end
end
function UpdateCamera()
  if realmUnlockedRevealOneshotCam ~= nil then
    realmUnlockedRevealOneshotCam:Update()
  end
  if state == states.STATE_REALM_SELECT then
    game.Camera.SubmitCameraByName("PLYR_RealmSelect_Idle_Swipe")
  elseif state == states.STATE_REALM_TRAVEL then
    if bridgeRotating then
      game.Camera.SubmitCameraByName("PLYR_RealmSelect_Activated_Roam")
    end
  elseif jotunheimFailActive and not jotunheimFailRootsDestroyed then
    game.Camera.SubmitCameraByName("PLYR_Nar_JotFail_010")
    if jotunheimFailActive_rootZoom then
      game.Camera.SubmitCameraByName("PLYR_Nar_JotFail_020")
    end
  else
    game.SubObject.Sleep(thisObj)
  end
end
function InTutorial()
  return player:HasMarker(tutorialMarkers.TUTORIAL_ACTIVE)
end
function UpdateRealmSelectionInterface()
  miniTemple_Rotation:ClearAllAnimCallbacks()
  if state ~= states.STATE_INACTIVE then
    local selectedRealm = LD.GetSelectedRealm()
    UI_Update_RT_Menu()
    if RealmIsUnlocked(selectedRealm) then
      ShowMiniTowerFX(selectedRealm, 2)
    end
    SetPadColor(selectedRealm)
  end
end
function SetPadColor(realm)
  player.Pad:SetLightColor(realmPadColors[realm])
end
function ResetPadColor()
  player.Pad:ResetLightColor()
end
function Event_RealmLocked(realm)
  fxScript.Event_RealmLocked(realm)
end
function Event_RealmUnlocked(realm)
  fxScript.Event_RealmUnlocked(realm)
end
function Event_OnPlatformRotationStart()
  fxScript.Event_OnPlatformRotationStart()
end
function Event_OnFirstInteractStart()
  fxScript.Event_OnFirstInteractStart()
end
function Event_OnInteractStart()
  fxScript.Event_OnInteractStart()
end
function Event_OnRealmSelectionChanged()
  fxScript.Event_OnRealmSelectionChanged()
end
function Event_OnRealmSelectionConfirmed(selectedRealm)
  fxScript.Event_OnRealmSelectionConfirmed(selectedRealm)
end
function Event_RootCrystalLiftAnimDone()
  rootCrystalHolder:ClearAllAnimCallbacks()
  fxScript.Event_RootCrystalLiftAnimDone()
end
function Event_OnBifrostInserted()
  fxScript.Event_OnBifrostInserted()
end
function Event_OnCrystalLower(realm)
  fxScript.Event_OnCrystalLower(realm)
end
function Event_OnCrystalRaise(monitor, realm)
  if monitor ~= nil then
    monitor:Stop()
    monitor:Terminate()
    monitor = nil
  end
  fxScript.Event_OnCrystalRaise(realm)
end
function Event_OnDeviceAlignedToRealm()
  local selRealm = LD.GetSelectedRealm()
  if LD.GetCurrentRealm() ~= "Midgard" then
    AnimateTempleFall(-0.5)
  end
  fxScript.Event_OnDeviceAlignedToRealm()
  if LD.GetEntityVariable("CompletedCineNumber") >= 570 and selRealm == "Jotunheim" then
    currentPressurePlate = selRealm
    GameObjects.Cine_SayingGoodbye_Group.LuaObjectScript.SayingGoodbyeSequence(rootCrystalHolder)
    return
  end
  if selRealm ~= "Midgard" then
    local realmNameLower = string.lower(selRealm)
    local gem = thisLevel:FindSingleGameObject("cr_" .. realmNameLower)
    local rootAnimRate = 1
    if gem then
      gem:JumpAnimToFrame(0)
      gem:PlayAnimToFrame(360, rootAnimRate)
      local gemAnimMonitor = monitors.CreateAnimFrameMonitor(gem)
      gemAnimMonitor:OnFrameForward(220, function()
        Event_OnCrystalRaise(gemAnimMonitor, selRealm)
      end)
    end
    rootCrystalHolder.LuaObjectScript.Reset()
    rootCrystalHolder.LuaObjectScript.Extend()
    rootCrystalHolder:OnAnimDone(thisObj, "Event_RootCrystalLiftAnimDone")
  end
end
function Event_OnFXLoadSequenceStart()
  local travelDuration = CheckCustomTravelDuration() or 7
  LD.CallFunctionAfterDelay(CheckDestinationWads, travelDuration)
end
function CheckCustomTravelDuration()
  local completedCine = game.Level.GetVariable("CompletedCineNumber")
  if completedCine <= 200 then
    return 22.33
  elseif (completedCine == 387 or completedCine == 388) and LD.GetCurrentRealm() == "Midgard" then
    return 31
  end
  return nil
end
function CheckDestinationWads()
  local realmMarkerName = "LOAD_MARKER_"
  local currentRealm = LD.GetCurrentRealm()
  if game.Level.GetVariable("CompletedCineNumber") == 470 then
    realmMarkerName = realmMarkerName .. "HelR1"
  elseif currentRealm == "Alfheim" then
    realmMarkerName = realmMarkerName .. "ALf"
  elseif currentRealm == "Muspelheim" then
    realmMarkerName = realmMarkerName .. "Musp"
  elseif currentRealm == "Svartalfheim" then
    realmMarkerName = realmMarkerName .. "Svart"
  elseif currentRealm == "Jotunheim" then
    realmMarkerName = realmMarkerName .. "Jot"
  elseif currentRealm == "Helheim" then
    realmMarkerName = realmMarkerName .. "Hel"
  elseif currentRealm == "Midgard" then
    realmMarkerName = realmMarkerName .. "Mid"
  elseif currentRealm == "Niflheim" then
    realmMarkerName = realmMarkerName .. "Nif"
  end
  realmMarkerName = realmMarkerName .. "_RT"
  game.Map.LoadFastTravelWads(realmMarkerName, thisObj)
end
function OnFastTravelWadsLoaded(level)
  Event_OnLoadComplete()
end
function Event_OnLoadComplete()
  fxScript.Event_OnLoadComplete()
  if not jotunheimFailActive and LD.GetCurrentRealm() == "Midgard" then
    AnimateTempleFall(-0.5)
  end
end
function InJotunheimFailSequence()
  return jotunheimFailActive
end
function Event_FXSequenceEnd()
  SetState(states.STATE_INACTIVE)
  game.EvaluateLoadZones()
  UnlockSelectedRealmDoor(true, true)
  RealmTravelComplete()
  if LD.GetCurrentRealm() == "Helheim" then
    GameObjects.RealmTravelDoor_Helheim.LuaObjectScript.StartIceEffect()
  end
  if onRealmTravelComplete ~= nil then
    LD.ExecuteCallbacksForEvent(thisObj.Level, thisObj, onRealmTravelComplete, "Realm Travel Complete Event")
  end
  local selRealm = LD.GetSelectedRealm()
  LD.CallFunctionAfterDelay(function()
    local realmNameLower = string.lower(selRealm)
    local gem = thisLevel:FindSingleGameObject("cr_" .. realmNameLower)
    if gem then
      gem:PlayAnimToFrame(720)
    end
    rootCrystalHolder.LuaObjectScript.Retract(-2)
    if not jotunheimFailActive then
      LD.CallFunctionAfterDelay(function()
        SetRootBridgeFacing(selRealm)
        GameObjects.worldTreeBridge00_P.LuaObjectScript.Extend()
        GameObjects.worldTreeBridge00_P.LuaObjectScript.RegisterCustomCallbackOnAnimDone(function()
          EnableTable()
          Event_OnCrystalLower(selRealm)
          RealmTravelCompleteCheckpoint()
        end)
      end, 1)
    end
  end, 2.75)
  if jotunheimFailActive then
    LD.SetEntityVariable("NAR_RoadLoreAllowed", true)
  end
end
function RealmTravelCompleteCheckpoint()
  if game.Level.GetVariable("CompletedCineNumber") < 470 or game.Level.GetVariable("CompletedCineNumber") > 492 then
    local bookmarks = require("design.Bookmarks")
    local cineNumber = LD.GetEntityVariable("CompletedCineNumber")
    if RealmTravelCompleteCheckpointBookmarkCheck(bookmarks, cineNumber, "29_Caldera_020_HuldraReunion") then
      return
    elseif RealmTravelCompleteCheckpointBookmarkCheck(bookmarks, cineNumber, "07_Caldera_020_MidgardReturn") then
      return
    elseif RealmTravelCompleteCheckpointBookmarkCheck(bookmarks, cineNumber, "05_Caldera_040_TravelComplete") then
      game.World.EnablePlayerStateSoftSave()
      return
    else
      game.World.StoreCheckpoint()
    end
  end
end
function RealmTravelCompleteCheckpointBookmarkCheck(lib, cineNumber, strBookmarkName)
  local longName = "BOOKMARK_" .. strBookmarkName
  local varName = "SAVED_" .. longName
  local tableEntry = lib[longName]
  if cineNumber == tableEntry.Requirement and LD.GetEntityVariable(varName) == false then
    LD.SetEntityVariable(varName, true)
    game.World.StoreCheckpointAndBookmark(tableEntry)
    return true
  end
  return false
end
function ResetTempleRiseAnim_PreviousSelection()
  AnimateTowerReverse(LD.GetSelectedRealm())
  LD.SetSelectedRealm(initiallySelectedRealm)
  local desiredRingFrame = GetRealmFrameValue(initiallySelectedRealm)
  local ringRate = animRate / 2
  local diff = desiredRingFrame - selectionRing.AnimFrame
  local halfFrame = selectionRing.AnimLengthFrames / 2
  if diff < 0 and diff > -halfFrame or 0 < diff and diff > halfFrame then
    ringRate = -1 * ringRate
  end
  selectionRing:PlayAnimToFrame(desiredRingFrame, ringRate)
  PlaySoundTableRotationLoop(desiredRingFrame)
  miniTemple_Rotation:PlayAnimToFrame(desiredRingFrame, ringRate)
  miniTemple_Rotation:OnAnimationDone(thisObj, "MiniTempleAnimResetComplete", {Force = true})
end
function MiniTempleAnimResetComplete()
  miniTemple_Rotation:ClearAllAnimCallbacks()
  LD.AddControllerRumble({EffectName = "FFB_SMALL", Duration = 1})
end
function UI_Open_RT_Menu()
  PlayNameOnSound()
  uiCalls.UI_Global_Menu_Set_Exclusive_Access("GlobalRealmTable")
  local selectedRealmInfo = CreateSelectedRealmInfo()
  uiCalls.UI_Event_Open_Realm_Table_Menu(selectedRealmInfo)
  if LD.GetCurrentRealm() ~= "Midgard" and RealmIsUnlocked("Midgard") and RealmIsDiscoveredOnTable("Midgard") then
    uiCalls.SendSidebarDesignerMessage({
      Text = 43794,
      AdvanceType = uiCalls.msgParam.INFINITE_TIMER,
      Critical = true
    })
  end
end
function UI_Update_RT_Menu()
  local selectedRealmInfo = CreateSelectedRealmInfo()
  uiCalls.UI_Event_Update_Realm_Table_Menu(selectedRealmInfo)
end
function UI_Close_RT_Menu()
  uiCalls.UI_Global_Menu_Clear_Exclusive_Access("GlobalRealmTable")
  uiCalls.UI_Event_Close_Realm_Table_Menu()
  uiCalls.UI_Event_TurnOffDesignerMessage()
end
function OnUseWorld(level, obj)
  if realmControllerInteract:PlayerCanInteract() then
    if cineInteractionTriggers then
      LD.ExecuteCallbacksForEvent(thisObj.Level, thisObj, cineInteractionTriggers, "Cine Interaction Event")
    end
    if triggerCinematic == false then
      player:RequestInteract(obj, realmControllerInteract)
    end
    triggerCinematic = false
  end
end
function SetState(newState)
  if newState == states.STATE_INACTIVE or newState == states.STATE_REALM_SELECT or newState == states.STATE_REALM_TRAVEL then
    state = newState
  else
    engine.Warning("Trying to set the realm controller to a bad state in function SetState()")
  end
end
function OnInteractStart(level, obj, creature)
  if interactionOnStart ~= nil then
    LD.ExecuteCallbacksForEvent(thisObj.Level, thisObj, interactionOnStart, "Interaction Event Start")
  end
  Event_OnInteractStart()
  StartInteraction()
end
function CheckSonStateForWarp()
  if game.AIUtil.Distance(son, thisObj) > 5 then
    son:Warp(GameObjects.CA_RT_Idle.WorldPosition, GameObjects.CA_RT_Idle:GetWorldForward())
  end
end
function StartInteraction()
  game.Compass.SetDesignerForcedHide(true)
  initiallySelectedRealm = LD.GetBridgePosition()
  if initiallySelectedRealm == "Midgard" then
    initiallySelectedRealm = "Vanaheim"
  end
  LD.SetSelectedRealm(initiallySelectedRealm)
  if game.Level.GetVariable("CompletedCineNumber") <= 195 then
    GameObjects.Cine_RealmTravelIntro:CallScript("SetupCineSeq")
    LD.SetSelectedRealm("Vanaheim")
  else
    LD.PlaySingleSynchMove_KratosObject(thisObj, "synchJoint", "Realm Travel Table", "BRA_RealmTravelTableEnter", "", realmControllerInteract, false, nil, {completion_percentage = 0.75})
  end
  DisableTable()
  UpdateAvailableRealms_OnInteract()
  if pendingNewRealmUnlock == nil or game.Level.GetVariable("CompletedCineNumber") ~= 515 then
    AnimateTowerForward(initiallySelectedRealm)
  end
end
function UpdateAvailableRealms_OnInteract()
  local completedCineNumber = game.Level.GetVariable("CompletedCineNumber")
  if 370 < completedCineNumber and completedCineNumber < 387 then
    NarrativeLock("Helheim")
  elseif 387 <= completedCineNumber and completedCineNumber < 390 then
    NarrativeLock("Midgard")
  elseif completedCineNumber == 515 then
    if firstJotunheimAttempt == false and game.Level.GetVariable("CAL_RealmUnlocked_Jotunheim") == false then
      NarrativeLock("Jotunheim")
    end
  elseif completedCineNumber == 610 then
    NarrativeUnlock()
  end
  if not narrativeLock then
    if completedCineNumber <= 195 and RealmIsDiscoveredOnTable("Alfheim") == false and RealmIsUnlocked("Alfheim") == false then
      game.Level.SetVariable("CompletedCineNumber", 200)
      UnlockRealm("Alfheim")
      if player:HasMarker(tutorialMarkers.TUTORIAL_ACTIVE) == false then
        player:AddMarker(tutorialMarkers.TUTORIAL_ACTIVE)
      end
    end
    if completedCineNumber == 570 and RealmIsDiscoveredOnTable("Jotunheim") == false and RealmIsUnlocked("Jotunheim") == false then
      UnlockRealm("Jotunheim")
    end
    if game.Wallets.GetResourceValue("HERO", "MuspelheimCipherPiece") == 4 and RealmIsDiscoveredOnTable("Muspelheim") == false and RealmIsUnlocked("Muspelheim") == false then
      UnlockRealm("Muspelheim")
    end
    if game.Wallets.GetResourceValue("HERO", "NiflheimCipherPiece") == 4 and RealmIsDiscoveredOnTable("Niflheim") == false and RealmIsUnlocked("Niflheim") == false then
      UnlockRealm("Niflheim")
    end
  end
end
function OnInteractAbort(level, obj, creature)
  CleanupInteract()
end
function OnExitInteraction(level, obj, creature)
  CleanupInteract()
end
function CleanupInteract()
  UI_Close_RT_Menu()
  if state ~= states.STATE_REALM_TRAVEL then
    if not JotunheimFailStateConditionsMet() then
      game.Compass.SetDesignerForcedHide(false)
      EnableTable()
    end
    SetState(states.STATE_INACTIVE)
  end
  GameObjects.CA_RT_Idle.LuaObjectScript.Disable()
  RemoveMarker("Midgard_Travel_Allowed")
end
function AddMarker(Marker)
  if not player:HasMarker(Marker) then
    player:AddMarker(Marker)
  end
end
function RemoveMarker(Marker)
  if player:HasMarker(Marker) then
    player:RemoveMarker(Marker)
  end
end
function IsSelectedRealmUnlocked()
  local selRealm = LD.GetSelectedRealm()
  if selRealm == "Midgard" then
    selRealm = "Vanaheim"
  end
  return game.Level.GetVariable("CAL_RealmUnlocked_" .. selRealm)
end
function SelectedRealmIsNotCurrentRealm()
  local selRealm = LD.GetSelectedRealm()
  local curRealm = LD.GetCurrentRealm()
  if selRealm == "Midgard" then
    return "Vanaheim" ~= curRealm
  else
    return selRealm ~= curRealm
  end
end
function TriggerJotunheimFail()
  jotunheimFailActive = true
  DisablePlayerInput()
  LD.SetSelectedRealm("Midgard")
  LD.SetEntityVariable("NAR_RoadLoreAllowed", false)
  DisableTable()
  LD.CallFunctionAfterDelay(function()
    GameObjects.BTR_NeedCrystal.LuaObjectScript.PlayNeedCrystal()
  end, 1)
  game.Level.SetVariable("_GBL_RealmTravel_JotunheimFailed", true)
  NarrativeUnlock()
  LockRealm("Jotunheim")
  SetRealmDiscoveredOnTable("Jotunheim", false)
  local cal200 = game.FindLevel("Cal200_Shore")
  if cal200 ~= nil then
    cal200:GetGameObject("SnakeIdle"):CallScript("UpdateSnakeIdle")
  end
  game.FindLevel("Cal120_Airlock"):GetGameObject("Btr_Cal120"):CallScript("DisableTalkInteract")
  LD.CallFunctionAfterDelay(function()
    LD.ShowFX(GameObjects.rt_portal_open_jot_fail)
    GameObjects.bridgeSeq_exterior:Show()
    LD.ShowFX(GameObjects.rtBridge_opening_part:FindSingleGOByName("Cards"))
    fxScript.StartCoalesceFX()
    rootCrystalHolder.LuaObjectScript.Reset()
    rootCrystalHolder.LuaObjectScript.Extend(3)
    local animMonitor = monitors.CreateAnimFrameMonitor(rootCrystalHolder)
    animMonitor:OnFrame(rootCrystalHolder.AnimLengthFrames, function()
      JotunheimFail_CrystalRootExtended(animMonitor)
    end)
    GameObjects.worldTreeBridge00_P.LuaObjectScript.Retract(-6)
    game.EvaluateLoadZones()
  end, 1.75)
end
function JotunheimFail_CrystalRootExtended(monitor)
  local sequenceDuration = 19
  local timeUntilEndFX = 13.5
  LD.CallFunctionAfterDelay(function()
    GameObjects.BTR_NeedCrystal.LuaObjectScript.PlayNeedCrystal_Part02()
    LD.CallFunctionAfterDelay(function()
      jotunheimFailActive_rootZoom = true
    end, 3)
  end, 3)
  if monitor then
    monitor:Stop()
    monitor:Terminate()
    monitor = nil
  end
  LD.CallFunctionAfterDelay(function()
    fxScript.StartBeamImpactVibration()
    LD.ShowFX(GameObjects.beamFX_JotunheimFail)
    LD.ShowFX(GameObjects.beam_B_pulse)
    fxScript.StopVortexLeaves()
    PlaySoundJotFailBeam()
  end, 1.5)
  LD.CallFunctionAfterDelay(function()
    Event_OnLoadComplete()
  end, timeUntilEndFX - 1)
  LD.CallFunctionAfterDelay(function()
    UnlockSelectedRealmDoor(true, true)
    HideMiniTowerEmissive("Jotunheim")
    AnimateTowerReverse("Jotunheim")
    LD.HideFX(GameObjects.rt_portal_open_jot_fail)
    LD.HideFX(GameObjects.beamFX_JotunheimFail)
    rootCrystalHolder.Parent:SetMaterialSwap("jotunDissolve")
    thisLevel:PlayGlobalMaterialAnimation("t_wt_root_a_jotundissolve", "wt_root_jotundissolve")
  end, timeUntilEndFX)
  LD.CallFunctionAfterDelay(function()
    jotunheimFailRootsDestroyed = true
    EnablePlayerInput()
  end, timeUntilEndFX + 2.5)
  LD.CallFunctionAfterDelay(function()
    JotunheimFail_CrystalRootRetracted()
  end, sequenceDuration)
end
function JotunheimFail_CrystalRootRetracted()
  RequestBridgeAlignmentUpdate("Midgard", 0.65)
  rootCrystalHolder.LuaObjectScript.Reset()
  rootCrystalHolder:SetMaterialSwap("")
end
function LuaHook_InteractButtonDown()
  local completedCineNumber = LD.GetEntityVariable("CompletedCineNumber")
  local selectedRealm = LD.GetSelectedRealm()
  if IsSelectedRealmUnlocked() and SelectedRealmIsNotCurrentRealm() then
    if selectedRealm == "Jotunheim" then
      if 515 <= completedCineNumber and completedCineNumber < 570 then
        if firstJotunheimAttempt == false then
          firstJotunheimAttempt = true
          player:TriggerMoveEvent("RealmConfirm_FailJotunheim")
          TriggerJotunheimFail()
          return
        end
      elseif 570 <= completedCineNumber then
        player:TriggerMoveEvent("RealmConfirm_SayingGoodbye")
        return
      end
    else
      player:TriggerMoveEvent("RealmConfirm")
      return
    end
  end
  player:TriggerMoveEvent("RealmConfirm_Fail")
end
function LuaHook_RuneRevealIntroCam()
  if game.Level.GetVariable("CompletedCineNumber") == 515 and RealmIsDiscoveredOnTable("Jotunheim") == true then
    HideMiniTowerEmissive("Jotunheim")
    GameObjects.rt_mini_tower_jot_reveal:PlayAnimToEnd(0.65)
    PlaySoundJotMiniTowerRise()
    game.Blender.Trigger({
      Name = "FFB_GENERIC_RUMBLE_LOW",
      Duration = 4.5,
      TweenIn = {Time = 0},
      TweenOut = {Time = 0.25}
    })
    game.Blender.Trigger({
      Name = "FSE_sway_Walk_Slow",
      Duration = 4.5,
      TweenIn = {Time = 0.1},
      TweenOut = {Time = 1.2},
      Weight = 0.3
    })
    LD.CallFunctionAfterDelay(function()
      AnimateTowerForward(pendingNewRealmUnlock, 1)
    end, 2.5)
    LD.CallFunctionAfterDelay(function()
      ShowMiniTowerFX(pendingNewRealmUnlock, 2, 0.65)
    end, 3.5)
    realmUnlockedRevealOneshotCam = CCOS.OneShotCamera.New("PLYR_RealmSelect_Idle_JotunheimReveal", 7, nil)
    realmUnlockedRevealOneshotCam:Start()
    realmUnlockedRevealOneshotCam:SetCallback(DestroyRealmUnlockedOneshotCam)
  else
    if pendingNewRealmUnlock == nil and game.Level.GetVariable("CompletedCineNumber") == 200 then
      pendingNewRealmUnlock = "Alfheim"
    end
    AnimateTowerForward(pendingNewRealmUnlock, 1)
    ShowMiniTowerFX(pendingNewRealmUnlock, 2)
  end
end
function LuaHook_RuneRevealComplete()
  local completedCine = game.Level.GetVariable("CompletedCineNumber")
  if completedCine ~= 515 or completedCine == 515 and RealmIsDiscoveredOnTable("Jotunheim") == false then
    EnablePlayerInput()
    CheckRealmGemsOnEnter()
    UI_Open_RT_Menu()
    pendingNewRealmUnlock = nil
  end
end
function DestroyRealmUnlockedOneshotCam()
  LD.CallFunctionAfterDelay(function()
    CheckRealmGemsOnEnter()
    EnablePlayerInput()
    UI_Open_RT_Menu()
  end, 3)
  pendingNewRealmUnlock = nil
  jotReveal = true
  realmUnlockedRevealOneshotCam = nil
end
function LuaHook_RealmTravelConfirmed_Midgard()
  LD.SetSelectedRealm("Midgard")
end
function LuaHook_RealmTravelConfirmed()
  CheckSonStateForWarp()
  local selRealm = LD.GetSelectedRealm()
  local curRealm = LD.GetCurrentRealm()
  SetState(states.STATE_REALM_TRAVEL)
  UpdateAvailableRealms_OnRealmTravelStarted(selRealm)
  if player:HasMarker(tutorialMarkers.CONFIRM_SELECTION) then
    player:RemoveMarker(tutorialMarkers.CONFIRM_SELECTION)
  end
  if player:HasMarker(tutorialMarkers.TUTORIAL_ACTIVE) then
    player:RemoveMarker(tutorialMarkers.TUTORIAL_ACTIVE)
  end
  UI_Close_RT_Menu()
  LD.SetCurrentRealm(selRealm)
end
function OnBridgeAlignedToTravelRealm()
  bridgeRotating = false
  game.FX.StopEffect({
    EffectName = "FFB_GENERIC_RUMBLE_LOW"
  })
  game.FX.StopEffect({
    EffectName = "FSE_SWAY_CRANK_RUMBLE_SMALL"
  })
  LD.AddControllerRumble({EffectName = "FFB_GIANT", Duration = 0.5})
  controllerPlatform:ClearAllAnimCallbacks()
  StopMapRotationLoop()
  if jotunheimFailActive == false then
    local completedCineNumber = game.Level.GetVariable("CompletedCineNumber")
    if completedCineNumber < 470 or 490 < completedCineNumber then
      Event_OnDeviceAlignedToRealm()
    end
  else
    jotunheimFailActive = false
    jotunheimFailActive_rootZoom = false
    game.EvaluateLoadZones()
    ResetPressurePlatesAndRootBridgeToRealmDirection("Midgard")
    GameObjects.worldTreeBridge00_P.LuaObjectScript.Extend()
    GameObjects.worldTreeBridge00_P.LuaObjectScript.RegisterCustomCallbackOnAnimDone(function()
      EnableTable()
      LD.CompleteQuest("Quest_Caldera_Objective750")
      game.Compass.SetDesignerForcedHide(false)
      game.World.StoreCheckpoint()
    end)
  end
end
function UpdateAvailableRealms_OnStart(completedCineNum)
  if 390 <= completedCineNum and completedCineNum < 492 then
    NarrativeUnlock()
  end
  if game.Level.GetVariable("CAL_RealmTravelAvailable") then
    UnlockTable()
  else
    LockTable()
  end
end
function LuaHook_OnRingPushed()
  local selRealm = LD.GetSelectedRealm()
  GameObjects.ringVerticalAnim:PlayAnimToEnd()
  ResetDoorGlow(initiallySelectedRealm)
  if initiallySelectedRealm == "Helheim" then
    GameObjects.RealmTravelDoor_Helheim.LuaObjectScript.StopIceEffect()
  end
  local platformRotateDelay = 2
  if game.Level.GetVariable("CompletedCineNumber") <= 200 then
    game.UI.Idle(true, false)
    player:AddMarker(tutorialMarkers.TAKE_BIFROST)
    LD.CallFunctionAfterDelay(function()
      player:TriggerMoveEvent("kLEForceExit")
      game.UI.Idle(false, false)
      player:RemoveMarker(tutorialMarkers.TAKE_BIFROST)
    end, 1.5)
    platformRotateDelay = 4.25
  end
  LD.CallFunctionAfterDelay(function()
    Event_OnPlatformRotationStart()
    RequestBridgeAlignmentUpdate(selRealm, 2.75)
  end, platformRotateDelay)
  HideAll_LoadZones()
  Show_SelectedLoadZone()
  if onRealmTravelStart ~= nil then
    LD.ExecuteCallbacksForEvent(thisObj.Level, thisObj, onRealmTravelStart, "Realm Travel Start Event")
  end
  Event_OnRealmSelectionConfirmed(selRealm)
  PlaySoundSuccessfulPush()
end
function LuaHook_OnRingPushedLocked()
  GameObjects.ringVerticalAnim:PlayAnimToEnd()
  FireLockedRealmAttemptEvents()
end
function LuaHook_OnRingPushedLocked_RingReset()
  GameObjects.ringVerticalAnim:PlayAnimToEnd(-1)
end
function LuaHook_OnRingPushed_JotunheimFail()
  fxScript.Event_OnRealmSelectionConfirmed("Jotunheim")
  GameObjects.ringVerticalAnim:PlayAnimToEnd()
end
function LuaHook_SelectLeft()
  UpdateRealmSelectionRotation("left", 15)
end
function LuaHook_SelectLeft_UpdateUI()
  PlayNameOnSound()
  UpdateRealmSelectionInterface()
end
function LuaHook_SelectRight()
  UpdateRealmSelectionRotation("right", -15)
end
function LuaHook_SelectRight_UpdateUI()
  PlayNameOnSound()
  UpdateRealmSelectionInterface()
end
function CheckRealmGemsOnEnter(speed)
  local realmNames = LD.GetRealmInfo().names
  local selRealm = LD.GetSelectedRealm()
  local completedCineNumber = game.Level.GetVariable("CompletedCineNumber")
  for _, realm in pairs(realmNames) do
    if RealmIsUnlocked(realm) then
      if realm == selRealm then
        AnimateTowerForward(realm, speed)
        ShowMiniTowerFX(realm, 2)
      else
        ShowMiniTowerFX(realm, 1)
      end
    elseif RealmIsDiscoveredOnTable(realm) == true then
      ShowMiniTowerFX(realm, 1)
    end
  end
end
function HideAllMiniTowerFX(excludeRealm)
  local realmNames = LD.GetRealmInfo().names
  for _, realm in pairs(realmNames) do
    if realm ~= excludeRealm then
      HideMiniTowerFX(realm, 0)
      HideMiniTowerEmissive(realm)
    end
  end
end
function ShowMiniTowerFX(realm, state, rate)
  if rate == nil then
    rate = 2
  end
  if realm == "Midgard" then
    realm = "Vanaheim"
  end
  if RealmIsDiscoveredOnTable(realm) ~= nil then
    if RealmIsUnlocked(realm) then
      local currentFrame = GameObjects["tableLight_" .. realm].Child.AnimFrame
      local frame = state * 30
      if currentFrame > frame then
        rate = rate * -1
      end
      GameObjects["tableLight_" .. realm].Child:PlayAnimToFrame(frame, rate)
      GameObjects["ringSymbol_" .. realm].Child:PlayAnimToFrame(frame, rate)
      ShowMiniTowerEmissive(realm)
    elseif RealmIsDiscoveredOnTable(realm) == true then
      GameObjects["tableLight_" .. realm].Child:PlayAnimToFrame(22, rate)
    end
  end
end
function ShowMiniTowerEmissive(realm)
  if realm == "Midgard" then
    realm = "Vanaheim"
  end
  if RealmIsDiscoveredOnTable(realm) ~= nil then
    local material = "rt_mini_set"
    if realm == "Helheim" then
      material = material .. "A_hel"
    elseif realm == "Alfheim" then
      material = material .. "A_alf"
    elseif realm == "Jotunheim" then
      material = material .. "a_jot"
    elseif realm == "Muspelheim" then
      material = material .. "a_musp"
    elseif realm == "Niflheim" then
      material = material .. "a_nifl"
    end
    local rate = 2
    if pendingNewRealmUnlock ~= nil then
      rate = 1
    end
    thisLevel:PlayGlobalMaterialAnimation(material, "rt_mini_setA_light", {Rate = rate})
  end
end
function HideMiniTowerFX(realm, state)
  if realm == "Midgard" then
    realm = "Vanaheim"
  end
  if RealmIsDiscoveredOnTable(realm) ~= nil then
    local frame = state * 30
    GameObjects["ringGem_" .. realm]:PlayAnimToEnd(-1)
    GameObjects["tableLight_" .. realm].Child:PlayAnimToFrame(frame, -1.5)
    GameObjects["ringSymbol_" .. realm].Child:PlayAnimToFrame(frame, -1.5)
  end
end
function HideMiniTowerEmissive(realm)
  if realm == "Midgard" then
    realm = "Vanaheim"
  end
  if RealmIsDiscoveredOnTable(realm) ~= nil then
    local material = "rt_mini_set"
    if realm == "Helheim" then
      material = material .. "A_hel"
    elseif realm == "Alfheim" then
      material = material .. "A_alf"
    elseif realm == "Jotunheim" then
      material = material .. "a_jot"
    elseif realm == "Muspelheim" then
      material = material .. "a_musp"
    elseif realm == "Niflheim" then
      material = material .. "a_nifl"
    end
    thisLevel:PlayGlobalMaterialAnimation(material, "rt_mini_setA_light", {Rate = -1.5})
  end
end
function PauseAllMiniTowerAnims()
  for _, realm in pairs(LD.GetRealmInfo().names) do
    local towerName
    if realm == "Midgard" then
      towerName = "rt_mini_tower_Vanaheim"
    else
      towerName = "rt_mini_tower_" .. realm
    end
    GameObjects[towerName].Child:PauseAnim()
  end
end
function AnimateTowerForward(realm, speed)
  speed = speed or 2
  if realm == "Midgard" then
    realm = "Vanaheim"
  end
  if RealmIsUnlocked(realm) then
    local towerName = "rt_mini_tower_" .. realm
    if GameObjects[towerName].Child.AnimFrame ~= GameObjects[towerName].Child.AnimLengthFrames then
      GameObjects[towerName].Child:PlayAnimToEnd(speed)
    end
  end
end
function AnimateTowerReverse(realm)
  local towerName
  if realm == "Midgard" then
    towerName = "rt_mini_tower_Vanaheim"
  else
    towerName = "rt_mini_tower_" .. realm
  end
  GameObjects[towerName].Child:PlayAnimToEnd(-1)
end
function UpdateRealmSelectionRotation(dir, animRate)
  PlayLocationChangeSound()
  local selRealm = LD.GetSelectedRealm()
  if selRealm == "Midgard" then
    selRealm = "Vanaheim"
  end
  AnimateTowerReverse(selRealm)
  if RealmIsUnlocked(selRealm) then
    HideMiniTowerFX(selRealm, 1)
  end
  local oldGem = thisLevel:FindSingleGameObject("ringGem_" .. selRealm)
  if oldGem ~= nil then
    oldGem:PlayAnimToEnd(-3)
  end
  local newRealm, currentSelectionIndex
  local realmInfo = LD.GetRealmInfo()
  local realmNames = realmInfo.names
  for i = 1, #realmNames do
    if selRealm == realmNames[i] then
      currentSelectionIndex = i
      break
    end
  end
  if dir == "right" then
    if currentSelectionIndex == 1 then
      LD.SetSelectedRealm(realmNames[#realmNames])
      newRealm = realmNames[#realmNames]
    else
      LD.SetSelectedRealm(realmNames[currentSelectionIndex - 1])
      newRealm = realmNames[currentSelectionIndex - 1]
    end
  elseif dir == "left" then
    if currentSelectionIndex == #realmNames then
      LD.SetSelectedRealm(realmNames[1])
      newRealm = realmNames[1]
    else
      LD.SetSelectedRealm(realmNames[currentSelectionIndex + 1])
      newRealm = realmNames[currentSelectionIndex + 1]
    end
  end
  AnimateTowerForward(newRealm)
  local newGem = thisLevel:FindSingleGameObject("ringGem_" .. newRealm)
  if newGem ~= nil and RealmIsUnlocked(newRealm) then
    LD.CallFunctionAfterDelay(function()
      newGem:PlayAnimToEnd(1)
    end, 0.75)
  end
  local correctedRate = GetCorrectedRotationRate(animRate, selectionRing, realmInfo.frames[newRealm])
  if selRealm == "Vanaheim" and newRealm == "Jotunheim" then
    selectionRing:PlayAnimToFrame(2880, math.abs(correctedRate))
    miniTemple_Rotation:PlayAnimToFrame(2880, math.abs(correctedRate))
    PlaySoundTableRotationLoop(2880)
  else
    selectionRing:PlayAnimToFrame(realmInfo.frames[newRealm], correctedRate)
    miniTemple_Rotation:PlayAnimToFrame(realmInfo.frames[newRealm], correctedRate)
    PlaySoundTableRotationLoop(realmInfo.frames[newRealm])
  end
  FireRealmSelectionChangedEvents(newRealm)
  Event_OnRealmSelectionChanged()
  if onSelectionChanged ~= nil then
    LD.ExecuteCallbacksForEvent(thisObj.Level, thisObj, onSelectionChanged, "Realm Selection Changed Event")
  end
  if game.Level.GetVariable("CompletedCineNumber") <= 200 and newRealm == "Alfheim" then
    player:TriggerMoveEvent("kLENewRealmUnlocked")
    DisablePlayerInput()
    if player:HasMarker(tutorialMarkers.ROTATE_TABLE) then
      player:RemoveMarker(tutorialMarkers.ROTATE_TABLE)
    end
  end
end
function OnRealmSelectionChanged(fn)
  if realmSelectionChangedEvents == nil then
    realmSelectionChangedEvents = {}
  end
  realmSelectionChangedEvents[#realmSelectionChangedEvents + 1] = fn
end
function FireRealmSelectionChangedEvents(newRealm)
  if realmSelectionChangedEvents ~= nil then
    for _, fn in pairs(realmSelectionChangedEvents) do
      fn(newRealm)
    end
  end
end
function OnLockedRealmAttempt(fn)
  if lockedRealmAttemptEvents == nil then
    lockedRealmAttemptEvents = {}
  end
  lockedRealmAttemptEvents[#lockedRealmAttemptEvents + 1] = fn
end
function FireLockedRealmAttemptEvents()
  if lockedRealmAttemptEvents ~= nil then
    for _, fn in pairs(lockedRealmAttemptEvents) do
      fn(LD.GetSelectedRealm())
    end
  end
end
local regrowDelay = 1
function PressurePlateTriggered_Vanaheim()
  CheckPressurePlateState("Vanaheim", currentPressurePlate)
end
function PressurePlateTriggered_Svartalfheim()
  CheckPressurePlateState("Svartalfheim", currentPressurePlate)
end
function PressurePlateTriggered_Muspelheim()
  CheckPressurePlateState("Muspelheim", currentPressurePlate)
end
function PressurePlateTriggered_Niflheim()
  CheckPressurePlateState("Niflheim", currentPressurePlate)
end
function PressurePlateTriggered_Jotunheim()
  CheckPressurePlateState("Jotunheim", currentPressurePlate)
end
function PressurePlateTriggered_Helheim()
  CheckPressurePlateState("Helheim", currentPressurePlate)
end
function PressurePlateTriggered_Asgard()
  CheckPressurePlateState("Asgard", currentPressurePlate)
end
function PressurePlateTriggered_Alfheim()
  CheckPressurePlateState("Alfheim", currentPressurePlate)
end
function CheckPressurePlateState(newRealm)
  if PressurePlatesActive() and currentPressurePlate ~= newRealm then
    LD.CallFunctionAfterDelay(function()
      if player:InsideZone(GameObjects["pp_" .. newRealm].Child) then
        TriggerRegrowSequence_Retract(newRealm)
      end
    end, regrowDelay)
  end
end
function PressurePlatesActive()
  local completedCineNumber = LD.GetEntityVariable("CompletedCineNumber")
  local templeFlipped = LD.GetEntityVariable("CAL_TempleFlipped")
  if not (not (210 <= completedCineNumber) or templeFlipped) or templeFlipped and completedCineNumber >= cineNumber_TalismanAcquire then
    return true
  end
  return false
end
function TriggerRegrowSequence_Retract(newRealm)
  if son:InsideZone(GameObjects.SonRootBridgeCheck) then
    CheckPressurePlateState(newRealm)
  else
    ResetPreviousPressurePlate()
    currentPressurePlate = newRealm
    AnimateCurrentPressurePlate()
    if GameObjects.worldTreeBridge00_P.LuaObjectScript.IsRetracted() then
      TriggerRegrowSequence_Grow()
    else
      GameObjects.worldTreeBridge00_P.LuaObjectScript.Retract(-5)
      GameObjects.worldTreeBridge00_P.Child:OnAnimationDone(thisObj, "TriggerRegrowSequence_Grow", {Force = true})
    end
  end
end
function TriggerRegrowSequence_Grow()
  GameObjects.worldTreeBridge00_P.Child:ClearAllAnimCallbacks()
  GameObjects.rootBridgeDirectionControl:HideCollision()
  SetRootBridgeFacing(currentPressurePlate)
  GameObjects.rootBridgeDirectionControl:ShowCollision()
  GameObjects.worldTreeBridge00_P.LuaObjectScript.Extend(3)
end
function DoorOpened_ResetPressurePlates()
  local realm = LD.GetSelectedRealm()
  ResetPressurePlatesAndRootBridgeToRealmDirection(realm)
  local completedCineNumber = game.Level.GetVariable("CompletedCineNumber")
  if 205 <= completedCineNumber then
    AnimateRootBridge_OnEnterRoom(2.5, 3)
  end
end
function DoorOpened_Asgard_Custom()
  local completedCineNum = game.Level.GetVariable("CompletedCineNumber")
  if completedCineNum < cineNumber_TalismanAcquire then
    GameObjects.worldTreeBridge00_P.LuaObjectScript.Reset()
  else
    DoorOpened_ResetPressurePlates()
  end
end
function DoorFullyOpened_Asgard_Custom()
  GameObjects.RealmTravelDoor_Asgard.LuaObjectScript.CloseDoorAndDisable()
end
function ResetPressurePlatesAndRootBridgeToRealmDirection(realm)
  ResetAllPressurePlates()
  if realm == "Midgard" then
    realm = "Vanaheim"
  end
  currentPressurePlate = realm
  GameObjects["pp_" .. realm].Child:JumpAnimToFrame(GameObjects["pp_" .. realm].Child.AnimLengthFrames)
  GameObjects["pp_" .. realm].Child:PauseAnim()
  SetRootBridgeFacing(currentPressurePlate)
  GameObjects.worldTreeBridge00_P.LuaObjectScript.Reset()
end
function Callscript_AnimateRootBridge_Intro(level, obj)
  AnimateRootBridge_OnEnterRoom(1.25)
end
function AnimateRootBridge_OnEnterRoom(animRate, delay)
  animRate = animRate or 1
  delay = delay or 0
  LD.CallFunctionAfterDelay(function()
    GameObjects.worldTreeBridge00_P.LuaObjectScript.Extend(animRate)
  end, delay)
end
function ResetAllPressurePlates()
  for _, realm in pairs(LD.GetRealmInfo().names) do
    if realm == "Midgard" then
      realm = "Vanaheim"
    end
    GameObjects["pp_" .. realm].Child:PlayAnimToEnd(-1)
  end
end
function ResetPreviousPressurePlate()
  if currentPressurePlate ~= nil then
    GameObjects["pp_" .. currentPressurePlate].Child:PlayAnimToEnd(-1)
  end
end
function AnimateCurrentPressurePlate()
  GameObjects["pp_" .. currentPressurePlate].Child:PlayAnimToEnd(1)
  LD.AddControllerRumble({Effect = "FFB_SMALL", Duration = 1})
end
function SetRootBridgeFacing(realm)
  realm = realm or LD.GetSelectedRealm()
  if realm == "Midgard" then
    realm = "Vanaheim"
  end
  LD.SetFacingTowardObject(GameObjects.rootBridgeDirectionControl, GameObjects[realm .. "Direction"])
end
function RealmTravelComplete()
  local curRealm = LD.GetCurrentRealm()
  LD.SetRealmDiscovered(curRealm)
  if curRealm == "Midgard" then
    currentPressurePlate = "Vanaheim"
  else
    currentPressurePlate = curRealm
  end
  if curRealm == "Muspelheim" then
    LD.SetEntityVariable("MUS_EntryBanterTriggered", false)
  end
  if game.Level.GetVariable("CompletedCineNumber") <= 200 then
    game.Level.SetVariable("CompletedCineNumber", 205)
  end
  LD.SetEntityVariable("CAL_RealmChanged", true)
  EvaluateQuestObjectives(curRealm)
end
function Show_SelectedLoadZone()
  local zoneName
  if game.Level.GetVariable("CompletedCineNumber") == 470 then
    zoneName = "Helheim_Return1"
  else
    zoneName = LD.GetCurrentRealm() .. "_Realm_Travel_Room"
  end
  local currentLoadZone = loadZones:FindSingleGOByName(zoneName)
  currentLoadZone:ShowEntityVolume()
  game.EvaluateLoadZones()
end
function OnEvaluateLoadGroup_RealmTravel()
  if state == states.STATE_REALM_TRAVEL then
    return "RealmTravelActive"
  else
    if jotunheimFailActive then
      return "RealmTravelActive"
    end
    return "RealmTravelInactive"
  end
end
function HideAll_LoadZones()
  if loadZones ~= nil then
    for i = 1, #loadZones.Descendants do
      loadZones.Descendants[i]:HideEntityVolume()
    end
  end
end
function SetBridgeAlignmentImmediate(selRealm)
  selRealm = selRealm or LD.GetBridgePosition()
  local frame = LD.GetRealmFrame(selRealm)
  controllerPlatform:JumpAnimToFrame(frame)
  controllerPlatform:PauseAnim()
  miniTemple_Rotation:JumpAnimToFrame(frame)
  miniTemple_Rotation:PauseAnim()
  selectionRing:JumpAnimToFrame(frame)
  selectionRing:PauseAnim()
end
function SetBridgeAlignment(selRealm, frame, rate)
  selRealm = selRealm or LD.GetBridgePosition()
  frame = frame or LD.GetRealmFrame(selRealm)
  rate = rate or LD.GetCorrectedBridgeAnimRate(controllerPlatform, selRealm)
  if rate == 0 then
    SetBridgeAlignmentImmediate(selRealm)
  else
    controllerPlatform:PlayAnimToFrame(frame, rate)
    miniTemple_Rotation:PlayAnimToFrame(frame, rate)
    if LD.GetCurrentRealm() == "Midgard" or state ~= states.STATE_REALM_TRAVEL then
      selectionRing:PlayAnimToFrame(frame, rate)
    end
    game.Blender.Trigger({
      Name = "FSE_SWAY_CRANK_RUMBLE_SMALL",
      Duration = 50,
      TweenIn = {Time = 0},
      TweenOut = {Time = 0.25}
    })
    game.Blender.Trigger({
      Name = "FFB_GENERIC_RUMBLE_LOW",
      Duration = 50,
      TweenIn = {Time = 0},
      TweenOut = {Time = 0.25}
    })
    PlayMapRotationLoop()
    controllerPlatform:OnAnimationDone(thisObj, "OnBridgeAlignedToTravelRealm", {Force = true})
  end
end
function RequestBridgeAlignmentUpdate(realm, rate)
  if not rate then
    rate = 3
    local newFrame = LD.GetRealmFrame(realm)
    local currentFrame = selectionRing.AnimFrame
    local maxFrame = 2880
    local halfMax = 1440
    local diff = newFrame - currentFrame
    local halfFrame = selectionRing.AnimLengthFrames / 2
    if diff < 0 and diff > -halfMax or 0 < diff and diff > halfFrame then
      rate = -1 * rate
    end
  end
  LD.SetBridgePosition(realm, rate)
  GameObjects.worldTreeBridge00_P.LuaObjectScript.Retract(-6)
end
function GetCurrentPressurePlate()
  return currentPressurePlate
end
function GetCurrentAnimrate()
  return animRate
end
function GetCorrectedRotationRate(speed, rotObj, newFrame)
  local rate = math.abs(speed)
  local maxFrame = rotObj.AnimLengthFrames
  local halfMax = maxFrame / 2
  local diff = newFrame - rotObj.AnimFrame
  if diff < 0 and diff > -halfMax or 0 < diff and halfMax < diff then
    rate = rate * -1
  end
  return rate
end
function GetRealmFrameValue(realmName)
  return LD.GetRealmInfo().frames[realmName]
end
function GetInteract()
  return realmControllerInteract
end
function DisableTable()
  realmControllerInteract:Disable()
end
function EnableTable()
  realmControllerInteract:Enable()
end
function EnablePlayerInput()
  game.UI.Idle(false, false)
end
function DisablePlayerInput()
  game.UI.Idle(true, false)
end
function LockTable()
  realmControllerInteract:Lock()
  game.Level.SetVariable("CAL_RealmTravelAvailable", false)
end
function UnlockTable()
  realmControllerInteract:Unlock()
  game.Level.SetVariable("CAL_RealmTravelAvailable", true)
end
function EnableCinematicTrigger()
  triggerCinematic = true
end
function DisableCinematicTrigger()
  triggerCinematic = false
end
function ShowTravelCollision()
  GameObjects.travelCollision:ShowCollision()
end
function HideTravelCollision()
  GameObjects.travelCollision:HideCollision()
end
function ShowRootBridgeCollision()
  GameObjects.rootCollision:ShowCollision()
end
function HideRootBridgeCollision()
  GameObjects.rootCollision:HideCollision()
end
function ShowOutterWallCollision(realmDirection)
  realmDirection = realmDirection or LD.GetSelectedRealm()
  if realmDirection == "Midgard" then
    realmDirection = "Vanaheim"
  end
  GameObjects["bridgeCollision_" .. realmDirection]:ShowCollision()
end
function HideOutterWallCollision(realmDirection)
  realmDirection = realmDirection or LD.GetSelectedRealm()
  if realmDirection == "Midgard" then
    realmDirection = "Vanaheim"
  end
  GameObjects["bridgeCollision_" .. realmDirection]:HideCollision()
end
function ShowOutterWallCollision_All()
  for _, name in pairs(LD.GetRealmInfo().names) do
    GameObjects["bridgeCollision_" .. name]:ShowCollision()
  end
end
function UnlockSelectedRealmDoor(Immediate, PlayLightAnim)
  if Immediate == nil then
    Immediate = false
  end
  local completedCineNumber = LD.GetEntityVariable("CompletedCineNumber")
  local selRealm = LD.GetSelectedRealm()
  local allRealms = {"Midgard"}
  for _, realm in pairs(LD.GetRealmInfo().names) do
    allRealms[#allRealms + 1] = realm
  end
  for _, realm in pairs(allRealms) do
    if LD.GetCurrentRealm() ~= "Jotunheim" and realm == selRealm and WaitForHelheimReturnCompletion(completedCineNumber) == false then
      if realm == "Midgard" then
        realm = "Vanaheim"
      end
      local door = thisLevel:FindSingleGameObject("RealmTravelDoor_" .. realm)
      if door ~= nil then
        if LD.GetEntityVariable("CAL_TempleFlipped") and completedCineNumber < cineNumber_TalismanAcquire or completedCineNumber <= cineNumber_FirstInteract then
          LockDoor(door)
        else
          UnlockDoor(door, PlayLightAnim)
        end
      end
    elseif selRealm == "Midgard" and realm ~= "Vanaheim" or selRealm ~= "Midgard" then
      local door = thisLevel:FindSingleGameObject("RealmTravelDoor_" .. realm)
      if door ~= nil then
        LockDoor(door)
      end
    end
  end
end
function UnlockDoor(door, PlayLightAnim)
  door.LuaObjectScript.StartGlow(nil, PlayLightAnim)
  door.LuaObjectScript.Enable()
  local cineNum = game.Level.GetVariable("CompletedCineNumber")
  if 200 <= cineNum and cineNum <= 205 then
    door.LuaObjectScript.DisableOutterPrompt()
  end
  if 610 <= cineNum and LD.GetCurrentRealm() == "Midgard" then
    door.Child.LuaObjectScript.Unlock()
  end
end
function LockDoor(door)
  if LD.GetCurrentRealm() == "Jotunheim" and door == GameObjects.RealmTravelDoor_Jotunheim then
    door.LuaObjectScript.Disable()
    local cineNumber = game.Level.GetVariable("CompletedCineNumber")
    if cineNumber == 570 and door.LuaObjectScript.IsOpen() == false then
      door.LuaObjectScript.StartGlow(nil, true)
    end
  else
    door.LuaObjectScript.CloseDoorAndDisable()
    door.LuaObjectScript.EnableOutterPrompt()
    door.LuaObjectScript.DisableInnerPrompt()
    door.LuaObjectScript.StopGlow()
  end
end
function WaitForHelheimReturnCompletion(completedCineNumber)
  if 494 <= completedCineNumber and completedCineNumber <= 500 and LD.GetCurrentRealm() == "Helheim" then
    return true
  end
  return false
end
function InJotunheimAfterCompletion(completedCineNumber)
  if LD.GetCurrentRealm() == "Jotunheim" and 610 <= completedCineNumber then
    return true
  end
  return false
end
function ResetDoorGlow(realm, immediate)
  immediate = immediate or false
  if realm == "Midgard" then
    realm = "Vanaheim"
  end
  local door = thisLevel:FindSingleGameObject("RealmTravelDoor_" .. realm)
  if door then
    door.LuaObjectScript.StopGlow(immediate)
  end
end
function ShowDebugTable()
  if engine.IsDebug() then
    local debugTable = {}
    debugTable.Title = "Realm Controller Info"
    debugTable.Y = 10
    debugTable.TitleColor = engine.Vector.New(255, 0, 128)
    debugTable[#debugTable + 1] = {
      "Current Realm: ",
      LD.GetCurrentRealm()
    }
    debugTable[#debugTable + 1] = {
      "Selected Realm: ",
      LD.GetSelectedRealm()
    }
    debugTable[#debugTable + 1] = {
      "Initially selected Realm: ",
      initiallySelectedRealm
    }
    debugTable[#debugTable + 1] = {
      "Current State: ",
      state
    }
    debugTable[#debugTable + 1] = {""}
    debugTable[#debugTable + 1] = {
      "Previously Unlocked:"
    }
    for _, realm in pairs(LD.GetRealmInfo().names) do
      debugTable[#debugTable + 1] = {
        "  " .. realm .. ": ",
        tostring(RealmIsDiscoveredOnTable(realm))
      }
    end
    debugTable[#debugTable + 1] = {
      "Previously Unlocked (Enity):"
    }
    debugTable[#debugTable + 1] = {
      "  Midgard: ",
      tostring(game.Level.GetVariable("CAL_RealmDiscovered_Midgard"))
    }
    debugTable[#debugTable + 1] = {
      "  Jotunheim: ",
      tostring(game.Level.GetVariable("CAL_RealmDiscovered_Jotunheim"))
    }
    debugTable[#debugTable + 1] = {
      "  Alfheim: ",
      tostring(game.Level.GetVariable("CAL_RealmDiscovered_Alfheim"))
    }
    debugTable[#debugTable + 1] = {
      "  Helheim: ",
      tostring(game.Level.GetVariable("CAL_RealmDiscovered_Helheim"))
    }
    debugTable[#debugTable + 1] = {
      "  Niflheim: ",
      tostring(game.Level.GetVariable("CAL_RealmDiscovered_Niflheim"))
    }
    debugTable[#debugTable + 1] = {
      "  Muspelheim: ",
      tostring(game.Level.GetVariable("CAL_RealmDiscovered_Muspelheim"))
    }
    debugTable[#debugTable + 1] = {
      "Total Events (Enity): " .. tostring(game.Level.GetVariable("CAL_RealmTravel_EventsTriggered"))
    }
    debugTable[#debugTable + 1] = {""}
    debugTable[#debugTable + 1] = {
      "Narrative lock active: ",
      narrativeLock
    }
    engine.DrawDebugTable(debugTable)
  end
end
local ObjectiveActions = {
  {
    ActiveQuest = "Quest_Alfheim_Objective750",
    RequiredRealm = "Midgard",
    Action = "Complete"
  },
  {
    ActiveQuest = "Quest_Helheim_Objective021",
    RequiredRealm = "Midgard",
    Action = "Complete"
  },
  {
    ActiveQuest = "Quest_Helheim_Objective005",
    RequiredRealm = "Helheim",
    Action = "Complete"
  },
  {
    ActiveQuest = "Quest_Foothills_Objective503",
    RequiredRealm = "Alfheim",
    Action = "Complete"
  },
  {
    ActiveQuest = "Quest_Caldera_Objective670",
    RequiredRealm = "Midgard",
    Action = "Complete"
  }
}
function EvaluateQuestObjectives(realm)
  for _, v in ipairs(ObjectiveActions) do
    if v ~= nil and v.ActiveQuest ~= nil and realm == v.RequiredRealm then
      local questState = game.QuestManager.GetQuestState(v.ActiveQuest)
      if questState == "Active" then
        game.QuestManager.ProposeQuestState(v.ActiveQuest, v.Action)
      end
    end
  end
  if LD.GetEntityVariable("CompletedCineNumber") < 195 or LD.GetEntityVariable("CompletedCineNumber") > 210 and JotunheimFailStateConditionsMet() == false then
    game.Compass.SetDesignerForcedHide(false)
  end
end
function OnSaveCheckpoint(level, obj)
  return {
    currentPressurePlate = currentPressurePlate,
    firstJotunheimAttempt = firstJotunheimAttempt,
    jotReveal = jotReveal,
    narrativeLock = narrativeLock
  }
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  currentPressurePlate = savedInfo.currentPressurePlate
  firstJotunheimAttempt = savedInfo.firstJotunheimAttempt
  jotReveal = savedInfo.jotReveal or false
  narrativeLock = savedInfo.narrativeLock or false
end
local soundEmitter
local playedOnOnce = false
local playedOffOnce = false
function SoundInit()
  soundEmitter = thisObj:FindSingleSoundEmitterByName("SNDRealmTravelTable")
end
function PlayNameOnSound()
  if playedOnOnce == false then
    LD.PlaySound(soundEmitter, "SND_MAG_Realm_Room_Map_Location_Name_On")
    playedOnOnce = true
    playedOffOnce = false
  end
end
function PlayNameOffSound()
  if playedOffOnce == false then
    LD.PlaySound(soundEmitter, "SND_MAG_Realm_Room_Map_Location_Name_Off")
    playedOnOnce = false
    playedOffOnce = true
  end
end
function PlayLocationChangeSound()
  LD.PlaySound(soundEmitter, "SND_MAG_Realm_Room_Map_Location_Change")
end
function PlaySoundTableRotationLoop(endFrame)
  LD.PlaySound(soundEmitter, "SND_MAG_RealmTravel_Table_Small_Rotate_LP")
  selectionRing:OnAnimDone(thisObj, "StopSoundTableRotationLoop")
end
function StopSoundTableRotationLoop()
  LD.StopSound(soundEmitter, "SND_MAG_RealmTravel_Table_Small_Rotate_LP")
end
function PlaySoundSuccessfulPush()
end
function PlayMapRotationLoop()
  LD.PlaySound(soundEmitter, "SND_MAG_Realm_Room_Map_Rotate_LP")
end
function StopMapRotationLoop()
  LD.StopSound(soundEmitter, "SND_MAG_Realm_Room_Map_Rotate_LP")
end
function PlaySoundTravelActivationLoop()
  LD.PlaySound(soundEmitter, "SND_MAG_Realm_Room_Map_Activate_LP")
end
function StopSoundTravelActivationLoop()
  LD.StopSound(soundEmitter, "SND_MAG_Realm_Room_Map_Activate_LP")
end
function PlaySoundJotMiniTowerRise()
  LD.PlaySoundAfterDelay(soundEmitter, "SND_MAG_Realm_Room_Travel_Jotunheim_Hologram", 0.65)
end
function PlaySoundJotFailBeam()
  fxScript.PlaySoundJotunheimFail()
end
