public static void RemoveAvoidanceSource(Thing source)
        {
            AssertMap(source);
            if (!TryGetGridForMap(source.Map.uniqueID, out PlayerAvoidanceGrid grid))
            {
                return;
            }
            var thingId = source.thingIDNumber;
            var sources = grid.sources;

            for (int i = sources.Count - 1; i >= 0; i--)
            {
                if (sources[i].thingId == thingId)
                {
                    sources.RemoveAt(i);
                }
            }
            if (sources.Count == 0)
            {
                DiscardMap(source.Map);
            }
            else
            {
                var cellIndex = CellIndicesUtility.CellToIndex(source.Position, source.Map.Size.x);
                grid.byteGrid[cellIndex] = (byte)CalculatePathCostInCell(grid, cellIndex);
            }
        }
示例#2
0
    private static bool CanScatterAt(IntVec3 pos, Map map)
    {
        var terrainDef = map.terrainGrid.TerrainAt(CellIndicesUtility.CellToIndex(pos, map.Size.x));

        return((terrainDef == null || !terrainDef.IsWater || terrainDef.passability != Traversability.Impassable) &&
               !map.deepResourceGrid.GetCellBool(CellIndicesUtility.CellToIndex(pos, map.Size.x)));
    }
        public MapComponentSeenFog(Map map) : base(map)
        {
            mapCellLength = map.cellIndices.NumGridCells;
            mapSizeX      = map.Size.x;
            mapSizeZ      = map.Size.z;

            fogGrid   = map.fogGrid;
            thingGrid = map.thingGrid;
            mapDrawer = map.mapDrawer;

            designationManager = this.map.designationManager;

            maxFactionLoadId = 0;
            foreach (Faction faction in Find.World.factionManager.AllFactionsListForReading)
            {
                maxFactionLoadId = Math.Max(maxFactionLoadId, faction.loadID);
            }
            factionsShownCells = new int[maxFactionLoadId + 1][];

            knownCells       = new bool[mapCellLength];
            viewBlockerCells = new bool[mapCellLength];

            idxToCellCache         = new IntVec3[mapCellLength];
            compHideFromPlayerGrid = new List <CompHideFromPlayer> [mapCellLength];
            compAffectVisionGrid   = new List <CompAffectVision> [mapCellLength];
            for (int i = 0; i < mapCellLength; i++)
            {
                idxToCellCache[i] = CellIndicesUtility.IndexToCell(i, mapSizeX);

                compHideFromPlayerGrid[i] = new List <CompHideFromPlayer>(16);
                compAffectVisionGrid[i]   = new List <CompAffectVision>(16);
            }
        }
示例#4
0
        internal static void Postfix(ref float __result, IntVec3 c, Map ___map)
        {
            float result = 0;

            if (!cellPerlin.ContainsKey(CellIndicesUtility.CellToIndex(c, c.x + c.y)))
            {
                var   terrain          = c.GetTerrain(___map);
                float fertility        = terrain.fertility;
                var   map              = ___map;
                float temp             = map.TileInfo.temperature / 15;
                float rainfall         = map.TileInfo.rainfall / 1000;
                int   perlinSeed       = Find.World.info.Seed;
                float perlinNoiseValue = 0;
                PerlinNoise      = new Perlin(0.1, 10, 0.6, 12, perlinSeed, QualityMode.Low);
                perlinNoiseValue = PerlinNoise.GetValue(c);
                if (temp < 0.5)
                {
                    temp = 0.5f;
                }
                if (temp > 2.6)
                {
                    temp = 2.6f;
                }
                if (rainfall < 0.5)
                {
                    rainfall = 0.5f;
                }
                //Log.Error("" + map.Biome.plantDensity);
                result = ((perlinNoiseValue + 0.8f + fertility) / 2) * (((1 - map.Biome.plantDensity) + temp + rainfall) / 3);
                if (fertility > 1.1f)
                {
                    result *= 2;
                }
                else if (fertility < 0.5f)
                {
                    result /= 4;
                }
                if (!cellPerlin.ContainsKey(CellIndicesUtility.CellToIndex(c, c.x + c.y)))
                {
                    cellPerlin.Add(CellIndicesUtility.CellToIndex(c, c.x + c.y), result);
                }
                __result = result;
                return;
            }
            else
            {
                if (___map.weatherManager.curWeather.rainRate >= 1)
                {
                    result = cellPerlin[CellIndicesUtility.CellToIndex(c, c.x + c.y)] * 10;
                }
                else
                {
                    result = cellPerlin[CellIndicesUtility.CellToIndex(c, c.x + c.y)];
                }
                __result = result;
                return;
            }
        }
