local picklelib = require("core.pickle")
local DL = require("design.DesignerLibrary")
local positioning = require("behavior.positioning")
local uiCalls = require("ui.uicalls")
local traverselink = require("creature.traverselink")
traverselink.InstallHooks()
local globalLuaHooks = require("design.GlobalLuaHooks")
local mpicon = require("ui.mpicon")
globalLuaHooks.InstallHooks()
print("Witch00 main start")
Brain_Core = require("behavior.corebrain")
constants = {}
global = {}
local isInCombat = false
local isDebuffed = false
local isEscaping = false
local isCrumpled = false
local bossHealthBarOn = false
local powerLevel = "1"
local pLevelInt = 1
local creatureName
local rageGrabTextShow = false
local witchNavEvadeUsed = false
local witch20FrostBreathUsed = false
local origAggressiveMinDistance = 0
local origAggressiveMaxDistance = 0
local origAggressiveMinAngle = 0
local origAggressiveMaxAngle = 0
local witch20FrostBreathMinDistance = 2
local witch20FrostBreathMaxDistance = 5.5
constants.canEvade = false
local navEvadeMinDistance = 12
local navEvadeMaxDistance = 15
local navEvadeMinAngle = -180
local navEvadeMaxAngle = 180
local lootChance
local disableFlyerSpawn = false
local maxFlyerCount = 4
local flyerPowerLevel = "1-Easiest"
local flyerSpawnTypes = {}
function OnAIPostSpawn(ai)
  setupCharacter(ai)
end
function Brain_Core:OnSetPowerlevelOverrideCustom(ai, global, constants, level, isElite, forced)
  creatureName = ai:GetName()
  powerLevel = level
  ToggleCharacterConfig(ai, forced)
end
function setupCharacter(ai)
  local moveName = ""
  local aggroState = ""
  local spawnContext = ai:GetContext()
  creatureName = ai:GetName()
  if not ai:PickupIsAcquired("WitchRake") then
    ai:PickupAcquire("WitchRake")
  end
  origAggressiveMinDistance = constants.fightPosDataDefault.AggressiveMinDistance
  origAggressiveMaxDistance = constants.fightPosDataDefault.AggressiveMaxDistance
  origAggressiveMinAngle = constants.fightPosDataDefault.AggressiveMinAngle
  origAggressiveMaxAngle = constants.fightPosDataDefault.AggressiveMaxAngle
  if StartConfig ~= nil then
    if StartConfig.SpawnMove ~= nil then
      moveName = StartConfig.SpawnMove
    end
    if StartConfig.EliteDifficulty ~= nil and StartConfig.EliteDifficulty and not ai:PickupIsAcquired("Witch00_Elite") then
      ai:PickupAcquire("Witch00_Elite")
    end
    if StartConfig.DisableFlyerSpawn ~= nil and creatureName == "witch00" and StartConfig.DisableFlyerSpawn then
      disableFlyerSpawn = true
    end
    if StartConfig.MaxFlyerSpawnCount ~= nil then
      maxFlyerCount = StartConfig.MaxFlyerSpawnCount
    end
    if creatureName == "witch00" then
      if StartConfig.SpawnedFlyerPowerLevel ~= nil then
        flyerPowerLevel = StartConfig.SpawnedFlyerPowerLevel
      end
      if StartConfig.SpawnedFlyerTypeSeidr then
        table.insert(flyerSpawnTypes, "Seidr")
      end
      if StartConfig.SpawnedFlyerTypeFire then
        table.insert(flyerSpawnTypes, "Fire")
      end
      if StartConfig.SpawnedFlyerTypeIce then
        table.insert(flyerSpawnTypes, "Ice")
      end
      if StartConfig.SpawnedFlyerTypeSuicide then
        table.insert(flyerSpawnTypes, "Suicide")
      end
      if StartConfig.SpawnedFlyerTypeBlind then
        table.insert(flyerSpawnTypes, "Blind")
      end
      if StartConfig.SpawnedFlyerTypePossess then
        table.insert(flyerSpawnTypes, "Possess")
      end
      if #flyerSpawnTypes == 0 then
        print("Witch00 -- no flyer spawn-type specified, so defaulting to Seidr type")
        table.insert(flyerSpawnTypes, "Seidr")
      end
    end
  end
  ToggleCharacterConfig(ai, not game.CHECK_FEATURE("PREEMPT_SPAWN_CONFIG"))
  if ai:IsPlayingMove("MOV_SpawnUnawareStealth") or moveName == "BRA_Spawn" or moveName == "MOV_SpawnTimedUnawareStealth_3Sec" or moveName == "MOV_SpawnUnawareIdle" then
    aggroState = "UNAWARE_STEALTH"
  end
  if aggroState ~= "" then
    global.aggroState = aggroState
  end
  if moveName ~= "" then
    ai:ForceMove(moveName)
  end
  SoundInit(ai)
  if ai:AttributeGetValue("Difficulty") >= 3 and ai.GroundLevel ~= nil and string.find(ai.GroundLevel.Name, "Stn430_") ~= nil then
    ai:PickupAcquire("PowerLevelPenalty")
  end
  DL.NewGamePlusLevelBoost(ai, "Witch00_PowerLevel")
  DL.NewGamePlusLevelBoost(ai, "Witch10_PowerLevel")
  DL.NewGamePlusLevelBoost(ai, "Witch20_PowerLevel")
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 creatureName ~= nil then
    if creatureName == "witch00" then
      ai:HideJoint(ai:GetJointIndex("CN_20_pendantPatch1"))
      navEvadeMinDistance = 9
      navEvadeMaxDistance = 12
      if override ~= nil and override == true then
        if pLevelInt <= 2 then
          ai:SetCharacterConfig("config00")
        elseif 3 <= pLevelInt and pLevelInt <= 4 then
          ai:SetCharacterConfig("config00_hard")
        elseif 5 <= pLevelInt then
          ai:SetCharacterConfig("config00_veryhard")
        end
      end
    elseif creatureName == "witch10" then
      ai:HideJoint(ai:GetJointIndex("CN_20_pendantPatch1"))
      navEvadeMinDistance = 12
      navEvadeMaxDistance = 15
      if override ~= nil and override == true then
        if pLevelInt <= 2 then
          ai:SetCharacterConfig("config10")
        elseif 3 <= pLevelInt and pLevelInt <= 4 then
          ai:SetCharacterConfig("config10_hard")
        elseif 5 <= pLevelInt then
          ai:SetCharacterConfig("config10_veryhard")
        end
      end
    elseif creatureName == "witch20" then
      ai:ShowJoint(ai:GetJointIndex("CN_20_pendantPatch1"))
      navEvadeMinDistance = 10
      navEvadeMaxDistance = 13
      if override ~= nil and override == true then
        if pLevelInt <= 4 then
          ai:SetCharacterConfig("config20")
        elseif 5 <= pLevelInt then
          ai:SetCharacterConfig("config20_veryhard")
        end
      end
    end
  end
