local EC = require("design.Encounter")
local LD = require("design.LevelDesignLibrary")
local monitors = require("level.MonitorLibrary")
local timers = require("level.timer")
local checkpoint = require("level.checkpoint")
local CCOS = require("camera.camera_oneshot")
local CSL = require("camera.shakelibrary")
local player, son, thisLevel, wheelFree, wheelStuck, gateGroup, BoatBlocker_WaterWheel, HiddenClimb_01
local chainsBroken = false
local BrokenRoot_Gates_001
local blockDropped = false
local shipRuneRead = false
local Prologue_1_Encounter_1, Prologue_1_Encounter_2, Area_1_Encounter_1, Area_1_Encounter_2, Area_2_Encounter_1, Area_3_Encounter_1, Area_4_Encounter_1, Area_5_Encounter_1, Repop_A1E1, Repop_A2E1, ZM_A1_E1_Start, ZM_A1_E1_Start2, Jotunn_Wander_HealthMonitor, Traveler_Fight_Start, camOneShot_LookAtWheel, camOneShot_LookAtGates
local cameraExitChainRecenter = {
  TimeStart = 0,
  TimeDuration = 1.3,
  LockRecenter = 0.46,
  YawRange = -1,
  TriggerLeft = 120,
  ReturnLeft = 110,
  ReturnRight = 100,
  TriggerRight = 90,
  PitchRange = -1,
  TriggerUp = 6,
  ReturnUp = 0,
  ReturnDown = -6,
  TriggerDown = -10,
  RotationSpace = 1
}
local musOnceThru = false
function OnScriptLoaded(level)
  thisLevel = level
  player = game.Player.FindPlayer()
  son = game.AI.FindSon()
  HiddenClimb_01 = level:GetGameObject("HiddenClimb_01")
  BoatBlocker_WaterWheel = level:GetGameObject("BoatBlocker_WaterWheel")
  wheelFree = level:GetGameObject("wheelGroup_Free")
  wheelStuck = level:GetGameObject("wheelGroup_Stuck")
  gateGroup = level:GetGameObject("wheelTurnPuzzle")
  BrokenRoot_Gates_001 = level:GetGameObject("BrokenRoot_Gates_001")
  Witch_Prologue_1_()
  Witch_Prologue_2_()
  Helwalker_Area_1_()
  Helwalker_LedgeClimb()
  Area_2_()
  Area_3_()
  Area_4_()
  Area_5_()
  Repop_Area_1()
  Repop_Area_2()
  SoundInit()
  GameObjects.ChainPull_xx01xx.LuaObjectScript.OverrideCameraInteractApproach("ENV_Crank_Approach_RightJustified")
  GameObjects.ChainPull_xx01xx.LuaObjectScript.OverrideDefaultCameraRecenter(true, cameraExitChainRecenter)
  GameObjects.ChainPull_xx01xx.LuaObjectScript.OverrideDefaultCameraPitch(true, -7)
  GameObjects.ChainPull_xx01xx.LuaObjectScript.OverrideDefaultCameraYaw(true, 108)
  game.Audio.StartMusicMaster("SND_MX_XPL300_start_master")
end
function LoadCheck_stronghold()
  game.UI.LoadCheck("Xpl350_Stronghold")
end
function OnFirstStart(level)
  gateGroup:JumpAnimToFrame(0)
  gateGroup:PauseAnim()
  wheelStuck:PlayAnimCycle(1)
  HiddenClimb_01:Hide()
  BoatBlocker_WaterWheel:Hide()
  BrokenRoot_Gates_001:Hide()
  GameObjects.LiftGate3.LuaObjectScript.ExcludeSon()
  GameObjects.LiftGate4.LuaObjectScript.ExcludeSon()
  GameObjects.LiftGate5.LuaObjectScript.ExcludeSon()
end
function OnStart(level)
  if chainsBroken then
    gateGroup:JumpAnimToPercent(1)
  end
  if Area_4_Encounter_1:WasRunning() then
    Area_4_Encounter_1:OnEnemySpawn(function(enemy)
      LD.CallFunctionAfterDelay(function()
        enemy:ForceMove("BRA_CAAttack_SwordVertical")
      end, 0.5)
      Area_4_Encounter_1:StartWave(2)
      LD.CallFunctionAfterDelay(function()
        Area_4_Encounter_1:AlertEnemies(1)
      end, 2)
    end, {
      markerID = "Traveler_Boat"
    })
  end
  SetupShipRuneRead()
  SoundOnStart()
  GameObjects.LiftGate3.LuaObjectScript.SetAllowSyncWithSonNotAvailable()
  GameObjects.LiftGate4.LuaObjectScript.SetAllowSyncWithSonNotAvailable()
  GameObjects.LiftGate5.LuaObjectScript.SetAllowSyncWithSonNotAvailable()
  PatchQuestFixup()
end
function OnUpdate(level)
  if camOneShot_LookAtWheel ~= nil then
    camOneShot_LookAtWheel:Update()
  end
  if camOneShot_LookAtGates ~= nil then
    camOneShot_LookAtGates:Update()
  end
  if Area_2_Encounter_1 and Area_2_Encounter_1:IsRunning() and player:IsPlayingMove("MOV_CSRageGrabJotunnEnter") then
    Area_2_Encounter_1:StartWave()
  end