示例#5
0
        public void Clear()
        {
            int num = CellIndicesUtility.CellToIndex(IntVec3.Invalid, mapSizeX);

            for (int i = 0; i < grid.Length; i++)
            {
                grid[i] = num;
            }
        }
        private void init()
        {
            // Reveal the starting position if home map and no pawns (landing).
            if (map.IsPlayerHome && map.mapPawns.ColonistsSpawnedCount == 0)
            {
                IntVec3 playerStartSpot = MapGenerator.PlayerStartSpot;
                ShadowCaster.computeFieldOfViewWithShadowCasting(playerStartSpot.x, playerStartSpot.z, Mathf.RoundToInt(CompFieldOfViewWatcher.NON_MECH_DEFAULT_RANGE),
                                                                 viewBlockerCells, map.Size.x, map.Size.z,
                                                                 false, null, null, null, // Directly updating known cells. No need to call incrementSeen.
                                                                 knownCells, 0, 0, mapSizeX,
                                                                 null, 0, 0, 0, 0, 0);

                for (int i = 0; i < mapCellLength; i++)
                {
                    if (knownCells[i])
                    {
                        IntVec3 cell = CellIndicesUtility.IndexToCell(i, mapSizeX);
                        foreach (Thing t in map.thingGrid.ThingsListAtFast(cell))
                        {
                            CompMainComponent compMain = (CompMainComponent)t.TryGetComp(CompMainComponent.COMP_DEF);
                            if (compMain != null && compMain.compHideFromPlayer != null)
                            {
                                compMain.compHideFromPlayer.forceSeen();
                            }
                        }
                    }
                }
            }

            // Update all thing FoV and visibility.
            foreach (Thing thing in map.listerThings.AllThings)
            {
                if (thing.Spawned)
                {
                    CompMainComponent compMain = (CompMainComponent)thing.TryGetComp(CompMainComponent.COMP_DEF);
                    if (compMain != null)
                    {
                        if (compMain.compComponentsPositionTracker != null)
                        {
                            compMain.compComponentsPositionTracker.updatePosition();
                        }
                        if (compMain.compFieldOfViewWatcher != null)
                        {
                            compMain.compFieldOfViewWatcher.updateFoV();
                        }
                        if (compMain.compHideFromPlayer != null)
                        {
                            compMain.compHideFromPlayer.updateVisibility(true);
                        }
                    }
                }
            }

            // Redraw everything.
            mapDrawer.RegenerateEverythingNow();
        }
        public static bool ShouldAvoidCell(Map map, IntVec3 cell)
        {
            if (map == null || !cell.InBounds(map) || !TryGetGridForMap(map.uniqueID, out PlayerAvoidanceGrid grid))
            {
                return(false);
            }
            var cellIndex = CellIndicesUtility.CellToIndex(cell, map.Size.x);

            return(grid.byteGrid[cellIndex] > 0);
        }
示例#8
0
        private bool CellBoolDrawerGetBoolInt(int index)
        {
            IntVec3 intVec = CellIndicesUtility.IndexToCell(index, map.Size.x);

            if (intVec.Filled(map) || intVec.Fogged(map))
            {
                return(false);
            }
            return(FertilityAt(intVec) > 0.69f);
        }