end
local GetWitchArmorStage = function(C)
  if C:PickupIsAcquired("WitchArmor") then
    local pickupStage = C:PickupGetStage("WitchArmor")
    return pickupStage
  else
    return 0
  end
end
local GetWitchHealthThresholdStage = function(C)
  if C:PickupIsAcquired("HealthThreshold") then
    local pickupStage = C:PickupGetStage("HealthThreshold")
    return pickupStage
  else
    return 0
  end
end
function Brain_Core:OnEnterCombat(ai, global, constants)
  isInCombat = true
  _G.global.navBank = constants.CombatNavBank
  ai:SetNavBank(constants.CombatNavBank)
  local levelName = ai.Level.Name
  if string.find(levelName, "WAD_Cal270_StoneMasonLH_AI_02") ~= nil and not bossHealthBarOn then
    LuaHook_ShowHealth(ai)
  end
end
function LuaHook_ShowHealth(ai)
  mpicon.level.Create(ai:GetGameObject(), "BOSS_HEALTH_BAR_QUEST_WITCH")
  mpicon.level.SetTextObjectText(ai, "BOSS_HEALTH_BAR_QUEST_WITCH", "bossName", "[MSG:" .. 37163 .. "]")
  mpicon.level.SetTextObjectText(ai, "BOSS_HEALTH_BAR_QUEST_WITCH", "icon", "\199\153")
  bossHealthBarOn = true
  ai:ForceHideHealthBar()
  mpicon.level.PlayAnimation(ai, "BOSS_HEALTH_BAR_QUEST_WITCH", 0, "bossHealthBar_ToggleStunMeterOn")
  if ai.SetOverrideStatusEffectIconParent ~= nil then
    ai:SetOverrideStatusEffectIconParent("BOSS_HEALTH_BAR_QUEST_WITCH")
  end
end
function LuaHook_HideHealth(ai)
  if bossHealthBarOn then
    mpicon.level.Off(ai:GetGameObject(), "BOSS_HEALTH_BAR_QUEST_WITCH")
    bossHealthBarOn = false
  end
end
function Brain_Core:OnExitCombat(ai, global, constants)
  isInCombat = false
  _G.global.navBank = constants.DefaultNavBank
  ai:SetNavBank(constants.DefaultNavBank)
  local levelName = ai.Level.Name
  if string.find(levelName, "Cal270") ~= nil and bossHealthBarOn then
    mpicon.level.Off(ai:GetGameObject(), "BOSS_HEALTH_BAR_QUEST_WITCH")
    bossHealthBarOn = false
  end
end
function OnAIUpdate(ai)
  traverselink.OnUpdate(ai)
  if witch20FrostBreathUsed then
    if ai:IsPlayingMove("MOV_AttPowderRanged_Enter") or ai:IsPlayingMove("MOV_AttPowderRanged_Loop") then
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[1].Min = witch20FrostBreathMinDistance
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[1].Max = witch20FrostBreathMaxDistance
    else
      witch20FrostBreathUsed = false
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[1].Min = origAggressiveMinDistance
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[1].Max = origAggressiveMaxDistance
    end
  end
  if witchNavEvadeUsed then
    if ai:IsPlayingMove("MOV_EvadeNav") then
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[1].Min = navEvadeMinDistance
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[1].Max = navEvadeMaxDistance
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[2].Min = navEvadeMinAngle
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[2].Max = navEvadeMaxAngle
    else
      witchNavEvadeUsed = false
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[1].Min = origAggressiveMinDistance
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[1].Max = origAggressiveMaxDistance
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[2].Min = origAggressiveMinAngle
      constants.fightKnowledgeInputs.Zones.Default.Aggressive[1].Constraints[2].Max = origAggressiveMaxAngle
    end
  end
end
function _G.OnAICreateLuaState(ai)
  _G.OnAICreateLuaState = nil
