Exemplo n.º 1
0
        public static CoverageMap EmptyCoverageMap(Map map)
        {
            CoverageMap cm = new CoverageMap();

            cm.coverageMap = new bool[map.Size.x, map.Size.z];
            return(cm);
        }
Exemplo n.º 2
0
        //ResolveParams's GetCustom/SetCustom is broken now, and it is a sealed (WHY??!) struct (WHY??!?!?) so I neither can fix it, nor make a dirty hack.
        //Seems like I have to abandon this approach and make direct calls.
        static public void Scatter(ResolveParams rp, ScatterOptions options, CoverageMap coverage, List <AbstractDefenderForcesGenerator> generators)
        {
            Debug.Log(Debug.Scatter, "Running stand-alone scatterer");
            if (options == null)
            {
                Debug.Warning(Debug.Scatter, "Scatter options are null, aborting");
                return;
            }

            DateTime start = DateTime.UtcNow;

            Debug.Log(Debug.Scatter, "[0 s]: Loading blueprint of size {0} - {1} to deploy at {2}, {3}", options.minRadius, options.maxRadius, rp.rect.minX, rp.rect.minZ);

            Blueprint bp  = null;
            Map       map = BaseGen.globalSettings.map;

            //probably should split scattering options into several distinct objects
            string filename = options.blueprintFileName;

            if (string.IsNullOrEmpty(filename) || !BlueprintLoader.CanLoadBlueprintAtPath(filename))
            {
                bp = BlueprintFinder.FindRandomBlueprintWithParameters(out filename, options.minimumAreaRequired, options.minimumDensityRequired, 15, removeNonQualified: options.deleteLowQuality);
                if (string.IsNullOrEmpty(filename))
                {
                    //still null = no suitable blueprints, fail.
                    Debug.Warning(Debug.Scatter, "Blueprint name was null and could not find another suitable blueprint, skipping");
                    return;
                }
            }

            if (!options.shouldLoadPartOnly) //should not cut => load whole
            {
                if (bp == null)              //if not loaded yet
                {
                    bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename);
                }
            }
            else
            {
                int radius = Rand.Range(options.minRadius, options.maxRadius);
                if (bp == null)
                {
                    bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename).RandomPartCenteredAtRoom(new IntVec3(radius, 0, radius));
                }
                else
                {
                    bp = bp.RandomPartCenteredAtRoom(new IntVec3(radius, 0, radius));
                }
            }

            if (bp == null)
            {
                Debug.Warning(Debug.Scatter, "Blueprint is still null after attempting to load any qualifying, returning");
                return;
            }


            Debug.Extra(Debug.Scatter, "Blueprint loaded, cutting and searching for rooms");
            bp.CutIfExceedsBounds(map.Size);

            // Here we have our blueprint loaded and ready to action. Doing stuff:
            BlueprintPreprocessor.ProcessBlueprint(bp, options); //Preprocess: remove missing and unnecessary items according to options
            bp.FindRooms();                                      //Traverse blueprint and construct rooms map
            options.roomMap = bp.wallMap;

            //Debug.PrintIntMap(bp.wallMap, delta: 1);
            Debug.Extra(Debug.Scatter, "Rooms traversed, initializing transfer utility");

            BlueprintTransferUtility btu = new BlueprintTransferUtility(bp, map, rp, options); //prepare blueprint transferrer

            Debug.Extra(Debug.Scatter, "Initialized, removing incompatible items...");

            btu?.RemoveIncompatibleItems(); //remove incompatible items
            Debug.Extra(Debug.Scatter, "Recalculating stats...");

            bp.UpdateBlueprintStats(true); //Update total cost, items count, etc

            Debug.Extra(Debug.Scatter, "Deteriorating...");
            DeteriorationProcessor.Process(bp, options); //create deterioration maps and do deterioration

            Debug.Extra(Debug.Scatter, "Scavenging...");
            ScavengingProcessor sp = new ScavengingProcessor();

            sp.RaidAndScavenge(bp, options); //scavenge remaining items according to scavenge options

            Debug.Extra(Debug.Scatter, "[{0} s] Prepared, about to start transferring.", DateTime.UtcNow.Subtract(start).TotalSeconds);
            try {
                btu.Transfer(coverage); //transfer blueprint
                Debug.Extra(Debug.Scatter, "[{0} s] Transferred.", DateTime.UtcNow.Subtract(start).TotalSeconds);
            } catch (Exception e) {
                Debug.Error(Debug.BlueprintTransfer, "Failed to transfer blueprint due to {0}", e);
            }

            if (generators != null)
            {
                foreach (AbstractDefenderForcesGenerator generator in generators)
                {
                    try {
                        generator.GenerateForces(map, rp, options);
                    } catch (Exception e) {
                        Debug.Error(Debug.BlueprintTransfer, "Failed to generate forces: {0}", e);
                    }
                }
            }
            Debug.Log(Debug.Scatter, "[{0} s] Generated forces.", DateTime.UtcNow.Subtract(start).TotalSeconds);

            if (options.shouldAddFilth)
            {
                try {
                    btu.AddFilthAndRubble(); //add filth and rubble
                } catch (Exception e) {
                    Debug.Warning(Debug.BlueprintTransfer, "Failed to add filth and rubble: {0}", e);
                }
            }
            Debug.Extra(Debug.Scatter, "[{0} s] Spiced up with rubble. Completed.", DateTime.UtcNow.Subtract(start).TotalSeconds);

            Debug.Log(Debug.Scatter, "Chunk scattering finished, moving");
        }