end
function BoatBlocker_WaterWheel_CoL_Show()
  BoatBlocker_WaterWheel:Show()
end
function BoatBlocker_WaterWheel_CoL_Hide()
  BoatBlocker_WaterWheel:Hide()
end
function HiddenClimb()
  GameObjects.HiddenClimb_01:Show()
end
function ValidateBreakable(breakableRefnode)
  local breakableRef = breakableRefnode:FindSingleGOByName("Breakable")
  if breakableRef ~= nil and breakableRef.LuaObjectScript ~= nil then
    local breakableComponent = breakableRef:GetBreakable()
    if breakableComponent ~= nil and breakableComponent.Broken == false then
      return true
    end
  end
  return false
end
function EnableBifrostVibrate()
  if ValidateBreakable(GameObjects.BifrostVibrate_Fractured) == true then
    GameObjects.BifrostVibrate_Fractured:FindSingleGOByName("Breakable").LuaObjectScript.Enable()
  end
end
function EnableBifrostVibrate_ChestArea()
  if ValidateBreakable(GameObjects.BifrostVibrate_Fractured3_xx) == true then
    GameObjects.BifrostVibrate_Fractured3_xx:FindSingleGOByName("Breakable").LuaObjectScript.Enable()
  end
end
function StoreCheckpoint()
  game.World.StoreCheckpoint()
end
function PatchQuestFixup()
  local fatherSonScroll = game.Wallets.GetResourceValue("HERO", "Sindri02_FatherSon_Lore")
  local fatherSonQuest = game.QuestManager.GetQuestState("Quest_SecretBusiness02_Parent")
  if fatherSonScroll == 1 and fatherSonQuest == "Inactive" then
    LD.ActivateQuest("Quest_SecretBusiness02_Parent")
    local uiCalls = require("ui.uicalls")
    uiCalls.UI_Event_SendMsgToQuestLog({
      Category = 13956,
      Header = 13957,
      Body = 13959,
      MessageType = tweaks.tQuestUiMessage.eMessageType.kQMS_Default,
      Quest = "Quest_SecretBusiness02_Objective01"
    })
  end
end
function DropBlock()
  if blockDropped == false then
    GameObjects.EnvironmentEventEmitter_Falling_ClimberRock_01.LuaObjectScript.DisableAwarenessRemotely()
    Falling_ClimberRock_ShakeRumble()
    GameObjects.CA_Observe_DropBlock.LuaObjectScript.Disable()
    GameObjects.Stim_DropBlock_Interest.LuaObjectScript.Trigger()
    blockDropped = true
  end
end
function Enable_WaterWheel_Contexts()
  SetExploreContext()
  GameObjects.CA_WaterWheel_Sync.LuaObjectScript.Enable()
  GameObjects.LTW_WaterWheel_01.LuaObjectScript.Enable()
  GameObjects.CA_WaterWheel_Turret_01.LuaObjectScript.Enable()
  GameObjects.CA_WaterWheel_Turret_02.LuaObjectScript.Enable()
end
function Disable_WaterWheel_Contexts()
  SetClearAllContext()
  GameObjects.CA_WaterWheel_Sync.LuaObjectScript.Disable()
  GameObjects.LTW_WaterWheel_01.LuaObjectScript.Disable()
  GameObjects.CA_WaterWheel_Turret_01.LuaObjectScript.Disable()
  GameObjects.CA_WaterWheel_Turret_02.LuaObjectScript.Disable()
end
function Toggle_ChainCA()
  if chainsBroken == false then
    GameObjects.CA_Puzzled_Chain.LuaObjectScript.Enable()
  elseif chainsBroken == true then
    GameObjects.CA_ObserveFar_BigGate.LuaObjectScript.Enable()
  end
end
function Disable_ChainCA()
  GameObjects.CA_Puzzled_Chain.LuaObjectScript.Disable()
  GameObjects.CA_ObserveFar_BigGate.LuaObjectScript.Disable()
end
function Enable_BrazierArena_Contexts()
  if blockDropped == false then
    GameObjects.CA_Observe_DropBlock.LuaObjectScript.Enable()
  end
  GameObjects.CA_Brazier_WarmHands_01.LuaObjectScript.Enable()
  GameObjects.CA_Brazier_WarmHands_02.LuaObjectScript.Enable()
  GameObjects.CA_Brazier_Squat.LuaObjectScript.Enable()
  GameObjects.LTW_BrazierArena.LuaObjectScript.Enable()
  GameObjects.EnvironmentEventEmitter_BigGate_01.LuaObjectScript.DisableAwarenessRemotely()
  SetExploreContext()
  Big_WaterWheelLookAt_Stop()
end
function Disable_BrazierArena_Contexts()
  GameObjects.CA_Observe_DropBlock.LuaObjectScript.Disable()
  GameObjects.CA_Brazier_WarmHands_01.LuaObjectScript.Disable()
  GameObjects.CA_Brazier_WarmHands_02.LuaObjectScript.Disable()
  GameObjects.CA_Brazier_Squat.LuaObjectScript.Disable()
  GameObjects.LTW_BrazierArena.LuaObjectScript.Disable()
  SetBoatContext()
