local DL = require("design.DesignerLibrary")
local OffsetYVector = engine.Vector.New(0, 1, 0)
function setBestDodgeType(ai, sonPosRelative, dodgeObjectPosRelative, isPlayer, highLevel)
  if sonPosRelative ~= nil and dodgeObjectPosRelative ~= nil then
    local result = "none"
    if sonPosRelative == "objRight" and dodgeObjectPosRelative == "objLeft" or sonPosRelative == "objFront" and dodgeObjectPosRelative == "objLeft" or sonPosRelative == "objFront" and dodgeObjectPosRelative == "objRight" or sonPosRelative == "objLeft" and dodgeObjectPosRelative == "objRight" or sonPosRelative == "objBack" and dodgeObjectPosRelative == "objRight" then
      result = "EvadeBack"
    elseif sonPosRelative == "objLeft" and dodgeObjectPosRelative == "objLeft" or sonPosRelative == "objBack" and dodgeObjectPosRelative == "objLeft" or sonPosRelative == "objRight" and dodgeObjectPosRelative == "objRight" then
      result = "EvadeForward"
    elseif sonPosRelative == "objLeft" and dodgeObjectPosRelative == "objBack" or sonPosRelative == "objBack" and dodgeObjectPosRelative == "objBack" or sonPosRelative == "objRight" and dodgeObjectPosRelative == "objFront" or sonPosRelative == "objFront" and dodgeObjectPosRelative == "objFront" then
      result = "EvadeLeft"
    elseif sonPosRelative == "objRight" and dodgeObjectPosRelative == "objBack" or sonPosRelative == "objFront" and dodgeObjectPosRelative == "objBack" or sonPosRelative == "objLeft" and dodgeObjectPosRelative == "objFront" or sonPosRelative == "objBack" and dodgeObjectPosRelative == "objFront" then
      result = "EvadeRight"
    end
    local bInCombat = inCombat(ai)
    if bInCombat == true and isPlayer then
      result = "Combat" .. result
    elseif bInCombat == true then
      local shouldFaceTarget = ""
      local combatEvade = "Combat"
      if highLevel then
        shouldFaceTarget = "FaceTarget"
        combatEvade = ""
      end
      if dodgeObjectPosRelative == "objFront" then
        result = combatEvade .. "EvadeBack" .. shouldFaceTarget
      elseif dodgeObjectPosRelative == "objBack" then
        result = combatEvade .. "EvadeForward" .. shouldFaceTarget
      elseif dodgeObjectPosRelative == "objRight" then
        result = combatEvade .. "EvadeLeft" .. shouldFaceTarget
      elseif dodgeObjectPosRelative == "objLeft" then
        result = combatEvade .. "EvadeRight" .. shouldFaceTarget
      end
    end
    if result ~= "none" then
      result = "BRA_" .. result
    end
    return result
  end
end
function getBestAOETarget(ai)
  local selfCreature = ai:GetCreature()
  local enemiesNearby = selfCreature:FindEnemies(35)
  local bestAOETarget
  local AOERange = 5
  local bestEnemiesNearbyCounter = 0
  for _, thisEnemy in ipairs(enemiesNearby) do
    local enemiesNearbyCounter = 0
    local enemyPosition = thisEnemy:GetWorldPosition()
    if bestAOETarget == nil then
      bestAOETarget = thisEnemy
    end
    for _, thisEnemy2 in ipairs(enemiesNearby) do
      if AOERange >= enemyPosition:Distance(thisEnemy2:GetWorldPosition()) then
        enemiesNearbyCounter = enemiesNearbyCounter + 1
      end
    end
    if bestEnemiesNearbyCounter < enemiesNearbyCounter then
      bestEnemiesNearbyCounter = enemiesNearbyCounter
      bestAOETarget = thisEnemy
    end
  end
  if gVFSDebug.value and bestAOETarget ~= nil then
    local debugpos = bestAOETarget:GetWorldPosition()
    engine.DrawTextInWorld(debugpos + OffsetYVector, "I have " .. bestEnemiesNearbyCounter - 1 .. " guys near me in a 5 meter radius", 16711680)
    engine.DrawCircle(debugpos + OffsetYVector, 5, OffsetYVector, 16711680)
    engine.DrawCircle(debugpos + OffsetYVector, 0.5, OffsetYVector, 16711680)
  end
  return bestAOETarget