示例#9
0
        private bool CanScatterAt(IntVec3 pos, Map map)
        {
            int        num        = CellIndicesUtility.CellToIndex(pos, map.Size.x);
            TerrainDef terrainDef = map.terrainGrid.TerrainAt(num);

            if ((terrainDef != null && terrainDef.IsWater && terrainDef.passability == Traversability.Impassable) || !terrainDef.affordances.Contains(ThingDefOf.DeepDrill.terrainAffordanceNeeded))
            {
                return(false);
            }
            return(!map.deepResourceGrid.GetCellBool(num));
        }
示例#10
0
 public IntVec3 this[int index]
 {
     get
     {
         return(CellIndicesUtility.IndexToCell(grid[index], mapSizeX));
     }
     set
     {
         grid[index] = CellIndicesUtility.CellToIndex(value, mapSizeX);
     }
 }
示例#11
0
 public IntVec3 this[IntVec3 c]
 {
     get
     {
         int num = CellIndicesUtility.CellToIndex(c, mapSizeX);
         return(CellIndicesUtility.IndexToCell(grid[num], mapSizeX));
     }
     set
     {
         int num = CellIndicesUtility.CellToIndex(c, mapSizeX);
         grid[num] = CellIndicesUtility.CellToIndex(value, mapSizeX);
     }
 }
示例#12
0
 public IntVec3 this[int x, int z]
 {
     get
     {
         int num = CellIndicesUtility.CellToIndex(x, z, mapSizeX);
         return(CellIndicesUtility.IndexToCell(grid[num], mapSizeX));
     }
     set
     {
         int num = CellIndicesUtility.CellToIndex(x, z, mapSizeX);
         grid[num] = CellIndicesUtility.CellToIndex(x, z, mapSizeX);
     }
 }
示例#13
0
        //used as helper to verify, debugsettings => draw avoid grid is better once the grid sticks.
        private string GridToString(ByteGrid grid, Map map)
        {
            StringBuilder stringBuilder = new StringBuilder();

            for (int i = 0; i < map.Size.x; i++)
            {
                stringBuilder.AppendLine();
                for (int j = 0; j < map.Size.z; j++)
                {
                    stringBuilder.Append(grid[CellIndicesUtility.CellToIndex(i, j, map.Size.x)]);
                }
            }
            return(stringBuilder.ToString());
        }