Exemplo n.º 3
0
        public void Transfer(CoverageMap coverageMap)
        {
            //Planting blueprint
            float totalCost           = 0;
            int   transferredTerrains = 0;
            int   transferredTiles    = 0;
            int   totalTerrains       = 0;
            int   totalItems          = 0;

            //update rect to actual placement rect using width and height
            rp.rect = new CellRect(mapOriginX, mapOriginZ, blueprint.width, blueprint.height);

            Debug.Extra(Debug.BlueprintTransfer, "Clearing map...");

            for (int z = 0; z < blueprint.height; z++)
            {
                for (int x = 0; x < blueprint.width; x++)
                {
                    try {
                        IntVec3 mapLocation = new IntVec3(x + mapOriginX, 0, z + mapOriginZ);
                        //Check if thepoint is in allowed bounds of the map
                        if (!mapLocation.InBounds(map) || mapLocation.InNoBuildEdgeArea(map))
                        {
                            continue; //ignore invalid cells
                        }

                        if (options.overwritesEverything || Rand.Chance(0.6f))
                        {
                            if (blueprint.terrainMap[x, z] != null ||
                                blueprint.itemsMap[x, z].Count > 0 ||
                                blueprint.wallMap[x, z] > 1)
                            {
                                ClearCell(mapLocation, map, true);
                            }
                        }
                    } catch (Exception e) {
                        Debug.Warning(Debug.BlueprintTransfer, "Failed to clean cell at {0}, {1} because of {2}", x, z, e);
                    }
                }
            }

            Debug.Extra(Debug.BlueprintTransfer, "Transferring map objects");
            for (int z = 0; z < blueprint.height; z++)
            {
                for (int x = 0; x < blueprint.width; x++)
                {
                    IntVec3 mapLocation = new IntVec3(x + mapOriginX, 0, z + mapOriginZ);
                    if (coverageMap != null)
                    {
                        if (coverageMap.isMarked(mapLocation.x, mapLocation.z) == true) //cell was used earlier
                        {
                            continue;                                                   //skip already covered tiles
                        }
                        else
                        {
                            if (blueprint.wallMap[x, z] > 1 || blueprint.wallMap[x, z] == -1)
                            {
                                coverageMap.Mark(mapLocation.x, mapLocation.z);                                                               //mark cell as used
                            }
                        }
                    }


                    //Check if thepoint is in allowed bounds of the map
                    if (!mapLocation.InBounds(map) || mapLocation.InNoBuildEdgeArea(map))
                    {
                        continue; //ignore invalid cells
                    }

                    try {
                        //Construct terrain if some specific terrain stored in the blueprint
                        if (blueprint.terrainMap[x, z] != null)
                        {
                            totalTerrains++;
                            TerrainDef blueprintTerrain = TerrainDef.Named(blueprint.terrainMap[x, z].defName);
                            if (!map.terrainGrid.TerrainAt(mapLocation).IsWater)
                            {
                                map.terrainGrid.SetTerrain(mapLocation, blueprintTerrain);
                                totalCost += blueprint.terrainMap[x, z].cost;
                                transferredTerrains++;
                            }
                        }


                        //construct roof evetywhere if we doing complete transfer (ignoring outside: room with index 1).
                        if (blueprint.roofMap[x, z] == true && options.overwritesEverything && blueprint.wallMap[x, z] != 1)
                        {
                            map.roofGrid.SetRoof(mapLocation, RoofDefOf.RoofConstructed);
                        }


                        Debug.Extra(Debug.BlueprintTransfer, "Transferred terrain and roof at cell ({0}, {1})", x, z);
                    } catch (Exception e) {
                        Debug.Warning(Debug.BlueprintTransfer, "Failed to transfer terrain {0} at {1}, {2} because of {3}", blueprint.terrainMap[x, z].defName, x, z, e);
                    }

                    //Add items
                    if (blueprint.itemsMap[x, z] != null && blueprint.itemsMap[x, z].Count > 0 /* && cellUsed[mapLocation.x, mapLocation.z] == false*/)
                    {
                        totalItems += blueprint.itemsMap[x, z].Count;


                        foreach (ItemTile itemTile in blueprint.itemsMap[x, z])
                        {
                            Debug.Extra(Debug.BlueprintTransfer, "Creating thing {2} at cell ({0}, {1})", x, z, itemTile.defName);
                            Thing thing = MakeThingFromItemTile(itemTile);
                            if (thing != null)
                            {
                                try {
                                    Rot4 rotation = new Rot4(itemTile.rot);
                                    //check if there is anything we have to despawn in order to spawn our new item
                                    //we have to do this, because many dubs bad hygiene items enter endless cycle when removed during mapgen.
                                    foreach (IntVec3 occupiedCell in GenAdj.CellsOccupiedBy(mapLocation, rotation, thing.def.Size))
                                    {
                                        foreach (Thing existingItem in map.thingGrid.ThingsAt(occupiedCell).ToList())
                                        {
                                            if (GenSpawn.SpawningWipes(thing.def, existingItem.def))
                                            {
                                                if (thing.def.thingClass.ToString().Contains("DubsBadHygiene"))
                                                {
                                                    throw new Exception("Can't spawn item because it will destroy Dubs Bad Hygiene Item and it will lead to app freeze.");
                                                }
                                                existingItem.Destroy(DestroyMode.Vanish);
                                            }
                                        }
                                    }



                                    GenSpawn.Spawn(thing, mapLocation, map, rotation);
                                    Debug.Extra(Debug.BlueprintTransfer, "Spawned");
                                    try {
                                        switch (thing.def.tickerType)
                                        {
                                        case TickerType.Never:
                                            break;

                                        case TickerType.Normal:
                                            thing.Tick();
                                            break;

                                        case TickerType.Long:
                                            thing.TickLong();
                                            break;

                                        case TickerType.Rare:
                                            thing.TickRare();
                                            break;
                                        }
                                        //Debug.Message("Ticked");
                                    } catch (Exception e) {
                                        Debug.Log(Debug.BlueprintTransfer, "Exception while tried to perform tick for {0} of cost {1}, retrhrowing...", thing.def.defName, itemTile.cost);
                                        thing.Destroy();
                                        throw e;
                                    }

                                    //Debug.Message("Setting up props");
                                    //Breakdown breakdownables: it't yet impossible to silently breakdown an item which is not spawned.
                                    CompBreakdownable b = thing.TryGetComp <CompBreakdownable>();
                                    if (b != null && options.enableDeterioration)
                                    {
                                        if (Rand.Chance(0.8f))
                                        {
                                            b.DoBreakdown();
                                        }
                                    }

                                    //reduce HP for haulable things in water
                                    if (thing.def.EverHaulable)
                                    {
                                        TerrainDef t = map.terrainGrid.TerrainAt(mapLocation);
                                        if (t != null && t.IsWater)
                                        {
                                            thing.HitPoints = (thing.HitPoints - 10) / Rand.Range(5, 20) + Rand.Range(1, 10); //things in marsh or river are really in bad condition
                                        }
                                    }
                                    Debug.Extra(Debug.BlueprintTransfer, "Item completed");

                                    transferredTiles++;
                                    totalCost += itemTile.cost;
                                } catch (Exception e) {
                                    Debug.Warning(Debug.BlueprintTransfer, "Failed to spawn item {0} of cost {1} because of exception {2}", thing, itemTile.cost, e.Message);
                                    //ignore
                                }
                            }
                        }
                    }
                }
            }

            Debug.Log(Debug.BlueprintTransfer, "Finished transferring");
            if (options.shouldKeepDefencesAndPower)
            {
                RestoreDefencesAndPower();
            }
            options.uncoveredCost = totalCost;
            Debug.Log(Debug.BlueprintTransfer, "Transferred blueprint of size {0}x{1}, age {2}, total cost of approximately {3}. Items: {4}/{5}, terrains: {6}/{7}", blueprint.width, blueprint.height, -blueprint.dateShift, totalCost, transferredTiles, totalItems, transferredTerrains, totalTerrains);
        }