end
function Enable_UpperDock_Contexts()
  GameObjects.CA_ObserveFar_Ship.LuaObjectScript.Enable()
  GameObjects.CA_LedgeSit.LuaObjectScript.Enable()
end
function Xpl300_GateOpen()
  GameObjects.xpl300_gateBreak01.Child:GetBreakable():Break()
end
function SetBoatContext()
  son:CallScript("EnterBehaviorContext", "BOAT_CONTEXT_CONFIG_RIGHT")
end
function SetExploreContext()
  son:CallScript("EnterBehaviorContext", "WAIT_AND_EXPLORE_BEHAVIOR_CONTEXT_CONFIG")
end
function SetClearAllContext()
  son:CallScript("ClearBehaviorContext")
end
function Big_GatesLookAt_Start()
  GameObjects.EnvironmentEventEmitter_BigGate_01.LuaObjectScript.EnableAwarenessRemotely()
end
function Big_WaterWheelLookAt_Start()
  GameObjects.EnvironmentEventEmitter_BigWaterWheel_01.LuaObjectScript.EnableAwarenessRemotely()
end
function Big_WaterWheelLookAt_Stop()
  GameObjects.EnvironmentEventEmitter_BigWaterWheel_01.LuaObjectScript.DisableAwarenessRemotely()
end
function Falling_ClimberRock_Start()
  GameObjects.EnvironmentEventEmitter_Falling_ClimberRock_01.LuaObjectScript.EnableAwarenessRemotely()
end
function Falling_ClimberRock_ShakeRumble()
  timers.StartLevelTimer(0.6, function()
    CSL.PlayShake("FSE_SHAKE_GENERIC_GIANT", 2.5, 0, 0)
    game.Blender.Trigger({
      Name = "FFB_GENERIC_RUMBLE_STRONG",
      Duration = 0.5,
      TweenIn = {Time = 0},
      TweenOut = {Time = 0.5},
      Priority = 2
    })
  end)
end
function EnableSonGate()
  GameObjects.GenericSonInteract_crawlThrough.LuaObjectScript.Enable()
end
function SetupShipRuneRead()
  local fakeRunes = thisLevel:FindGameObjects("shipRune_Fake*")
  for _, v in pairs(fakeRunes) do
    v.Child:JumpAnimToFrame(0)
    v.Child:PauseAnim()
  end
end
function PlayShipRuneRead()
  local fakeRunes = thisLevel:FindGameObjects("shipRune_Fake*")
  if shipRuneRead == false then
    for _, v in pairs(fakeRunes) do
      v.Child:PlayAnimToEnd()
      shipRuneRead = true
    end
  end
end
function AxeHitChains()
  chainsBroken = true
  GameObjects.CA_Puzzled_Chain.LuaObjectScript.Disable()
  GameObjects.Stim_Celebrate_BigGate.LuaObjectScript.Trigger()
  gateGroup:PlayAnimToEnd()
  wheelStuck:PauseAnim()
  wheelFree:PlayAnimCycle(2.5)
  PlayWaterWheelGateOpenLoops()
  PlayWaterWheelLoops()
  xpl300PlayGateOpenMusic()
  GameObjects.TraverseLink1WheelPuzzle:HideTraverseLink()
  GameObjects.CA_ObserveFar_BigGate.LuaObjectScript.Enable()
  LD.CallFunctionAfterDelay(function()
    Area_1_Encounter_2:Start()
  end, 14)
  game.World.StoreCheckpoint()
  StartSlowWalk()
  LookAtWheel()
  timers.StartLevelTimer(3, LookAtGates)
  timers.StartLevelTimer(10, ClearSlowWalk)
end
function Hidden_area()
  GameObjects.HiddenArea_Collision:HideCollision()
end
function Hidden_area_02_CoL_Show()
  GameObjects.HiddenArea_Collision1:HideCollision()
end
function BridgeArea_Collision_Hide()
  CSL.PlayShake("FSE_SHAKE_GENERIC_MEDIUM", 2.5, 0, 0)
  game.Blender.Trigger({
    Name = "FFB_GENERIC_RUMBLE_STRONG",
    Duration = 0.5,
    TweenIn = {Time = 0},
    TweenOut = {Time = 0.5},
    Priority = 2
  })
  GameObjects.BridgeArea_Collision:HideCollision()
  GameObjects.BridgeDrop_SpinSystem.LuaObjectScript.SetPermLock()
end
function FinalChest_Collision_Hide()
  GameObjects.FinalChest_Collision:HideCollision()
end
function BrokenRoot_Gates_001_Show()
  BrokenRoot_Gates_001:Show()
end
function AreaAnnounce_StongHold()
  local uiCalls = require("ui.uicalls")
  uiCalls.UI_Event_DiscoverLocation("HuldraStronghold")
