local statemachine = require("ai.statemachine")
local tablex = require("core.tablex")
local picklelib = require("core.pickle")
local DL = require("design.DesignerLibrary")
local ND = require("design.NarrativeDesignLibrary")
local LD = require("design.LevelDesignLibrary")
local globalLuaHooks = require("design.GlobalLuaHooks")
globalLuaHooks.InstallHooks()
local traverselink = require("creature.traverselink")
traverselink.InstallHooks()
Brain_Core = require("behavior.corebrain")
constants = {}
global = {}
local player
local powerLevel = "1"
local pLevelInt = 1
local bodyType
local detectAggroStateFromSpawnMove = function(ai)
  local spawnContext = ai:GetContext()
  if DL.CheckCreatureContext(spawnContext, "INCOMBAT") then
    global.aggroState = "INCOMBAT"
  elseif DL.CheckCreatureContext(spawnContext, "UNAWARE") then
    global.aggroState = "UNAWARE"
  elseif DL.CheckCreatureContext(spawnContext, "NONHOSTILE") then
    global.aggroState = "NONHOSTILE"
  elseif DL.CheckCreatureContext(spawnContext, "PASSIVE") then
    global.aggroState = "PASSIVE"
  end
end
function OnAIPostSpawn(ai)
  player = game.Player.FindPlayer()
  detectAggroStateFromSpawnMove(ai)
  setupCharacter(ai)
  local positioning = Brain_Core:GetPositioning()
  LD.PlaySound(ai:FindSingleSoundEmitterByName("SNDMouth"), "SND_CHR_Projection_Nav_Idle_LP")
end
function Brain_Core:OnSetPowerlevelOverrideCustom(ai, global, constants, level, isElite, forced)
  powerLevel = level
  ToggleCharacterConfig(ai, forced)
end
function ToggleCharacterConfig(ai, override)
  if powerLevel == "1" then
    pLevelInt = 1
  elseif powerLevel == "2" then
    pLevelInt = 2
  elseif powerLevel == "3" then
    pLevelInt = 3
  elseif powerLevel == "4" then
    pLevelInt = 4
  elseif powerLevel == "5" then
    pLevelInt = 5
  elseif powerLevel == "6" then
    pLevelInt = 6
  elseif powerLevel == "7" then
    pLevelInt = 7
  elseif powerLevel == "8" then
    pLevelInt = 8
  else
    pLevelInt = powerLevel
  end
  if bodyType ~= nil then
    if bodyType == "Seidr" then
      global.DTree = "DTR_PROJECTION00_OFFENSIVE"
      if not ai:PickupIsAcquired("Projection_Seidr") then
        ai:PickupAcquire("Projection_Seidr")
      end
      if override ~= nil and override == true then
        if 4 < pLevelInt then
          ai:SetCharacterConfig("Projection_seidr_veryhard")
        else
          ai:SetCharacterConfig("Projection_seidr_moderate")
        end
      end
    elseif bodyType == "Hellwalker" then
      global.DTree = "DTR_PROJECTION00_OFFENSIVE"
      if not ai:PickupIsAcquired("Projection_Helwalker") then
        ai:PickupAcquire("Projection_Helwalker")
      end
      if override ~= nil and override == true then
        if 4 < pLevelInt then
          ai:SetCharacterConfig("Projection_helwalker_veryhard")
        else
          ai:SetCharacterConfig("Projection_helwalker_moderate")
        end
      end
    elseif bodyType == "Freya" then
      global.DTree = "DTR_PROJECTION20_OFFENSIVE"
      if override ~= nil and override == true then
        ai:SetCharacterConfig("Projection_freya")
      end
      if not ai:PickupIsAcquired("Projection_Freya") then
        ai:PickupAcquire("Projection_Freya")
      end
    end
  end