end
local MoveAwayFromAlly = function(ai)
  local nearbyFriendlies = ai:FindFriendlies(2)
  local evadeDirection
  local isStealthed = ai:PickupIsAcquired("WitchStealth")
  if 0 < #nearbyFriendlies and not isStealthed then
    for _, creature in ipairs(nearbyFriendlies) do
      local creatureName = creature:GetName()
      if creature ~= ai and 0 < creature:GetHitPoints() and (creatureName == "witch00" or creatureName == "witch10" or creatureName == "witch20") then
        local frontAngle = DL.FrontAngle(ai, creature)
        if frontAngle < 0 and -180 <= frontAngle then
          evadeDirection = "right"
          break
        elseif 0 < frontAngle and frontAngle <= 180 then
          evadeDirection = "left"
          break
        end
      end
    end
    if evadeDirection ~= nil then
      local jointIndex = ai:GetJointIndex("zeroJoint")
      local zeroJointFacingLeft = ai:GetWorldJointLeft(jointIndex)
      local zeroJointFacingUp = ai:GetWorldJointUp(jointIndex)
      local offset = engine.Vector.New(0, 2, 0)
      local offsetZeroJoint = ai.WorldPosition + offset
      local toDown = zeroJointFacingUp * -3
      if evadeDirection == "left" then
        local toLeft = zeroJointFacingLeft * 4
        local offsetLeft = offsetZeroJoint + toLeft
        local offsetLeftDown = offsetLeft + toDown
        offsetLeft.y = offsetZeroJoint.y
        local hitLeft = game.World.RaycastCollision(offsetZeroJoint, offsetLeft, {SourceGameObject = ai, FindAnything = true})
        if not hitLeft then
          local hitLeftDown = game.World.RaycastCollision(offsetZeroJoint, offsetLeftDown, {SourceGameObject = ai, FindAnything = true})
          if hitLeftDown then
            ai:ForceMove("BRA_RepositionL")
          end
        else
          return
        end
      elseif evadeDirection == "right" then
        local toRight = zeroJointFacingLeft * -4
        local offsetRight = offsetZeroJoint + toRight
        local offsetRightDown = offsetRight + toDown
        offsetRight.y = offsetZeroJoint.y
        local hitRight = game.World.RaycastCollision(offsetZeroJoint, offsetRight, {SourceGameObject = ai, FindAnything = true})
        if not hitRight then
          local hitRightDown = game.World.RaycastCollision(offsetZeroJoint, offsetRightDown, {SourceGameObject = ai, FindAnything = true})
          if hitRightDown then
            ai:ForceMove("BRA_RepositionR")
          end
        else
          return
        end
      end
    end
  end
end
local CheckForClearEvadePath = function(C, cardinalDirection, distanceCheck)
  local ai = C:GetAI()
  local jointIndex = ai:GetJointIndex("zeroJoint")
  local zeroJointFacingUp = ai:GetWorldJointUp(jointIndex)
  local offset = engine.Vector.New(0, 1.5, 0)
  local offsetZeroJoint = ai.WorldPosition + offset
  local toDown = zeroJointFacingUp * -3
  if cardinalDirection == "forward" then
    local zeroJointFacingFwd = ai:GetWorldJointForward(jointIndex)
    local toFront = zeroJointFacingFwd * distanceCheck
    local offsetFront = offsetZeroJoint + toFront
    offsetFront.y = offsetZeroJoint.y
    local hitFront = game.World.RaycastCollision(offsetZeroJoint, offsetFront, {
      SourceGameObject = ai,
      EntityType = game.CollisionType.New("kEnvironment", "kInvisibleBarrier")
    })
    if not hitFront then
      local offsetFrontDown = offsetFront + toDown
      local hitFrontDown = game.World.RaycastCollision(offsetZeroJoint, offsetFrontDown, {
        SourceGameObject = ai,
        EntityType = game.CollisionType.New("kEnvironment", "kInvisibleBarrier")
      })
      if hitFrontDown then
        return true
      else
        return false
      end
    else
      return false
    end
  elseif cardinalDirection == "back" then
    local zeroJointFacingFwd = ai:GetWorldJointForward(jointIndex)
    local toBack = zeroJointFacingFwd * (distanceCheck * -1)
    local offsetBack = offsetZeroJoint + toBack
    offsetBack.y = offsetZeroJoint.y
    local hitBack = game.World.RaycastCollision(offsetZeroJoint, offsetBack, {
      SourceGameObject = ai,
      EntityType = game.CollisionType.New("kEnvironment", "kInvisibleBarrier")
    })
    if not hitBack then
      local offsetBackDown = offsetBack + toDown
      local hitBackDown = game.World.RaycastCollision(offsetZeroJoint, offsetBackDown, {
        SourceGameObject = ai,
        EntityType = game.CollisionType.New("kEnvironment", "kInvisibleBarrier")
      })
      if hitBackDown then
        return true
      else
        return false
      end
    else
      return false
    end
  elseif cardinalDirection == "left" then
    local zeroJointFacingLeft = ai:GetWorldJointLeft(jointIndex)
    local toLeft = zeroJointFacingLeft * distanceCheck
    local offsetLeft = offsetZeroJoint + toLeft
    offsetLeft.y = offsetZeroJoint.y
    local hitLeft = game.World.RaycastCollision(offsetZeroJoint, offsetLeft, {
      SourceGameObject = ai,
      EntityType = game.CollisionType.New("kEnvironment", "kInvisibleBarrier")
    })
    if not hitLeft then
      local offsetLeftDown = offsetLeft + toDown
      local hitLeftDown = game.World.RaycastCollision(offsetZeroJoint, offsetLeftDown, {
        SourceGameObject = ai,
        EntityType = game.CollisionType.New("kEnvironment", "kInvisibleBarrier")
      })
      if hitLeftDown then
        return true
      else
        return false
      end
    else
      return false
    end
  elseif cardinalDirection == "right" then
    local zeroJointFacingLeft = ai:GetWorldJointLeft(jointIndex)
    local toRight = zeroJointFacingLeft * (distanceCheck * -1)
    local offsetRight = offsetZeroJoint + toRight
    offsetRight.y = offsetZeroJoint.y
    local hitRight = game.World.RaycastCollision(offsetZeroJoint, offsetRight, {
      SourceGameObject = ai,
      EntityType = game.CollisionType.New("kEnvironment", "kInvisibleBarrier")
    })
    if not hitRight then
      local offsetRightDown = offsetRight + toDown
      local hitRightDown = game.World.RaycastCollision(offsetZeroJoint, offsetRightDown, {
        SourceGameObject = ai,
        EntityType = game.CollisionType.New("kEnvironment", "kInvisibleBarrier")
      })
      if hitRightDown then
        return true
      else
        return false
      end
    else
      return false
    end
  else
    print("[Witch] Did NOT pass a valid cardinalDirection into CheckForClearEvadePath()")
    return false
  end
