/// <summary> /// Пока примитивная логика, не стартуем если враги есть рядом /// </summary> /// <param name="facility"></param> /// <param name="createdUnassignedUnits"></param> /// <returns></returns> private static bool CanStartProduction(FacilityEx facility, MyLivingUnit[] createdUnassignedUnits) { var isProductionTickExceed = GlobalHelper.Game.TickCount - GlobalHelper.World.TickIndex < ConfigurationHelper.StopProductionWhenTicksToEndGameRemaining; //var testStopProduction = (GlobalHelper.World.TickIndex / 1000) % 2 == 1; //Остановим производство, если слишком много юнитов //Для варианта с туманом, если их больше n //Для варианта без тумана, если количество превышает кол-во врага в n раз var isUnitsTooMuch = (GlobalHelper.Mode == GameMode.FacFow ? UnitHelper.UnitsAlly.Length > 750 : UnitHelper.UnitsAlly.Length - UnitHelper.UnitsEnemy.Length > 300) && GlobalHelper.World.TickIndex > 10000; var clusters = MyStrategy.LazyClusters.Value; var facilityX = facility.Left + GlobalHelper.Game.FacilityWidth / 2; var facilityY = facility.Top + GlobalHelper.Game.FacilityHeight / 2; var isEnemyNear = clusters.Any(cluster => { var clusterUnitsX = cluster.Sum(x => x.X) / cluster.Count; var clusterUnitsY = cluster.Sum(x => x.Y) / cluster.Count; var isInRange = GeometryHelper.GetDistancePower2To(facilityX, facilityY, clusterUnitsX, clusterUnitsY) <= ConfigurationHelper.EnemyNearOurFacilityWarningLostRangePow2; return(isInRange); }); var result = !isProductionTickExceed && !isUnitsTooMuch && !isEnemyNear; return(result); }
public static HasTargetToNuclearAttackResult HasTargetToNuclearAttack(MyLivingUnit[] selectedUnits) { var allEnemiesCanBeAttacked = new Dictionary <long, List <MyLivingUnit> >(); foreach (var selectedUnit in selectedUnits) { var enemyUnitsInRange = UnitHelper.UnitsEnemy .Where(x => { var visionRange = GetVisionRangeByWeather(selectedUnit); return(GeometryHelper.PointIsWithinCircle(selectedUnit.X, selectedUnit.Y, visionRange, x.X, x.Y)); }).ToArray(); foreach (var enemyUnitInRange in enemyUnitsInRange) { var enemyId = enemyUnitInRange.Id; if (!allEnemiesCanBeAttacked.ContainsKey(enemyId)) { allEnemiesCanBeAttacked[enemyId] = new List <MyLivingUnit>(); } allEnemiesCanBeAttacked[enemyId].Add(selectedUnit); } } if (allEnemiesCanBeAttacked.Count == 0) { return(new HasTargetToNuclearAttackResult() { Success = false }); } var enemiesCanBeAttacked = allEnemiesCanBeAttacked.Select(x => UnitHelper.Units[x.Key]).ToList(); var nsRange = GlobalHelper.Game.TacticalNuclearStrikeRadius; var maxNsDamage = GlobalHelper.Game.MaxTacticalNuclearStrikeDamage; var enemiesWithDamage = new List <Tuple <MyLivingUnit, double> >(allEnemiesCanBeAttacked.Count); var minEnemiesToAttack = GetMinEnemiesToAttackNuclearStrike(); foreach (var enemyCanBeAttacked in enemiesCanBeAttacked) { var allEnemiesFromEnemyRange = UnitHelper.UnitsEnemy .Where(x => GeometryHelper.PointIsWithinCircle(enemyCanBeAttacked.X, enemyCanBeAttacked.Y, nsRange, x.X, x.Y)).ToArray(); if (allEnemiesFromEnemyRange.Length < minEnemiesToAttack) { continue; } double totalDamage = 0; foreach (var enemyFromEnemyRange in allEnemiesFromEnemyRange) { var distance = PotentialFieldsHelper.GetDistanceTo(enemyCanBeAttacked.X, enemyCanBeAttacked.Y, enemyFromEnemyRange.X, enemyFromEnemyRange.Y); //Урон - это расстояние от эпиценра * урон var damage = ((nsRange - distance) / nsRange) * maxNsDamage; var speedDamageCoef = GetDamageCoefficientByVehicleTypeSpeed(enemyFromEnemyRange.Type); damage *= speedDamageCoef; if (damage > enemyFromEnemyRange.Durability) { totalDamage += maxNsDamage; } else { totalDamage += damage; } } var allAlliesFromEnemyRange = UnitHelper.UnitsAlly .Where(x => GeometryHelper.PointIsWithinCircle(enemyCanBeAttacked.X, enemyCanBeAttacked.Y, nsRange, x.X, x.Y)).ToArray(); foreach (var allyFromEnemyRange in allAlliesFromEnemyRange) { var distance = PotentialFieldsHelper.GetDistanceTo(enemyCanBeAttacked.X, enemyCanBeAttacked.Y, allyFromEnemyRange.X, allyFromEnemyRange.Y); //Урон - это расстояние от эпиценра * урон var damage = ((nsRange - distance) / nsRange) * maxNsDamage; if (damage > allyFromEnemyRange.Durability) { totalDamage -= 100; } else { totalDamage -= damage; } } enemiesWithDamage.Add(new Tuple <MyLivingUnit, double>(enemyCanBeAttacked, totalDamage)); } if (enemiesWithDamage.Count == 0) { return(new HasTargetToNuclearAttackResult() { Success = false }); } var maxTotalDamage = enemiesWithDamage.Select(x => x.Item2).Max(); //Выгода по урону не в пользу нас, не планируем удар if (maxTotalDamage < 0) { return(new HasTargetToNuclearAttackResult() { Success = false }); } var enemyUnitWithMaxDamage = enemiesWithDamage.First(x => Math.Abs(x.Item2 - maxTotalDamage) < 0.00000001).Item1; #if DEBUG RewindClient.RewindClient.Instance.Circle(enemyUnitWithMaxDamage.X, enemyUnitWithMaxDamage.Y, enemyUnitWithMaxDamage.Radius * 3, Color.Red); #endif var alliesCanAttackEnemyWithMaxDamage = allEnemiesCanBeAttacked[enemyUnitWithMaxDamage.Id]; var alliesWithRange = alliesCanAttackEnemyWithMaxDamage.Select(x => new { Ally = x, Range = GeometryHelper.GetDistancePower2To(x.X, x.Y, enemyUnitWithMaxDamage.X, enemyUnitWithMaxDamage.Y) }).ToList(); var maxRange = alliesWithRange.Select(x => x.Range).Max(); var ally = alliesWithRange.First(x => Math.Abs(x.Range - maxRange) < 0.00000001).Ally; #if DEBUG RewindClient.RewindClient.Instance.Circle(ally.X, ally.Y, ally.Radius * 3, Color.Purple); var vr = GetVisionRangeByWeather(ally); RewindClient.RewindClient.Instance.Circle(ally.X, ally.Y, vr, Color.FromArgb(100, 255, 0, 200)); #endif return(new HasTargetToNuclearAttackResult() { Success = true, SelectedUnitRes = ally, EnemyRes = enemyUnitWithMaxDamage }); }
public static void UpdateFacilitiesStates() { var facilityWidth = GlobalHelper.Game.FacilityWidth; var facilityHeight = GlobalHelper.Game.FacilityHeight; var worldFacilities = GlobalHelper.World.Facilities; foreach (var worldFacility in worldFacilities) { if (!FacilityHelper.Facilities.ContainsKey(worldFacility.Id)) { FacilityHelper.Facilities.Add(worldFacility.Id, new FacilityEx()); } var side = Side.Neutral; if (worldFacility.OwnerPlayerId == GlobalHelper.Me.Id) { side = Side.Our; } else if (worldFacility.OwnerPlayerId == GlobalHelper.Enemy.Id) { side = Side.Enemy; } var facility = FacilityHelper.Facilities[worldFacility.Id]; var gotMineThisTick = facility.Side != Side.Our && side == Side.Our; var lostMineThisTick = facility.Side == Side.Our && side != Side.Our; facility.Id = worldFacility.Id; //facility.OwnerPlayerId = worldFacility.OwnerPlayerId; facility.VehicleType = worldFacility.VehicleType; facility.ProductionProgress = worldFacility.ProductionProgress; facility.Type = worldFacility.Type; facility.CapturePoints = worldFacility.CapturePoints; facility.Left = worldFacility.Left; facility.Top = worldFacility.Top; facility.Side = side; facility.GotMineThisTick = gotMineThisTick; facility.LostMineThisTick = lostMineThisTick; if (facility.Type == FacilityType.VehicleFactory) { var createdUnassignedUnits = facility.GetCreatedUnassignedUnits(); var needStopProduction = NeedStopProduction(facility, createdUnassignedUnits); var canStartProduction = CanStartProduction(facility, createdUnassignedUnits); //Если захватили здание if (gotMineThisTick) { //И можно стартовать производствао if (canStartProduction) { facility.ProductionInProgress = true; QueueHelper.Queue.Enqueue(new StartProduction(facility)); } else { facility.ProductionInProgress = false; } } //Если производство было остановлено и можно запускать заного else if (!facility.ProductionInProgress && canStartProduction && facility.Side == Side.Our) { facility.ProductionInProgress = true; QueueHelper.Queue.Enqueue(new StartProduction(facility)); } else { var needCreateGroupFromProducingUnits = lostMineThisTick || (facility.ProductionCount > 0 && createdUnassignedUnits.Length >= facility.ProductionCount); if (needCreateGroupFromProducingUnits) { if (!facility.FacilityGroupCreating) { facility.FacilityGroupCreating = true; QueueHelper.Queue.Enqueue(new SelectUnits(facility.Left, facility.Top, facility.Left + facilityWidth, facility.Top + facilityHeight, facility.LastAssignedVehicleType)); var vehicleType = facility.LastAssignedVehicleType ?? VehicleType.Tank; QueueHelper.Queue.Enqueue(new AddSelecteUnitsToNewGroupTask(vehicleType)); if (needStopProduction) { facility.ProductionInProgress = false; QueueHelper.Queue.Enqueue(new StopProduction(facility)); } else if (canStartProduction) { facility.ProductionInProgress = true; QueueHelper.Queue.Enqueue(new StartProduction(facility)); } } } else if (needStopProduction && facility.Side == Side.Our && facility.ProductionInProgress) { if (createdUnassignedUnits.Length > 0) { QueueHelper.Queue.Enqueue(new SelectUnits(facility.Left, facility.Top, facility.Left + facilityWidth, facility.Top + facilityHeight, facility.LastAssignedVehicleType)); var vehicleType = facility.LastAssignedVehicleType ?? VehicleType.Tank; QueueHelper.Queue.Enqueue(new AddSelecteUnitsToNewGroupTask(vehicleType)); } facility.ProductionInProgress = false; QueueHelper.Queue.Enqueue(new StopProduction(facility)); } } } } if (GlobalHelper.Mode == GameMode.FacFow) { foreach (var myGroup in GroupHelper.Groups) { var groupUnits = UnitHelper.UnitsAlly.Where(x => x.Groups.Contains(myGroup.Id)).ToArray(); var xCenter = groupUnits.Sum(x => x.X) / groupUnits.Length; var yCenter = groupUnits.Sum(x => x.Y) / groupUnits.Length; foreach (var facility in FacilityHelper.Facilities.Values) { if (facility.Side == Side.Our) { facility.LastVisitedTick = GlobalHelper.World.TickIndex; } else { var fx = facility.Left + GlobalHelper.Game.FacilityWidth / 2; var fy = facility.Top + GlobalHelper.Game.FacilityHeight / 2; var currentDistance = GeometryHelper.GetDistancePower2To(xCenter, yCenter, fx, fy); var recheckDistancePow2 = ConfigurationHelper.RecheckFacilityDistansePow2; if (currentDistance <= recheckDistancePow2) { facility.LastVisitedTick = GlobalHelper.World.TickIndex; } } } } } }
private static bool NeedStopProduction(FacilityEx facility, MyLivingUnit[] createdUnassignedUnits) { var isProductionTickExceed = GlobalHelper.Game.TickCount - GlobalHelper.World.TickIndex < ConfigurationHelper.StopProductionWhenTicksToEndGameRemaining; //var testStopProduction = (GlobalHelper.World.TickIndex / 1000) % 2 == 1; //Остановим производство, если слишком много юнитов //Для варианта с туманом, если их больше n //Для варианта без тумана, если количество превышает кол-во врага в n раз var isUnitsTooMuch = (GlobalHelper.Mode == GameMode.FacFow ? UnitHelper.UnitsAlly.Length > 750 : UnitHelper.UnitsAlly.Length - UnitHelper.UnitsEnemy.Length > 300) && GlobalHelper.World.TickIndex > 10000; var clusters = MyStrategy.LazyClusters.Value; //var res = BattleHelper.CalculatePower(enemies, currentSelectedGroup.VehicleType, basePower); var isEnemyCanBeatProducingGroupTooClose = false; if (facility.Side == Side.Our && clusters.Count > 0 && createdUnassignedUnits.Length > 0) { var vehicleType = createdUnassignedUnits[0].Type; var basePower = PotentialFieldsHelper.EnemyPowerToDodge; var facilityUnitsX = createdUnassignedUnits.Sum(x => x.X) / createdUnassignedUnits.Length; var facilityUnitsY = createdUnassignedUnits.Sum(x => x.Y) / createdUnassignedUnits.Length; isEnemyCanBeatProducingGroupTooClose = clusters.Any(cluster => { var clusterUnitsX = cluster.Sum(x => x.X) / cluster.Count; var clusterUnitsY = cluster.Sum(x => x.Y) / cluster.Count; var isInRange = GeometryHelper.GetDistancePower2To(facilityUnitsX, facilityUnitsY, clusterUnitsX, clusterUnitsY) <= ConfigurationHelper.EnemyNearOurFacilityWarningRangePow2; if (!isInRange) { return(false); } var res = BattleHelper.CalculatePower(cluster, vehicleType, PotentialFieldsHelper.EnemyPowerToDodge); var enemyPower = res.EnemyPower; var canAttackSomeone = res.CanAttackSomeone; var existGroupPower = createdUnassignedUnits.Sum(y => BattleHelper.GetPowerHealthMulitplier(y.Type, y.Durability)) * basePower; bool needStayOnFacility; //Если строящаяся группа сильнее или чуть чуть слабее, то не уходим if (existGroupPower * 1.2 > enemyPower) { needStayOnFacility = true; //needStayOnFacility = canAttackSomeone; } else { //Если у врага нулевая сила, никуда не уходим needStayOnFacility = (Math.Abs(enemyPower) < PotentialFieldsHelper.Epsilon); } return(!needStayOnFacility); }); } var result = isProductionTickExceed || isUnitsTooMuch || isEnemyCanBeatProducingGroupTooClose /*|| testStopProduction*/; if (result) { var a = 0; } return(result); }
public static void AppendEnemyPower(List <List <DbScanHelper.Point> > clusters, bool applyNuclearStrikePower) { var basePower = EnemyPowerToDodge; var currentSelectedGroup = GroupHelper.CurrentGroup; //Хак по задержке вертов при старте, тянемся к ифвам if (currentSelectedGroup.VehicleType == VehicleType.Helicopter && GlobalHelper.World.TickIndex < 800) { var ifvGroup = GroupHelper.Groups.FirstOrDefault(x => x.VehicleType == VehicleType.Ifv); if (ifvGroup != null) { var ifvUnits = UnitHelper.UnitsAlly.Where(x => x.Groups.Contains(ifvGroup.Id)).ToArray(); var ifvX = ifvUnits.Sum(x => x.X) / ifvUnits.Length; var ifvY = ifvUnits.Sum(x => x.Y) / ifvUnits.Length; var eCellX = (int)ifvX / PpSize; var eCellY = (int)ifvY / PpSize; ApplyPower(PotentialFields, eCellX, eCellY, RangePowerMask49, -(float)ifvUnits.Length * basePower / 2); return; } } var selectedUnits = UnitHelper.UnitsAlly.Where(x => x.Groups.Contains(GroupHelper.CurrentGroup.Id)).ToArray(); var myGroupPower = selectedUnits .Sum(x => BattleHelper.GetPowerHealthMulitplier(currentSelectedGroup.VehicleType, x.Durability)) * basePower; var minEnemiesToAttack = NuclearStrikeHelper.GetMinEnemiesToAttackNuclearStrike(); foreach (var enemies in clusters) { var ex = enemies.Sum(x => x.X) / enemies.Count; var ey = enemies.Sum(x => x.Y) / enemies.Count; var eCellX = (int)ex / PpSize; var eCellY = (int)ey / PpSize; var res = BattleHelper.CalculatePower(enemies, currentSelectedGroup.VehicleType, basePower); var enemyPower = res.EnemyPower; var canAttackSomeone = res.CanAttackSomeone; //Если готовы нанести ядерный удар if (applyNuclearStrikePower) { //И врагов в кластере достаточно для удара, сделаем врагов притягиваемыми if (enemies.Count >= minEnemiesToAttack) { ApplyPower(PotentialFields, eCellX, eCellY, RangePowerMask49, -enemyPower); } } else { if (canAttackSomeone) { var pwr = enemyPower - myGroupPower; if (pwr >= 0) { //Если атакуют вертов, попробуем укрыться за Ifv if (currentSelectedGroup.VehicleType == VehicleType.Helicopter && enemies.Any(x => x.Type == VehicleType.Fighter) && pwr > 0) { var sx = selectedUnits.Sum(x => x.X) / selectedUnits.Length; var sy = selectedUnits.Sum(x => x.Y) / selectedUnits.Length; var distanceLow = GeometryHelper.GetDistancePower2To(sx, sy, ex, ey) < (300 * 300); if (distanceLow) { var ifvGroup = GroupHelper.Groups.FirstOrDefault(x => x.VehicleType == VehicleType.Ifv); if (ifvGroup != null) { var ifvUnits = UnitHelper.UnitsAlly.Where(x => x.Groups.Contains(ifvGroup.Id)).ToArray(); var ifvX = ifvUnits.Sum(x => x.X) / ifvUnits.Length; var ifvY = ifvUnits.Sum(x => x.Y) / ifvUnits.Length; var ifvCellX = (int)ifvX / PpSize; var ifvCellY = (int)ifvY / PpSize; ApplyPower(PotentialFields, ifvCellX, ifvCellY, RangePowerMask49, -(float)ifvUnits.Length * basePower); } } } ApplyPower(PotentialFields, eCellX, eCellY, RangePowerMask7, pwr); } else { ApplyPower(PotentialFields, eCellX, eCellY, RangePowerMask49, pwr); } } else { ApplyPower(PotentialFields, eCellX, eCellY, RangePowerMask7, enemyPower); } } } }