public bool TryAssignAttack(bool replace = true) { bool didAssignAttack = TryAssignAttackUnit(replace, Owner, AllUnits, AggroRadius); // we prioritize units over buildings, since units can fight back // At this time, only bad guys can attack buildings. May need to change // this if we decide to add units that are built by the bad guys: if (!didAssignAttack && Owner.UnitData.IsEnemy) { #if DEBUG if (AllBuildings == null) { throw new NullReferenceException($"Need to assign {nameof(AllBuildings)} when instantiating this unit."); } #endif float buildingAggroSquared = (AggroRadius + 24) * (AggroRadius + 24); var foundBuilding = AllBuildings .Where(item => (item.Position - Owner.Position).LengthSquared() < buildingAggroSquared) .OrderBy(item => (item.Position - Owner.Position).LengthSquared()) .FirstOrDefault(); if (foundBuilding != null) { var attackBuildingGoal = Owner.AssignAttackGoal(foundBuilding, replace); // prefer attacking units: attackBuildingGoal.PreferAttackingUnits = true; didAssignAttack = true; } } return(didAssignAttack); }
internal void AssignAttackThenRetreat(float worldX, float worldY, bool replace = true) { // we'll just make a circle: var circle = new Circle(); circle.Radius = AttackThenRetreat.BuildingAttackingRadius;; circle.X = worldX; circle.Y = worldY; var buildingsToTarget = AllBuildings .Where(item => item.CollideAgainst(circle)) .Take(3) .ToList(); // if there's no buildings, then just do a regular attack move: if (buildingsToTarget.Count == 0) { AssignMoveAttackGoal(worldX, worldY, replace); } else { var goal = new AttackThenRetreat(); goal.StartX = this.X; goal.StartY = this.Y; goal.TargetX = worldX; goal.TargetY = worldY; goal.AllUnits = AllUnits; goal.BuildingsToFocusOn.AddRange(buildingsToTarget); goal.Owner = this; if (replace) { this.HighLevelGoals.Clear(); } this.HighLevelGoals.Push(goal); this.ImmediateGoal = null; } }
public WalkToHighLevelGoal GetResourceReturnWalkGoal() { WalkToHighLevelGoal walkGoal = null; // Set up to return resource // Find "closest" building by position comparison. // FUTURE: Get building with shorted node path (in case closest is a long winding path). ResourceReturnBuilding = AllBuildings .Where(building => building.BuildingData.Name == BuildingData.TownHall && building.IsConstructionComplete) .OrderBy(building => (building.Position - Owner.Position).Length()) .FirstOrDefault(); if (ResourceReturnBuilding != null) { walkGoal = new WalkToHighLevelGoal(); ResourceReturnBuildingTile = GetSingleTile(ResourceReturnBuilding.Position); Vector3 pointSlightlySkewedTowardOwner = DeterminePositionWithinTileSlightlyCloserToOwner(ResourceReturnBuildingTile.Position, ResourceReturnBuildingTile.Width); walkGoal = new WalkToHighLevelGoal(); walkGoal.Owner = Owner; walkGoal.TargetPosition = pointSlightlySkewedTowardOwner; walkGoal.ForceAttemptToGetToExactTarget = true; } return(walkGoal); }