end
function Brain_Core:OnUpdateCombat(ai, global, constants, dTreeParams)
  if ai:IsInNavigationMove() then
    MoveAwayFromAlly(ai)
  end
  if isDebuffed and global.target and ai.HitPoints > 0 and 1 < GetWitchArmorStage(ai) then
    local distToTarget = global.target:GetWorldPosition():Distance(ai:GetWorldPosition())
    if distToTarget <= 7 and not ai:HasMarker("AI_Attack") then
      isDebuffed = false
      ai:ForceMove("BRA_EvadeSelector")
    else
      isDebuffed = false
    end
  end
  if isCrumpled and GetWitchHealthThresholdStage(ai) ~= 2 then
    ai:PickupRelinquish("WitchPauseArmorMeter")
    isCrumpled = false
  end
end
function Brain_Core:OnHitReaction(event, ai, global, constants)
  if not isDebuffed and global.target and ai.HitPoints > 0 and GetWitchArmorStage(ai) <= 1 then
    isDebuffed = true
  end
  if ai:PickupIsAcquired("WitchArmor") and ai:PickupGetStage("WitchArmor") == 0 and ai:PickupIsAcquired("PowerLevelPenalty") == false and event.enemyId ~= DL.HashCreatureID(ai, "SON00") then
    local damageDone = event.damage
    if ai:AttributeGetValue("Difficulty") >= 3 then
      ai:MeterSetValue("WitchComboBreakerMeter", ai:MeterGetValue("WitchComboBreakerMeter") + damageDone * 1.2)
    else
      ai:MeterSetValue("WitchComboBreakerMeter", ai:MeterGetValue("WitchComboBreakerMeter") + damageDone * 2)
    end
  end
end
picklelib.Install()
function Pickle(GO)
  print("global.target = ", global.target)
  return {
    global = global
  }
end
function Unpickle(GO, t)
  print("unpickled global.target = ", t.global.target)
  global = t.global
end
function LuaHook_CheckCanReact(ai)
  if ai:MeterGetValue("WitchComboBreakerMeter") <= 99 then
    return false
  else
    return true
  end
end
function LuaHook_WitchMaskBreak(C, data)
  if creatureName == "witch00" and 5 <= pLevelInt then
    C:HideJoint(C:GetJointIndex("Mask_06"))
    C:HideJoint(C:GetJointIndex("Mask_06_LOD1"))
    C:HideJoint(C:GetJointIndex("Mask_06_LOD2"))
    C:HideJoint(C:GetJointIndex("Mask_05"))
    C:HideJoint(C:GetJointIndex("Mask_05_LOD1"))
    C:HideJoint(C:GetJointIndex("Mask_05_LOD2"))
    C:HideJoint(C:GetJointIndex("Mask_05_LOD3"))
    C:HideJoint(C:GetJointIndex("Mask_04"))
    C:HideJoint(C:GetJointIndex("Mask_04_LOD1"))
    C:HideJoint(C:GetJointIndex("Mask_04_LOD2"))
    C:HideJoint(C:GetJointIndex("Mask_04_LOD3"))
    C:HideJoint(C:GetJointIndex("Mask_03"))
    C:HideJoint(C:GetJointIndex("Mask_03_LOD1"))
    C:HideJoint(C:GetJointIndex("Mask_03_LOD2"))
    C:HideJoint(C:GetJointIndex("Mask_02"))
    C:HideJoint(C:GetJointIndex("Mask_02_LOD1"))
    C:HideJoint(C:GetJointIndex("Mask_02_LOD2"))
    C:HideJoint(C:GetJointIndex("Mask_02_LOD3"))
  elseif creatureName == "witch10" then
    if pLevelInt <= 2 then
      C:HideJoint(C:GetJointIndex("hard_mask03"))
      C:HideJoint(C:GetJointIndex("hard_mask03_LOD1"))
      C:HideJoint(C:GetJointIndex("hard_mask03_LOD2"))
      C:HideJoint(C:GetJointIndex("hard_mask03_LOD3"))
      C:HideJoint(C:GetJointIndex("hard_mask02"))
      C:HideJoint(C:GetJointIndex("hard_mask02_LOD1"))
      C:HideJoint(C:GetJointIndex("hard_mask02_LOD2"))
      C:HideJoint(C:GetJointIndex("hard_mask02_LOD3"))
      C:HideJoint(C:GetJointIndex("hard_mask04"))
      C:HideJoint(C:GetJointIndex("hard_mask04_LOD1"))
      C:HideJoint(C:GetJointIndex("hard_mask04_LOD2"))
    elseif 3 <= pLevelInt and pLevelInt <= 4 then
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_02"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_02_LOD1"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_02_LOD2"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_02_LOD3"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_05"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_05_LOD1"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_05_LOD2"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_05_LOD3"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_04"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_04_LOD1"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_04_LOD2"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_04_LOD3"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_03"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_03_LOD1"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_03_LOD2"))
      C:HideJoint(C:GetJointIndex("_10_skull_chunk_03_LOD3"))
    elseif 5 <= pLevelInt then
      C:HideJoint(C:GetJointIndex("veryhard_mask03"))
      C:HideJoint(C:GetJointIndex("veryhard_mask03_LOD1"))
      C:HideJoint(C:GetJointIndex("veryhard_mask03_LOD2"))
      C:HideJoint(C:GetJointIndex("veryhard_mask03_LOD3"))
      C:HideJoint(C:GetJointIndex("veryhard_mask02"))
      C:HideJoint(C:GetJointIndex("veryhard_mask02_LOD1"))
      C:HideJoint(C:GetJointIndex("veryhard_mask02_LOD2"))
      C:HideJoint(C:GetJointIndex("veryhard_mask02_LOD3"))
      C:HideJoint(C:GetJointIndex("veryhard_mask05"))
      C:HideJoint(C:GetJointIndex("veryhard_mask05_LOD1"))
      C:HideJoint(C:GetJointIndex("veryhard_mask05_LOD2"))
      C:HideJoint(C:GetJointIndex("veryhard_mask05_LOD3"))
      C:HideJoint(C:GetJointIndex("veryhard_mask04"))
      C:HideJoint(C:GetJointIndex("veryhard_mask04_LOD1"))
      C:HideJoint(C:GetJointIndex("veryhard_mask04_LOD2"))
      C:HideJoint(C:GetJointIndex("veryhard_mask04_LOD3"))
    end
  end