end
function inCombat(ai)
  if _G.global.overrides.suppressCombat then
    return false, 0, {}
  end
  if game.Level.GetVariable("SON_DisableCombat") then
    return false, 0, {}
  end
  local player = game.Player.FindPlayer()
  local testTargets = FindLivingEnemiesExludeMarked(player, 30, "DoNotEvaluate")
  local isInCombat = game.Combat.GetCombatStatus()
  return isInCombat, #testTargets, testTargets
end
function HookGetConfidence(ai, data)
  return data:FindOutcomeBranchesEntry(getConfidence(ai, _G.global))
end
function getPlayerTarget()
  return game.Player.FindPlayer():GetTargetCreature()
end
function getConfidence(ai, global, constants)
  local targetType
  if global.sTargetMode == "AcquireKratosTarget" and global.goPlayerTarget ~= nil then
    targetType = global.goPlayerTarget:GetName()
  elseif global.combatTarget ~= nil then
    targetType = global.combatTarget:GetName()
  end
  if targetType == nil then
    return "normal"
  end
  local totalConfidence = 0
  totalConfidence = totalConfidence + getEnemyKnowledgeValue(ai, global, constants, targetType) / 2
  if totalConfidence < 0.3 then
    return "fearful"
  elseif totalConfidence < 0.6 then
    return "normal"
  else
    return "confident"
  end
end
function getConfidenceByType(ai, global, constants, enemyID)
  local totalConfidence = getEnemyKnowledgeValue(ai, global, constants, enemyID) / 2
  if totalConfidence < 0.3 then
    return "fearful"
  elseif totalConfidence < 0.6 then
    return "normal"
  else
    return "confident"
  end
end
function getEnemyKnowledgeValue(ai, global, constants, enemyID)
  if global.stats.enemyKnowledgeData.humanoid[enemyID] == nil then
    return 0
  else
    return global.stats.enemyKnowledgeData.humanoid[enemyID]
  end
end
function increaseConfidenceLevel(ai, global, constants, subclasstype, enemyID, value)
  if global.stats.enemyKnowledgeData[subclasstype][enemyID] == nil then
    global.stats.enemyKnowledgeData[subclasstype][enemyID] = 0
  end
  global.stats.enemyKnowledgeData[subclasstype][enemyID] = global.stats.enemyKnowledgeData[subclasstype][enemyID] + value
end
function sendTurnOffUI_Event(ai, global, constants)
  for c in game.Creature.IterateAllCreatures() do
    if ai ~= c:GetAI() then
      engine.SendHook("OnHideUIHook", c)
    end
  end
end
function markedUI_Logic(ai, global, constants)
  if global.playerMove == nil then
    global.playerMove = "none"
    global.playerPreviousTarget = nil
  end
  local playergameObject = game.Player.FindPlayer()
  local playerTarget = getPlayerTarget()
  if playergameObject:IsPlayingMove("MOV_AimLoopEnter") or playergameObject:IsPlayingMove("MOV_AimLoop") then
    if global.playerPreviousTarget ~= playerTarget and playerTarget ~= nil then
      local confidence = getConfidenceByType(ai, global, constants, playerTarget:GetName())
      engine.SendHook("OnShowUIHook", playerTarget, confidence)
      if global.playerPreviousTarget ~= nil then
        engine.SendHook("OnHideUIHook", global.playerPreviousTarget)
      end
      global.playerPreviousTarget = playerTarget
      global.playerMove = "MOV_AimLoopEnter"
    elseif playerTarget == nil and global.playerMove ~= "NoTarget" and global.playerPreviousTarget ~= nil then
      engine.SendHook("OnHideUIHook", global.playerPreviousTarget)
      global.playerMove = "NoTarget"
      global.playerPreviousTarget = nil
    end
  end
  if not playergameObject:IsPlayingMove("MOV_AimLoopEnter") and not playergameObject:IsPlayingMove("MOV_AimLoop") and (global.playerMove == "MOV_AimLoopEnter" or global.playerMove == "NoTarget") then
    sendTurnOffUI_Event(ai, global, constants)
    global.playerMove = "NotMOV_AimLoopEnter"
    global.playerPreviousTarget = nil
  end
