local statemachine = require("ai.statemachine")
local tablex = require("core.tablex")
local picklelib = require("core.pickle")
local DL = require("design.DesignerLibrary")
local navbranchlogic = require("creature.navBranchLogic_SmallNonStrafe")
local traverselink = require("creature.traverselink")
traverselink.InstallHooks()
local globalLuaHooks = require("design.GlobalLuaHooks")
globalLuaHooks.InstallHooks()
Brain_Core = require("behavior.corebrain")
constants = {}
global = {}
local powerLevel = "1"
function LuaHook_ClearArrow(ai, data)
  game.Combat.RemoveArrows(ai)
end
function LuaHook_CrawlerEvade_CollisionCheck(ai, data)
  local distanceAmount = 5
  local jointIndex = ai:GetJointIndex("zeroJoint")
  local zeroJointFacingFwd = ai:GetWorldJointForward(jointIndex)
  local zeroJointFacingLeft = ai:GetWorldJointLeft(jointIndex)
  local offset = engine.Vector.New(0, 1.5, 0)
  local offsetZeroJoint = ai.WorldPosition + offset
  local toBack = zeroJointFacingFwd * -distanceAmount
  local offsetBack = offsetZeroJoint + toBack
  offsetBack.y = offsetZeroJoint.y
  local hitBack = game.World.RaycastCollision(offsetZeroJoint, offsetBack, {SourceGameObject = ai, FindAnything = true})
  local toLeft = zeroJointFacingLeft * distanceAmount
  local offsetLeft = offsetZeroJoint + toLeft
  offsetLeft.y = offsetZeroJoint.y
  local hitLeft = game.World.RaycastCollision(offsetZeroJoint, offsetLeft, {SourceGameObject = ai, FindAnything = true})
  local toRight = zeroJointFacingLeft * -distanceAmount
  local offsetRight = offsetZeroJoint + toRight
  offsetRight.y = offsetZeroJoint.y
  local hitRight = game.World.RaycastCollision(offsetZeroJoint, offsetRight, {SourceGameObject = ai, FindAnything = true})
  if ai:DebugIsSelectedCreature() then
    engine.DrawLine(offsetZeroJoint, offsetBack, 8388736)
    engine.DrawLine(offsetZeroJoint, offsetLeft, 8388736)
    engine.DrawLine(offsetZeroJoint, offsetRight, 8388736)
  end
  if not hitBack and not hitRight and not hitLeft then
    return data:FindOutcomeBranchesEntry("EvadeAny")
  elseif not hitBack then
    return data:FindOutcomeBranchesEntry("EvadeBack")
  elseif not hitRight then
    return data:FindOutcomeBranchesEntry("EvadeRight")
  elseif not hitLeft then
    return data:FindOutcomeBranchesEntry("EvadeLeft")
  else
    return data:FindOutcomeBranchesEntry("EvadeFailed")
  end
end
function LuaHook_CrawlerStrafe_CollisionCheck(ai, data)
  local distanceAmount = 5
  local jointIndex = ai:GetJointIndex("zeroJoint")
  local zeroJointFacingFwd = ai:GetWorldJointForward(jointIndex)
  local zeroJointFacingLeft = ai:GetWorldJointLeft(jointIndex)
  local offset = engine.Vector.New(0, 1.5, 0)
  local offsetZeroJoint = ai.WorldPosition + offset
  local toLeft = zeroJointFacingLeft * distanceAmount
  local offsetLeft = offsetZeroJoint + toLeft
  offsetLeft.y = offsetZeroJoint.y
  local hitLeft = game.World.RaycastCollision(offsetZeroJoint, offsetLeft, {SourceGameObject = ai, FindAnything = true})
  local toRight = zeroJointFacingLeft * -distanceAmount
  local offsetRight = offsetZeroJoint + toRight
  offsetRight.y = offsetZeroJoint.y
  local hitRight = game.World.RaycastCollision(offsetZeroJoint, offsetRight, {SourceGameObject = ai, FindAnything = true})
  if ai:DebugIsSelectedCreature() then
    engine.DrawLine(offsetZeroJoint, offsetLeft, 8388736)
    engine.DrawLine(offsetZeroJoint, offsetRight, 8388736)
  end
  if not hitRight and not hitLeft then
    return data:FindOutcomeBranchesEntry("StrafeAny")
  elseif not hitRight then
    return data:FindOutcomeBranchesEntry("StrafeRight")
  elseif not hitLeft then
    return data:FindOutcomeBranchesEntry("StrafeLeft")
  else
    return data:FindOutcomeBranchesEntry("StrafeFailed")
  end
end
function LuaHook_CrawlerBurrow_CollisionCheck(ai, data)
  local distanceAmount = 1.5
  local jointIndex = ai:GetJointIndex("zeroJoint")
  local zeroJointFacingFwd = ai:GetWorldJointForward(jointIndex)
  local offset = engine.Vector.New(0, 1, 0)
  local offsetZeroJoint = ai.WorldPosition + offset
  local toFront = zeroJointFacingFwd * distanceAmount
  local offsetFront = offsetZeroJoint + toFront
  offsetFront.y = offsetFront.y
  local hitFront = game.World.RaycastCollision(offsetZeroJoint, offsetFront, {SourceGameObject = ai, FindAnything = true})
  if ai:DebugIsSelectedCreature() then
    engine.DrawLine(offsetZeroJoint, offsetFront, 8388736)
  end
  if hitFront then
    return data:FindOutcomeBranchesEntry("ForceBurrowExit")
  end