end
function Witch_Prologue_1_()
  Prologue_1_Encounter_1 = EC.NewEncounter(thisLevel, "Witch Prologue 1", {CheckpointOnComplete = false})
  Prologue_1_Encounter_1:AddWave({
    {
      spawners = "Witch_10_SPA",
      spawnLocators = "P_Loc_1",
      useSpawnLocatorsOnly = true,
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0.1
    }
  })
  Prologue_1_Encounter_1:SetStartZone(GameObjects.EntZn_Witch_Prologue)
end
function Witch_Prologue_2_()
  Prologue_1_Encounter_2 = EC.NewEncounter(thisLevel, "Witch Prologue 2", {CheckpointOnComplete = false})
  Prologue_1_Encounter_2:AddWave({
    {
      spawners = "Witch_10_SPB",
      spawnLocators = "P_Loc_2",
      useSpawnLocatorsOnly = true,
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0.1
    }
  })
  Prologue_1_Encounter_2:SetStartZone(GameObjects.EntZn_Witch_Prologue2)
  Prologue_1_Encounter_2:OnStart(function()
    Prologue_1_Encounter_1:DespawnEnemies(1)
  end)
end
function Helwalker_Area_1_()
  local powerLevel
  local cineNumber = game.Level.GetVariable("CompletedCineNumber")
  if 375 <= cineNumber and cineNumber <= 599 then
    powerLevel = 4
  elseif 600 <= cineNumber then
    powerLevel = 5
  end
  Area_1_Encounter_1 = EC.NewEncounter(thisLevel, "[Area 1]Helwalker Fight", {
    AutoResetOnReload = true,
    CheckpointOnComplete = true,
    LeashZone = "LeashZoneXpl300_2",
    LodLow = 44,
    LodHigh = 50
  })
  Area_1_Encounter_1:AddWave({
    powerLevel = powerLevel,
    {
      spawners = "Bandit_00_SA",
      spawnLocators = "A1_G_Loc_1",
      markerID = "BanditRunA",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0.1
    },
    {
      spawners = "Bandit_00_SB",
      spawnLocators = "A1_G_Loc_2",
      markerID = "BanditRunB",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0.6
    }
  })
  Area_1_Encounter_1:AddWave({
    powerLevel = powerLevel,
    {
      spawners = "Fanatic_00_SC",
      spawnLocators = "A1B_Loc_*",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 2,
      totalSpawns = 2,
      spawnCooldown = 0.4
    },
    {
      spawners = "Bandit_00_SFG",
      spawnLocators = "A1_Loc_*",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 1
    }
  })
  Area_1_Encounter_1:AddWave({
    {
      spawners = "Witch_10_SPC",
      spawnLocators = "P_Loc_3",
      useSpawnLocatorsOnly = true,
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0.1,
      powerLevel = powerLevel
    }
  })
  Area_1_Encounter_1:SetStartZone(GameObjects.EntZn_Arena_1_Encounter_Spawn)
  Area_1_Encounter_1:OnStart(function()
    Prologue_1_Encounter_2:DespawnEnemies(1)
  end)
  Area_1_Encounter_1:OnEnemyDeath(function()
    Area_1_Encounter_1:StartWave(3)
  end, {count = 4})
  ZM_A1_E1_Start = monitors.CreateEntityZoneMonitor(player, GameObjects.EntZn_Arena_1_Encounter_Start)
  ZM_A1_E1_Start:OnEnter(function()
    local thisAIA = LD.FindSingleAIByMarker("BanditRunA")
    local thisAIB = LD.FindSingleAIByMarker("BanditRunB")
  end)
  ZM_A1_E1_Start2 = monitors.CreateEntityZoneMonitor(player, GameObjects.EntZn_Arena_1_Encounter_Start2)
  ZM_A1_E1_Start2:OnEnter(function()
    Area_1_Encounter_1:StartWave(2)
  end)
end
function Helwalker_LedgeClimb()
  local powerLevel
  local cineNumber = game.Level.GetVariable("CompletedCineNumber")
  if 375 <= cineNumber and cineNumber <= 599 then
    powerLevel = 4
  elseif 600 <= cineNumber then
    powerLevel = 5
  end
  Area_1_Encounter_2 = EC.NewEncounter(thisLevel, "[Area 1]Helwalker Fight Ledge", {
    AutoResetOnReload = true,
    CheckpointOnComplete = true,
    LeashZone = "LeashZoneXpl300_2",
    LodLow = 38,
    LodHigh = 48
  })
  Area_1_Encounter_2:AddWave({
    powerLevel = powerLevel,
    {
      spawners = "Bandit_00_SFL",
      spawnLocators = "A1L_Loc_1",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0
    },
    {
      spawners = "Bandit_00_SFL",
      spawnLocators = "A1L_Loc_2",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0.7
    }
  })
