public static List <CustomVector> PlaceAt(CustomVector point, StructureLayoutDef building, CustomVector[][] grid) { RectUtils.HeightWidthFromLayout(building, out int height, out int width); List <CustomVector> doors = GetDoorsInLayout(building); List <CustomVector> doorsAdjusted = new List <CustomVector>(); for (int i = (int)point.X; i < width + point.X; i++) { for (int j = (int)point.Y; j < height + point.Y; j++) { CellType type = doors.FindAll(d => i == d.X + point.X && j == d.Y + point.Y).Any() ? CellType.DOOR : CellType.BUILDING; if (type == CellType.DOOR) { doorsAdjusted.Add(new CustomVector(i, j)); } if (grid[i][j] != null) { grid[i][j].Type = type; } else { grid[i][j] = new CustomVector(i, j, type: type); } } } return(doorsAdjusted); }
public static bool CanPlaceAt(CustomVector point, StructureLayoutDef building, CustomVector[][] grid) { bool result = true; RectUtils.HeightWidthFromLayout(building, out int height, out int width); for (int i = (int)point.X - 1; i < width + point.X + 1 && result; i++) { for (int j = (int)(point.Y - 1); j < height + point.Y + 1 && result; j++) { if (IsInBound(i, j, grid.Length, grid[0].Length)) { if (grid[i][j] != null && grid[i][j].Type != CellType.NONE) { return(false); } } else { return(false); } } } return(result); }
public override bool CanUseWith(IncidentParms parms, PawnGroupKindDef groupKind) { CGO.fallingStructure = this.def.GetModExtension <FallingStructure>(); if (CGO.fallingStructure.needToHaveSettlements && !Find.World.worldObjects.Settlements.FindAll(s => s.Faction == parms.faction).Any()) { return(false); } if (CGO.fallingStructure.canBeUsedBy.Contains(parms.faction.def)) { CGO.fallingStructureChoosen = LayoutUtils.ChooseWeightedStruct(CGO.fallingStructure.WeightedStructs, parms).structureLayoutDef; if (CGO.fallingStructureChoosen != null) { RectUtils.HeightWidthFromLayout(CGO.fallingStructureChoosen, out int h, out int w); return(parms.points >= this.MinimumPoints(parms.faction, groupKind) && this.FindRect((Map)parms.target, h, w) != IntVec3.Invalid); } else { return(false); } } else { return(false); } }
private static void QuickspawnStructure() { if (DefDatabase <StructureLayoutDef> .AllDefs.Count() > 0) { List <DebugMenuOption> list = new List <DebugMenuOption>(); foreach (StructureLayoutDef localDef2 in DefDatabase <StructureLayoutDef> .AllDefs) { StructureLayoutDef localDef = localDef2; list.Add(new DebugMenuOption(localDef.defName, DebugMenuOptionMode.Tool, delegate() { if (UI.MouseCell().InBounds(Find.CurrentMap)) { RectUtils.HeightWidthFromLayout(localDef, out int h, out int w); CellRect cellRect = CellRect.CenteredOn(UI.MouseCell(), w, h); foreach (List <string> item in localDef.layouts) { GenUtils.GenerateRoomFromLayout(item, cellRect, Find.CurrentMap, localDef); } } })); } Find.WindowStack.Add(new Dialog_DebugOptionListLister(list)); } }
public override bool TryResolveRaidSpawnCenter(IncidentParms parms) { RectUtils.HeightWidthFromLayout(CGO.fallingStructureChoosen, out int h, out int w); Map map = (Map)parms.target; parms.spawnCenter = this.FindRect(map, h, w); parms.spawnRotation = Rot4.Random; return(true); }
public override void Generate(Map map, GenStepParams parms) { StructureLayoutDef structureLayoutDef = structureLayoutDefs.RandomElement(); RectUtils.HeightWidthFromLayout(structureLayoutDef, out int h, out int w); CellRect cellRect = CellRect.CenteredOn(map.Center, w, h); GenUtils.PreClean(map, cellRect, structureLayoutDef.roofGrid, fullClear); foreach (List <string> item in structureLayoutDef.layouts) { GenUtils.GenerateRoomFromLayout(item, cellRect, map, structureLayoutDef); } if (shouldRuin) { CGO.factionSettlement = new CustomGenOption { filthTypes = filthTypes, scatterThings = scatterThings, scatterChance = scatterChance }; ResolveParams rp = new ResolveParams { faction = map.ParentFaction, rect = cellRect }; foreach (string resolver in ruinSymbolResolvers) { if (!(ruinSymbolResolvers.Contains("kcsg_randomroofremoval") && resolver == "kcsg_scatterstuffaround")) { BaseGen.symbolStack.Push(resolver, rp, null); } } } // Flood refog if (map.mapPawns.FreeColonistsSpawned.Count > 0) { FloodFillerFog.DebugRefogMap(map); } }
public override void Resolve(ResolveParams rp) { CGO.currentGenStep = "Generating structures"; foreach (KeyValuePair <CustomVector, StructureLayoutDef> keyValue in CGO.vectStruct) { CGO.currentGenStepMoreInfo = "Generating " + keyValue.Value.defName; RectUtils.HeightWidthFromLayout(keyValue.Value, out int height, out int width); IntVec3 limitMin = new IntVec3 { x = CGO.offset.x + (int)keyValue.Key.X, z = CGO.offset.z - (int)keyValue.Key.Y - height + 1 }; CellRect rect = new CellRect(limitMin.x, limitMin.z, width, height); foreach (List <string> item in keyValue.Value.layouts) { GenUtils.GenerateRoomFromLayout(item, rect, BaseGen.globalSettings.map, keyValue.Value); } if (keyValue.Value.isStorage) { ResolveParams rstock = rp; rstock.rect = new CellRect(limitMin.x, limitMin.z, width, height); BaseGen.symbolStack.Push("kcsg_storagezone", rstock, null); } } if (CGO.settlementLayoutDef.addLandingPad && ModLister.RoyaltyInstalled) { if (rp.rect.TryFindRandomInnerRect(new IntVec2(9, 9), out CellRect rect, null)) { CGO.currentGenStepMoreInfo = "Generating landing pad"; ResolveParams resolveParams = rp; resolveParams.rect = rect; BaseGen.symbolStack.Push("landingPad", resolveParams, null); BaseGen.globalSettings.basePart_landingPadsResolved++; } } BaseGen.symbolStack.Push("kcsg_gridsecondpass", rp, null); }
/// <summary> /// Generate a grid, add the preexisting vanilla road if needed. Add main roads. Fill the potential point list, add buildings on grid and fill the origin/layout dictionnary /// </summary> /// <param name="seed">Seed for Random</param> /// <param name="sld">SettlementLayoutDef to get all StructureLayoutDef authorized</param> /// <param name="map">The map</param> /// <returns></returns> public static CustomVector[][] GenerateGrid(int seed, SettlementLayoutDef sld, Map map) { CGO.currentGenStepMoreInfo = "Generating grid and main road"; int mapWidth = Math.Min(map.Size.x, sld.settlementSize.x), mapHeight = Math.Min(map.Size.z, sld.settlementSize.z); // Search for the smallest sized allowed structure. It will be the radius between potential building spawn points CGO.radius = 9999; for (int i = 0; i < sld.allowedStructures.Count; i++) { foreach (StructureLayoutDef item in DefDatabase <StructureLayoutDef> .AllDefsListForReading.FindAll(s => s.tags.Contains(sld.allowedStructuresConverted[i].structureLayoutTag))) { RectUtils.HeightWidthFromLayout(item, out int height, out int width); if (height < CGO.radius) { CGO.radius = height; } if (width < CGO.radius) { CGO.radius = width; } } } CGO.radius += 2; // Add to radius to ensure no building touch one another // Initialize the grid used for generation Random r = new Random(seed); CustomVector[][] grid = new CustomVector[mapWidth][]; for (int i = 0; i < mapWidth; i++) { grid[i] = new CustomVector[mapHeight]; for (int j = 0; j < mapHeight; j++) { grid[i][j] = new CustomVector(i, j); } } // Exclude non bridgeable cells for (int i = 0; i < mapWidth; i++) { for (int j = 0; j < mapHeight; j++) { TerrainDef t = map.terrainGrid.TerrainAt(new IntVec3(CGO.offset.x + i, 0, CGO.offset.y + j)); if (t.HasTag("Water") && (t.affordances == null || !t.affordances.Contains(TerrainAffordanceDefOf.Bridgeable))) { grid[i][j].Type = CellType.WATER; } } } // Main roads CGO.usePathCostReduction = false; // No path cost reduction for main road, for them to be distinct DrawXMainRoad(grid, mapWidth, mapHeight, 15, r); DrawYMainRoad(grid, mapWidth, mapHeight, 15, r); // If bigger sized settlement, add more main roads for (int i = 0; i < mapWidth / 100; i++) { if (i == 0) { DrawXMainRoad(grid, mapWidth, mapHeight, mapWidth / 2, r); DrawYMainRoad(grid, mapWidth, mapHeight, mapHeight / 2, r); } else { DrawXMainRoad(grid, mapWidth, mapHeight, 50, r); DrawYMainRoad(grid, mapWidth, mapHeight, 50, r); } } // Get vanilla world road type and use it if present if (CGO.preRoadTypes?.Count > 0) { for (int i = 0; i < mapWidth; i++) { for (int j = 0; j < mapHeight; j++) { TerrainDef t = map.terrainGrid.TerrainAt(new IntVec3(CGO.offset.x + i, 0, CGO.offset.y + j)); if (CGO.preRoadTypes.Contains(t)) { grid[i][j].Type = CellType.MAINROAD; // Add vanilla generated road to the grid } } } } CGO.usePathCostReduction = true; // Renable path cost reduction CGO.vectors = PoissonDiskSampling.Run(50, mapWidth, mapHeight, r, grid); // Get all possible points with radius CGO.doors = BuildingPlacement.Run(sld, grid, 50); // Place buildings on grid and add them/their origin into vectStruct return(grid); }
public static void Generate(Map map, IntVec3 c, CustomGenOption sf, string symbolResolver = "kcsg_settlement") { CGO.useStructureLayout = sf.useStructureLayout; if (sf.useStructureLayout) { CGO.structureLayoutDef = LayoutUtils.ChooseLayoutFrom(sf.chooseFromlayouts); } else { CGO.settlementLayoutDef = sf.chooseFromSettlements.RandomElement(); } // Get faction Faction faction; if (map.ParentFaction == null || map.ParentFaction == Faction.OfPlayer) { faction = Find.FactionManager.RandomEnemyFaction(false, false, true, TechLevel.Undefined); } else { faction = map.ParentFaction; } // Get settlement size int width; int height; if (sf.useStructureLayout) { RectUtils.HeightWidthFromLayout(CGO.structureLayoutDef, out height, out width); } else { SettlementLayoutDef temp = CGO.settlementLayoutDef; height = temp.settlementSize.x; width = temp.settlementSize.z; } IntVec3 intVec3 = c; if (CGO.factionSettlement.tryFindFreeArea) { bool success = RCellFinder.TryFindRandomCellNearTheCenterOfTheMapWith(cell => new CellRect(cell.x - width / 2, cell.z - height / 2, width, height).Cells.All(pC => pC.Walkable(map) && !pC.GetTerrain(map).affordances.Contains(TerrainAffordanceDefOf.Bridgeable)), map, out intVec3); KLog.Message($"Trying to find free spawn area success: {success}"); } CellRect rect = new CellRect(intVec3.x - width / 2, intVec3.z - height / 2, width, height); rect.ClipInsideMap(map); ResolveParams rp = default; rp.faction = faction; rp.rect = rect; BaseGen.globalSettings.map = map; BaseGen.symbolStack.Push(symbolResolver, rp, null); BaseGen.Generate(); }
public override void PostMapGenerate(Map map) { if (Find.TickManager.TicksGame > 5f || chooseFrom.Count <= 0 || PrepareCarefully_Util.pcScenariosSave.Count <= 0) { return; } StructureLayoutDef structureLayoutDef; if (ModLister.GetActiveModWithIdentifier("EdB.PrepareCarefully") != null) { structureLayoutDef = PrepareCarefully_Util.pcScenariosSave.First().Key; nearMapCenter = PrepareCarefully_Util.pcScenariosSave.First().Value; } else { structureLayoutDef = chooseFrom.RandomElement(); } RectUtils.HeightWidthFromLayout(structureLayoutDef, out int h, out int w); CellRect cellRect = this.CreateCellRect(map, h, w); if (preGenClear) { GenUtils.PreClean(map, cellRect, structureLayoutDef.roofGrid, fullClear); } foreach (List <string> item in structureLayoutDef.layouts) { GenUtils.GenerateRoomFromLayout(item, cellRect, map, structureLayoutDef, spawnConduits); } if (spawnTheStartingPawn && Find.GameInitData != null) { List <List <Thing> > thingsGroups = new List <List <Thing> >(); foreach (Pawn startingAndOptionalPawn in Find.GameInitData.startingAndOptionalPawns) { thingsGroups.Add(new List <Thing>() { startingAndOptionalPawn }); } List <Thing> thingList = new List <Thing>(); foreach (ScenPart allPart in Find.Scenario.AllParts) { thingList.AddRange(allPart.PlayerStartingThings()); } int index = 0; foreach (Thing thing in thingList) { if (thing.def.CanHaveFaction) { thing.SetFactionDirect(Faction.OfPlayer); } thingsGroups[index].Add(thing); ++index; if (index >= thingsGroups.Count) { index = 0; } } IntVec3 center = map.Center; Pos offset = structureLayoutDef.spawnAtPos.RandomElement(); center.x += offset.x; center.y += offset.y; KLog.Message($"Spawning pawns and stuff at {center}"); this.DropThingGroupsAt(center, map, thingsGroups, instaDrop: (Find.GameInitData.QuickStarted || this.method != PlayerPawnsArriveMethod.DropPods), leaveSlag: true, allowFogged: false); } if (map.mapPawns.FreeColonistsSpawned.Count > 0) { FloodFillerFog.DebugRefogMap(map); } }
public override List <Pawn> SpawnThreats(IncidentParms parms) { RectUtils.HeightWidthFromLayout(CGO.fallingStructureChoosen, out int h, out int w); CellRect cellRect = CellRect.CenteredOn(parms.spawnCenter, w, h); List <string> allSymbList = new List <string>(); Map map = (Map)parms.target; foreach (string str in CGO.fallingStructureChoosen.layouts[0]) { List <string> symbSplitFromLine = str.Split(',').ToList(); symbSplitFromLine.ForEach((s) => allSymbList.Add(s)); } List <TTIR> fallers = new List <TTIR>(); Dictionary <ActiveDropPodInfo, IntVec3> pods = new Dictionary <ActiveDropPodInfo, IntVec3>(); int l = 0; foreach (IntVec3 cell in cellRect.Cells) { if (l < allSymbList.Count && allSymbList[l] != ".") { SymbolDef temp = DefDatabase <SymbolDef> .GetNamed(allSymbList[l], false); Thing thing; if (temp.thingDef != null && !CGO.fallingStructure.thingsToSpawnInDropPod.Contains(temp.thingDef)) { TTIR ttir = new TTIR(); thing = ThingMaker.MakeThing(temp.thingDef, temp.stuffDef); thing.SetFactionDirect(parms.faction); if (!CGO.fallingStructure.spawnDormantWhenPossible && thing.TryGetComp <CompCanBeDormant>() is CompCanBeDormant ccbd && ccbd != null) { ccbd.wakeUpOnTick = Find.TickManager.TicksGame + 150; } if (thing.def.rotatable && thing.def.category == ThingCategory.Building) { ttir.rot = new Rot4(temp.rotation.AsInt); } ThingDef faller = new ThingDef { thingClass = CGO.fallingStructure.skyfaller, category = ThingCategory.Ethereal, useHitPoints = false, drawOffscreen = true, tickerType = TickerType.Normal, altitudeLayer = AltitudeLayer.Skyfaller, drawerType = DrawerType.RealtimeOnly, defName = temp.thingDef.defName, label = temp.thingDef.label + " (incoming)", size = new IntVec2(thing.def.size.x, thing.def.size.z) }; faller.skyfaller = new SkyfallerProperties() { shadowSize = new UnityEngine.Vector2(thing.def.size.x + 1, thing.def.size.z + 1), ticksToImpactRange = new IntRange(150, 150), movementType = SkyfallerMovementType.Decelerate }; ttir.faller = faller; ttir.toSpawn = thing; ttir.cell = cell; fallers.Add(ttir); } else if (temp.thingDef != null) { thing = ThingMaker.MakeThing(temp.thingDef, temp.stuffDef); thing.SetFactionDirect(parms.faction); ActiveDropPodInfo activeDropPodInfo = new ActiveDropPodInfo(); activeDropPodInfo.innerContainer.TryAdd(thing); activeDropPodInfo.openDelay = 40; activeDropPodInfo.leaveSlag = false; pods.Add(activeDropPodInfo, cell); } } l++; } // ARRIVAL fallers.ForEach(ttir => this.SpawnSkyfaller(ttir.faller, ttir.toSpawn, ttir.cell, map, ttir.rot)); for (int i = 0; i < pods.Count; i++) { DropPodUtility.MakeDropPodAt(pods.ElementAt(i).Value, map, pods.ElementAt(i).Key); } IncidentParms parms1 = parms; RCellFinder.TryFindRandomCellNearWith(parms.spawnCenter, i => i.Walkable(map), map, out parms1.spawnCenter, 33, 40); base.SpawnThreats(parms1); CGO.ClearFalling(); return(null); }