end
function LuaHook_CrawlerIntroBurrow_SpawnBandit(ai)
  local position = ai:GetWorldPosition()
  local facing = ai:GetWorldForward()
  local currentLevel = ai.Level
  local bandit00ConfigsSeidrModerate = {
    "seidr01_moderate",
    "seidr02_moderate",
    "seidr03_moderate"
  }
  local randomConfig = math.random(1, #bandit00ConfigsSeidrModerate)
  local charConfig = bandit00ConfigsSeidrModerate[randomConfig]
  local bandit = game.AI.Spawn(currentLevel, position, facing, "CRT_Bandit00", "BRA_SpawnCrawlerIntro_BanditBurrow", {BodyType = "Seidr"}, charConfig)
end
function LuaHook_CrawlerIntroEmerge_SpawnBandit(ai)
  local position = ai:GetWorldPosition()
  local facing = ai:GetWorldForward()
  local currentLevel = ai.Level
  local bandit00ConfigsSeidrModerate = {
    "seidr01_moderate",
    "seidr02_moderate",
    "seidr03_moderate"
  }
  local randomConfig = math.random(1, #bandit00ConfigsSeidrModerate)
  local charConfig = bandit00ConfigsSeidrModerate[randomConfig]
  local bandit = game.AI.Spawn(currentLevel, position, facing, "CRT_Bandit00", "BRA_SpawnCrawlerIntro_BanditEmerge", {BodyType = "Seidr"}, charConfig)
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_Crawler_RageEnter(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kHead, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kLeftChest, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightChest, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kFrontAbdomen, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLeg, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kLeftBack, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kRightBack, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kBackAbdomen, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLeg, 0.4)
end
function LuaHook_AddBlood_Crawler_RageSlams(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kHead, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kLeftChest, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightChest, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kFrontAbdomen, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontUpperArm, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLowerArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontUpperArm, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLowerArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLeg, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLeg, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftBack, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kRightBack, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kBackAbdomen, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackUpperArm, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLowerArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackUpperArm, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLowerArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLeg, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLeg, 0.2)
end
function OnAIPostSpawn(ai)
  setupCharacter(ai)
end
function Brain_Core:OnSetPowerlevelOverrideCustom(ai, global, constants, level, isElite, forced)
  powerLevel = level
  ToggleCharacterConfig(ai, forced)
end
function setupCharacter(ai)
  local moveName = ""
  local aggroState = ""
  local spawnContext = ai:GetContext()
  if StartConfig ~= nil then
    if StartConfig.EliteDifficulty ~= nil and StartConfig.EliteDifficulty then
      if not ai:PickupIsAcquired("Crawler00_Elite") then
        ai:PickupAcquire("Crawler00_Elite")
      end
      if not ai:PickupIsAcquired("Crawler00_Elite_EyeGlow") then
        ai:PickupAcquire("Crawler00_Elite_EyeGlow")
      end
    end
    if StartConfig.AggroState ~= nil then
      DL.switch(StartConfig.AggroState):caseof({
        Unaware = function()
          aggroState = "UNAWARE"
        end,
        Passive = function()
          aggroState = "PASSIVE"
        end,
        NonHostile = function()
          aggroState = "NONHOSTILE"
        end,
        InCombat = function()
          aggroState = "INCOMBAT"
        end
      })
    end
    if StartConfig.SpawnMove ~= nil then
      moveName = StartConfig.SpawnMove
    end
  end
  ToggleCharacterConfig(ai, not game.CHECK_FEATURE("PREEMPT_SPAWN_CONFIG"))
  if aggroState == "" then
    if DL.CheckCreatureContext(spawnContext, "UNAWARE") then
      aggroState = "UNAWARE"
    elseif DL.CheckCreatureContext(spawnContext, "NONHOSTILE") then
      aggroState = "NONHOSTILE"
    else
      aggroState = "INCOMBAT"
    end
  end
  global.aggroState = aggroState
  if moveName ~= "" then
    ai:ForceMove(moveName)
  end
  DL.NewGamePlusLevelBoost(ai, "Crawler00_PowerLevel")
end
function ToggleCharacterConfig(ai, override)
  local pLevelInt = 1
  if 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 override ~= nil and override == true then
    if pLevelInt <= 4 then
      ai:SetCharacterConfig("CrawlerTail_easy")
    else
      ai:SetCharacterConfig("CrawlerTail_hard")
    end
  end
end
function OnAIUpdate(ai)
  traverselink.OnUpdate(ai)
end
function _G.OnAICreateLuaState(ai)
  local positioning = Brain_Core:GetPositioning()
  positioning.AddStandardPositioningZone("Burrow", constants.fightPosDataBurrow, constants.fightKnowledgeInputs)
  _G.OnAICreateLuaState = nil
end
function Brain_Core:OnUpdateCombat(ai, global, constants, dTreeParams)
  if ai:PickupIsAcquired("Crawler_BurrowState") then
    constants.fightKnowledgeInputs.CurrentZoneSet = "Burrow"
  elseif ai:HasMarker("PausePositionUpdates") == false then
    constants.fightKnowledgeInputs.CurrentZoneSet = "Default"
  end
  if ai:PickupIsAcquired("Crawler_BurrowState") and ai:HasMarker("DoNotEvaluate") == false then
    ai:AddMarker("DoNotEvaluate")
  elseif ai:PickupIsAcquired("Crawler_BurrowState") == false and ai:HasMarker("DoNotEvaluate") == true then
    ai:RemoveMarker("DoNotEvaluate")
  end
end
picklelib.Install()
function Pickle(GO)
  return {
    global = global
  }
end
function Unpickle(GO, t)
  global = t.global
end