end
function Area_2_()
  local powerLevel
  local cineNumber = game.Level.GetVariable("CompletedCineNumber")
  if 375 <= cineNumber and cineNumber <= 599 then
    powerLevel = 4
  elseif 600 <= cineNumber then
    powerLevel = 5
  end
  Area_2_Encounter_1 = EC.NewEncounter(thisLevel, "[Area 2]EC:1 Fight Xpl300", {
    AutoResetOnReload = true,
    CheckpointOnComplete = true,
    LeashZone = "LeashZoneXpl300_1",
    LodLow = 38,
    LodHigh = 48
  })
  Area_2_Encounter_1:AddWave({
    powerLevel = powerLevel,
    {
      spawners = "Jotunn_10_Wander",
      markerID = "Jotunn_Wander",
      spawnLocators = "A2_U_Loc_1",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0.1
    },
    {
      spawners = "Brawler_00_SRC",
      spawnLocators = "A2_O_Loc_5",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0.1
    }
  })
  Area_2_Encounter_1:AddWave({
    {
      spawners = "Bandit_00_SRF",
      spawnLocators = "A2_O_Loc_6",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 2,
      powerLevel = powerLevel
    }
  })
  Area_2_Encounter_1:AddWave({
    triggerWaveFromScript = true,
    {
      spawners = "Bandit_00_SRF",
      spawnLocators = "A2_O_Loc_6",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 1,
      powerLevel = powerLevel
    }
  })
  Area_2_Encounter_1:AddWave({
    triggerWaveFromScript = true,
    {
      spawners = "Bandit_00_SRF",
      spawnLocators = "A2_O_Loc_6",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 2,
      totalSpawns = 2,
      spawnCooldown = 2,
      powerLevel = powerLevel
    }
  })
  Area_2_Encounter_1:SetStartZone(GameObjects.EntZn_Arena_2_Encounter_Start)
  Area_2_Encounter_1:OnStart(function()
    ZM_A1_E1_Start = monitors.CreateEntityZoneMonitor(player, GameObjects.EntZn_Arena_2_Encounter_Start2)
    ZM_A1_E1_Start:OnEnter(function()
      Area_2_Encounter_1:AlertEnemies(1)
    end)
  end)
  Area_2_Encounter_1:OnEnemySpawn(Jotunn_Wander_Health_Encounter, {
    markerID = "Jotunn_Wander"
  })
end
local Jotunn_Next = function()
  Area_2_Encounter_1:StartWave()
end
function Jotunn_Wander_Health_Encounter(Enemy)
  if Enemy ~= nil then
    local Jotunn_Health = Enemy:GetHitPoints()
    Jotunn_Wander_HealthMonitor = monitors.CreateHealthMonitor(Enemy)
    local Health_Phase_1 = Jotunn_Health * 0.9
    local Health_Phase_2 = Jotunn_Health * 0.5
    local Health_Phase_3 = Jotunn_Health * 0.2
    Jotunn_Wander_HealthMonitor:OnHealthLessThan(Health_Phase_1, Jotunn_Next)
    Jotunn_Wander_HealthMonitor:OnHealthLessThan(Health_Phase_2, Jotunn_Next)
    Jotunn_Wander_HealthMonitor:OnHealthLessThan(Health_Phase_3, Jotunn_Next)
  end
end
function Area_3_()
  local powerLevel
  local cineNumber = game.Level.GetVariable("CompletedCineNumber")
  if 375 <= cineNumber and cineNumber <= 599 then
    powerLevel = 4
  elseif 600 <= cineNumber then
    powerLevel = 5
  end
  Area_3_Encounter_1 = EC.NewEncounter(thisLevel, "[Area 3]EC:1 Fight Xpl300", {CheckpointOnComplete = true})
  Area_3_Encounter_1:AddWave({
    powerLevel = powerLevel,
    {
      spawners = "Flyer_00_SFG",
      spawnLocators = "A3_Loc_4",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0
    },
    {
      spawners = "Flyer_00_SFG",
      spawnLocators = "A3_Loc_6",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0.4
    },
    {
      spawners = "Wolf_00_P_SR",
      spawnLocators = "A3_LocW",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0
    }
  })
  Area_3_Encounter_1:SetStartZone(GameObjects.EntZn_Arena_3_Encounter_Start)
end
function Area_4_()
  local powerLevel
  local cineNumber = game.Level.GetVariable("CompletedCineNumber")
  if 375 <= cineNumber and cineNumber <= 599 then
    powerLevel = 4
  elseif 600 <= cineNumber then
    powerLevel = 5
  end
  Area_4_Encounter_1 = EC.NewEncounter(thisLevel, "[Area 4]EC:1 Fight Xpl300", {
    AutoResetOnReload = true,
    CheckpointOnComplete = true,
    CheckpointOverrideObject = GameObjects.CheckpointOverride_SindriQuest2,
    StartMusic = "SND_MX_XPL300_fight20_in",
    StopMusic = "SND_MX_XPL300_fight20_out"
  })
  Area_4_Encounter_1:AddWave({
    {
      spawners = "Traveler_Ber_S",
      markerID = "Traveler_Boat",
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 1,
      powerLevel = powerLevel
    }
  })
  Area_4_Encounter_1:AddWave({
    triggerWaveFromScript = true,
    powerLevel = powerLevel,
    {
      spawners = "Fanatic_00_SS",
      spawnLocators = "A4_Loc_9",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 1
    },
    {
      spawners = "Fanatic_00_SS",
      spawnLocators = "A4_Loc_11",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 1
    }
  })
  Traveler_Fight_Start = monitors.CreateEntityZoneMonitor(player, GameObjects.EntZn_Arena_4_Encounter_Spawn)
  Traveler_Fight_Start:OnEnter(function()
    Area_4_Encounter_1:Start()
    LD.CallFunctionAfterDelay(function()
      local thisAIC = LD.FindSingleAIByMarker("Traveler_Boat")
      if thisAIC ~= nil then
        thisAIC:ForceMove("BRA_CAAttack_SwordVertical")
        Area_4_Encounter_1:StartWave(2)
        LD.CallFunctionAfterDelay(function()
          Area_4_Encounter_1:AlertEnemies(1)
        end, 2)
        GameObjects.Cine_SindriQuest2.LuaObjectScript.TravellerAttackStart()
      end
    end, 67)
  end)
  Area_4_Encounter_1:OnComplete(function()
    PostBoatFightBanter()
    EnableBifrostVibrate_ChestArea()
  end)