end
function LuaHook_Witch20FrostBreath(C, data)
  witch20FrostBreathUsed = true
end
function LuaHook_WitchNavEvade(C, data)
  witchNavEvadeUsed = true
end
function LuaHook_RageGrabTextShow(C, data)
  if not rageGrabTextShow then
    rageGrabTextShow = true
    uiCalls.SendSidebarDesignerMessage({
      Text = 40867,
      AdvanceType = uiCalls.msgParam.INFINITE_TIMER
    })
  end
end
function LuaHook_RageGrabTextHide(C, data)
  if rageGrabTextShow then
    uiCalls.UI_Event_TurnOffDesignerMessage()
    rageGrabTextShow = false
  end
end
function LuaHook_GetIsWitchEscaping(C, data)
  if isEscaping then
    return true
  else
    return false
  end
end
function LuaHook_ResetIsWitchEscaping(C, data)
  isEscaping = false
end
function LuaHook_WitchCrumpled(C, data)
  C:PickupAcquire("WitchPauseArmorMeter")
  isCrumpled = true
end
function LuaHook_PersistentFXAcquirePickupSetStage(C, data)
  C:PickupAcquire("WitchPersistentFX")
  if C:PickupIsAcquired("WitchPersistentFX") then
    if creatureName == "witch00" then
      C:PickupSetStage("WitchPersistentFX", 1)
    elseif creatureName == "witch10" then
      C:PickupSetStage("WitchPersistentFX", 2)
    elseif creatureName == "witch20" then
      C:PickupSetStage("WitchPersistentFX", 3)
    end
  else
    print("WITCH ISSUE - WitchPersistentFX pickup was not acquired when it should have been -- stage cannot be set")
  end
  if not C:PickupIsAcquired("WitchArmor") then
    C:PickupAcquire("WitchArmor")
    C:PickupSetStage("WitchArmor", 4)
  end
end
function LuaHook_TargetKratos(C, data)
  global.targetParams = "FIND_TARGET_PARAMETERS_COMBAT_KRATOS_ONLY"
end
function LuaHook_EvadeFXAcquirePickupSetStage(C, data)
  if not C:PickupIsAcquired("WitchStealth") then
    C:PickupAcquire("WitchStealth")
    if C:PickupIsAcquired("WitchStealth") then
      if creatureName == "witch00" then
        C:PickupSetStage("WitchStealth", 1)
      elseif creatureName == "witch10" then
        C:PickupSetStage("WitchStealth", 2)
      elseif creatureName == "witch20" then
        C:PickupSetStage("WitchStealth", 3)
      end
    else
      print("WITCH ISSUE - WitchStealth pickup was not acquired when it should have been -- stage cannot be set")
    end
  end
  LuaHook_RemoveEyeGlowIfElite(C, nil)
end
function LuaHook_RemoveEyeGlowIfElite(C, data)
  if C:PickupIsAcquired("Witch00_Elite_EyeGlow") then
    C:PickupRelinquish("Witch00_Elite_EyeGlow")
  end
end
function LuaHook_GainEyeGlowIfElite(C, data)
  if C:PickupIsAcquired("Witch00_Elite") and not C:PickupIsAcquired("Witch00_Elite_EyeGlow") then
    C:PickupAcquire("Witch00_Elite_EyeGlow")
  end
end
function LuaHook_CanSpawnFlyers(C, data)
  if C:PickupIsAcquired("PowerLevelPenalty") then
    return false
  end
  local existingFlyerCount = 0
  local nearbyFriendlies = C:FindFriendlies(50)
  for _, creature in ipairs(nearbyFriendlies) do
    local creatureName = creature:GetName()
    if creature ~= C and 0 < creature:GetHitPoints() and (creatureName == "flyer00" or creatureName == "flyer10") then
      existingFlyerCount = existingFlyerCount + 1
    end
  end
  local flyersNeeded = maxFlyerCount - existingFlyerCount
  if 0 < flyersNeeded then
    return true
  else
    return false
  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_Witch_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.4)
  player:AddBlood(game.GameObject.eRegionId.kFrontAbdomen, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontUpperArm, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLowerArm, 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.1)
  player:AddBlood(game.GameObject.eRegionId.kRightBackUpperArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLowerArm, 0.4)
end
function LuaHook_AddBlood_Witch_RagePunch(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.2)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLowerArm, 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.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLowerArm, 0.4)
end
function LuaHook_AddBlood_Witch_RageKnee(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kHead, 0.2)
  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.kRightFrontLowerArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLeg, 0.4)
  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.kRightBackLowerArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLeg, 0.4)
end
function GetFlyerSpawnConfigString(pLevel, flyerType)
  local intValue = 1
  local charConfig
  if pLevel == "1" then
    intValue = 1
  elseif pLevel == "2" then
    intValue = 2
  elseif pLevel == "3" then
    intValue = 3
  elseif pLevel == "4" then
    intValue = 4
  elseif pLevel == "5" then
    intValue = 5
  elseif pLevel == "6" then
    intValue = 6
  elseif pLevel == "7" then
    intValue = 7
  elseif pLevel == "8" then
    intValue = 8
  elseif pLevel == "1" then
    intValue = 9
  end
  if flyerType == "Seidr" then
    if 4 < intValue then
      charConfig = "Flyer_seidr_hard"
    else
      charConfig = "Flyer_seidr_easy"
    end
  elseif flyerType == "Fire" then
    if 4 < intValue then
      charConfig = "Flyer_fire_hard"
    else
      charConfig = "Flyer_fire_easy"
    end
  elseif flyerType == "Suicide" then
    if 4 < intValue then
      charConfig = "Flyer_suicide_hard"
    else
      charConfig = "Flyer_suicide_easy"
    end
  elseif flyerType == "Ice" then
    if 4 < intValue then
      charConfig = "Flyer_ice_hard"
    else
      charConfig = "Flyer_ice_easy"
    end
  elseif flyerType == "Blind" then
    if 4 < intValue then
      charConfig = "Flyer_blind_hard"
    else
      charConfig = "Flyer_blind_easy"
    end
  elseif flyerType == "Possess" then
    if 4 < intValue then
      charConfig = "Flyer_posses_hard"
    else
      charConfig = "Flyer_posses_easy"
    end
  else
    print("!!!! FLYER !!!! -- something wasnt set correctly on the spawner, so proper config and dTree are not set")
  end
  return charConfig
