public static IntVec3 BestCarnivalSetupPosition(IntVec3 initPos, Map map) { IntVec3 averageColPos; if (!(averageColPos = CellsUtil.ApproxClosestColonistBuilding(map, initPos, ThingDefOf.Door)).IsValid && !(averageColPos = CellsUtil.ApproxClosestColonistBuilding(map, initPos, ThingDefOf.Wall)).IsValid) { averageColPos = AverageColPos; } else { averageColPos = averageColPos.AverageWith(AverageColPos); } var distSqrdToColony = initPos.DistanceToSquared(averageColPos); if (Prefs.DevMode) { Log.Message("[Carnivale] setupSpot: initPos=" + initPos + ", averageColPos=" + averageColPos + ", distSqrdToColony=" + distSqrdToColony); } var result = initPos; if (!TryCarnivalSetupPosition_Triangular(initPos, averageColPos, distSqrdToColony, map, out result)) { if (Prefs.DevMode) { Log.Warning("\t[Carnivale] setupSpot: triangular algorithm failed. Using old random iteration algorithm."); } TryCarnivalSetupPosition_Random(initPos, averageColPos, 7, map, out result); } if (Prefs.DevMode) { if (result == initPos) { Log.Error(string.Concat(new object[] { "[Carnivale] Could not find carnival setup spot from ", initPos, ", expect more errors. Using ", initPos })); } Log.Message("[Carnivale] setupSpot: final pass: "******". distToColony=" + result.DistanceTo(averageColPos)); map.debugDrawer.FlashCell(result, 0.5f, "Setup Spot"); } return(result); }
public static void Cleanup() { cachedRoles.Clear(); cachedInfo = null; CellsUtil.Cleanup(); }
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."); } } }
public static IntVec3 PreCalculateBannerCell() { if (!Info.Active) { Log.Error("[Carnivale] Tried to perform a cell calculation while current carnival is inactive."); return(IntVec3.Invalid); } var map = Info.map; var setupCentre = Info.setupCentre; var baseRadius = Info.baseRadius; var minDistToCentre = baseRadius / 2; var maxDistToCentre = baseRadius + 3f; var minDistSqrdToCentre = (int)(minDistToCentre * minDistToCentre * 2); var maxDistSqrdToCentre = (int)(maxDistToCentre * maxDistToCentre * 2); IntVec3 colonistPos; if (!(colonistPos = CellsUtil.ApproxClosestColonistBuilding(map, setupCentre, ThingDefOf.Door)).IsValid) { colonistPos = CellsUtil.AverageColonistPosition(map); } else { colonistPos = colonistPos.AverageWith(CellsUtil.AverageColonistPosition(map)); } // Initial pass var closestCell = CellRect.CenteredOn(setupCentre, (int)maxDistToCentre).EdgeCells.ClosestCellTo(colonistPos, map); if (Prefs.DevMode) { Log.Message("[Carnivale] bannerCell initial pass: "******"Road")) { adjustedCell += IntVec3.East * 2; } else if ((adjustedCell + IntVec3.West * 2).GetTerrain(map).HasTag("Road")) { adjustedCell += IntVec3.West * 2; } else { adjustedCell += IntVec3.North; } closestCell = adjustedCell; if (Prefs.DevMode) { Log.Message("\t[Carnivale] bannerCell road pass: "******". distSqrdToCentre=" + dist + ", minDistSqrdToCentre=" + minDistSqrdToCentre + ", maxDistSqrdToCentre=" + maxDistSqrdToCentre); } break; } else { if (Prefs.DevMode) { Log.Warning("\t[Carnivale] bannerCell road pass failure: " + rcell + ". distSqrdToCentre=" + dist + ", minDistSqrdToCentre=" + minDistSqrdToCentre + ", maxDistSqrdToCentre=" + maxDistSqrdToCentre); } } } // line of sight pass if (!GenSight.LineOfSight(setupCentre, closestCell, map)) { Func <IntVec3, float> weightLoSSetupCentre = c => 2f / (setupCentre.CountObstructingCellsTo(c, map) + 1f); Func <IntVec3, float> weightLoSColony = c => 1f / (c.CountObstructingCellsTo(colonistPos, map) + 1f); Func <IntVec3, float> weightBest = c => (weightLoSSetupCentre(c) == 2f ? 2f : 0f) + (weightLoSColony(c) == 1f ? 1f : 0f); var candidateCells = CellTriangle .FromTarget(setupCentre, closestCell, 45f, maxDistToCentre) .Where(c => c.InBounds(map) && c.DistanceToSquared(setupCentre) >= minDistSqrdToCentre); try { closestCell = candidateCells.MaxBy(weightBest); if (Prefs.DevMode) { Log.Message("\t[Carnivale] bannerCell optimal LoS pass: "******"\t[Carnivale] bannerCell sub-optimal LoS pass: "******"\t[Carnivale] bannerCell failed LoS passes. Is candidateCells empty? Leaving it at: " + closestCell); } } } // Mountain proximity pass var attempts = 0; IntVec3 nearestMineable; while (attempts < 10 && closestCell.DistanceSquaredToNearestMineable(map, 12, out nearestMineable) <= 36) { closestCell = CellRect.CenteredOn(closestCell, 5).FurthestCellFrom(nearestMineable); attempts++; if (Prefs.DevMode) { Log.Message("\t[Carnivale] bannerCell mountain proximity pass #" + attempts + ": " + closestCell); } } if (attempts == 10 && Prefs.DevMode) { Log.Warning("\t[Carnivale] bannerCell mountain proximity passes took too many tries. Leaving it at: " + closestCell); } // End passes if (Prefs.DevMode) { Log.Message("[Carnivale] bannerCell pre-buildability pass: " + closestCell); } return(closestCell); }