end
function Area_5_()
  local powerLevel
  local cineNumber = game.Level.GetVariable("CompletedCineNumber")
  if 375 <= cineNumber and cineNumber <= 599 then
    powerLevel = 4
  elseif 600 <= cineNumber then
    powerLevel = 5
  end
  Area_5_Encounter_1 = EC.NewEncounter(thisLevel, "[Area 5]EC:1 Fight Xpl300", {CheckpointOnComplete = true})
  Area_5_Encounter_1:AddWave({
    powerLevel = powerLevel,
    {
      spawners = "Bandit_00_SLVSH",
      spawnLocators = "A5_Loc_U_4",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0
    },
    {
      spawners = "Bandit_00_SFGSW",
      spawnLocators = "A5_Loc_O_7",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 3
    },
    {
      spawners = "Flyer_00_SFG",
      spawnLocators = "A5_Loc_O_6",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 1
    },
    {
      spawners = "Flyer_00_SFG",
      spawnLocators = "A5_Loc_O_4",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 2
    }
  })
  Area_5_Encounter_1:SetStartZone(GameObjects.EntZn_Arena_5_Encounter_Start)
  Area_5_Encounter_1:OnStart(function()
    GameObjects.deathplane_level1:HideCollision()
  end)
  Area_5_Encounter_1:OnStart(function()
    GameObjects.CA_LowerDocks_Turret_01.LuaObjectScript.Enable()
  end)
  Area_5_Encounter_1:OnComplete(function()
    GameObjects.deathplane_level1:ShowCollision()
  end)
  Area_5_Encounter_1:OnComplete(function()
    GameObjects.CA_LowerDocks_Turret_01.LuaObjectScript.Disable()
  end)
end
function Repop_Area_1()
  Repop_A1E1 = EC.NewEncounter(thisLevel, "[Repop Area 1]Helwalker Fight", {
    CheckpointOnComplete = false,
    LeashZone = "LeashZoneXpl300_2",
    RepopulationEncounter = true,
    MustHaveCompletedList = {
      "[Area 1]Helwalker Fight",
      "[Area 5]EC:1 Fight Xpl300"
    }
  })
  Repop_A1E1:AddWave({
    timeBeforeNextWave = 7,
    {
      spawners = "T6_Witch_10_SPC",
      spawnLocators = "P_Loc_3",
      useSpawnLocatorsOnly = true,
      maxActive = 1,
      totalSpawns = 1,
      spawnCooldown = 0.1
    }
  })
  Repop_A1E1:AddWave({
    {
      spawners = "T5_Bandit_00_SFG",
      spawnLocators = "A1_Loc_*",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 2,
      totalSpawns = 2,
      spawnCooldown = 1
    }
  })
  Repop_A1E1:SetStartZone(GameObjects.EntZn_Arena_1_Encounter_Start2)
end
function Repop_Area_2()
  Repop_A2E1 = EC.NewEncounter(thisLevel, "Repop [Area 2]", {
    CheckpointOnComplete = false,
    LeashZone = "LeashZoneXpl300_1",
    RepopulationEncounter = true,
    MustHaveCompletedList = {
      "[Area 2]EC:1 Fight Xpl300",
      "[Area 5]EC:1 Fight Xpl300"
    }
  })
  Repop_A2E1:AddWave({
    {
      spawners = "T6_Bandit_00_SRF",
      spawnLocators = "A2_O_Loc_6",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 2,
      totalSpawns = 3,
      initialSpawnAmount = 1,
      initialSpawnCooldown = 0,
      spawnCooldown = 4
    },
    {
      spawners = "T5_Bandit_E_SRF",
      spawnLocators = "A2_O_Loc_6",
      useSpawnLocatorsOnly = true,
      spawnWad = "Xpl300_AI",
      maxActive = 1,
      totalSpawns = 1,
      initialSpawnAmount = 1,
      initialSpawnCooldown = 2,
      spawnCooldown = {3, 7}
    }
  })
  Repop_A2E1:SetStartZone(GameObjects.EntZn_Repop_A2E1)
end
function BanterStrongholdEntranceCheck()
  local questState = game.QuestManager.GetQuestState("Quest_Sindri_Epic_02_Objective_01")
  if questState == "Active" then
    return true
  else
    return false
  end
