local timer = require("level.timer")
local LD = require("design.LevelDesignLibrary")
local DL = require("design.DesignerLibrary")
local bboardUtil = require("game.BlackboardUtil")
local summonedGO, son
local state = "init"
local sequenceState = "init"
local sequenceTimer = 0
local counter = 0
local projectileCount = 18
local projectiles = {}
local originalPosition, originalOrientation, originalLeft
local unitTime = 0.016
local upgradeLevel = 3
local concussionType = "Boar_Collision_Random_"
local spawnMaterialDone = true
local spawnMaterialAnimName = "creatureON"
local summonFXName = "Bifrost_Boar_Spawn"
local trailName = "Bifrost_Boar_Run"
local rumbleParams = {
  EffectName = "FFB_LOOP_MEDIUM",
  Duration = 2.75
}
local rumbleParams2 = {
  EffectName = "FFB_LOOP_MEDIUM",
  Duration = 3.5
}
local rumbleParams3 = {
  EffectName = "FFB_LOOP_MEDIUM",
  Duration = 4.5
}
local shakeParams = {
  EffectName = "FSE_shake_temp_Generic_Medium",
  Duration = 6.5
}
local arrowTypeIsLight = true
local destroyFromScript = false
function OnScriptLoaded(level, go)
  son = game.AI.FindSon()
  if son:PickupIsAcquired("SonArrow_Shock") then
    concussionType = "Boar_Collision_Shock_Random_"
    spawnMaterialAnimName = "creature_shock"
    summonFXName = "SonTeleport_Enter_Shock"
    trailName = "Electric_Boar_Run"
    arrowTypeIsLight = false
  end
  upgradeLevel = game.Wallets.GetResourceValue("HERO", "SummonBoar")
  local hero = game.Player.FindPlayer()
  if hero:PickupIsAcquired("SummonBoar") then
    upgradeLevel = hero:PickupGetStage("SummonBoar") + 1
  end
  if upgradeLevel == nil or upgradeLevel <= 0 then
    upgradeLevel = 1
  end
  originalOrientation = son:GetWorldForward()
  local target = son:GetTargetCreature()
  if target ~= nil then
    originalOrientation = (target.WorldPosition - son.WorldPosition):Normalized()
  end
  originalPosition = son.WorldPosition + originalOrientation * 2
  local navLoc = game.NavMesh.ClosestLocation(originalPosition, son)
  if navLoc ~= nil and navLoc.Position ~= nil then
    originalPosition = navLoc.Position
  end
  originalLeft = son:GetWorldLeft()
end
function OnUpdate(level, go)
  unitTime = level:GetUnitTime()
  SequenceLogic(level, go)
  UpdateBoars(level)
  if sequenceState == "over" and #projectiles <= 0 then
    go:Destroy()
  end
end
function ShootArrowLogic(level, go)
  timer.StartLevelTimer(0.85, function()
    AddProjectile(level, go, -1.25, "randomBurstInit")
    AddProjectile(level, go, 1.25, "randomBurstInit")
  end)
