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); }
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); }