end
function LuaHook_SpawnFlyer(C, data)
  local spawnJointIndex = C:GetJointIndex("JOBack3")
  local spawnJointPos = C:GetWorldJointPosition(spawnJointIndex)
  local flyerTypeTotal = #flyerSpawnTypes
  local flyerTypeIndex = 1
  local spawnedFlyer
  if 1 < flyerTypeTotal then
    flyerTypeIndex = math.random(1, flyerTypeTotal)
  end
  local flyerTypeToSpawn = flyerSpawnTypes[flyerTypeIndex]
  if flyerPowerLevel == "1-Easiest" or flyerPowerLevel == "1-Easy" then
    flyerPowerLevel = "1"
  elseif flyerPowerLevel == "8-Hardest" or flyerPowerLevel == "8-Hard" then
    flyerPowerLevel = "8"
  end
  if game.CHECK_FEATURE("PREEMPT_SPAWN_CONFIG") then
    local charConfig = GetFlyerSpawnConfigString(flyerPowerLevel, flyerTypeToSpawn)
    if flyerTypeToSpawn ~= "Possess" then
      spawnedFlyer = game.AI.Spawn(C.Level, spawnJointPos, C:GetWorldForward(), "CRT_Flyer00", "BRA_SpawnFromWitch", {PowerLevel = flyerPowerLevel, FlyerType = flyerTypeToSpawn}, charConfig)
    elseif flyerTypeToSpawn == "Possess" then
      spawnedFlyer = game.AI.Spawn(C.Level, spawnJointPos, C:GetWorldForward(), "CRT_Flyer10", "BRA_SpawnFromWitch", {PowerLevel = flyerPowerLevel, FlyerType = flyerTypeToSpawn}, charConfig)
    end
    if spawnedFlyer ~= nil and game.Encounters.AddSpawnToEncounter then
      game.Encounters.AddSpawnToEncounter(C, spawnedFlyer)
    end
  else
    if flyerTypeToSpawn ~= "Possess" then
      spawnedFlyer = game.AI.Spawn(C.Level, spawnJointPos, C:GetWorldForward(), "CRT_Flyer00", "BRA_SpawnFromWitch", {PowerLevel = flyerPowerLevel, FlyerType = flyerTypeToSpawn})
    elseif flyerTypeToSpawn == "Possess" then
      spawnedFlyer = game.AI.Spawn(C.Level, spawnJointPos, C:GetWorldForward(), "CRT_Flyer10", "BRA_SpawnFromWitch", {PowerLevel = flyerPowerLevel, FlyerType = flyerTypeToSpawn})
    end
    if spawnedFlyer ~= nil then
      spawnedFlyer:CallScript("LuaHook_SetSpawnParamsFromWitch", flyerPowerLevel, flyerTypeToSpawn)
      if game.Encounters.AddSpawnToEncounter then
        game.Encounters.AddSpawnToEncounter(C, spawnedFlyer)
      end
    end
  end
end
function LuaHook_IsFlyerSpawnDisabled(C, data)
  if disableFlyerSpawn then
    return true
  else
    return false
  end
end
function LuaHook_WitchBeatdownDropHealth(ai, data)
  if lootChance == nil then
    lootChance = ai:LookupFloatConstant("WITCH_RAGE_PUNCH_LOOT_CHANCE")
  end
  local random = math.random()
  if random > lootChance then
    return
  end
  local jointIndex = ai:GetJointIndex("JOHead1")
  local jointPos = ai:GetWorldJointPosition(jointIndex)
  local jointDir = ai:GetWorldForward()
  jointPos = jointPos + jointDir * math.random(0.15, 0.5)
  local spawnArgs = {
    SpawnObject = "golootGenericHealthRune",
    OffsetPosition = jointPos,
    Level = game.Level.GetPermLevel()
  }
  game.Player.FindPlayer():CallScript("LuaHook_SpawnGameObject", spawnArgs)
end
function OnWeaponApproaching(gameObject, attacker, weapon, side)
  local ai = gameObject:GetCreature():GetAI()
  local isStealthed = ai:PickupIsAcquired("WitchStealth")
  if not isStealthed and isInCombat and ai:HasMarker("AxeTossEvade") then
    ai:ForceMove("BRA_AxeTossEvadeSelector")
  end
end
function LuaHook_EvadeIfPossible(C, data)
  if constants.canEvade and C.HitPoints > 0 then
    local ai = C:GetAI()
    ai:ForceMove("BRA_EvadeSelector")
    constants.canEvade = false
    isEscaping = true
  end
end
function LuaHook_BackCollisionBranchExit(C, data)
  local clearPathCheck = CheckForClearEvadePath(C, "back", 2.5)
  return clearPathCheck
end
function LuaHook_LeftCollisionBranchExit(C, data)
  local clearPathCheck = CheckForClearEvadePath(C, "left", 2.5)
  return clearPathCheck
end
function LuaHook_RightCollisionBranchExit(C, data)
  local clearPathCheck = CheckForClearEvadePath(C, "right", 2.5)
  return clearPathCheck
end
function LuaHook_BackEvadeDistanceCheck(C, data)
  if global.target ~= nil then
    local distToTarget = global.target:GetWorldPosition():Distance(C:GetWorldPosition())
    if distToTarget < 3 and C.HitPoints > 0 then
      if CheckForClearEvadePath(C, "back", 9.5) then
        OnEvadeBehavior(C)
        return data:FindOutcomeBranchesEntry("EvadeBackFar")
      end
    elseif CheckForClearEvadePath(C, "back", 6.5) then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("EvadeBackMid")
    elseif CheckForClearEvadePath(C, "back", 3.5) then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("EvadeBackShort")
    else
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("Cornered")
    end
  end