end
function SequenceLogic(level, go)
  if sequenceState == "init" then
    if upgradeLevel == 1 then
      game.FX.SubmitEffect(rumbleParams)
    elseif upgradeLevel == 2 then
      game.FX.SubmitEffect(rumbleParams2)
    else
      game.FX.SubmitEffect(rumbleParams3)
    end
    game.FX.SubmitEffect(shakeParams)
    AddProjectile(level, go, 0, "burstInit")
    sequenceState = "initWait"
    sequenceTimer = 0
  elseif sequenceState == "initWait" then
    sequenceTimer = sequenceTimer + unitTime
    if 0.25 < sequenceTimer then
      sequenceTimer = 0
      sequenceState = "spawnFirstRow"
      AddProjectile(level, go, -1, "burstInit")
      AddProjectile(level, go, 1, "burstInit")
    end
  elseif sequenceState == "spawnFirstRow" then
    sequenceTimer = sequenceTimer + unitTime
    if 0.25 < sequenceTimer then
      sequenceTimer = 0
      sequenceState = "spawnSecondRow"
      AddProjectile(level, go, -2, "burstInit")
      AddProjectile(level, go, 2, "burstInit")
    end
  elseif sequenceState == "spawnSecondRow" then
    sequenceTimer = sequenceTimer + unitTime
    if 0.25 < sequenceTimer then
      sequenceTimer = 0
      sequenceState = "spawnThirdRow"
      AddProjectile(level, go, -3, "burstInit")
      AddProjectile(level, go, 3, "burstInit")
    end
  elseif sequenceState == "spawnThirdRow" then
    sequenceTimer = sequenceTimer + unitTime
    if 0.25 < sequenceTimer then
      sequenceTimer = 0
      sequenceState = "spawnFinalRow"
      AddProjectile(level, go, -4, "burstInit")
      AddProjectile(level, go, 4, "burstInit")
    end
  elseif sequenceState == "spawnFinalRow" then
    sequenceState = "done"
    if upgradeLevel == 1 then
      timer.StartLevelTimer(0.35, function()
        AddProjectile(level, go, 0, "randomBurstInit")
      end)
      timer.StartLevelTimer(0.5, function()
        AddProjectile(level, go, -1.25, "randomBurstInit")
        AddProjectile(level, go, 1.25, "randomBurstInit")
        son:TriggerMoveEvent("kLE_FinishLoop")
        sequenceState = "over"
      end)
    end
    if 1 < upgradeLevel then
      timer.StartLevelTimer(0.35, function()
        AddProjectile(level, go, 0, "randomBurstInit")
      end)
      timer.StartLevelTimer(0.5, function()
        AddProjectile(level, go, -1.25, "randomBurstInit")
        AddProjectile(level, go, 1.25, "randomBurstInit")
      end)
      timer.StartLevelTimer(0.7, function()
        AddProjectile(level, go, 0, "randomBurstInit")
      end)
      timer.StartLevelTimer(0.85, function()
        AddProjectile(level, go, -1.25, "randomBurstInit")
        AddProjectile(level, go, 1.25, "randomBurstInit")
      end)
      timer.StartLevelTimer(1.05, function()
        AddProjectile(level, go, 0, "randomBurstInit")
      end)
      timer.StartLevelTimer(1.2, function()
        AddProjectile(level, go, -1.25, "randomBurstInit")
        AddProjectile(level, go, 1.25, "randomBurstInit")
        if upgradeLevel == 2 then
          son:TriggerMoveEvent("kLE_FinishLoop")
          sequenceState = "over"
        end
      end)
    end
    if 2 < upgradeLevel then
      timer.StartLevelTimer(0.85, function()
        AddProjectile(level, go, -1.25, "randomBurstInit")
        AddProjectile(level, go, 1.25, "randomBurstInit")
      end)
      timer.StartLevelTimer(1.05, function()
        AddProjectile(level, go, 0, "randomBurstInit")
      end)
      timer.StartLevelTimer(1.2, function()
        AddProjectile(level, go, -1.25, "randomBurstInit")
        AddProjectile(level, go, 1.25, "randomBurstInit")
      end)
      timer.StartLevelTimer(1.4, function()
        AddProjectile(level, go, 0, "randomBurstInit")
      end)
      timer.StartLevelTimer(1.55, function()
        AddProjectile(level, go, -1.25, "randomBurstInit")
        AddProjectile(level, go, 1.25, "randomBurstInit")
      end)
      timer.StartLevelTimer(1.75, function()
        AddProjectile(level, go, 0, "randomBurstInit")
      end)
      timer.StartLevelTimer(1.9, function()
        AddProjectile(level, go, -1.25, "randomBurstInit")
        AddProjectile(level, go, 1.25, "randomBurstInit")
        sequenceState = "over"
        son:TriggerMoveEvent("kLE_FinishLoop")
      end)
    end
  end
end
local trailOn = false
function AddProjectile(level, go, offsetAmount, state)
  local son = game.AI.FindSon()
  if not (not destroyFromScript and (son == nil or son:HasMarker("DoNotFollowupPriority"))) or son == nil then
    return
  end
  local boar1 = {}
  local offset = originalLeft * offsetAmount
  boar1.gameObject = game.FX.Spawn("boar01", level)
  boar1.direction = originalOrientation
  boar1.position = originalPosition + offset
  boar1.state = state
  boar1.lifetime = 1
  boar1.timer = 0
  boar1.spawned = false
  if trailOn == true then
    boar1.trail = game.FX.Spawn(trailName, level)
    boar1.trail:SetWorldPosition(boar1.position)
    trailOn = false
  else
    trailOn = true
  end
  boar1.gameObject:SetWorldPosition(boar1.position)
  table.insert(projectiles, boar1)