end
function setupCharacter(ai)
  ai:PickupAcquire("Barefoot_MFX_Pickup", 0)
  if StartConfig ~= nil then
    if StartConfig.PowerLevel ~= nil then
      powerLevel = StartConfig.PowerLevel
    end
    if StartConfig.EliteDifficulty ~= nil and StartConfig.EliteDifficulty and not ai:PickupIsAcquired("Projection00_Elite") then
      ai:PickupAcquire("Projection00_Elite")
    end
    if StartConfig.BodyType ~= nil then
      bodyType = StartConfig.BodyType
    end
  end
  ToggleCharacterConfig(ai, not game.CHECK_FEATURE("PREEMPT_SPAWN_CONFIG"))
  DL.NewGamePlusLevelBoost(ai, "Projection00_PowerLevel")
  DL.NewGamePlusLevelBoost(ai, "Projection20_PowerLevel")
end
function OnAIUpdate(ai)
  traverselink.OnUpdate(ai)
end
function _G.OnAICreateLuaState(ai)
  _G.OnAICreateLuaState = nil
end
function Brain_Core:OnEnterCombat(ai, global, constants)
end
function Brain_Core:OnUpdateCombat(ai, global, constants)
  if global.targetParams == "FIND_TARGET_PARAMETERS_COMBAT_BALDUR_ONLY" then
    ai:SetProximityWeight(10)
  end
  if Brain_Core:GetDebugTable(ai) then
    local debugTable = {}
    Brain_Core:AddCustomDebugTable(debugTable)
  end
end
function Brain_Core:OnBroadcastReaction(event, ai, global, constants)
end
function Brain_Core:OnDeath(ai, attacker, deathByDespawn)
end
function LuaHook_StopProjectionLoop(ai, data)
  LD.StopSound(ai:FindSingleSoundEmitterByName("SNDMouth"), "SND_CHR_Projection_Nav_Idle_LP")
end
function LuaHook_Evade_CollisionCheck(ai, data)
  return DL.LuaHook_Evade_CollisionCheckShared(ai, data, 10, false)
end
function LuaHook_ClearArrow(ai, data)
  game.Combat.RemoveArrows(ai)
  ai:Hide()
end
function LuaHook_TargetBaldur()
  if global.targetParams ~= "FIND_TARGET_PARAMETERS_COMBAT_BALDUR_ONLY" then
    global.targetParams = "FIND_TARGET_PARAMETERS_COMBAT_BALDUR_ONLY"
  end
end
function LuaHook_TargetKratos()
  if global.targetParams ~= "FIND_TARGET_PARAMETERS_COMBAT_KRATOS_ONLY" then
    global.targetParams = "FIND_TARGET_PARAMETERS_COMBAT_KRATOS_ONLY"
  end
end
function LuaHookDecision_IsTargetInSynchMove()
  if DL.CheckCreatureContext(global.target:GetContext(), "PROJECTION_GRAB") == true then
    return true
  else
    return false
  end
end
function LuaHookDecision_IsPlayerInSynchMove()
  if player:IsDoingSyncMove() then
    return true
  else
    return false
  end
end
function LuaHookDecision_IsBaldurInSynchMove()
  for c in game.Creature.IterateAllCreatures() do
    local creatureName = c:GetName()
    if creatureName == "baldur00" then
      local baldurCreature = c
      if baldurCreature:IsDoingSyncMove() then
        return true
      else
        return false
      end
    end
  end
end
function LuaHook_AddBlood_Cleave_Impact(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kHead, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftChest, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightChest, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kFrontAbdomen, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontUpperArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLowerArm, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontUpperArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLowerArm, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLeg, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLeg, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBack, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBack, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kBackAbdomen, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackUpperArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLowerArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightBackUpperArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLowerArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLeg, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLeg, 0.1)
end
function LuaHook_AddBlood_Projection_RageEnter(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kHead, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftChest, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightChest, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kFrontAbdomen, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontUpperArm, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLowerArm, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kLeftBack, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBack, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kBackAbdomen, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackUpperArm, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLowerArm, 0.6)
end
function LuaHook_AddBlood_Projection_RageKill(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kHead, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kLeftChest, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kRightChest, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kFrontAbdomen, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontUpperArm, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLowerArm, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontUpperArm, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLowerArm, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLeg, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLeg, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftBack, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightBack, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kBackAbdomen, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackUpperArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLowerArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightBackUpperArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLowerArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLeg, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLeg, 0.2)
end
function LuaHook_AddBlood_Projection_Explode(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kHead, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kLeftChest, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kRightChest, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kFrontAbdomen, 1)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontUpperArm, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLowerArm, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontUpperArm, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLowerArm, 0.8)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLeg, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLeg, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftBack, 1)
  player:AddBlood(game.GameObject.eRegionId.kRightBack, 1)
  player:AddBlood(game.GameObject.eRegionId.kBackAbdomen, 1)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackUpperArm, 1)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLowerArm, 1)
  player:AddBlood(game.GameObject.eRegionId.kRightBackUpperArm, 1)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLowerArm, 1)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLeg, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLeg, 0.4)