end
function LuaHook_ForwardShuffleCheck(C, data)
  if CheckForClearEvadePath(C, "forward", 6) then
    return true
  else
    return false
  end
end
function LuaHook_BackShuffleCheck(C, data)
  if CheckForClearEvadePath(C, "back", 5) then
    return true
  else
    return false
  end
end
function LuaHook_BackRepositionCheck(C, data)
  if CheckForClearEvadePath(C, "back", 8) then
    return true
  else
    return false
  end
end
function LuaHook_ForwardEvadeBehindPlayerCheck(C, data)
  if not CheckForClearEvadePath(C, "back", 5) then
    if CheckForClearEvadePath(C, "forward", 16) then
      return true
    else
      return false
    end
  else
    return false
  end
end
function LuaHook_SideEvadeCheck(C, data)
  if global.target and C.HitPoints > 0 then
    local leftClear = CheckForClearEvadePath(C, "left", 4)
    local rightClear = CheckForClearEvadePath(C, "right", 4)
    if leftClear and rightClear then
      local random = math.random(1, 2)
      if random == 1 then
        OnEvadeBehavior(C)
        return data:FindOutcomeBranchesEntry("EvadeLeft")
      else
        OnEvadeBehavior(C)
        return data:FindOutcomeBranchesEntry("EvadeRight")
      end
    elseif leftClear and not rightClear then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("EvadeLeft")
    elseif rightClear and not leftClear then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("EvadeRight")
    elseif not leftClear and not rightClear then
      return data:FindOutcomeBranchesEntry("Nothing")
    end
  else
    print("[Witch00] Something went wrong - Witch cannot evade, she has no target")
  end
end
function LuaHook_EvadeCheck(C, data)
  local healthThreshPickup = C:PickupIsAcquired("HealthThreshold")
  local pickupStage = 0
  local armorStage = GetWitchArmorStage(C)
  if healthThreshPickup then
    pickupStage = C:PickupGetStage("HealthThreshold")
  end
  local sonRunePickup = C:PickupIsAcquired("SonRune")
  local sonRuneStage = 0
  if sonRunePickup then
    sonRuneStage = C:PickupGetStage("SonRune")
  end
  if global.target and 0 < C.HitPoints and not C:HasMarker("InCSMove") and pickupStage ~= 2 and 1 < armorStage and not C:HasMarker("React_Crumple") and sonRuneStage ~= 2 then
    local ai = C:GetAI()
    local evadeDir
    local distToTarget = global.target:GetWorldPosition():Distance(C:GetWorldPosition())
    if distToTarget < 3 then
      if CheckForClearEvadePath(C, "back", 9) then
        evadeDir = "backFar"
      end
      if evadeDir ~= "backFar" and CheckForClearEvadePath(C, "back", 6) then
        evadeDir = "backMid"
      end
    end
    if distToTarget < 5 and evadeDir == nil and evadeDir == nil and CheckForClearEvadePath(C, "back", 4) then
      evadeDir = "backShort"
    end
    if 5 <= distToTarget or evadeDir == nil then
      local canEvadeLeft = CheckForClearEvadePath(C, "left", 4)
      local canEvadeRight = CheckForClearEvadePath(C, "right", 4)
      if canEvadeLeft and canEvadeRight then
        local random = math.random(1, 2)
        if random == 1 then
          evadeDir = "left"
        else
          evadeDir = "right"
        end
      elseif canEvadeLeft and not canEvadeRight then
        evadeDir = "left"
      elseif canEvadeRight and not canEvadeLeft then
        evadeDir = "right"
      elseif not canEvadeLeft and not canEvadeRight then
        evadeDir = "cornered"
      end
    end
    if evadeDir == "cornered" then
      if distToTarget < 4 then
        if CheckForClearEvadePath(C, "forward", 6) then
          local leftClear = CheckForClearEvadePath(C, "left", 1)
          local rightClear = CheckForClearEvadePath(C, "right", 1)
          if leftClear and rightClear then
            local random = math.random(1, 2)
            if random == 1 then
              evadeDir = "corneredFL"
            else
              evadeDir = "corneredFR"
            end
          elseif leftClear and not rightClear then
            evadeDir = "corneredFL"
          elseif rightClear and not leftClear then
            evadeDir = "corneredFR"
          elseif not rightClear and not leftClear then
            evadeDir = "corneredFL"
          end
        end
      else
        evadeDir = "nothing"
      end
    end
    if evadeDir == "left" then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("EvadeLeft")
    elseif evadeDir == "right" then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("EvadeRight")
    elseif evadeDir == "backShort" then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("EvadeBackShort")
    elseif evadeDir == "backMid" then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("EvadeBackMid")
    elseif evadeDir == "backFar" then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("EvadeBackFar")
    elseif evadeDir == "corneredFL" then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("CorneredFL")
    elseif evadeDir == "corneredFR" then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("CorneredFR")
    elseif evadeDir == "totallyCornered" then
      OnEvadeBehavior(C)
      return data:FindOutcomeBranchesEntry("TotallyCornered")
    elseif evadeDir == "nothing" then
      return data:FindOutcomeBranchesEntry("Nothing")
    end
  elseif (C:HasMarker("InCSMove") or C:HasMarker("React_Crumple") or pickupStage == 2 or armorStage <= 1) and global.target and 0 < C.HitPoints then
    return data:FindOutcomeBranchesEntry("SlowedDontEvade")
  else
    print("[Witch] Something went wrong - Witch cannot evade, she has no target")
    return data:FindOutcomeBranchesEntry("Nothing")
  end
end
function LuaHook_RemoveSlow(C)
  if C:PickupIsSlotUsed("Frost") then
    C:PickupRelinquish("Debuff_Slow")
  end
