public static void Drop(Beaver dropper, IEnumerable <Tile> targets, string resource) { if (!dropper.CanAct() || dropper.GetCount(resource) == 0) { return; } var target = targets.FirstOrDefault(t => t == dropper.Tile || dropper.Tile._HasNeighbor(t)); if (target != null) { dropper.Drop(target, resource, dropper.GetCount(resource)); } }
/// <summary>Builds lodges</summary> private bool Build(Beaver b) { // Check if it can even build a lodge if (b.Branches <= 0) { return(false); } bool retValue = false; // Find suitable building spot bool foodOnly = true; // ReSharper disable once AccessToModifiedClosure Func <Tile, bool> isTarget = t => t.LodgeOwner == null && t.Spawner == null && t.FlowDirection == null && this.IsNextTo(t, n1 => this.IsNextTo(n1, n2 => n2.Spawner != null && (!foodOnly || n2.Spawner.Type == "food") && !this.ClaimedResources.Contains(n2.Id))); IEnumerable <Tile> basePath; if (this.NextLodge == null) { // Look for a spot two spaces away from an unclaimed food spot basePath = this.FindPathCustom(b.Tile, (t, parent) => { double cost = this.GetCost(t, parent, b); if (cost < 0) { return(cost); } return(isTarget(t) ? 0 : cost); }) .Skip(1); // Look for a spot two spaces away from any unclaimed resource if (!basePath.Any()) { foodOnly = false; basePath = this.FindPathCustom(b.Tile, (t, parent) => { double cost = this.GetCost(t, parent, b); if (cost < 0) { return(cost); } return(isTarget(t) ? 0 : cost); }) .Skip(1); } // Set this as the next lodge spot if (basePath.Any()) { this.NextLodge = basePath.Last(); } } else { basePath = this.FindPathCustom(b.Tile, this.NextLodge).Skip(1); } // Traverse path LinkedList <Tile> path = new LinkedList <Tile>(basePath); while (path.Any()) { // If can't move if (b.Moves < b.MoveCost(path.First()) || !b.Move(path.First())) { break; } path.RemoveFirst(); retValue = true; } // Try to build a lodge Tile target = b.Tile; if (isTarget(b.Tile)) { if (b.Actions > 0 && target.Branches >= this.Player.BranchesToBuildLodge) { if (AI.Verbose) { Console.WriteLine("Building lodge"); } b.BuildLodge(); this.NextLodge = null; retValue = true; // Set nearby food source as "claimed" // TODO: If the lodge is destroyed, unclaim those sources IEnumerable <Tile> sources = from n1 in new[] { target.TileNorth, target.TileEast, target.TileSouth, target.TileWest } where n1 != null from n2 in new[] { n1.TileNorth, n1.TileEast, n1.TileSouth, n1.TileWest } where n2?.Spawner != null select n2; foreach (Tile source in sources) { this.ClaimedResources.Add(source.Id); } } else if (b.Actions > 0 && b.Branches > 0) { if (AI.Verbose) { Console.WriteLine("Dropping branches for lodge"); } b.Drop(target, nameof(b)); // branches retValue = true; } } return(retValue); }
/// <summary>Stores carried resources in lodges</summary> private bool Store(Beaver b) { // Don't bother storing if it doesn't have a full inventory if (b.Branches + b.Food < b.Job.CarryLimit) { return(false); } bool retValue = false; // Function for finding movement targets Func <Tile, bool> isTarget = t => t.LodgeOwner == this.Player; // Find nearest lodge, skipping current node IEnumerable <Tile> basePath = this.FindPathCustom(b.Tile, (t, parent) => { double cost = this.GetCost(t, parent, b); if (cost < 0) { return(cost); } return(this.IsNextTo(t, isTarget) ? 0 : cost); }) .Skip(1); // Traverse path LinkedList <Tile> path = new LinkedList <Tile>(basePath); while (path.Any()) { // If can't move anymore if (b.Moves < b.MoveCost(path.First()) || !b.Move(path.First())) { break; } path.RemoveFirst(); retValue = true; } // Drop off resources at lodge Tile target = this.GetNeighborWhere(b.Tile, isTarget); if (target != null && b.Actions > 0) { if (AI.Verbose) { Console.WriteLine("Dropping resources on lodge"); } if (b.Branches > 0) { b.Drop(target, "b"); // branches } if (b.Food > 0) { b.Drop(target, "f"); // food } retValue = true; } return(retValue); }