private static IntVec3 FindCenterWaterCell(Map map, bool landing = false) { TraverseParms tp = TraverseParms.For(TraverseMode.NoPassClosedDoors, Danger.Deadly, false); Predicate <IntVec3> validator = (IntVec3 x) => GenGridVehicles.Standable(x, map) && !x.Fogged(map) && map.GetCachedMapComponent <VehicleMapping>().VehicleReachability.CanReachMapEdge(x, tp); IntVec3 result; if (RCellFinder.TryFindRandomCellNearTheCenterOfTheMapWith(null /*input validator here*/, map, out result)) { return(result); //REDO } Log.Warning("Could not find any valid center cell."); return(CellFinder.RandomCell(map)); }
public static RegionType GetExpectedRegionType(this IntVec3 c, Map map) { if (!c.InBoundsShip(map)) { return(RegionType.None); } if (!(c.GetDoor(map) is null)) { return(RegionType.Portal); } if (GenGridVehicles.Walkable(c, map.GetCachedMapComponent <VehicleMapping>())) { return(RegionType.Normal); } return(RegionType.ImpassableFreeAirExchange); }
private static IntVec3 FindNearEdgeWaterCell(Map map) { Predicate <IntVec3> validator = (IntVec3 x) => GenGridVehicles.Standable(x, map) && !x.Fogged(map); Faction hostFaction = map.ParentFaction; IntVec3 root; if (CellFinder.TryFindRandomEdgeCellWith(validator, map, CellFinder.EdgeRoadChance_Ignore, out root)) { return(CellFinderExtended.RandomClosewalkCellNear(root, map, 5, null)); } if (CellFinder.TryFindRandomEdgeCellWith(validator, map, CellFinder.EdgeRoadChance_Ignore, out root)) { return(CellFinderExtended.RandomClosewalkCellNear(root, map, 5, null)); } Log.Warning("Could not find any valid edge cell."); return(CellFinder.RandomCell(map)); }
public static bool TryFindRandomReachableCellNear(IntVec3 root, Map map, float radius, TraverseParms traverseParms, Predicate <IntVec3> validator, Predicate <VehicleRegion> regionValidator, out IntVec3 result, int maxRegions = 999999) { if (map is null) { Log.ErrorOnce("Tried to find reachable cell using SPExtended in a null map", 61037855); result = IntVec3.Invalid; return(false); } VehicleRegion region = VehicleGridsUtility.GetRegion(root, map, RegionType.Set_Passable); if (region is null) { result = IntVec3.Invalid; return(false); } Rot4 dir = Find.World.CoastDirectionAt(map.Tile).IsValid ? Find.World.CoastDirectionAt(map.Tile) : !Find.WorldGrid[map.Tile].Rivers.NullOrEmpty() ? Ext_Map.RiverDirection(map) : Rot4.Invalid; result = RandomEdgeCell(dir, map, (IntVec3 c) => GenGridVehicles.Standable(c, map) && !c.Fogged(map), 0); return(true); }
public static void EnterAndSpawn(Caravan caravan, Map map, CaravanEnterMode enterMode, CaravanDropInventoryMode dropInventoryMode = CaravanDropInventoryMode.DoNotDrop, bool draftColonists = false, Predicate <IntVec3> extraValidator = null) { bool coastalSpawn = caravan.HasBoat(); if (enterMode == CaravanEnterMode.None) { Log.Error(string.Concat(new object[] { "Caravan ", caravan, " tried to enter map ", map, " with no enter mode. Defaulting to edge." })); enterMode = CaravanEnterMode.Edge; } List <Pawn> pawns = new List <Pawn>(caravan.PawnsListForReading).ToList(); IntVec3 enterCell = pawns.NotNullAndAny(v => v.IsBoat()) ? GetWaterCell(caravan, map, CaravanEnterMode.Edge) : GetEnterCellVehicle(caravan, map, enterMode, extraValidator); Rot4 edge = enterMode == CaravanEnterMode.Edge ? CellRect.WholeMap(map).GetClosestEdge(enterCell) : Rot4.North; Predicate <IntVec3> validator = (IntVec3 c) => coastalSpawn?GenGridVehicles.Standable(c, map) : GenGrid.Standable(c, map); Func <Pawn, IntVec3> spawnCellGetter = (Pawn p) => CellFinderExtended.RandomSpawnCellForPawnNear(enterCell, map, p, validator); SpawnVehicles(caravan, pawns, map, spawnCellGetter, edge, draftColonists); }
/// <summary> /// Ensures the cellrect inhabited by <paramref name="vehicleDef"/> contains no Things that will block pathing and movement at <paramref name="cell"/>. /// </summary> /// <param name="pawn"></param> /// <param name="c"></param> public static bool CellRectStandable(this VehicleDef vehicleDef, Map map, IntVec3 cell, Rot4?rot = null) { IntVec2 dimensions = vehicleDef.Size; if (rot?.IsHorizontal ?? false) { int x = dimensions.x; dimensions.x = dimensions.z; dimensions.z = x; } foreach (IntVec3 cell2 in CellRect.CenteredOn(cell, dimensions.x, dimensions.z)) { if (vehicleDef.IsBoat() && !GenGridVehicles.Standable(cell2, map)) { return(false); } else if (!GenGrid.Standable(cell2, map)) { return(false); } } return(true); }
/// <summary> /// Catch All for vehicle related Things spawned in. Handles GodMode placing of vehicle buildings, corrects immovable spawn locations, and registers air defenses /// </summary> /// <param name="newThing"></param> /// <param name="loc"></param> /// <param name="map"></param> /// <param name="rot"></param> /// <param name="__result"></param> /// <param name="wipeMode"></param> /// <param name="respawningAfterLoad"></param> /// <returns></returns> public static bool RegisterThingSpawned(Thing newThing, ref IntVec3 loc, Map map, Rot4 rot, Thing __result, WipeMode wipeMode, bool respawningAfterLoad) { if (newThing.def is VehicleBuildDef def) { if (!VehicleMod.settings.debug.debugSpawnVehicleBuildingGodMode && newThing.HitPoints == newThing.MaxHitPoints) { VehiclePawn vehiclePawn = VehicleSpawner.GenerateVehicle(def.thingToSpawn, newThing.Faction); // (VehiclePawn)PawnGenerator.GeneratePawn(def.thingToSpawn); if (def.soundBuilt != null) { def.soundBuilt.PlayOneShot(new TargetInfo(loc, map, false)); } VehiclePawn vehicleSpawned = (VehiclePawn)GenSpawn.Spawn(vehiclePawn, loc, map, rot, WipeMode.FullRefund, false); vehicleSpawned.Rename(); __result = vehicleSpawned; AchievementsHelper.TriggerVehicleConstructionEvent(vehicleSpawned); return(false); } } else if (newThing is VehiclePawn vehicle) { bool standable = true; foreach (IntVec3 c in vehicle.PawnOccupiedCells(loc, rot)) { if (!c.InBounds(map) || (vehicle.IsBoat() ? GenGridVehicles.Impassable(c, map) : GenGrid.Impassable(c, map))) { standable = false; break; } } bool validator(IntVec3 c) { foreach (IntVec3 c2 in vehicle.PawnOccupiedCells(c, rot)) { if (vehicle.IsBoat() ? GenGridVehicles.Impassable(c, map) : GenGrid.Impassable(c, map)) { return(false); } } return(true); } if (standable) { return(true); } if (!CellFinder.TryFindRandomCellNear(loc, map, 20, validator, out IntVec3 newLoc, 100)) { Log.Error($"Unable to find location to spawn {newThing.LabelShort} after 100 attempts. Aborting spawn."); return(false); } loc = newLoc; } else if (newThing is Pawn pawn && !pawn.Dead) { try { var positionManager = map.GetCachedMapComponent <VehiclePositionManager>(); if (positionManager.PositionClaimed(loc)) { VehiclePawn inPlaceVehicle = positionManager.ClaimedBy(loc); CellRect occupiedRect = inPlaceVehicle.OccupiedRect().ExpandedBy(1); Rand.PushState(); for (int i = 0; i < 3; i++) { IntVec3 newLoc = occupiedRect.EdgeCells.Where(c => GenGrid.InBounds(c, map) && GenGrid.Standable(c, map)).RandomElementWithFallback(inPlaceVehicle.Position); if (occupiedRect.EdgeCells.Contains(newLoc)) { loc = newLoc; break; } occupiedRect = occupiedRect.ExpandedBy(1); } Rand.PopState(); } } catch (Exception ex) { Log.Error($"Pawn {newThing.Label} could not be readjusted for spawn location. Exception={ex.Message}"); } }
/// <summary> /// Intercepts FloatMenuMakerMap call to restrict by size and call through to custom water based pathing requirements /// </summary> /// <param name="clickCell"></param> /// <param name="pawn"></param> /// <param name="__result"></param> /// <returns></returns> public static bool GotoLocationShips(IntVec3 clickCell, Pawn pawn, ref FloatMenuOption __result) { if (pawn is VehiclePawn vehicle) { if (vehicle.Faction != Faction.OfPlayer || !vehicle.CanMoveFinal) { return(false); } if (VehicleMod.settings.main.fullVehiclePathing && vehicle.LocationRestrictedBySize(clickCell)) { Messages.Message("VehicleCannotFit".Translate(), MessageTypeDefOf.RejectInput); return(false); } if (vehicle.CompFueledTravel != null && vehicle.CompFueledTravel.EmptyTank) { Messages.Message("VehicleOutOfFuel".Translate(), MessageTypeDefOf.RejectInput); return(false); } Debug.Message("-> " + clickCell + " | " + vehicle.Map.terrainGrid.TerrainAt(clickCell).LabelCap + " | " + vehicle.Map.GetCachedMapComponent <VehicleMapping>().VehiclePathGrid.CalculatedCostAt(clickCell) + " - " + vehicle.Map.GetCachedMapComponent <VehicleMapping>().VehiclePathGrid.pathGrid[vehicle.Map.cellIndices.CellToIndex(clickCell)]); if (vehicle.IsBoat() && !VehicleMod.settings.debug.debugDisableWaterPathing) { int num = GenRadial.NumCellsInRadius(2.9f); int i = 0; IntVec3 curLoc; while (i < num) { curLoc = GenRadial.RadialPattern[i] + clickCell; if (GenGridVehicles.Standable(curLoc, vehicle.Map)) { if (curLoc == vehicle.Position || vehicle.beached) { __result = null; return(false); } if (!ShipReachabilityUtility.CanReachShip(vehicle, curLoc, PathEndMode.OnCell, Danger.Deadly, false, TraverseMode.ByPawn)) { Debug.Message($"Cant Reach {curLoc} with {vehicle.Label}"); __result = new FloatMenuOption("CannotSailToCell".Translate(), null, MenuOptionPriority.Default, null, null, 0f, null, null); return(false); } Action action = delegate() { Job job = new Job(JobDefOf.Goto, curLoc); if (vehicle.Map.exitMapGrid.IsExitCell(Verse.UI.MouseCell())) { job.exitMapOnArrival = true; } else if (!vehicle.Map.IsPlayerHome && !vehicle.Map.exitMapGrid.MapUsesExitGrid && CellRect.WholeMap(vehicle.Map).IsOnEdge(Verse.UI.MouseCell(), 3) && vehicle.Map.Parent.GetComponent <FormCaravanComp>() != null && MessagesRepeatAvoider.MessageShowAllowed("MessagePlayerTriedToLeaveMapViaExitGrid-" + vehicle.Map.uniqueID, 60f)) { FormCaravanComp component = vehicle.Map.Parent.GetComponent <FormCaravanComp>(); if (component.CanFormOrReformCaravanNow) { Messages.Message("MessagePlayerTriedToLeaveMapViaExitGrid_CanReform".Translate(), vehicle.Map.Parent, MessageTypeDefOf.RejectInput, false); } else { Messages.Message("MessagePlayerTriedToLeaveMapViaExitGrid_CantReform".Translate(), vehicle.Map.Parent, MessageTypeDefOf.RejectInput, false); } } if (vehicle.jobs.TryTakeOrderedJob(job, JobTag.Misc)) { MoteMaker.MakeStaticMote(curLoc, vehicle.Map, ThingDefOf.Mote_FeedbackGoto, 1f); } }; __result = new FloatMenuOption("GoHere".Translate(), action, MenuOptionPriority.GoHere, null, null, 0f, null, null) { autoTakeable = true, autoTakeablePriority = 10f }; return(false); } else { i++; } } } else { int num = GenRadial.NumCellsInRadius(2.9f); int i = 0; IntVec3 curLoc; while (i < num) { curLoc = GenRadial.RadialPattern[i] + clickCell; if (GenGrid.Standable(curLoc, pawn.Map)) { if (curLoc == pawn.Position) { __result = null; return(false); } if (!ReachabilityUtility.CanReach(pawn, curLoc, PathEndMode.OnCell, Danger.Deadly, false)) { Debug.Message($"Cant Reach {curLoc} with {vehicle.Label}"); __result = new FloatMenuOption("CannotSailToCell".Translate(), null, MenuOptionPriority.Default, null, null, 0f, null, null); return(false); } Action action = delegate() { Job job = new Job(JobDefOf.Goto, curLoc); if (pawn.Map.exitMapGrid.IsExitCell(Verse.UI.MouseCell())) { job.exitMapOnArrival = true; } else if (!pawn.Map.IsPlayerHome && !pawn.Map.exitMapGrid.MapUsesExitGrid && CellRect.WholeMap(pawn.Map).IsOnEdge(Verse.UI.MouseCell(), 3) && pawn.Map.Parent.GetComponent <FormCaravanComp>() != null && MessagesRepeatAvoider.MessageShowAllowed("MessagePlayerTriedToLeaveMapViaExitGrid-" + pawn.Map.uniqueID, 60f)) { FormCaravanComp component = pawn.Map.Parent.GetComponent <FormCaravanComp>(); if (component.CanFormOrReformCaravanNow) { Messages.Message("MessagePlayerTriedToLeaveMapViaExitGrid_CanReform".Translate(), pawn.Map.Parent, MessageTypeDefOf.RejectInput, false); } else { Messages.Message("MessagePlayerTriedToLeaveMapViaExitGrid_CantReform".Translate(), pawn.Map.Parent, MessageTypeDefOf.RejectInput, false); } } if (pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc)) { MoteMaker.MakeStaticMote(curLoc, pawn.Map, ThingDefOf.Mote_FeedbackGoto, 1f); } }; __result = new FloatMenuOption("GoHere".Translate(), action, MenuOptionPriority.GoHere, null, null, 0f, null, null) { autoTakeable = true, autoTakeablePriority = 10f }; return(false); } else { i++; } } } __result = null; return(false); } else { if (PathingHelper.VehicleInCell(pawn.Map, clickCell)) { __result = new FloatMenuOption("CannotGoNoPath".Translate(), null, MenuOptionPriority.Default, null, null, 0f, null, null); return(false); } } return(true); }
public static bool LocationRestrictedBySize(this VehiclePawn pawn, IntVec3 dest) { return(CellRect.CenteredOn(dest, pawn.def.Size.x, pawn.def.Size.z).NotNullAndAny(c2 => pawn.IsBoat() ? (!c2.InBoundsShip(pawn.Map) || GenGridVehicles.Impassable(c2, pawn.Map)) : (!c2.InBounds(pawn.Map) || MultithreadHelper.ImpassableReverseThreaded(c2, pawn.Map, pawn))) && CellRect.CenteredOn(dest, pawn.def.Size.z, pawn.def.Size.x).NotNullAndAny(c2 => pawn.IsBoat() ? (!c2.InBoundsShip(pawn.Map) || GenGridVehicles.Impassable(c2, pawn.Map)) : (!c2.InBounds(pawn.Map) || MultithreadHelper.ImpassableReverseThreaded(c2, pawn.Map, pawn)))); }