示例#14
0
        static void Prefix(Projectile __instance, Thing hitThing, Vector3 ___origin)
        {
            Map map = __instance.Map;

            if (map == null)
            {
                return;
            }

            GunPropDef prop = GunplaySetup.GunProp(__instance.EquipmentDef);

            if (prop == null)
            {
                return;
            }

            MaterialKind kind = MaterialKind.None;

            if (hitThing != null)
            {
                kind = MaterialKindGetter.Get(hitThing);
            }

            if (kind == MaterialKind.None)
            {
                TerrainDef terrainDef = map.terrainGrid.TerrainAt(CellIndicesUtility.CellToIndex(__instance.Position, map.Size.x));
                kind = MaterialKindGetter.Get(terrainDef);
            }

            if (Gunplay.settings.enableSounds)
            {
                SoundDef sound = prop.projectileImpactSound == null ? null : prop.projectileImpactSound.Effect(kind);
                if (sound != null)
                {
                    sound.PlayOneShot(new TargetInfo(__instance.Position, map, false));
                }
            }

            if (Gunplay.settings.enableEffects)
            {
                EffecterDef effecterDef = prop.projectileImpactEffect == null ? null : prop.projectileImpactEffect.Effect(kind);
                if (effecterDef != null)
                {
                    Effecter effecter = new Effecter(effecterDef);
                    effecter.Trigger(__instance, new TargetInfo(___origin.ToIntVec3(), __instance.Map));
                    effecter.Cleanup();
                }
            }
        }
        public static void AddAvoidanceSource(Thing source, int pathCost)
        {
            AssertMap(source);
            pathCost = Mathf.Max(0, pathCost);
            if (!TryGetGridForMap(source.Map.uniqueID, out PlayerAvoidanceGrid grid))
            {
                grid = new PlayerAvoidanceGrid(source.Map);
                grids.Add(grid);
            }
            var cellIndex    = CellIndicesUtility.CellToIndex(source.Position, source.Map.Size.x);
            var previousCost = CalculatePathCostInCell(grid, cellIndex);
            var currentCost  = Mathf.Min(byte.MaxValue, previousCost + pathCost);

            grid.byteGrid[cellIndex] = (byte)currentCost;
            grid.sources.Add(new AvoidanceSource(source.thingIDNumber, cellIndex, currentCost - previousCost));
        }
        public static bool Prefix(MethodBase __originalMethod, SectionLayer_Things __instance, ref string __state)
        {
            if (Active)
            {
                __instance.ClearSubMeshes(MeshParts.All);
                Profiler prof = null;
                foreach (IntVec3 intVec in __instance.section.CellRect)
                {
                    List <Thing> list  = __instance.Map.thingGrid.ThingsListAt(intVec);
                    int          count = list.Count;
                    for (int i = 0; i < count; i++)
                    {
                        Thing thing = list[i];

                        __state = "Flag check";
                        prof    = Analyzer.Start(__state, null, null, null, null, __originalMethod);
                        var flag =
                            ((thing.def.seeThroughFog ||
                              !__instance.Map.fogGrid.fogGrid[
                                  CellIndicesUtility.CellToIndex(thing.Position, __instance.Map.Size.x)]) &&
                             thing.def.drawerType != DrawerType.None &&
                             (thing.def.drawerType != DrawerType.RealtimeOnly || !__instance.requireAddToMapMesh) &&
                             (thing.def.hideAtSnowDepth >= 1f || __instance.Map.snowGrid.GetDepth(thing.Position) <=
                              thing.def.hideAtSnowDepth) && thing.Position.x == intVec.x &&
                             thing.Position.z == intVec.z);
                        prof.Stop();

                        if (flag)
                        {
                            __state = thing.def.defName;
                            prof    = Analyzer.Start(__state, null, null, null, null, __originalMethod);
                            __instance.TakePrintFrom(thing);
                            prof.Stop();
                        }
                    }
                }

                __state = "Finalize mesh";
                prof    = Analyzer.Start(__state, null, null, null, null, __originalMethod);
                __instance.FinalizeMesh(MeshParts.All);
                prof.Stop();
                return(false);
            }

            return(true);
        }
示例#17
0
        private Color CellBoolDrawerGetExtraColorInt(int index)
        {
            float num = FertilityAt(CellIndicesUtility.IndexToCell(index, map.Size.x));

            if (num <= 0.95f)
            {
                return(LowFertilityColor);
            }
            if (num <= 1.1f)
            {
                return(MediumFertilityColor);
            }
            if (num >= 1.1f)
            {
                return(HighFertilityColor);
            }
            return(Color.white);
        }
示例#18
0
 public IntVec3 IndexToCell(int ind)
 {
     return(CellIndicesUtility.IndexToCell(ind, mapSizeX));
 }
示例#19
0
 public int CellToIndex(int x, int z)
 {
     return(CellIndicesUtility.CellToIndex(x, z, mapSizeX));
 }
示例#20
0
 public int CellToIndex(IntVec3 c)
 {
     return(CellIndicesUtility.CellToIndex(c, mapSizeX));
 }
