List <SprinklerInfo> findAllSprinklers(GameLocation location)
        {
            List <SprinklerInfo> sprinklers = new List <SprinklerInfo>();

            // search through the map looking for sprinklers
            for (int tileX = 0; tileX < location.map.Layers[0].LayerWidth; ++tileX)
            {
                for (int tileY = 0; tileY < location.map.Layers[0].LayerHeight; ++tileY)
                {
                    Vector2 key = new Vector2(tileX, tileY);
                    if (location.Objects.ContainsKey(key))
                    {
                        StardewValley.Object obj = location.Objects[key];

                        // if the object is a sprinkler, classify it and, if eligible, add it to the list
                        if (obj.Name.Contains("Sprinkler"))
                        {
                            SprinklerInfo candidate = new SprinklerInfo();
                            candidate.position = new Point(tileX, tileY);

                            // classify candidate
                            if (obj.Name.Contains("Quality"))
                            {
                                candidate.type = PlantingMinionTask.SprinklerTypes.Quality;
                            }
                            else if (obj.Name.Contains("Iridium"))
                            {
                                candidate.type = PlantingMinionTask.SprinklerTypes.Iridium;
                            }
                            else
                            {
                                candidate.type = PlantingMinionTask.SprinklerTypes.Standard;
                            }

                            // determine if eligible (that is, the sprinkler isn't completely surrounded by crops already)
                            bool[,] map = PlantingMinionTask.getSprinklerMapFromType(candidate.type);
                            for (int x = candidate.position.X - 2; x <= candidate.position.X + 2; ++x)
                            {
                                for (int y = candidate.position.Y - 2; y <= candidate.position.Y + 2; ++y)
                                {
                                    if (map[x - candidate.position.X + 2, y - candidate.position.Y + 2])
                                    {
                                        if (location.doesTileHaveProperty(x, y, "Diggable", "Back") != null)
                                        {
                                            Vector2 pos = new Vector2(x, y);

                                            //if (location.isTileLocationTotallyClearAndPlaceable(x,y))
                                            if ((!location.terrainFeatures.ContainsKey(pos) ||
                                                 (location.isTileHoeDirt(pos) && !location.isCropAtTile(x, y))) &&
                                                !location.Objects.ContainsKey(pos) &&
                                                location.map.GetLayer("Paths")?.PickTile(new xTile.Dimensions.Location(x, y), Game1.viewport.Size) == null &&
                                                location.isTilePassable(new xTile.Dimensions.Location(x, y), Game1.viewport))
                                            {
                                                candidate.seedsRequired++;
                                            }
                                        }
                                    }
                                }
                            }

                            if (candidate.seedsRequired > 0)
                            {
                                sprinklers.Add(candidate);
                            }
                        }
                    }
                }
            }

            return(sprinklers);
        }
        private void spawnMinionsForPlanting(GameLocation location, StardewValley.Farmer who, int seedIndex, ref int numSeeds, int fertilizerIndex, ref int numFertilizer)
        {
            const int sprinklersPerMinion = 15;

            Stopwatch sw = new Stopwatch();

            sw.Start();

            // clear previous tasks
            SkeletalMinionsMod.taskPool.clearTasks(location,
                                                   new List <string>
            {
                nameof(PlantingMinionTask)
            });

            // find all eligible sprinklers
            List <SprinklerInfo> sprinklers = findAllSprinklers(location);

            int numSkeletons = sprinklers.Count / sprinklersPerMinion;

            if (numSkeletons == 0)
            {
                numSkeletons = 1;
            }

            int totalSeedCount       = numSeeds;
            int totalFertilizerCount = numFertilizer;

            // create tasks from sprinklers
            foreach (SprinklerInfo sprinkler in sprinklers)
            {
                PlantingMinionTask task = new PlantingMinionTask(location, sprinkler.position, sprinkler.type, sprinkler.seedsRequired, seedIndex, fertilizerIndex);
                SkeletalMinionsMod.taskPool.addTask(task);
            }

            List <Point> spawnPoints = findNearestSpawnLocations(who.getTileLocationPoint(), location, (uint)numSkeletons);

            // spawn skeletons
            for (int i = 0; i < spawnPoints.Count; ++i)
            {
                SkeletalMinion minion = new SkeletalMinion(new Vector2(spawnPoints[i].X, spawnPoints[i].Y) * Game1.tileSize, location, who, SkeletalMinionsMod.taskPool, new List <string> {
                    nameof(PlantingMinionTask)
                });

                int seedsToAdd      = Math.Min(totalSeedCount / numSkeletons, numSeeds);
                int fertilizerToAdd = Math.Min(totalFertilizerCount / numSkeletons, numFertilizer);

                numSeeds      -= seedsToAdd;
                numFertilizer -= fertilizerToAdd;

                if (seedsToAdd > 0)
                {
                    minion.addItemToInventory(new StardewValley.Object(seedIndex, seedsToAdd));
                }
                if (fertilizerToAdd > 0)
                {
                    minion.addItemToInventory(new StardewValley.Object(fertilizerIndex, fertilizerToAdd));
                }

                location.characters.Add(minion);
                Utility.drawLightningBolt(new Vector2(spawnPoints[i].X * Game1.tileSize, spawnPoints[i].Y * Game1.tileSize), location);
            }
            sw.Stop();
            SkeletalMinionsMod.mod.Monitor.Log($"Spawning (planting) minions took {sw.ElapsedMilliseconds} ms.");
        }