end
function BanterGateLockedCheck()
  local questState = game.QuestManager.GetQuestState("Quest_Sindri_Epic_02_Objective_01")
  if questState == "Active" then
    return true
  else
    return false
  end
end
function CompleteObjective01()
  LD.CompleteQuest("Quest_Sindri_Epic_02_Objective_01")
end
function CompleteObjective01Safety()
  LD.CompleteQuest("Quest_Sindri_Epic_02_Objective_01")
end
function CompleteObjective02()
  LD.CompleteQuest("Quest_Sindri_Epic_02_Objective_02")
end
function BanterGateUnlockedCheck()
  local questState = game.QuestManager.GetQuestState("Quest_Sindri_Epic_02_Objective_03")
  if questState == "Active" then
    return true
  else
    return false
  end
end
function BanterWhatHappenedCheck()
  local questState = game.QuestManager.GetQuestState("Quest_Sindri_Epic_02_Objective_03")
  if questState == "Active" then
    return true
  else
    return false
  end
end
function CompleteObjective03()
  LD.CompleteQuest("Quest_Sindri_Epic_02_Objective_03")
  game.SubObject.SoftSave()
  game.Audio.StartMusic("SND_MX_XPL300_approach_ship")
end
function CompleteObjective03_Failsafe()
  LD.CompleteQuest("Quest_Sindri_Epic_02_Objective_03")
end
function PostBoatFightBanter()
  game.Audio.PlayBanter("Sindri02_LeftBehind")
end
function PlayRuneReadBanter()
  game.Audio.PlayBanter("Sindri02_RuneRead01")
end
function ShowDebugTable()
  local debugTable = {}
  debugTable.Title = "Xpl300 Info"
  debugTable.X = 50
  debugTable.Y = 10
  debugTable.TitleColor = engine.Vector.New(255, 0, 128)
  debugTable[#debugTable + 1] = {
    "chainsBroken: ",
    chainsBroken
  }
  debugTable[#debugTable + 1] = {
    "wheelFree: ",
    wheelFree.AnimFrame
  }
  engine.DrawDebugTable(debugTable)
end
function CompleteObjective05()
  local questState = game.QuestManager.GetQuestState("Quest_Sindri_Epic_02_Objective_05")
  if questState == "Active" then
    LD.CompleteQuest("Quest_Sindri_Epic_02_Objective_05")
    game.Compass.SetGatewayMarkerIsOpen("SH_300_Helper29", false)
  end
end
function CompleteObjective06()
  local questState = game.QuestManager.GetQuestState("Quest_Sindri_Epic_02_Objective_06")
  if questState == "Active" then
    LD.CompleteQuest("Quest_Sindri_Epic_02_Objective_06")
  end
end
function BanterSecretBusinessQuest()
  game.Audio.PlayBanter("Sindri02_FoundDiary", StartSecretBusiness02)
end
function StartSecretBusiness02()
  local uiCalls = require("ui.uicalls")
  uiCalls.UI_Event_SendMsgToQuestLog({
    Category = 13956,
    Header = 13957,
    Body = 13959,
    MessageType = tweaks.tQuestUiMessage.eMessageType.kQMS_Default,
    Quest = "Quest_SecretBusiness02_Objective01"
  })
end
local WaterWheelEmitter, wheelCreakEmitters, wheelGateEmitters, wheelSloshEmitter, splashEmitter
local xpl300Music = false
local xpl300approachMusic = false
local WaterWheelSoundEvents = {
  OnSpinAxle = "SND_MECH_Waterwheel_Lrg_Rotate_Axle_End_LP_Xpl300",
  OnSpinWheel = "SND_MECH_Waterwheel_Lrg_Rotate_Ring_LP_Xpl300",
  OnSpinSlosh = "SND_MECH_Waterwheel_Water_Near_Splash_Slosh_LP"
}
local bridgeDropSoundEmitter
local bridgeDropSoundEvent = "SND_MECH_Wood_Bridge_Drop_Xpl300"
function SoundInit()
  WaterWheelEmitter = GameObjects.wheelGroup_Free.SoundEmitters[1]
  wheelCreakEmitters = GameObjects.SNDWheelCreakGrp.SoundEmitters
  wheelGateEmitters = GameObjects.SNDWheelGateGrp.SoundEmitters
  wheelSloshEmitter = GameObjects.SNDGrpWaterWheelSlosh.SoundEmitters[1]
  splashEmitter = GameObjects.SNDGrpJumpThroughWater:FindSingleSoundEmitterByName("SNDJumpThroughWater")
  bridgeDropSoundEmitter = GameObjects.drawBridgeObj.SoundEmitters[1]
end
function SoundOnStart()
  if chainsBroken then
    PlayWaterWheelLoops()
  end
  GameObjects.QuestLoreMarker:FindSingleGOByName("pSonReadRune").LuaObjectScript.LoreMarkerRuneReadSoundSetup()
  GameObjects.SonBoostDoor_01.LuaObjectScript.SoundSetup({EndFrame = 50})