示例#21
0
        public void SpawnDynamicMinerals()
        {
            foreach (ThingDef_DynamicMineral mineralType in DefDatabase <ThingDef_DynamicMineral> .AllDefs)
            {
                //var watch = System.Diagnostics.Stopwatch.StartNew();
                //Log.Message("Trying to spawn " + mineralType.defName);


                // Check that the map type is ok
                if (!mineralType.CanSpawnInBiome(map))
                {
                    continue;
                }
                //Log.Message("   Biome OK");

                // Get number of positions to check
                float perMapGrowthFactor = mineralType.GrowthRateAtMap(map);
                //Log.Message("   perMapGrowthFactor: " + perMapGrowthFactor);
                //Log.Message("   spawnProb: " + mineralType.spawnProb);
                float numToCheck = map.Area * mineralType.spawnProb * perMapGrowthFactor * MineralsMain.Settings.mineralSpawningSetting;
                if (numToCheck <= 0)
                {
                    continue;
                }

                // If less than one cell should be checked, randomly decide to check one or none
                if (numToCheck < 1)
                {
                    if (Rand.Range(0f, 1f) < numToCheck)
                    {
                        numToCheck = 1;
                    }
                    else
                    {
                        continue;
                    }
                }

                // Never check more than 1/10 of the map (performance failsafe)
                if (numToCheck > map.Area / 10)
                {
                    numToCheck = map.Area / 10;
                }

                // Round to integer
                numToCheck = (float)Math.Round(numToCheck);

                //Log.Message("   numToCheck: " + numToCheck);

                // Try to spawn in a subset of positions
                for (int i = 0; i < numToCheck; i++)
                {
                    // Pick a random location
                    IntVec3 aPos = CellIndicesUtility.IndexToCell(Rand.RangeInclusive(0, map.Area - 1), map.Size.x);

                    // Dont always spawn if growth rate is not good
                    if (Rand.Range(0f, 1f) > mineralType.GrowthRateAtPos(map, aPos, false))
                    {
                        continue;
                    }

//                    // If it is an associated ore, find a position nearby
//                    if (mineralType.PosIsAssociatedOre(map, aPos))
//                    {
//                        IntVec3 dest;
//                        if (mineralType.TryFindReproductionDestination(map, aPos, out dest))
//                        {
//                            aPos = dest;
//                        }
//                    }


                    // Try to spawn at that location
                    //Log.Message("Trying to spawn " + mineralType.defName);
                    //mineralType.TrySpawnAt(aPos, map, 0.01f);
                    mineralType.TrySpawnCluster(map, aPos, Rand.Range(0.01f, 0.05f), Rand.Range(mineralType.minSpawnClusterSize, mineralType.maxSpawnClusterSize));
                }

                //watch.Stop();
                //Log.Message("Spawning " + mineralType.defName + " took: " + watch.ElapsedMilliseconds);
            }
        }
        private void init()
        {
            // Retrieve map sections and store in a linear array.
            Section[,] mapDrawerSections = (Section[, ])Traverse.Create(mapDrawer).Field("sections").GetValue();
            sectionsSizeX = mapDrawerSections.GetLength(0);
            sectionsSizeY = mapDrawerSections.GetLength(1);

            sections = new Section[sectionsSizeX * sectionsSizeY];
            for (int y = 0; y < sectionsSizeY; y++)
            {
                for (int x = 0; x < sectionsSizeX; x++)
                {
                    sections[y * sectionsSizeX + x] = mapDrawerSections[x, y];
                }
            }

            // Initialize mining designators (add notifications intercepted by detours aren't fired on load).
            List <Designation> designations = map.designationManager.allDesignations;

            for (int i = 0; i < designations.Count; i++)
            {
                Designation des = designations[i];
                if (des.def == DesignationDefOf.Mine && !des.target.HasThing)
                {
                    registerMineDesignation(des);
                }
            }

            // Reveal the starting position if home map and no pawns (landing).
            if (map.IsPlayerHome && map.mapPawns.ColonistsSpawnedCount == 0)
            {
                IntVec3 playerStartSpot = MapGenerator.PlayerStartSpot;
                ShadowCaster.computeFieldOfViewWithShadowCasting(playerStartSpot.x, playerStartSpot.z, Mathf.RoundToInt(CompFieldOfViewWatcher.NON_MECH_DEFAULT_RANGE),
                                                                 viewBlockerCells, map.Size.x, map.Size.z,
                                                                 false, null, null, null, // Directly updating known cells. No need to call incrementSeen.
                                                                 knownCells, 0, 0, mapSizeX,
                                                                 null, 0, 0, 0, 0, 0);

                for (int i = 0; i < mapCellLength; i++)
                {
                    if (knownCells[i])
                    {
                        IntVec3 cell = CellIndicesUtility.IndexToCell(i, mapSizeX);
                        foreach (Thing t in map.thingGrid.ThingsListAtFast(cell))
                        {
                            CompMainComponent compMain = (CompMainComponent)t.TryGetComp(CompMainComponent.COMP_DEF);
                            if (compMain != null && compMain.compHideFromPlayer != null)
                            {
                                compMain.compHideFromPlayer.forceSeen();
                            }
                        }
                    }
                }
            }

            // Update all thing FoV and visibility.
            foreach (Thing thing in map.listerThings.AllThings)
            {
                if (thing.Spawned)
                {
                    CompMainComponent compMain = (CompMainComponent)thing.TryGetComp(CompMainComponent.COMP_DEF);
                    if (compMain != null)
                    {
                        if (compMain.compComponentsPositionTracker != null)
                        {
                            compMain.compComponentsPositionTracker.updatePosition();
                        }
                        if (compMain.compFieldOfViewWatcher != null)
                        {
                            compMain.compFieldOfViewWatcher.updateFoV();
                        }
                        if (compMain.compHideFromPlayer != null)
                        {
                            compMain.compHideFromPlayer.updateVisibility(true);
                        }
                    }
                }
            }

            // Redraw everything.
            mapDrawer.RegenerateEverythingNow();
        }
