private static IEnumerable <Blueprint> PlaceTentBlueprints() { // main chapiteau ThingDef tentDef; Rot4 rot = info.setupCentre.RotationFacing(info.bannerCell).Opposite; IntVec3 tentSpot; if (availableCrates.Any(c => c.def == _DefOf.Carn_Crate_TentHuge)) { tentDef = _DefOf.Carn_TentChap; tentSpot = FindRadialPlacementFor(tentDef, rot, info.setupCentre, 11); if (tentSpot.IsValid) { RemoveFirstCrateOf(_DefOf.Carn_Crate_TentHuge); CarnUtils.ClearThingsFor(info.map, tentSpot, tentDef.size, rot, 2); yield return(PlaceBlueprint(tentDef, tentSpot, rot)); } else { Log.Error("Could not find placement for " + tentDef + ", which is a major attraction. Tell Xnope to get it together."); } } // lodging tents tentDef = _DefOf.Carn_TentLodge; rot = Rot4.Random; tentSpot = FindRadialPlacementFor(tentDef, rot, info.carnivalArea.ContractedBy(9).FurthestCellFrom(CellsUtil.AverageColonistPosition(info.map)), 7); IntVec3 lineDirection = rot.ToIntVec3(1); // shifted clockwise by 1 int numFailures = 0; bool firstNewPass = true; while (numFailures < 30 && availableCrates.Any(t => t.def == _DefOf.Carn_Crate_TentLodge)) { // Following works as intended iff size.x == size.y if (!firstNewPass) { // try adding tent next in a an adjacent line tentSpot += lineDirection * ((tentDef.size.x + 1)); } if (CanPlaceBlueprintAt(tentSpot, tentDef, rot)) { // bingo firstNewPass = false; RemoveFirstCrateOf(_DefOf.Carn_Crate_TentLodge); CarnUtils.ClearThingsFor(info.map, tentSpot, tentDef.size, rot, 1); yield return(PlaceBlueprint(tentDef, tentSpot, rot)); } else if (numFailures % 3 != 0) { // try different line directions rot.AsByte++; lineDirection = rot.ToIntVec3(1); numFailures++; } else { // Find new placement if next spot and any of its rotations don't work tentSpot = FindRadialPlacementFor(tentDef, rot, tentSpot, (int)info.baseRadius / 2); if (!tentSpot.IsValid) { // suboptimal random placement tentSpot = FindRandomPlacementFor(tentDef, rot, false, 5); } firstNewPass = true; } } if (numFailures == 30 && availableCrates.Any(t => t.def == _DefOf.Carn_Crate_TentLodge)) { Log.Error("Tried too many times to place tents. Some may not be built."); } // manager tent if (!availableCrates.Any(c => c.def == _DefOf.Carn_Crate_TentMan)) { yield break; } rot = Rot4.Random; tentDef = _DefOf.Carn_TentLodgeMan; // Try to place near other tents tentSpot = FindRadialCardinalPlacementFor(tentDef, rot, tentSpot, 10); if (tentSpot.IsValid) { RemoveFirstCrateOf(_DefOf.Carn_Crate_TentMan); CarnUtils.ClearThingsFor(info.map, tentSpot, tentDef.size, rot, 1); yield return(PlaceBlueprint(tentDef, tentSpot, rot)); } else { // suboptimal placement tentSpot = FindRadialPlacementFor(tentDef, rot, info.setupCentre, (int)info.baseRadius / 2); if (tentSpot.IsValid) { RemoveFirstCrateOf(_DefOf.Carn_Crate_TentMan); CarnUtils.ClearThingsFor(info.map, tentSpot, tentDef.size, rot, 1); yield return(PlaceBlueprint(tentDef, tentSpot, rot)); } else { Log.Error("Found no valid placement for manager tent. It will not be placed."); } } }