コード例 #1
0
ファイル: CarnCellFinder.cs プロジェクト: Pyr3z/Carnivale
        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);
        }
コード例 #2
0
ファイル: CarnUtils.cs プロジェクト: Pyr3z/Carnivale
 public static void Cleanup()
 {
     cachedRoles.Clear();
     cachedInfo = null;
     CellsUtil.Cleanup();
 }
コード例 #3
0
        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.");
                }
            }
        }
コード例 #4
0
ファイル: CarnCellFinder.cs プロジェクト: Pyr3z/Carnivale
        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);
        }