end
local GetCenterOfScreenEnemyPriority = function(screenPenetration, jointName)
  local player = game.Player.FindPlayer()
  local creaturesAroundPlayer = getOnScreenEnemySorted()
  local bestscreenpen = 0
  local mostCenterCreature
  for _, thisCreature in ipairs(creaturesAroundPlayer) do
    if not thisCreature:HasMarker("DoNotTarget") then
      local creatureJointPosition = DL.GetWorldJointPositionByName(thisCreature, jointName)
      if creatureJointPosition ~= nil then
        local distance = (thisCreature.WorldPosition - player.WorldPosition):Length()
        local distWeight = 0
        distWeight = (1 - distance / 12) * 0.75
        if distWeight < 0 then
          distWeight = 0
        end
        local thisCreaturePen = game.Camera.GetViewPenetration(creatureJointPosition, 0, 0) + distWeight
        local stringID = thisCreature:GetName()
        if stringID == "witch00" or stringID == "witch10" or stringID == "witch20" then
          thisCreaturePen = thisCreaturePen + 0.25
        elseif stringID == "flyer00" or stringID == "flyer10" or stringID == "flyer20" then
          thisCreaturePen = thisCreaturePen + 0.2
        end
        if bestscreenpen < thisCreaturePen then
          mostCenterCreature = thisCreature
          bestscreenpen = thisCreaturePen
        end
      end
    end
  end
  if screenPenetration <= bestscreenpen then
    return mostCenterCreature
  end
  return nil
end
local GetCenterOfScreenEnemy = function(screenPenetration, jointName)
  local player = game.Player.FindPlayer()
  local creaturesAroundPlayer = player:FindEnemies(100)
  local bestscreenpen = 0
  local mostCenterCreature
  for _, thisCreature in ipairs(creaturesAroundPlayer) do
    if not thisCreature:HasMarker("DoNotTarget") then
      local creatureJointPosition = DL.GetWorldJointPositionByName(thisCreature, jointName)
      if creatureJointPosition ~= nil then
        local thisCreaturePen = game.Camera.GetViewPenetration(creatureJointPosition, 0, 0)
        if bestscreenpen < thisCreaturePen then
          mostCenterCreature = thisCreature
          bestscreenpen = thisCreaturePen
        end
      end
    end
  end
  if screenPenetration <= bestscreenpen then
    return mostCenterCreature
  end
  return nil