end
local spawnfxOn = false
function UpdateBoars(level)
  local sizeProjectile = #projectiles
  local yOffset = son.WorldPosition.y
  for i = sizeProjectile, 1, -1 do
    local thisProjectile = projectiles[i]
    if thisProjectile.gameObject == nil then
      thisProjectile.lifeTime = 0
    elseif thisProjectile.state == "init" then
      if thisProjectile.spawned == false then
        thisProjectile.spawned = true
        if spawnfxOn then
          local spawnfx = game.FX.Spawn(summonFXName, level, {AutoDelete = true})
          spawnfx:SetWorldPosition(thisProjectile.position)
          spawnfxOn = false
        else
          spawnfxOn = true
        end
      else
        thisProjectile.gameObject:SetWorldFacing(thisProjectile.direction)
        thisProjectile.gameObject:StartMaterialAnim("navHopStopF")
        thisProjectile.gameObject:ShowJoint(thisProjectile.gameObject:GetJointIndex("boar_stream"))
        thisProjectile.timer = 0
        thisProjectile.state = "introWait"
        thisProjectile.randomSize = 1.65
        thisProjectile.startedMaterialAnim = false
      end
    elseif thisProjectile.state == "introWait" then
      if thisProjectile.startedMaterialAnim == false then
        thisProjectile.startedMaterialAnim = true
        if spawnMaterialDone then
          thisProjectile.gameObject:StartMaterialAnim(spawnMaterialAnimName)
          SoundSpawnBoar(thisProjectile)
        end
      end
      if thisProjectile.gameObject.AnimPercent > 0.9 then
        thisProjectile.state = "burst"
      end
    elseif thisProjectile.state == "randomBurstInit" then
      if spawnfxOn then
        local spawnfx = game.FX.Spawn(summonFXName, level, {AutoDelete = true})
        spawnfx:SetWorldPosition(thisProjectile.position)
        spawnfxOn = false
      else
        spawnfxOn = true
      end
      thisProjectile.rotationSpeed = (math.random() - 0.5) * 60
      thisProjectile.randomSize = math.random() * 0.5 + 0.75
      thisProjectile.state = "randomBurst"
    elseif thisProjectile.state == "randomBurst" then
      if thisProjectile.spawned == false then
        thisProjectile.spawned = true
        thisProjectile.gameObject:ShowJoint(thisProjectile.gameObject:GetJointIndex("boar_stream"))
      else
        local combatCollision = thisProjectile.gameObject:FindSingleGOByName("CombatCollisionManager")
        combatCollision.LuaObjectScript.Enable()
        combatCollision.LuaObjectScript.ChangeCombatCollisionType(concussionType .. math.random(0, 3))
        thisProjectile.gameObject:SetWorldFacing(thisProjectile.direction)
        thisProjectile.gameObject:StartMaterialAnim("navRunF_01")
        thisProjectile.gameObject:SetScale(thisProjectile.randomSize)
        thisProjectile.state = "wildRush"
        thisProjectile.startedMaterialAnim = false
      end
    elseif thisProjectile.state == "wildRush" then
      if thisProjectile.startedMaterialAnim == false then
        thisProjectile.startedMaterialAnim = true
        if spawnMaterialDone then
          thisProjectile.gameObject:StartMaterialAnim(spawnMaterialAnimName)
          SoundSpawnBoar(thisProjectile)
        end
      end
      local position = thisProjectile.position + thisProjectile.direction * 12 * unitTime
      position.y = yOffset
      thisProjectile.gameObject:SetWorldPosition(position)
      thisProjectile.gameObject:SetWorldFacing(thisProjectile.direction)
      thisProjectile.gameObject:SetScale(thisProjectile.randomSize)
      thisProjectile.position = position
      thisProjectile.direction = thisProjectile.direction:RotateXZ(thisProjectile.rotationSpeed * unitTime)
      if thisProjectile.trail ~= nil then
        thisProjectile.trail:SetWorldPosition(thisProjectile.gameObject:GetWorldJointPosition(thisProjectile.gameObject:GetJointIndex("JOHead1")))
      end
    elseif thisProjectile.state == "burstInit" then
      if spawnfxOn then
        local spawnfx = game.FX.Spawn(summonFXName, level, {AutoDelete = true})
        spawnfx:SetWorldPosition(thisProjectile.position)
        spawnfxOn = false
      else
        spawnfxOn = true
      end
      thisProjectile.state = "burst"
      thisProjectile.randomSize = math.random() * 0.5 + 0.75
    elseif thisProjectile.state == "burst" then
      if thisProjectile.spawned == false then
        thisProjectile.spawned = true
        thisProjectile.gameObject:ShowJoint(thisProjectile.gameObject:GetJointIndex("boar_stream"))
      else
        local combatCollision = thisProjectile.gameObject:FindSingleGOByName("CombatCollisionManager")
        combatCollision.LuaObjectScript.Enable()
        combatCollision.LuaObjectScript.ChangeCombatCollisionType(concussionType .. math.random(0, 3))
        thisProjectile.gameObject:SetWorldFacing(thisProjectile.direction)
        thisProjectile.gameObject:SetScale(thisProjectile.randomSize)
        thisProjectile.gameObject:StartMaterialAnim("navRunF_01")
        if thisProjectile.trail ~= nil then
          thisProjectile.trail:SetWorldPosition(thisProjectile.gameObject:GetWorldJointPosition(thisProjectile.gameObject:GetJointIndex("JOHead1")))
        end
        thisProjectile.state = "rush"
        thisProjectile.startedMaterialAnim = false
      end
    elseif thisProjectile.state == "rush" then
      if thisProjectile.startedMaterialAnim == false then
        thisProjectile.startedMaterialAnim = true
        if spawnMaterialDone then
          thisProjectile.gameObject:StartMaterialAnim(spawnMaterialAnimName)
          SoundSpawnBoar(thisProjectile)
        end
      end
      local position = thisProjectile.position + thisProjectile.direction * 12 * unitTime
      position.y = yOffset
      thisProjectile.gameObject:SetWorldPosition(position)
      thisProjectile.position = position
      thisProjectile.gameObject:SetScale(thisProjectile.randomSize)
      if thisProjectile.trail ~= nil then
        thisProjectile.trail:SetWorldPosition(thisProjectile.gameObject:GetWorldJointPosition(thisProjectile.gameObject:GetJointIndex("JOHead1")))
      end
    end
    thisProjectile.lifetime = thisProjectile.lifetime - unitTime
    if 0 >= thisProjectile.lifetime then
      if spawnfxOn then
        local spawnfx = game.FX.Spawn(summonFXName, level, {AutoDelete = true})
        spawnfx:SetWorldPosition(thisProjectile.position)
        spawnfxOn = false
      else
        spawnfxOn = true
      end
      SoundDespawn(thisProjectile)
      if thisProjectile.gameObject ~= nil then
        thisProjectile.gameObject:Destroy()
      end
      if thisProjectile.trail ~= nil then
        thisProjectile.trail:Destroy()
      end
      table.remove(projectiles, i)
    end
  end