示例#23
0
        public void RegenerateMesh()
        {
            foreach (var m in meshes)
            {
                m.Clear();
            }
            meshes.Clear();

            float y = AltitudeLayer.MapDataOverlay.AltitudeFor();

            int            cells  = 0;
            List <Vector3> verts  = new List <Vector3>();
            List <Color>   colors = new List <Color>();
            List <int>     tris   = new List <int>();
            Mesh           mesh   = new Mesh();

            var mapSize = parentAreaExt.Map.Size;

            BitArray exclusionBA         = null;
            bool     needToCalcExclusion = true;

            var innerAreas = parentAreaExt.InnerAreas;

            for (int i = 0; i < innerAreas.Count; ++i)
            {
                Area            area = innerAreas[i].Key;
                AreaExtOperator op   = innerAreas[i].Value;

                if (op == AreaExtOperator.Inclusion)
                {
                    if (needToCalcExclusion)
                    {
                        exclusionBA = new BitArray(mapSize.x * mapSize.z);
                        exclusionBA.SetAll(false);

                        for (int j = i + 1; j < innerAreas.Count; ++j)
                        {
                            if (innerAreas[j].Value != AreaExtOperator.Exclusion)
                            {
                                continue;
                            }

                            exclusionBA = exclusionBA.Or(AreaExt.GetAreaBitArray(innerAreas[j].Key));
                        }

                        exclusionBA = exclusionBA.Not();
                    }

                    CellRect cellRect = new CellRect(0, 0, mapSize.x, mapSize.z);
                    for (int j = cellRect.minX; j <= cellRect.maxX; j++)
                    {
                        for (int k = cellRect.minZ; k <= cellRect.maxZ; k++)
                        {
                            int index = CellIndicesUtility.CellToIndex(j, k, mapSize.x);
                            if (area[index] && exclusionBA[index])
                            {
                                verts.Add(new Vector3((float)j, y, (float)k));
                                verts.Add(new Vector3((float)j, y, (float)(k + 1)));
                                verts.Add(new Vector3((float)(j + 1), y, (float)(k + 1)));
                                verts.Add(new Vector3((float)(j + 1), y, (float)k));
                                colors.Add(area.Color);
                                colors.Add(area.Color);
                                colors.Add(area.Color);
                                colors.Add(area.Color);

                                int count = verts.Count;
                                tris.Add(count - 4);
                                tris.Add(count - 3);
                                tris.Add(count - 2);
                                tris.Add(count - 4);
                                tris.Add(count - 2);
                                tris.Add(count - 1);

                                cells++;
                                if (cells >= 16383)
                                {
                                    mesh.SetVertices(verts);
                                    mesh.SetColors(colors);
                                    mesh.SetTriangles(tris, 0);

                                    verts.Clear();
                                    colors.Clear();
                                    tris.Clear();

                                    meshes.Add(mesh);
                                    mesh = new Mesh();

                                    cells = 0;
                                }
                            }
                        }
                    }
                }
                else
                {
                    needToCalcExclusion = true;
                }
            }

            if (verts.Count > 0)
            {
#if DEBUG
                Log.Message(string.Format("Vertices: {0}", verts.Count));
#endif
                mesh.SetVertices(verts);
                mesh.SetColors(colors);
                mesh.SetTriangles(tris, 0);
                meshes.Add(mesh);
            }

            if (material == null)
            {
                material             = SolidColorMaterials.SimpleSolidColorMaterial(new Color(1f, 1f, 1f, opacity), true);
                material.renderQueue = 3600;
            }

            dirty = false;
        }