end
function ReturnBestTargetObject(global, constants)
  if constants.shootTargetInfo == nil then
    constants.shootTargetInfo = {}
  end
  local reticleHitData, reticleHitPosition, reticleHitGameObject, reticleHitJointId
  local playerInAimMode = global.Player:HasMarker("Aiming")
  local playercombattarget = global.Player:GetTargetCreature()
  reticleHitData = global.Player.SonReticleHitData
  reticleHitPosition = reticleHitData.HitPosition
  reticleHitGameObject = reticleHitData.HitGameObject
  reticleHitJointId = reticleHitData.HitJointId
  local isCrystal = reticleHitGameObject ~= nil and reticleHitGameObject:HasMarker("SonTarget")
  local validReticleTarget = reticleHitGameObject ~= nil and (isCrystal or reticleHitGameObject:GetCreature() ~= nil and reticleHitGameObject ~= game.AI.FindSon() and reticleHitGameObject:GetCreature().GetHitPoints ~= nil and reticleHitGameObject:GetCreature():GetHitPoints() > 0 and reticleHitGameObject:HasMarker("DoNotTarget") == false)
  constants.shootTargetInfo.isCrystal = isCrystal
  constants.shootTargetInfo.targetJoint = nil
  if playerInAimMode then
    if validReticleTarget == true then
      constants.shootTargetInfo.shootType = "combatTarget"
      constants.shootTargetInfo.target = reticleHitGameObject
      if reticleHitJointId ~= nil then
        constants.shootTargetInfo.targetJoint = reticleHitJointId
      end
    elseif playercombattarget ~= nil and not DL.TargetObstructed(global.Player, playercombattarget) then
      constants.shootTargetInfo.shootType = "combatTarget"
      constants.shootTargetInfo.target = playercombattarget
    else
      constants.shootTargetInfo.shootType = "reticle"
      constants.shootTargetInfo.target = nil
    end
  else
    local potentialTarget
    local reticleCreature = GetCenterOfScreenEnemyPriority(0.4, "JOHead1")
    local usedReticle = false
    local lockOnTarget = global.Player:GetLockOnTarget()
    if lockOnTarget ~= nil then
      potentialTarget = lockOnTarget
    elseif reticleCreature ~= nil then
      potentialTarget = reticleCreature
    elseif playercombattarget ~= nil then
      potentialTarget = playercombattarget
    else
      local closestEnemy = DL.GetClosestOnScreenEnemy()
      if closestEnemy ~= nil then
        potentialTarget = closestEnemy
      elseif validReticleTarget then
        potentialTarget = reticleHitGameObject
        usedReticle = true
      end
    end
    if potentialTarget == nil then
      constants.shootTargetInfo.shootType = "reticle"
      constants.shootTargetInfo.target = nil
    else
      constants.shootTargetInfo.shootType = "combatTarget"
      constants.shootTargetInfo.target = potentialTarget
      if usedReticle == true and reticleHitJointId ~= nil then
        constants.shootTargetInfo.targetJoint = reticleHitJointId
      end
    end
  end
  constants.shootTargetInfo.position = reticleHitPosition
  if constants.shootTargetInfo ~= nil and constants.shootTargetInfo.target ~= nil and constants.shootTargetInfo.target.GetCreature ~= nil and constants.shootTargetInfo.target:GetCreature() ~= nil then
    if constants.previousShotTargetTimer > constants.previousShotTargetTimerReset then
      constants.previousShotTarget = nil
    end
    if constants.previousShotTarget ~= nil and (constants.previousShotTarget.GetHitPoints ~= nil and 0 >= constants.previousShotTarget:GetHitPoints() or constants.previousShotTarget.GetHitPoints == nil) then
      constants.previousShotTarget = nil
    end
    if constants.previousShotTarget == nil then
      constants.previousShotTarget = constants.shootTargetInfo.target
    elseif playerInAimMode == false and constants.previousShotTarget ~= nil and constants.previousShotTarget:GetAI() ~= nil and constants.previousShotTarget:GetAI():CheckDecision("tweak_Decision_OnCamera") and constants.previousShotTargetTimer < constants.previousShotTargetTimerReset then
      constants.shootTargetInfo.target = constants.previousShotTarget
      constants.shootTargetInfo.shootType = "combatTarget"
      constants.shootTargetInfo.targetJoint = nil
      constants.shootTargetInfo.position = constants.previousShotTarget.WorldPosition
    end
  end
  if constants.shootTargetInfo.targetJoint == nil and constants.shootTargetInfo.target ~= nil and constants.shootTargetInfo.target.GetCreature ~= nil and constants.shootTargetInfo.target:GetCreature() ~= nil then
    local headIndex = constants.shootTargetInfo.target:FindJointIndex("JOHead1")
    if headIndex ~= nil then
      constants.shootTargetInfo.targetJoint = headIndex
      constants.shootTargetInfo.position = constants.shootTargetInfo.target:GetWorldJointPosition(headIndex)
    end
  end
  constants.previousShotTargetTimer = 0
end
function returnBestPlayerTargetCreature(global, saveRaycastLocation)
  local player = game.Player.FindPlayer()
  local reticleCreature = _G.constants.reticleCreature
  if reticleCreature ~= nil then
    reticleCreature = reticleCreature:GetCreature()
    if reticleCreature == game.AI.FindSon() then
      reticleCreature = nil
    end
  end
  local hitLoc = _G.constants.hitLoc
  if saveRaycastLocation then
    global.rayCastHitLocation = hitLoc
  end
  local playerInAimMode = player:HasMarker("Aiming")
  local playerTargetValue = getPlayerTarget()
  local targetOfPlayer
  if playerInAimMode == true then
    if reticleCreature ~= nil then
      targetOfPlayer = reticleCreature
    elseif playerTargetValue ~= nil then
      targetOfPlayer = playerTargetValue
    end
  elseif playerTargetValue ~= nil then
    targetOfPlayer = playerTargetValue
  else
    local reticleCreature = GetCenterOfScreenEnemy(0.4, "JOHead1")
    if reticleCreature ~= nil then
      targetOfPlayer = reticleCreature
    else
      local playercombattarget = player:GetTargetCreature()
      if playercombattarget ~= nil then
        targetOfPlayer = playercombattarget
      else
        local closestEnemy = DL.GetClosestOnScreenEnemy()
        if closestEnemy ~= nil then
          targetOfPlayer = closestEnemy
        end
      end
    end
  end
  if _G.constants.previousShotTargetTimer > _G.constants.previousShotTargetTimerReset then
    _G.constants.previousShotTarget = nil
  end
  if _G.constants.previousShotTarget == nil then
    _G.constants.previousShotTarget = targetOfPlayer
  elseif playerInAimMode == false and _G.constants.previousShotTarget ~= nil and _G.constants.previousShotTarget:GetAI() ~= nil and _G.constants.previousShotTarget:GetAI():CheckDecision("tweak_Decision_OnCamera") and _G.constants.previousShotTargetTimer < _G.constants.previousShotTargetTimerReset then
    targetOfPlayer = _G.constants.previousShotTarget
  end
  _G.constants.previousShotTargetTimer = 0
  return targetOfPlayer