end
function PlayWaterWheelLoops()
  LD.PlayRestartableSoundLoop(WaterWheelEmitter, WaterWheelSoundEvents.OnSpinAxle)
  LD.PlayRestartableSoundLoop(wheelSloshEmitter, WaterWheelSoundEvents.OnSpinSlosh)
  for i = 1, #wheelCreakEmitters do
    LD.PlayRestartableSoundLoop(wheelCreakEmitters[i], WaterWheelSoundEvents.OnSpinWheel)
  end
end
function StopWaterWheelLoop()
  LD.StopSound(WaterWheelEmitter, WaterWheelSoundEvents.OnSpinAxle)
end
function PlayWaterWheelGateOpenLoops()
  for i = 1, #wheelGateEmitters do
    LD.PlaySound(wheelGateEmitters[i], "SND_MECH_Waterwheel_Gate_Lift_LP")
    LD.StopSoundOnFrame(wheelGateEmitters[i], gateGroup, "SND_MECH_Waterwheel_Gate_Lift_LP", 370, "forward")
  end
end
function PlaySoundBridgeDropOnAddImpulse()
  if GameObjects.drawBridgeObj.AnimFrame == 0 then
    LD.PlaySound(bridgeDropSoundEmitter, bridgeDropSoundEvent)
  end
end
function audioWaterSplash()
  LD.PlaySound(splashEmitter, "SND_AMB_EMIT_Water_Jump_Through")
end
function xple300EnterMusic()
  if xpl300approachMusic == false then
    game.Audio.StartMusic("SND_MX_XPL300_approach_sindri")
    xpl300approachMusic = true
  elseif xpl300approachMusic == true and musOnceThru == true and xpl300Music == false then
    game.Audio.StartCheckpointedMusic("SND_MX_XPL300_explore2_in")
    xpl300Music = true
  end
end
function xpl300Dock1Music()
  game.Audio.StartCheckpointedMusic("SND_MX_XPL300_explore2_in")
end
function xpl300AfterSindriCavernMusic()
  game.Audio.StartMusic("SND_MX_XPL300_enter_cavern")
end
function xpl300BigGateRoomMusic()
  if xpl300Music == false then
    game.Audio.StartCheckpointedMusic("SND_MX_XPL300_explore2_in")
    xpl300Music = true
  end
end
function xpl300FastTravelMusic()
  game.Audio.StartCheckpointedMusic("SND_MX_XPL300_explore2_in")
  xpl300Music = true
end
function xpl300ReturnToSindriMusic()
  if xpl300Music == true then
    game.Audio.StartMusic("SND_MX_XPL300_explore2_out")
    musOnceThru = true
  end
end
function xpl300ExitMusic()
  if xpl300Music == true then
    game.Audio.StartMusic("SND_MX_XPL300_idle")
    xpl300Music = false
  end
end
function xpl300PlayGateOpenMusic()
  game.Audio.StartCheckpointedMusic("SND_MX_XPL300_gate_open")
end
function DestroyOneShot_LookAtWheel()
  camOneShot_LookAtWheel = nil
end
function DestroyOneShot_LookAtGates()
  camOneShot_LookAtGates = nil
end
function LookAtWheel()
  game.Blender.Trigger({
    Name = "FFB_GENERIC_RUMBLE_LOW",
    Duration = 6,
    TweenIn = {Time = 5},
    TweenOut = {Time = 6},
    Priority = 2
  })
  camOneShot_LookAtWheel = CCOS.OneShotCamera.New("PLYR_NAR_Vista_Xpl300_WheelFree_Wheel", 6)
  camOneShot_LookAtWheel:SetCallback(DestroyOneShot_LookAtWheel)
  camOneShot_LookAtWheel:Start()
end
function LookAtGates()
  camOneShot_LookAtGates = CCOS.OneShotCamera.New("PLYR_NAR_Vista_Xpl300_WheelFree_Gate", 7)
  camOneShot_LookAtGates:SetCallback(DestroyOneShot_LookAtGates)
  camOneShot_LookAtGates:Start()
end
function StartSlowWalk()
  local player = game.Player.FindPlayer()
  player:SetMaxSpeedOverride(1.5)
end
function ClearSlowWalk()
  local player = game.Player.FindPlayer()
  player:ClearMaxSpeedOverride()
end
function DisableBoatLoreEnteringXpl300()
  LD.DisableBoatLoreWithoutStoryTime()
end
function EnableBoatLoreExitingXpl300()
  LD.EnableBoatLoreWithoutStoryTime(45)
end
function OnSaveCheckpoint(level)
  return {
    levelstate = checkpoint.Save(),
    chainsBroken = chainsBroken,
    blockDropped = blockDropped,
    xpl300approachMusic = xpl300approachMusic,
    musOnceThru = musOnceThru
  }
end
function OnRestoreCheckpoint(level, savedInfo)
  checkpoint.Restore(savedInfo.levelstate)
  chainsBroken = savedInfo.chainsBroken
  blockDropped = savedInfo.blockDropped
  xpl300approachMusic = savedInfo.xpl300approachMusic
  musOnceThru = savedInfo.musOnceThru
end