end
function OnEvadeBehavior(C)
  if C:PickupIsSlotUsed("Frost") then
    C:PickupRelinquish("Debuff_Slow")
    local healthThreshPickup = C:PickupIsAcquired("HealthThreshold")
    if healthThreshPickup then
      local pickupStage = C:PickupGetStage("HealthThreshold")
      if pickupStage == 2 then
        C:PickupSetStage("HealthThreshold", 0)
      end
    end
  end
end
function LuaHook_RepositionCheck(C, data)
  if global.target and C.HitPoints > 0 then
    local ai = C:GetAI()
    local evadeDir
    local distToTarget = global.target:GetWorldPosition():Distance(C:GetWorldPosition())
    local canEvadeLeft = CheckForClearEvadePath(C, "left", 5)
    local canEvadeRight = CheckForClearEvadePath(C, "right", 5)
    local canEvadeForward = CheckForClearEvadePath(C, "forward", 5)
    local canEvadeBack = CheckForClearEvadePath(C, "back", 5)
    if 18 < distToTarget and canEvadeForward then
      evadeDir = "forward"
    elseif distToTarget < 5 and canEvadeBack then
      print("reposition back")
      evadeDir = "back"
    end
    if evadeDir == nil then
      if canEvadeLeft and canEvadeRight then
        local random = math.random(1, 2)
        if random == 1 then
          evadeDir = "right"
        else
          evadeDir = "left"
        end
      elseif canEvadeLeft and not canEvadeRight then
        evadeDir = "left"
      elseif not canEvadeLeft and canEvadeRight then
        evadeDir = "right"
      end
    end
    if evadeDir == "forward" then
      return data:FindOutcomeBranchesEntry("RepositionF")
    elseif evadeDir == "back" then
      return data:FindOutcomeBranchesEntry("RepositionB")
    elseif evadeDir == "right" then
      return data:FindOutcomeBranchesEntry("RepositionR")
    elseif evadeDir == "left" then
      return data:FindOutcomeBranchesEntry("RepositionL")
    elseif evadeDir == nil then
      return data:FindOutcomeBranchesEntry("Nothing")
    end
  else
    print("[Witch] Something went wrong - Witch cannot reposition, she has no target")
    return data:FindOutcomeBranchesEntry("Nothing")
  end
end
local mouthEmitter, witchFoleyLoops
local witch00FoleyLoops = {
  "SND_CHR_Witch_Cloth_Movement_LP",
  "SND_CHR_Witch_Gear_Beads_Movement_LP",
  "SND_CHR_Witch_Gear_Lantern_Movement_LP",
  "SND_CHR_Witch_Gear_Wicker_Basket_Movement_LP"
}
local witch10FoleyLoops = {
  "SND_CHR_Witch_Cloth_Movement_LP",
  "SND_CHR_Witch_Gear_Beads_Movement_LP",
  "SND_CHR_Witch_Gear_Bones_LP",
  "SND_CHR_Witch_Gear_Jewelry_Movement_LP"
}
local witch20FoleyLoops = {
  "SND_CHR_Witch_Cloth_Movement_LP",
  "SND_CHR_Witch_Gear_Beads_Movement_LP",
  "SND_CHR_Witch_Gear_Wicker_Basket_Movement_LP"
}
local witchFoleyMovementSounds
local witch00FoleyMovementSoundsOverride = {
  "SND_CHR_Witch_Cloth_General_Swing",
  "SND_CHR_Witch_Gear_Beads_Movement_Swing",
  "SND_CHR_Witch_Gear_Lantern_Movement_Swing",
  "SND_CHR_Witch_Gear_Wicker_Basket_Movement_Swing"
}
local witch10FoleyMovementSoundsOverride = {
  "SND_CHR_Witch_Cloth_General_Swing",
  "SND_CHR_Witch_Gear_Beads_Movement_Swing",
  "SND_CHR_Witch_Gear_Bones_Swing",
  "SND_CHR_Witch_Gear_Jewelry_Movement_Swing"
}
local witch20FoleyMovementSoundsOverride = {
  "SND_CHR_Witch_Cloth_General_Swing",
  "SND_CHR_Witch_Gear_Beads_Movement_Swing",
  "SND_CHR_Witch_Gear_Wicker_Basket_Movement_Swing"
}
function SoundInit(ai)
  mouthEmitter = ai:FindSingleSoundEmitterByName("SNDMouth")
  if creatureName ~= nil then
    if creatureName == "witch00" then
      witchFoleyLoops = witch00FoleyLoops
      witchFoleyMovementSounds = witch00FoleyMovementSoundsOverride
    elseif creatureName == "witch10" then
      witchFoleyLoops = witch10FoleyLoops
      witchFoleyMovementSounds = witch10FoleyMovementSoundsOverride
    elseif creatureName == "witch20" then
      witchFoleyLoops = witch20FoleyLoops
      witchFoleyMovementSounds = witch20FoleyMovementSoundsOverride
    else
      print("[Witch -> Sound -> SoundInit()] ISSUE: creatureName is not nil but does not fall into any of the variations setup, is the current creatureName a new variation?")
    end
  else
    print("[Witch -> Sound -> SoundInit()] ISSUE: creatureName is nil! No sound tables overrided")
  end
end
function LuaHook_Sound_StartFoleyLoops()
  PlaySoundsInTable(witchFoleyLoops)
end
function LuaHook_Sound_StopFoleyLoop()
  StopSoundsInTable(witchFoleyLoops)
end
function LuaHook_Sound_PlayFoleyMovement()
  PlaySoundsInTable(witchFoleyMovementSounds)
end
function PlaySoundsInTable(soundTable)
  if soundTable ~= nil then
    for _, soundEvent in ipairs(soundTable) do
      if mouthEmitter ~= nil and not mouthEmitter:IsPlaying(soundEvent) then
        mouthEmitter:Start(soundEvent)
      end
    end
  end
end
function StopSoundsInTable(soundTable)
  if soundTable ~= nil then
    for _, soundEvent in ipairs(soundTable) do
      mouthEmitter:Stop(soundEvent)
    end
  end
end