end
function returnDistanceFromWallFacing(ai)
  local raycastOrigin = ai.WorldPosition + engine.Vector.New(0, 0.5, 0)
  local raycastEnd = raycastOrigin + ai:GetWorldForward() * 30
  local collisionParams = {
    SourceGameObject = ai,
    EntityType = game.CollisionType.New("kEnvironment")
  }
  local hit = game.World.RaycastCollision(raycastOrigin, raycastEnd, collisionParams)
  if hit ~= nil then
    return hit.Position:Distance(ai.WorldPosition)
  end
  return 30
end
local getNumberOfOnScreenEnemy = function()
  local count = 0
  local player = game.Player.FindPlayer()
  local creaturesOnScreen = {}
  local creaturesAroundPlayer = DL.FindLivingEnemies(player, 35)
  for _, thisCreature in ipairs(creaturesAroundPlayer) do
    if thisCreature:GetAI():CheckDecision("tweak_Decision_OnCamera") then
      count = count + 1
    end
  end
  return count
end
local getOnScreenEnemy = function(radius, notOnScreen)
  local player = game.Player.FindPlayer()
  local creaturesOnScreen = {}
  local creaturesAroundPlayer = DL.FindLivingEnemies(player, radius)
  for _, thisCreature in ipairs(creaturesAroundPlayer) do
    if thisCreature:GetAI():CheckDecision("tweak_Decision_OnCamera") then
      if notOnScreen == false then
        table.insert(creaturesOnScreen, thisCreature)
      end
    elseif notOnScreen == true then
      table.insert(creaturesOnScreen, thisCreature)
    end
  end
  return creaturesOnScreen
end
local getEnemiesBehind = function(ai)
  local player = game.Player.FindPlayer()
  local enemiesBehind = {}
  local creaturesAroundPlayer = DL.FindLivingEnemies(player, 35)
  for _, thisCreature in ipairs(creaturesAroundPlayer) do
    local angle = DL.FrontAngle(ai, thisCreature)
    if 125 < angle or angle < -125 then
      table.insert(enemiesBehind, thisCreature)
    end
  end
  return enemiesBehind
end
function getOnScreenEnemySorted()
  local player = game.Player.FindPlayer()
  local creaturesOnScreen = {}
  local creaturesAroundPlayer = DL.FindLivingEnemies(player, 35)
  for _, thisCreature in ipairs(creaturesAroundPlayer) do
    if thisCreature:GetAI():CheckDecision("tweak_Decision_OnCamera") then
      table.insert(creaturesOnScreen, thisCreature)
    end
  end
  return creaturesOnScreen
