Example #1
0
        public TargetPriorityCalculation CalculateTargetPriority(IEnumerable <UnitCalculation> allies, IEnumerable <UnitCalculation> enemies)
        {
            var calculation = new TargetPriorityCalculation
            {
                TargetPriority = TargetPriority.Attack
            };

            var allyHealth  = allies.Sum(e => e.SimulatedHitpoints);
            var enemyHealth = enemies.Sum(e => e.SimulatedHitpoints);

            var allyAttributes  = allies.SelectMany(e => e.Attributes).Distinct();
            var enemyAttributes = enemies.SelectMany(e => e.Attributes).Distinct();

            var allyDps  = allies.Sum(e => e.SimulatedDamagePerSecond(enemyAttributes, true, true));
            var enemyDps = enemies.Sum(e => e.SimulatedDamagePerSecond(allyAttributes, true, true));

            var allyHps  = allies.Sum(e => e.SimulatedHealPerSecond);
            var enemyHps = enemies.Sum(e => e.SimulatedHealPerSecond);

            var secondsToKillEnemies = 1000f;

            if (allyDps - enemyHps > 0)
            {
                secondsToKillEnemies = enemyHealth / (allyDps - enemyHps);
            }

            var secondsToKillAllies = 1000f;

            if (enemyDps - allyHps > 0)
            {
                secondsToKillAllies = allyHealth / (enemyDps - allyHps);
            }

            calculation.OverallWinnability = secondsToKillAllies / secondsToKillEnemies; // higher the number the better
            if (secondsToKillEnemies == 0)
            {
                calculation.OverallWinnability = 1000f;
            }
            calculation.Overwhelm = calculation.OverallWinnability > 20;

            var airAttackingEnemies = enemies.Where(e => e.DamageAir || e.Unit.UnitType == (uint)UnitTypes.PROTOSS_SHIELDBATTERY);
            var airKillSeconds      = 1000f;

            if (allies.Count(a => a.Unit.IsFlying && a.DamageAir) > 0)
            {
                var seconds = GetKillSeconds(airAttackingEnemies, allies);
                if (seconds > 0)
                {
                    airKillSeconds = seconds;
                }
                else
                {
                    airKillSeconds = 0.00001f;
                }
            }

            calculation.AirWinnability = secondsToKillAllies / airKillSeconds;

            var groundAttackingEnemies = enemies.Where(e => e.DamageGround || e.Unit.UnitType == (uint)UnitTypes.TERRAN_MEDIVAC || e.Unit.UnitType == (uint)UnitTypes.PROTOSS_WARPPRISM || e.Unit.UnitType == (uint)UnitTypes.PROTOSS_SHIELDBATTERY);
            var groundKillSeconds      = 1000f;

            if (allies.Count(a => !a.Unit.IsFlying && a.DamageGround) > 0)
            {
                var seconds = GetKillSeconds(groundAttackingEnemies, allies);
                if (seconds > 0)
                {
                    groundKillSeconds = seconds;
                }
                else
                {
                    groundKillSeconds = 0.00001f;
                }
            }

            calculation.GroundWinnability = secondsToKillAllies / groundKillSeconds;

            if (calculation.OverallWinnability < 1 && calculation.AirWinnability < 1 && calculation.GroundWinnability < 1)
            {
                if (enemyHps > enemyDps && groundAttackingEnemies.Count(u => u.Unit.UnitType == (uint)UnitTypes.TERRAN_SCV) > 2)
                {
                    var lowerHps = enemyHealth / (allyDps - (enemyHps / 5));
                    if (secondsToKillAllies / lowerHps > 1)
                    {
                        calculation.TargetPriority = TargetPriority.KillWorkers; // can win by targetting repairing scvs
                        return(calculation);
                    }
                }

                calculation.TargetPriority = TargetPriority.Retreat;
                return(calculation);
            }

            if (calculation.GroundWinnability > calculation.AirWinnability)
            {
                var bunker = groundAttackingEnemies.Where(b => b.Unit.UnitType == (uint)UnitTypes.TERRAN_BUNKER).FirstOrDefault();
                if (bunker != null && groundAttackingEnemies.Count() < 10)
                {
                    if (bunker.Unit.BuildProgress < 1 || (bunker.Unit.Health > 100 && enemyHps > enemyDps && groundAttackingEnemies.Count(u => u.Unit.UnitType == (uint)UnitTypes.TERRAN_SCV) > 2))
                    {
                        calculation.TargetPriority = TargetPriority.KillWorkers;
                        return(calculation);
                    }

                    calculation.TargetPriority = TargetPriority.KillBunker;
                    return(calculation);
                }
                calculation.TargetPriority = TargetPriority.WinGround;
            }
            else if (calculation.AirWinnability > calculation.GroundWinnability)
            {
                calculation.TargetPriority = TargetPriority.WinAir;
            }

            return(calculation);
        }
