public override void Generate(Map map, GenStepParams parms) { //add standard ruins along with real. if (RealRuins_ModSettings.preserveStandardRuins) { GenStep scatterOriginalRuins = new GenStep_ScatterRuinsSimple(); scatterOriginalRuins.Generate(map, parms); } //skip generation due to low blueprints count if (SnapshotStoreManager.Instance.StoredSnapshotsCount() < 10) { Debug.Error(Debug.Scatter, "Skipping ruins gerenation due to low blueprints count."); return; } //Skip generation for starting tile if corresponding settings flag is set if (RealRuins_ModSettings.startWithoutRuins) { int homes = 0; var allMaps = Find.Maps; for (int i = 0; i < allMaps.Count; i++) { Map someMap = allMaps[i]; if (someMap.IsPlayerHome) { homes++; } } if (homes == 1 && Find.TickManager.TicksGame < 10) { return; //single home => we're generating that single home => that's starting map => no ruins here if this option is selected. } } //Skip generation on other ruins world objects foreach (WorldObject wo in Find.World.worldObjects.ObjectsAt(map.Tile)) { if (wo is RealRuinsPOIWorldObject || wo is AbandonedBaseWorldObject) { return; } } if (!map.TileInfo.WaterCovered) { float densityMultiplier = 1.0f; float scaleMultiplier = 1.0f; float distanceToSettlement = 0.0f; float totalDensity = RealRuins_ModSettings.defaultScatterOptions.densityMultiplier; currentOptions = RealRuins_ModSettings.defaultScatterOptions.Copy(); //store as instance variable to keep accessible on subsequent ScatterAt calls if (RealRuins_ModSettings.defaultScatterOptions.enableProximity) { distanceToSettlement = CalculateDistanceToNearestSettlement(map); if (distanceToSettlement >= 16 && Rand.Chance(0.5f)) { totalDensity = 0; } if (totalDensity > 0) { densityMultiplier = (float)(Math.Exp(1.0 / (distanceToSettlement / 10.0 + 0.3)) - 0.7); scaleMultiplier = (float)(Math.Exp(1 / (distanceToSettlement / 5 + 0.5)) - 0.3); } else { densityMultiplier = 0.0f; } currentOptions.densityMultiplier *= densityMultiplier; currentOptions.minRadius = Math.Min(60, Math.Max(6, (int)(currentOptions.minRadius * scaleMultiplier))); //keep between 6 and 60 currentOptions.maxRadius = Math.Min(60, Math.Max(6, (int)(currentOptions.maxRadius * scaleMultiplier))); //keep between 6 and 60 currentOptions.scavengingMultiplier *= scaleMultiplier * densityMultiplier; currentOptions.deteriorationMultiplier += Math.Min(0.2f, (1.0f / (scaleMultiplier * densityMultiplier * 3))); if (densityMultiplier > 20.0f) { densityMultiplier = 20.0f; } while (densityMultiplier * currentOptions.maxRadius > 800) { densityMultiplier *= 0.9f; //WHAT? Why not 800/radius? } } //number of ruins based on density settings var num = (int)((float)map.Area / 10000.0f) * Rand.Range(1 * totalDensity, 2 * totalDensity); Debug.Log(Debug.Scatter, "dist {0}, dens {1} (x{2}), scale x{3} ({4}-{5}), scav {6}, deter {7}", distanceToSettlement, currentOptions.densityMultiplier, densityMultiplier, scaleMultiplier, currentOptions.minRadius, currentOptions.maxRadius, currentOptions.scavengingMultiplier, currentOptions.deteriorationMultiplier); Debug.Log(Debug.Scatter, "Spawning {0} ruin chunks", num); BaseGen.globalSettings.map = map; bool shouldUnpause = false; Find.TickManager.Pause(); if (!Find.TickManager.Paused) { Find.TickManager.TogglePaused(); shouldUnpause = true; } CoverageMap coverageMap = CoverageMap.EmptyCoverageMap(map); for (int i = 0; i < num; i++) { try { //We use copy of scatteroptions because each scatteroptions represents separate chunk with separate location, size, maps, etc. //should use struct instead? is it compatible with IExposable? ResolveParams rp = default(ResolveParams); List <AbstractDefenderForcesGenerator> generators = new List <AbstractDefenderForcesGenerator>(); if (Rand.Chance(currentOptions.hostileChance)) { if (Rand.Chance(0.8f)) { generators = new List <AbstractDefenderForcesGenerator> { new AnimalInhabitantsForcesGenerator() }; } else { generators = new List <AbstractDefenderForcesGenerator> { new MechanoidsForcesGenerator(0) }; } } rp.faction = Find.FactionManager.OfAncientsHostile; var center = CellFinder.RandomNotEdgeCell(10, map); rp.rect = new CellRect(center.x, center.z, 1, 1); //after generation will be extended to a real size RuinsScatterer.Scatter(rp, currentOptions.Copy(), coverageMap, generators); } catch { Debug.Warning(Debug.Scatter, "Could not scatter a single ruins chunk."); } } if (shouldUnpause) { //Debug.Message("Finished spawning, unpausing"); Find.TickManager.TogglePaused(); } } }
public override void Generate(Map map, GenStepParams parms) { Find.TickManager.Pause(); //Debug.Message("Overridden LARGE generate"); RealRuinsPOIComp poiComp = map.Parent.GetComponent <RealRuinsPOIComp>(); string filename = SnapshotStoreManager.Instance.SnapshotNameFor(poiComp.blueprintName, poiComp.gameName); Debug.Log("Spawning POI: Preselected file name is {0}", filename); Debug.Log("Location is {0} {1}", poiComp.originX, poiComp.originZ); currentOptions = RealRuins_ModSettings.defaultScatterOptions.Copy(); //store as instance variable to keep accessible on subsequent ScatterAt calls currentOptions.minRadius = 400; currentOptions.maxRadius = 400; currentOptions.scavengingMultiplier = 0.0f; currentOptions.deteriorationMultiplier = 0.0f; currentOptions.hostileChance = 0.0f; currentOptions.blueprintFileName = filename; currentOptions.costCap = -1; currentOptions.startingPartyPoints = -1; currentOptions.minimumCostRequired = 0; currentOptions.minimumDensityRequired = 0.0f; currentOptions.minimumAreaRequired = 0; currentOptions.deleteLowQuality = false; currentOptions.shouldKeepDefencesAndPower = true; currentOptions.shouldLoadPartOnly = false; currentOptions.shouldAddRaidTriggers = false; currentOptions.claimableBlocks = false; if (poiComp.poiType == (int)POIType.Ruins || map.ParentFaction == null) { /*if (Rand.Chance(0.1f)) { * currentOptions.wallsDoorsOnly = true; * } else { * currentOptions.deteriorationMultiplier = Math.Abs(Rand.Gaussian(0, 0.15f)); * }*/ currentOptions.shouldAddFilth = true; currentOptions.forceFullHitPoints = false; currentOptions.enableDeterioration = true; currentOptions.overwritesEverything = false; currentOptions.costCap = (int)Math.Abs(Rand.Gaussian(0, 10000)); currentOptions.itemCostLimit = Rand.Range(50, 300); } else { currentOptions.shouldAddFilth = false; currentOptions.forceFullHitPoints = true; currentOptions.enableDeterioration = false; currentOptions.overwritesEverything = true; } currentOptions.overridePosition = new IntVec3(poiComp.originX, 0, poiComp.originZ); currentOptions.centerIfExceedsBounds = true; var bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename); //FOR DEBUG LOGGING //var a = new BlueprintAnalyzer(bp, currentOptions); //a.Analyze(); Debug.Log(Debug.BlueprintTransfer, "Trying to place POI map at tile {0}, at {1},{2} to {3},{4} ({5}x{6})", map.Parent.Tile, poiComp.originX, poiComp.originZ, poiComp.originX + bp.width, poiComp.originZ + bp.height, bp.width, bp.height); var generators = GeneratorsForBlueprint(bp, poiComp, map.Parent.Faction); ResolveParams resolveParams = default(ResolveParams); BaseGen.globalSettings.map = map; resolveParams.faction = map.ParentFaction; resolveParams.rect = new CellRect(currentOptions.overridePosition.x, currentOptions.overridePosition.z, map.Size.x - currentOptions.overridePosition.x, map.Size.z - currentOptions.overridePosition.z); BaseGen.globalSettings.mainRect = resolveParams.rect; float uncoveredCost = currentOptions.uncoveredCost; if (resolveParams.faction != null) { //Debug.Log("Mannable count: {0}", poiComp.mannableCount); ManTurrets((int)(poiComp.mannableCount * 1.25f + 1), resolveParams, map); } RuinsScatterer.Scatter(resolveParams, currentOptions, null, generators); //ok, but why LIFO? Queue looks more suitable for map generation. //Looks like it was done for nested symbols resolving, but looks strange anyway. BaseGen.symbolStack.Push("chargeBatteries", resolveParams); BaseGen.symbolStack.Push("ensureCanHoldRoof", resolveParams); BaseGen.symbolStack.Push("refuel", resolveParams); BaseGen.Generate(); if (generators != null) { foreach (AbstractDefenderForcesGenerator generator in generators) { generator.GenerateStartingParty(map, resolveParams, currentOptions); } } }
public override void Generate(Map map, GenStepParams parms) { Find.TickManager.Pause(); //Debug.Message("Overridden LARGE generate"); string filename = map.Parent.GetComponent <RuinedBaseComp>()?.blueprintFileName; Debug.Log(Debug.Scatter, "Large Ruins - Preselected file name is {0}", filename); currentOptions = RealRuins_ModSettings.defaultScatterOptions.Copy(); //store as instance variable to keep accessible on subsequent ScatterAt calls currentOptions.minRadius = 200; currentOptions.maxRadius = 200; currentOptions.scavengingMultiplier = 0.1f; currentOptions.deteriorationMultiplier = 0.0f; currentOptions.hostileChance = 1.0f; currentOptions.blueprintFileName = filename; currentOptions.costCap = map.Parent.GetComponent <RuinedBaseComp>()?.currentCapCost ?? -1; currentOptions.startingPartyPoints = (int)(map.Parent.GetComponent <RuinedBaseComp>()?.raidersActivity ?? -1); currentOptions.minimumCostRequired = (int)Math.Min(100000.0f, RealRuins_ModSettings.ruinsCostCap); currentOptions.minimumDensityRequired = 0.015f; currentOptions.minimumAreaRequired = 6400; currentOptions.deleteLowQuality = false; //do not delete since we have much higher requirements for base ruins currentOptions.shouldKeepDefencesAndPower = true; currentOptions.shouldLoadPartOnly = false; currentOptions.shouldAddRaidTriggers = Find.Storyteller.difficulty.allowBigThreats; currentOptions.claimableBlocks = false; currentOptions.enableDeterioration = false; ResolveParams resolveParams = default(ResolveParams); BaseGen.globalSettings.map = map; resolveParams.faction = Find.FactionManager.OfAncientsHostile; resolveParams.rect = new CellRect(0, 0, map.Size.x, map.Size.z); List <AbstractDefenderForcesGenerator> generators = new List <AbstractDefenderForcesGenerator> { new BattleRoyaleForcesGenerator() }; BaseGen.globalSettings.mainRect = resolveParams.rect; float uncoveredCost = currentOptions.uncoveredCost; if (uncoveredCost < 0) { if (Rand.Chance(0.5f)) { uncoveredCost = -uncoveredCost; //adding really small party } } RuinsScatterer.Scatter(resolveParams, currentOptions, null, generators); BaseGen.symbolStack.Push("chargeBatteries", resolveParams); BaseGen.symbolStack.Push("refuel", resolveParams); BaseGen.Generate(); //adding starting party //don't doing it via basegen because of uh oh i don't remember, something with pawn location control if (generators != null) { foreach (AbstractDefenderForcesGenerator generator in generators) { generator.GenerateStartingParty(map, resolveParams, currentOptions); } } }