end
function spairs(t, order)
  local keys = {}
  for k in pairs(t) do
    keys[#keys + 1] = k
  end
  if order then
    table.sort(keys, function(a, b)
      return order(t, a, b)
    end)
  else
    table.sort(keys)
  end
  local i = 0
  return function()
    i = i + 1
    if keys[i] then
      return keys[i], t[keys[i]]
    end
  end
end
function CallTurnShootEvent(ai, global, constants, position, commandedShot)
  local desiredDirectionDelta = DL.FrontAngleFromPoint(ai, position)
  if _G.gVFSDebug.value then
    engine.DrawFillSphere(ai.WorldPosition, 0.005, 16777215, 5)
    engine.DrawFillSphere(position, 0.25, 16711680, 5)
    engine.DrawLine(ai.WorldPosition, position, 16711935, 5)
  end
  local eventName = ""
  local movementName = "Idle"
  local shotType = "ShootBow"
  local turnType = "Turn0"
  local targetType = ""
  if commandedShot == true then
    shotType = "CommandArrowElectric"
  end
  if ai:HasMarker("RunStopShootBow") then
    local locomotionInfo = ai:GetLocomotionInfo()
    if locomotionInfo.PathStraightDistance ~= nil and locomotionInfo.PathStraightDistance > 3 and not ai:HasMarker("NotInCombat") then
      movementName = "Run"
    else
      movementName = "RunStop"
    end
  end
  if -60 <= desiredDirectionDelta and desiredDirectionDelta <= 60 then
    turnType = "Turn0"
  elseif 60 < desiredDirectionDelta and desiredDirectionDelta <= 150 then
    turnType = "Turn120R"
  elseif 150 < desiredDirectionDelta and desiredDirectionDelta <= 180 then
    turnType = "Turn180R"
  elseif desiredDirectionDelta < -60 and -150 <= desiredDirectionDelta then
    turnType = "Turn120L"
  elseif desiredDirectionDelta < -150 and -180 <= desiredDirectionDelta then
    turnType = "Turn180L"
  end
  if ai.OwnedPOI and ai.OwnedPOI:FindLuaTableAttribute("PostUp") then
    if -40 <= desiredDirectionDelta and desiredDirectionDelta <= 40 and (ai:IsPlayingMove("MOV_CA_PostUpReady_Loop") or ai:IsPlayingMove("MOV_CA_PostUp_Loop")) then
      ai:TriggerMoveEvent("kLEPostUpBowFire")
    end
    return
  end
  if not global.warpTargetRot then
    global.warpTargetRot = game.AI.FindSon():GetAnimDriver("WarpTargetRot")
  end
  global.warpTargetRot.ValueVec = position - ai.WorldPosition
  ai:TriggerMoveEvent("kLE" .. movementName .. shotType .. turnType)
end
function ReturnAllValidAggroableCreatures(ai, global, constants, radius)
  local enemies = ai:FindEnemies(radius)
  for i = #enemies, 1, -1 do
    local creatureID = DL.ReturnStringID(enemies[i])
    if creatureID ~= nil then
      local canEngage = creatureID == "WITCH00" or creatureID == "WITCH10" or creatureID == "WITCH10" or creatureID == "DRAUGR00" or creatureID == "BANDIT00" or creatureID == "DARKONE00" or creatureID == "WOLF00" or creatureID == "WOLF10" or creatureID == "WULVER00" or creatureID == "WULVER10" or creatureID == "FLYER00" or creatureID == "FLYER10" or creatureID == "FLYER20"
      if enemies[i]:GetActionRank() ~= "kARHigh" and canEngage and enemies[i]:GetCreature():GetHitPoints() <= 0 or enemies[i]:HasMarker("Dormant") or enemies[i]:HasMarker("DoNotEvaluate") then
        table.remove(enemies, i)
      end
    end
  end
  return enemies
end
function LargeCreatureExists(ai, global, constants, radius)
  if constants.largeCreatureTarget == nil then
    if constants.largeCreatureFinderTimer > 5 then
      constants.largeCreatureFinderTimer = 0
      if ai:CheckDecision("tweak_Decision_LargeEnemy1") then
        local enemies = ai:FindEnemies(radius)
        for _, i in ipairs(enemies) do
          local creatureID = DL.ReturnStringID(i)
          if creatureID ~= nil then
            local canEngage = creatureID == "TROLL00" or creatureID == "TROLL10" or creatureID == "TROLL20" or creatureID == "TROLL30" or creatureID == "JOTUNN00" or creatureID == "JOTUNN10" or creatureID == "JOTUNN20" or creatureID == "GOLEM00" or creatureID == "GOLEM10" or creatureID == "GOLEM20"
            if canEngage == true then
              constants.largeCreatureTarget = i
              return i
            end
          end
        end
      end
    end
  elseif (constants.largeCreatureTarget.WorldPosition - ai.WorldPosition):Length() > radius + 10 then
    constants.largeCreatureTarget = nil
  end
  return constants.largeCreatureTarget
end
function IsMountable(creatureID)
  return creatureID == "FANATIC00" or creatureID == "BANDIT00" or creatureID == "DRAUGR00" or creatureID == "BRAWLER00" or creatureID == "DARKONE00" or creatureID == "PROJECTION00" or creatureID == "PROJECTION10"
end
function CanMeleeAgainst(creatureID)
  return creatureID == "WITCH00" or creatureID == "WITCH10" or creatureID == "WITCH20" or creatureID == "BANDIT00" or creatureID == "FANATIC00" or creatureID == "DRAUGR00" or creatureID == "BRAWLER00" or creatureID == "DARKONE00" or creatureID == "PROJECTION00" or creatureID == "PROJECTION10" or creatureID == "WOLF00" or creatureID == "WOLF10" or creatureID == "CRAWLER00" or creatureID == "CRAWLER10" or creatureID == "FLYER00" or creatureID == "FLYER10" or creatureID == "FLYER20"
end
local FocusKratos = function(ai, global, constants, duration)
  constants.focusDuration = duration or 6
  ai:SetFocus(game.Player.FindPlayer())
end
local GetHighestRankingChar = function(ai, global)
  local rankValues = {
    tweaks.eActionRank.kARHigh,
    tweaks.eActionRank.kARMedium,
    tweaks.eActionRank.kARLow
  }
  local potentialChar
  for _, i in ipairs(rankValues) do
    potentialChar = global.Player:GetNearestCreatureWithActionRank(i)
    if potentialChar ~= nil then
      return potentialChar
    end
  end
  return nil
end
local GetHighRankAveragePosition = function(ai, global)
  local player = game.Player.FindPlayer()
  local enemies = player:FindEnemies(6)
  local pos
  local numEnemies = 0
  for _, i in ipairs(enemies) do
    if i:GetActionRank() == "kARHigh" then
      if pos == nil then
        pos = i.WorldPosition
      else
        pos = pos + i.WorldPosition
      end
      numEnemies = numEnemies + 1
    end
  end
  if pos ~= nil then
    return pos / numEnemies
  end
  return nil
end
local CanPerformSkill = function(constants, skillName)
  local getValue = _G.constants[skillName]
  if getValue == nil then
    return false
  end
  return getValue
end
local FindClosestLivingEnemyExcludeMarker = function(ai, radius, marker)
  local enemies = ai:FindEnemies(radius)
  local thisEnemy
  for i = #enemies, 1, -1 do
    if enemies[i]:GetCreature():GetHitPoints() <= 0 or enemies[i]:HasMarker(marker) then
      table.remove(enemies, i)
    else
      thisEnemy = enemies[i]
      break
    end
  end
  return thisEnemy
end
function FindLivingEnemiesExludeMarked(ai, radius, marker)
  local enemies = ai:FindEnemies(radius)
  for i = #enemies, 1, -1 do
    if enemies[i]:GetCreature():GetHitPoints() <= 0 or enemies[i]:HasMarker(marker) or enemies[i]:HasMarker("Dormant") or enemies[i]:HasMarker("DoNotEvaluate") then
      table.remove(enemies, i)
    end
  end
  return enemies
end
return {
  setBestDodgeType = setBestDodgeType,
  getBestAOETarget = getBestAOETarget,
  inCombat = inCombat,
  increaseConfidenceLevel = increaseConfidenceLevel,
  getConfidence = getConfidence,
  markedUI_Logic = markedUI_Logic,
  getPlayerTarget = getPlayerTarget,
  ReturnBestTargetObject = ReturnBestTargetObject,
  returnBestPlayerTargetCreature = returnBestPlayerTargetCreature,
  returnDistanceFromWallFacing = returnDistanceFromWallFacing,
  getEnemiesBehind = getEnemiesBehind,
  getOnScreenEnemySorted = getOnScreenEnemySorted,
  getNumberOfOnScreenEnemy = getNumberOfOnScreenEnemy,
  getOnScreenEnemy = getOnScreenEnemy,
  CallTurnShootEvent = CallTurnShootEvent,
  ReturnAllValidAggroableCreatures = ReturnAllValidAggroableCreatures,
  FocusKratos = FocusKratos,
  IsMountable = IsMountable,
  LargeCreatureExists = LargeCreatureExists,
  CanMeleeAgainst = CanMeleeAgainst,
  GetHighestRankingChar = GetHighestRankingChar,
  GetHighRankAveragePosition = GetHighRankAveragePosition,
  CanPerformSkill = CanPerformSkill,
  FindClosestLivingEnemyExcludeMarker = FindClosestLivingEnemyExcludeMarker,
  FindLivingEnemiesExludeMarked = FindLivingEnemiesExludeMarked
}
