public static void Prefix(SiegeMonster __instance)
 {
     if (enemyAssignments.ContainsKey(__instance))
     {
         enemyAssignments.Remove(__instance);
     }
 }
            public static void Postfix(IMoveableUnit __result)
            {
                SiegeMonster ogre = __result as SiegeMonster;

                if (ogre != null && !enemyAssignments.ContainsKey(ogre))
                {
                    enemyAssignments[ogre] = ogreStartPoints;
                }
            }
        private static bool TargetTypeInvalid(IMoveTarget target)
        {
            UnitSystem.Army army = target as UnitSystem.Army;
            SiegeMonster    ogre = target as SiegeMonster;

            if (ogre != null)
            {
                return(ogre.IsInvalid());
            }
            if (army != null)
            {
                return(army.IsInvalid());
            }
            return(true);
        }
        private static IMoveTarget GetNextViking(Vector3 pos, float range)
        {
            // Refer to SiegeMonster::ClosestMonster and UnitSystem::GetClosestDamageable.
            float       rangeSquared           = range * range;
            float       currentClosestDistance = float.MaxValue;
            int         currentLowestAssigned  = int.MaxValue;
            IMoveTarget nextViking             = null;

            foreach (IMoveTarget viking in enemyAssignments.Keys)
            {
                UnitSystem.Army army = viking as UnitSystem.Army;
                SiegeMonster    ogre = viking as SiegeMonster;
                if ((army == null && ogre == null) ||
                    (army != null && (army.IsInvalid() || !OnSameLandmass(pos, army.GetPos()))) ||
                    (ogre != null && (ogre.IsInvalid() || !OnSameLandmass(pos, ogre.GetPos()))) ||
                    !TargetTypeEnabled(viking))
                {
                    continue;
                }

                // Select the closest viking squad or ogre with the least points to obey the assignment and distribution
                // rules.
                int   assigned        = enemyAssignments[viking];
                float distanceSquared = Mathff.DistSqrdXZ(pos, viking.GetPos());

                if (distanceSquared > rangeSquared || assigned > currentLowestAssigned)
                {
                    continue;
                }

                if (nextViking == null || assigned < currentLowestAssigned ||
                    (distanceSquared < currentClosestDistance && assigned == currentLowestAssigned))
                {
                    nextViking             = viking;
                    currentClosestDistance = distanceSquared;
                    currentLowestAssigned  = assigned;
                }
            }
            return(nextViking);
        }
        private static bool TargetTypeEnabled(IMoveTarget target)
        {
            UnitSystem.Army army = target as UnitSystem.Army;
            SiegeMonster    ogre = target as SiegeMonster;

            if (ogre != null)
            {
                return(settings.ogres.Value);
            }
            if (army != null)
            {
                if (army.armyType == UnitSystem.ArmyType.Default)
                {
                    return(settings.defaultViking.Value);
                }
                if (army.armyType == UnitSystem.ArmyType.Thief)
                {
                    return(settings.thieves.Value);
                }
            }
            return(false);
        }
        // Takes into account if move target is a Transport Ship. Since Transport Ship is not IProjectileHitable, this
        // returns the ShipBase, which is IProjectileHitable.
        private static System.Object GetAttackTarget(UnitSystem.Army army, ArcherGeneral archerGeneral)
        {
            if (army.locked && army.moveTarget != null)
            {
                System.Object moveTarget = army.moveTarget;
                Vector3       targetPos;

                // Refer to ProjectileDefense::GetTarget for getting target position.
                if (moveTarget is TroopTransportShip)
                {
                    // Prevents friendly fire.
                    if (((TroopTransportShip)moveTarget).TeamID() != 0)
                    {
                        ShipBase shipBase = ((TroopTransportShip)moveTarget).shipBase;
                        moveTarget = shipBase;
                        targetPos  = shipBase.GetPos();
                    }
                    else
                    {
                        return(null);
                    }
                }
                else if (moveTarget is SiegeMonster)
                {
                    SiegeMonster ogre = (SiegeMonster)moveTarget;
                    if (ogre.IsInvalid())
                    {
                        // Ogre died or got on a ship, stop tracking.
                        army.moveTarget = null;
                        return(null);
                    }
                    targetPos = ogre.GetPos();
                }
                else if (moveTarget is IProjectileHitable)
                {
                    if (moveTarget is UnitSystem.Army && ((UnitSystem.Army)moveTarget).IsInvalid())
                    {
                        // Army died or got on a ship, stop tracking.
                        army.moveTarget = null;
                        return(null);
                    }
                    targetPos = ((IProjectileHitable)moveTarget).GetPosition();
                }
                else
                {
                    return(null);
                }

                // If moveTarget is not in range, returning null will make archer seek another target until moveTarget
                // is in range. This is because moveTarget will not change until it is dead, or the player clicked on a
                // different target.
                // Refer to ArcherGeneral::Update and ProjectileDefense::GetTarget for range calculation.
                Vector3 archerPos   = army.GetPos();
                float   attackRange = archerGeneral.FullRange(archerGeneral.attackRange) + 1f;
                if (!ProjectileDefense.TestRange(targetPos, archerPos, attackRange))
                {
                    return(null);
                }
                return(moveTarget);
            }
            else
            {
                // If not on ship, don't change the behavior.
                return(army.moveTarget);
            }
        }
            static void Postfix(TroopTransportShip __instance, IMoveTarget target, List <IMoveableUnit> ___loadTarget)
            {
                if (__instance.TeamID() != 0 || target == null || target.TeamID() == 0 || target.TeamID() == -1)
                {
                    // Not an allied ship, no target, target is allied, or target is environment.
                    // Refer to UnitSystem::UpdatePathing for determining if target is an enemy.
                    return;
                }

                // Check if ship has archers.
                bool shipHasArchers = false;

                // Refer to TroopTransportShip::UpdateArmyPosition.
                for (int i = 0; i < ___loadTarget.Count(); i++)
                {
                    UnitSystem.Army army = ___loadTarget[i] as UnitSystem.Army;
                    if (army != null)
                    {
                        bool isArcher = army.armyType == UnitSystem.ArmyType.Archer;
                        if (isArcher)
                        {
                            shipHasArchers = true;
                            break;
                        }
                    }
                }

                if (shipHasArchers)
                {
                    IMoveTarget archersTarget = null;

                    if (target is SiegeMonster)
                    {
                        SiegeMonster ogre            = (SiegeMonster)target;
                        bool         ogreTargettable = !ogre.IsInvalid();
                        bool         ogreDead        = ogre.IsDead();

                        if (ogreTargettable)
                        {
                            // Ogre is on land.
                            archersTarget = target;
                        }
                        else if (!ogreTargettable && !ogreDead)
                        {
                            // Ogre is on a ship. Assumption is that the closest ship is the ship it's on.
                            Vector3 pos = ogre.GetPos();

                            // Refer to ProjectileDefense::GetTarget
                            IProjectileHitable closestShip = ShipSystem.inst.GetClosestShipToAttack(pos, 1, 1f);
                            ShipBase           shipBase    = closestShip as ShipBase;
                            if (shipBase != null)
                            {
                                archersTarget = shipBase.GetComponentInParent <TroopTransportShip>();
                            }
                        }
                    }
                    else if (target is TroopTransportShip || target is IProjectileHitable)
                    {
                        archersTarget = target;
                    }

                    // Set archer target.
                    if (archersTarget != null)
                    {
                        for (int i = 0; i < ___loadTarget.Count(); i++)
                        {
                            UnitSystem.Army army = ___loadTarget[i] as UnitSystem.Army;
                            if (army != null)
                            {
                                bool isArcher = army.armyType == UnitSystem.ArmyType.Archer;
                                if (isArcher)
                                {
                                    army.moveTarget = archersTarget;
                                }
                            }
                        }
                    }
                }
            }