Example #2
0
        public UnitCalculation(Unit unit, int repairers, SharkyUnitData sharkyUnitData, SharkyOptions sharkyOptions, UnitDataService unitDataService, int frame)
        {
            TargetPriorityCalculation = new TargetPriorityCalculation();
            oneSecondInFrames         = sharkyOptions.FramesPerSecond;

            //PreviousUnits = new Dictionary<int, Unit>();
            //PreviousUnits[frame] = unit;
            PreviousUnit = unit;
            Unit         = unit;
            UnitTypeData = sharkyUnitData.UnitData[(UnitTypes)unit.UnitType];

            Velocity        = 0;
            AverageVelocity = 0;
            Vector          = Vector2.Zero;
            AverageVector   = Vector2.Zero;
            Position        = new Vector2(unit.Pos.X, unit.Pos.Y);

            FrameLastSeen = frame;

            var unitRange = unitDataService.GetRange(unit);

            if (unitRange == 0)
            {
                Range = 0;
            }
            else
            {
                Range = unitRange + unit.Radius;
            }

            Start = new Vector2(unit.Pos.X, unit.Pos.Y);

            if (unit.UnitType == (uint)UnitTypes.PROTOSS_COLOSSUS || unit.UnitType == (uint)UnitTypes.PROTOSS_IMMORTAL || unit.UnitType == (uint)UnitTypes.PROTOSS_PHOTONCANNON || unit.UnitType == (uint)UnitTypes.PROTOSS_MOTHERSHIP ||
                unit.UnitType == (uint)UnitTypes.TERRAN_MISSILETURRET ||
                unit.UnitType == (uint)UnitTypes.ZERG_SPORECRAWLER || unit.UnitType == (uint)UnitTypes.ZERG_SPINECRAWLER)
            {
                End = Start; // facing is always 0 for these units, can't calculate where they're aiming
            }
            else
            {
                var endX = (float)(Range * Math.Sin(unit.Facing + (Math.PI / 2)));
                var endY = (float)(Range * Math.Cos(unit.Facing + (Math.PI / 2)));
                End = new Vector2(endX + unit.Pos.X, unit.Pos.Y - endY);
            }

            DamageRadius      = 1; // TODO: get damage radius
            EstimatedCooldown = 0; // TODO: get estimated cooldown

            DamageAir = false;
            if (unitDataService.CanAttackAir((UnitTypes)unit.UnitType))
            {
                DamageAir = true;
            }
            DamageGround = false;
            if (unitDataService.CanAttackGround((UnitTypes)unit.UnitType))
            {
                DamageGround = true;
            }
            Damage  = unitDataService.GetDamage(unit);
            Dps     = unitDataService.GetDps(unit);
            Weapon  = unitDataService.GetWeapon(unit);
            Weapons = UnitTypeData.Weapons.ToList();
            if (Weapons == null || Weapons.Count() == 0)
            {
                Weapons = new List <Weapon>();
                if (Weapon != null)
                {
                    Weapons.Add(Weapon);
                }
            }

            SimulatedHitpoints = Unit.Health + Unit.Shield;
            if (Unit.BuffIds.Contains((uint)Buffs.IMMORTALOVERLOAD))
            {
                SimulatedHitpoints += 100;
            }
            if (unit.UnitType == (uint)UnitTypes.PROTOSS_WARPPRISM)
            {
                SimulatedHitpoints += 500;
            }

            if (sharkyUnitData.ZergTypes.Contains((UnitTypes)Unit.UnitType))
            {
                SimulatedHealPerSecond = 0.38f;
            }
            else if (repairers > 0 && UnitTypeData.Attributes.Contains(SC2APIProtocol.Attribute.Mechanical))
            {
                SimulatedHealPerSecond = (float)(unit.HealthMax / (UnitTypeData.BuildTime / sharkyOptions.FramesPerSecond)) * repairers;
            }
            else if (Unit.UnitType == (uint)UnitTypes.TERRAN_MEDIVAC && Unit.Energy > 10)
            {
                SimulatedHealPerSecond = 12.6f;
            }
            else if (Unit.UnitType == (uint)UnitTypes.ZERG_QUEEN && Unit.Energy >= 50)
            {
                SimulatedHealPerSecond = 20;
            }
            else
            {
                SimulatedHealPerSecond = 0;
            }

            if (Unit.UnitType == (uint)UnitTypes.TERRAN_BUNKER && Unit.BuildProgress == 1) // assume 4 marines
            {
                Range        = 6;
                DamageAir    = true;
                DamageGround = true;
                Damage       = 6;
                Dps          = Damage * 4 / 0.61f;
            }

            Attributes = UnitTypeData.Attributes;

            UnitClassifications = new List <UnitClassification>();
            if (UnitTypeData.Attributes.Contains(SC2APIProtocol.Attribute.Structure))
            {
                if (sharkyUnitData.ResourceCenterTypes.Contains((UnitTypes)unit.UnitType))
                {
                    UnitClassifications.Add(UnitClassification.ResourceCenter);
                    UnitClassifications.Add(UnitClassification.ProductionStructure);
                }
                if (sharkyUnitData.DefensiveStructureTypes.Contains((UnitTypes)unit.UnitType))
                {
                    UnitClassifications.Add(UnitClassification.DefensiveStructure);
                }
            }
            else if (unit.UnitType == (uint)UnitTypes.TERRAN_SCV || unit.UnitType == (uint)UnitTypes.PROTOSS_PROBE || unit.UnitType == (uint)UnitTypes.ZERG_DRONE)
            {
                UnitClassifications.Add(UnitClassification.Worker);
            }
            else if (unit.UnitType == (uint)UnitTypes.ZERG_QUEEN || unit.UnitType == (uint)UnitTypes.TERRAN_MULE || unit.UnitType == (uint)UnitTypes.ZERG_OVERLORD || unit.UnitType == (uint)UnitTypes.ZERG_LARVA || unit.UnitType == (uint)UnitTypes.ZERG_EGG)
            {
            }
            else
            {
                UnitClassifications.Add(UnitClassification.ArmyUnit);
            }

            if (sharkyUnitData.DetectionTypes.Contains((UnitTypes)unit.UnitType))
            {
                UnitClassifications.Add(UnitClassification.Detector);
            }
            if (sharkyUnitData.AbilityDetectionTypes.Contains((UnitTypes)unit.UnitType))
            {
                UnitClassifications.Add(UnitClassification.DetectionCaster);
            }
            if (sharkyUnitData.CloakableAttackers.Contains((UnitTypes)unit.UnitType))
            {
                UnitClassifications.Add(UnitClassification.Cloakable);
            }

            EnemiesInRange   = new List <UnitCalculation>();
            EnemiesInRangeOf = new List <UnitCalculation>();
            NearbyAllies     = new List <UnitCalculation>();
            NearbyEnemies    = new List <UnitCalculation>();
            Attackers        = new List <UnitCalculation>();
            IncomingDamage   = 0;
        }