Exemplo n.º 4
0
        public override void Generate(Map map, GenStepParams parms)
        {
            //add standard ruins along with real.
            if (RealRuins_ModSettings.preserveStandardRuins)
            {
                GenStep scatterOriginalRuins = new GenStep_ScatterRuinsSimple();
                scatterOriginalRuins.Generate(map, parms);
            }
            //skip generation due to low blueprints count
            if (SnapshotStoreManager.Instance.StoredSnapshotsCount() < 10)
            {
                Debug.Error(Debug.Scatter, "Skipping ruins gerenation due to low blueprints count.");
                return;
            }

            //Skip generation for starting tile if corresponding settings flag is set
            if (RealRuins_ModSettings.startWithoutRuins)
            {
                int homes   = 0;
                var allMaps = Find.Maps;
                for (int i = 0; i < allMaps.Count; i++)
                {
                    Map someMap = allMaps[i];
                    if (someMap.IsPlayerHome)
                    {
                        homes++;
                    }
                }

                if (homes == 1 && Find.TickManager.TicksGame < 10)
                {
                    return;                                                //single home => we're generating that single home => that's starting map => no ruins here if this option is selected.
                }
            }

            //Skip generation on other ruins world objects
            foreach (WorldObject wo in Find.World.worldObjects.ObjectsAt(map.Tile))
            {
                if (wo is RealRuinsPOIWorldObject || wo is AbandonedBaseWorldObject)
                {
                    return;
                }
            }

            if (!map.TileInfo.WaterCovered)
            {
                float densityMultiplier    = 1.0f;
                float scaleMultiplier      = 1.0f;
                float distanceToSettlement = 0.0f;
                float totalDensity         = RealRuins_ModSettings.defaultScatterOptions.densityMultiplier;
                currentOptions = RealRuins_ModSettings.defaultScatterOptions.Copy(); //store as instance variable to keep accessible on subsequent ScatterAt calls

                if (RealRuins_ModSettings.defaultScatterOptions.enableProximity)
                {
                    distanceToSettlement = CalculateDistanceToNearestSettlement(map);
                    if (distanceToSettlement >= 16 && Rand.Chance(0.5f))
                    {
                        totalDensity = 0;
                    }

                    if (totalDensity > 0)
                    {
                        densityMultiplier = (float)(Math.Exp(1.0 / (distanceToSettlement / 10.0 + 0.3)) - 0.7);
                        scaleMultiplier   = (float)(Math.Exp(1 / (distanceToSettlement / 5 + 0.5)) - 0.3);
                    }
                    else
                    {
                        densityMultiplier = 0.0f;
                    }

                    currentOptions.densityMultiplier       *= densityMultiplier;
                    currentOptions.minRadius                = Math.Min(60, Math.Max(6, (int)(currentOptions.minRadius * scaleMultiplier))); //keep between 6 and 60
                    currentOptions.maxRadius                = Math.Min(60, Math.Max(6, (int)(currentOptions.maxRadius * scaleMultiplier))); //keep between 6 and 60
                    currentOptions.scavengingMultiplier    *= scaleMultiplier * densityMultiplier;
                    currentOptions.deteriorationMultiplier += Math.Min(0.2f, (1.0f / (scaleMultiplier * densityMultiplier * 3)));


                    if (densityMultiplier > 20.0f)
                    {
                        densityMultiplier = 20.0f;
                    }
                    while (densityMultiplier * currentOptions.maxRadius > 800)
                    {
                        densityMultiplier *= 0.9f; //WHAT? Why not 800/radius?
                    }
                }

                //number of ruins based on density settings
                var num = (int)((float)map.Area / 10000.0f) * Rand.Range(1 * totalDensity, 2 * totalDensity);

                Debug.Log(Debug.Scatter, "dist {0}, dens {1} (x{2}), scale x{3} ({4}-{5}), scav {6}, deter {7}", distanceToSettlement, currentOptions.densityMultiplier, densityMultiplier, scaleMultiplier, currentOptions.minRadius, currentOptions.maxRadius, currentOptions.scavengingMultiplier, currentOptions.deteriorationMultiplier);
                Debug.Log(Debug.Scatter, "Spawning {0} ruin chunks", num);
                BaseGen.globalSettings.map = map;

                bool shouldUnpause = false;
                Find.TickManager.Pause();
                if (!Find.TickManager.Paused)
                {
                    Find.TickManager.TogglePaused();
                    shouldUnpause = true;
                }

                CoverageMap coverageMap = CoverageMap.EmptyCoverageMap(map);

                for (int i = 0; i < num; i++)
                {
                    try {
                        //We use copy of scatteroptions because each scatteroptions represents separate chunk with separate location, size, maps, etc.
                        //should use struct instead? is it compatible with IExposable?
                        ResolveParams rp = default(ResolveParams);

                        List <AbstractDefenderForcesGenerator> generators = new List <AbstractDefenderForcesGenerator>();
                        if (Rand.Chance(currentOptions.hostileChance))
                        {
                            if (Rand.Chance(0.8f))
                            {
                                generators = new List <AbstractDefenderForcesGenerator> {
                                    new AnimalInhabitantsForcesGenerator()
                                };
                            }
                            else
                            {
                                generators = new List <AbstractDefenderForcesGenerator> {
                                    new MechanoidsForcesGenerator(0)
                                };
                            }
                        }
                        rp.faction = Find.FactionManager.OfAncientsHostile;
                        var center = CellFinder.RandomNotEdgeCell(10, map);
                        rp.rect = new CellRect(center.x, center.z, 1, 1); //after generation will be extended to a real size
                        RuinsScatterer.Scatter(rp, currentOptions.Copy(), coverageMap, generators);
                    } catch {
                        Debug.Warning(Debug.Scatter, "Could not scatter a single ruins chunk.");
                    }
                }

                if (shouldUnpause)
                {
                    //Debug.Message("Finished spawning, unpausing");
                    Find.TickManager.TogglePaused();
                }
            }
        }
        public void Transfer()
        {
            //Planting blueprint
            float totalCost           = 0;
            int   transferredTerrains = 0;
            int   transferredTiles    = 0;
            int   totalTerrains       = 0;
            int   totalItems          = 0;

            //update rect to actual placement rect using width and height
            rp.rect = new CellRect(mapOriginX, mapOriginZ, blueprint.width, blueprint.height);
            CoverageMap coverageMap = null;

            rp.TryGetCustom <CoverageMap>(Constants.CoverageMap, out coverageMap);

            for (int z = 0; z < blueprint.height; z++)
            {
                for (int x = 0; x < blueprint.width; x++)
                {
                    IntVec3 mapLocation = new IntVec3(x + mapOriginX, 0, z + mapOriginZ);
                    //Check if thepoint is in allowed bounds of the map
                    if (!mapLocation.InBounds(map) || mapLocation.InNoBuildEdgeArea(map))
                    {
                        continue; //ignore invalid cells
                    }

                    if (options.overwritesEverything || Rand.Chance(0.6f))
                    {
                        if (blueprint.terrainMap[x, z] != null ||
                            blueprint.itemsMap[x, z].Count > 0 ||
                            blueprint.wallMap[x, z] > 1)
                        {
                            ClearCell(mapLocation, map, true);
                        }
                    }
                }
            }


            for (int z = 0; z < blueprint.height; z++)
            {
                for (int x = 0; x < blueprint.width; x++)
                {
                    IntVec3 mapLocation = new IntVec3(x + mapOriginX, 0, z + mapOriginZ);
                    if (coverageMap != null)
                    {
                        if (coverageMap.isMarked(mapLocation.x, mapLocation.z) == true) //cell was used earlier
                        {
                            continue;                                                   //skip already covered tiles
                        }
                        else
                        {
                            if (blueprint.wallMap[x, z] > 1 || blueprint.wallMap[x, z] == -1)
                            {
                                coverageMap.Mark(mapLocation.x, mapLocation.z);                                                               //mark cell as used
                            }
                        }
                    }

                    //Check if thepoint is in allowed bounds of the map
                    if (!mapLocation.InBounds(map) || mapLocation.InNoBuildEdgeArea(map))
                    {
                        continue; //ignore invalid cells
                    }

                    //Construct terrain if some specific terrain stored in the blueprint
                    if (blueprint.terrainMap[x, z] != null)
                    {
                        totalTerrains++;
                        TerrainDef blueprintTerrain = TerrainDef.Named(blueprint.terrainMap[x, z].defName);
                        if (!map.terrainGrid.TerrainAt(mapLocation).IsWater)
                        {
                            map.terrainGrid.SetTerrain(mapLocation, blueprintTerrain);
                            totalCost += blueprint.terrainMap[x, z].cost;
                            transferredTerrains++;
                        }
                    }

                    //construct roof evetywhere if we doing complete transfer (ignoring outside: room with index 1).
                    if (blueprint.roofMap[x, z] == true && options.overwritesEverything && blueprint.wallMap[x, z] != 1)
                    {
                        map.roofGrid.SetRoof(mapLocation, RoofDefOf.RoofConstructed);
                    }


                    //Add items
                    if (blueprint.itemsMap[x, z] != null && blueprint.itemsMap[x, z].Count > 0 /* && cellUsed[mapLocation.x, mapLocation.z] == false*/)
                    {
                        totalItems += blueprint.itemsMap[x, z].Count;

                        bool cellIsAlreadyCleared = false;
                        foreach (ItemTile itemTile in blueprint.itemsMap[x, z])
                        {
                            if (!cellIsAlreadyCleared)   //first item to be spawned should also clear place for itself. we can't do it beforehand because we don't know if it will be able and get a chance to be spawned.
                            {
                                bool forceCleaning = (blueprint.wallMap[x, z] > 1) && Rand.Chance(0.9f);

                                if (!ClearCell(mapLocation, map, forceCleaning))
                                {
                                    break; //if cell was not cleared successfully -> break things placement cycle and move on to the next item
                                }
                                else
                                {
                                    cellIsAlreadyCleared = true;
                                }
                            }

                            Thing thing = MakeThingFromItemTile(itemTile);
                            if (thing != null)
                            {
                                try {
                                    GenSpawn.Spawn(thing, mapLocation, map, new Rot4(itemTile.rot));
                                    try {
                                        switch (thing.def.tickerType)
                                        {
                                        case TickerType.Never:
                                            break;

                                        case TickerType.Normal:
                                            thing.Tick();
                                            break;

                                        case TickerType.Long:
                                            thing.TickLong();
                                            break;

                                        case TickerType.Rare:
                                            thing.TickRare();
                                            break;
                                        }
                                        //Debug.Message("Ticked");
                                    } catch (Exception e) {
                                        //Debug.Message("Exception while tried to perform tick for {0} of cost {1}", thing.def.defName, itemTile.cost);
                                        thing.Destroy();
                                        throw e;
                                    }

                                    //Debug.Message("Setting up props");
                                    //Breakdown breakdownables: it't yet impossible to silently breakdown an item which is not spawned.
                                    CompBreakdownable b = thing.TryGetComp <CompBreakdownable>();
                                    if (b != null && options.enableDeterioration)
                                    {
                                        if (Rand.Chance(0.8f))
                                        {
                                            b.DoBreakdown();
                                        }
                                    }

                                    //reduce HP for haulable things in water
                                    if (thing.def.EverHaulable)
                                    {
                                        TerrainDef t = map.terrainGrid.TerrainAt(mapLocation);
                                        if (t != null && t.IsWater)
                                        {
                                            thing.HitPoints = (thing.HitPoints - 10) / Rand.Range(5, 20) + Rand.Range(1, 10); //things in marsh or river are really in bad condition
                                        }
                                    }
                                    transferredTiles++;
                                    totalCost += itemTile.cost;
                                } catch (Exception e) {
                                    //Debug.Message("Failed to spawn item {0} of cost {1} because of exception", thing, itemTile.cost);
                                    //ignore
                                }
                            }
                        }
                    }
                }

                if (options.shouldKeepDefencesAndPower)
                {
                    RestoreDefencesAndPower();
                }
                options.uncoveredCost = totalCost;
            }
            Debug.Log(Debug.BlueprintTransfer, "Transferred blueprint of size {0}x{1}, age {2}, total cost of approximately {3}. Items: {4}/{5}, terrains: {6}/{7}", blueprint.width, blueprint.height, -blueprint.dateShift, totalCost, transferredTiles, totalItems, transferredTerrains, totalTerrains);
        }