示例#24
0
        public void SpawnDynamicMinerals()
        {
            foreach (ThingDef_DynamicMineral mineralType in DefDatabase <ThingDef_DynamicMineral> .AllDefs)
            {
                //var watch = System.Diagnostics.Stopwatch.StartNew();

                // Check that the map type is ok
                if (!mineralType.CanSpawnInBiome(map))
                {
                    continue;
                }

                // Get number of positions to check
                float numToCheck = map.Area * mineralType.spawnProb * MineralsMain.Settings.mineralSpawningSetting;

                if (numToCheck <1 & Rand.Range(0f, 1f)> numToCheck)
                {
                    continue;
                }
                else
                {
                    numToCheck = 1;
                }

                //Log.Message("Trying to spawn " + mineralType.defName + " with prob of " + mineralType.spawnProb + " and " + numToCheck + " blocks");


                // Try to spawn in a subset of positions
                for (int i = 0; i < numToCheck; i++)
                {
                    // Pick a random location
//                    IntVec3 aPos = map.AllCells.RandomElement(); // too slow
                    IntVec3 aPos = CellIndicesUtility.IndexToCell(Rand.RangeInclusive(0, map.Area - 1), map.Size.x);

                    // Dont always spawn if growth rate is not good
                    if (Rand.Range(0f, 1f) > mineralType.GrowthRateAtPos(map, aPos))
                    {
                        continue;
                    }

//                    // If it is an associated ore, find a position nearby
//                    if (mineralType.PosIsAssociatedOre(map, aPos))
//                    {
//                        IntVec3 dest;
//                        if (mineralType.TryFindReproductionDestination(map, aPos, out dest))
//                        {
//                            aPos = dest;
//                        }
//                    }


                    // Try to spawn at that location
                    //Log.Message("Trying to spawn " + mineralType.defName);
                    //mineralType.TrySpawnAt(aPos, map, 0.01f);
                    mineralType.SpawnCluster(map, aPos, Rand.Range(0.01f, 0.05f), Rand.Range(mineralType.minSpawnClusterSize, mineralType.maxSpawnClusterSize));
                }

                //watch.Stop();
                //Log.Message("Spawning " + mineralType.defName + " took: " + watch.ElapsedMilliseconds);
            }
        }