end
function LuaHookDecision_CanSplitPoolCheck(ai, data)
  local canSplit
  local pool = game.AI.PoolCount(ai.Level, "CRT_Projection00")
  if pool == 0 then
    canSplit = false
  else
    canSplit = true
  end
  return canSplit
end
function LuaHook_SummonProjection(ai, data)
  local spawnJointIndex = ai:GetJointIndex("zerojoint")
  local navPos
  local spawnPos = ai:GetWorldJointPosition(spawnJointIndex) + ai:GetWorldForward() * 2.5
  navPos = game.NavMesh.ClosestPoint(spawnPos)
  if navPos ~= nil then
    local summonedProjection = game.AI.Spawn(ai.Level, navPos, ai:GetWorldForward(), "CRT_Projection00", "BRA_SpawnInCombat", {PowerLevel = powerLevel, BodyType = bodyType})
    game.Encounters.AddSpawnToEncounter(ai, summonedProjection)
  end
end
function LuaHook_SplitProjection_Flyback(ai, data)
  if ai:PickupIsAcquired("Projection00_Elite") then
    ai:PickupRelinquish("Projection00_Elite")
  end
  local spawnJointIndex = ai:GetJointIndex("zerojoint")
  local navPos, navPos2
  local spawnPos = ai:GetWorldJointPosition(spawnJointIndex) + ai:GetWorldLeft() * 0.25 - ai:GetWorldForward() * 1
  local spawnPos2 = ai:GetWorldJointPosition(spawnJointIndex) - ai:GetWorldLeft() * 0.25 - ai:GetWorldForward() * 1
  local playerForward = player:GetWorldForward() * -1
  local aiForward = ai:GetWorldForward()
  local pool = game.AI.PoolCount(ai.Level, "CRT_Projection00")
  if pool == 0 then
    return
  elseif pool == 1 then
    navPos = game.NavMesh.ClosestPoint(spawnPos)
    navPos2 = nil
  else
    navPos = game.NavMesh.ClosestPoint(spawnPos)
    navPos2 = game.NavMesh.ClosestPoint(spawnPos2)
  end
  if navPos ~= nil then
    local charConfig = GetSummonedAllyConfigString(pLevelInt)
    local splitProjection = game.AI.Spawn(ai.Level, navPos, playerForward, "CRT_Projection00", "BRA_SpawnSplitFlyback", {PowerLevel = pLevelInt, BodyType = bodyType}, charConfig)
    game.Encounters.AddSpawnToEncounter(ai, splitProjection)
  end
  if navPos2 ~= nil then
    local charConfig = GetSummonedAllyConfigString(pLevelInt)
    local splitProjection2 = game.AI.Spawn(ai.Level, navPos2, playerForward, "CRT_Projection00", "BRA_SpawnSplitFlyback", {PowerLevel = pLevelInt, BodyType = bodyType}, charConfig)
    game.Encounters.AddSpawnToEncounter(ai, splitProjection2)
  end
end
function GetSummonedAllyConfigString(pLevelInt)
  local charConfig
  if bodyType == "Seidr" then
    if 4 < pLevelInt then
      charConfig = "Projection_seidr_veryhard"
    else
      charConfig = "Projection_seidr_moderate"
    end
  elseif bodyType == "Hellwalker" then
    if 4 < pLevelInt then
      charConfig = "Projection_helwalker_veryhard"
    else
      charConfig = "Projection_helwalker_moderate"
    end
  end
  if charConfig ~= nil then
    return charConfig
  end
end
picklelib.Install()
function Pickle(GO)
  return {
    global = global
  }
end
function Unpickle(GO, t)
  global = t.global
end