end
function DestroySummons()
  local sizeProjectile = #projectiles
  for i = sizeProjectile, 1, -1 do
    local thisProjectile = projectiles[i]
    thisProjectile.lifetime = -1
  end
  destroyFromScript = true
end
function SoundSpawnBoar(boar)
  local goSoundEmitter = boar.gameObject:FindSingleSoundEmitterByName("SNDboar00")
  if arrowTypeIsLight == true then
    LD.PlaySoundRingOut(goSoundEmitter, "SND_CHR_Son_Magic_Summon_Boar_A_Spawn")
    LD.PlaySound(goSoundEmitter, "SND_CHR_Son_Magic_Summon_Boar_A_LP")
  else
    LD.PlaySoundRingOut(goSoundEmitter, "SND_CHR_Son_Magic_Summon_Boar_B_Spawn")
    LD.PlaySound(goSoundEmitter, "SND_CHR_Son_Magic_Summon_Boar_B_LP")
  end
end
function SoundDespawn(boar)
  local goSoundEmitter = boar.gameObject:FindSingleSoundEmitterByName("SNDboar00")
  if arrowTypeIsLight == true then
    LD.PlaySoundRingOut(goSoundEmitter, "SND_CHR_Son_Magic_Dissapate_A")
  else
    LD.PlaySoundRingOut(goSoundEmitter, "SND_CHR_Son_Magic_Dissapate_B")
  end
end
