Example #1
0
        public BlueprintTransferUtility(Blueprint blueprint, Map map, ResolveParams rp, ScatterOptions options)
        {
            this.blueprint = blueprint;
            this.map       = map;
            this.rp        = rp;
            this.options   = options;

            Debug.Log("Transferring blueprint of faction {0}", rp.faction?.Name ?? "none");

            if (blueprint == null)
            {
                Debug.Error(Debug.BlueprintTransfer, "Attempting to configure transfer utility with empty blueprint!"); return;
            }
            if (map == null)
            {
                Debug.Error(Debug.BlueprintTransfer, "Attempting to configure transfer utility with empty map!"); return;
            }
            if (options == null)
            {
                Debug.Error(Debug.BlueprintTransfer, "Attempting to configure transfer utility with empty options!"); return;
            }

            mapOriginX = rp.rect.minX + rp.rect.Width / 2 - blueprint.width / 2;
            mapOriginZ = rp.rect.minZ + rp.rect.Height / 2 - blueprint.height / 2;

            if (mapOriginX < 0)
            {
                mapOriginX = 0;
            }
            if (mapOriginZ < 0)
            {
                mapOriginZ = 0;
            }

            if (mapOriginX + blueprint.width >= map.Size.x)
            {
                mapOriginX = map.Size.x - blueprint.width - 1;
            }

            if (mapOriginZ + blueprint.height >= map.Size.z)
            {
                mapOriginZ = map.Size.z - blueprint.height - 1;
            }

            if (options.overridePosition != IntVec3.Zero)
            {
                if (!options.centerIfExceedsBounds || (options.overridePosition.x + blueprint.width < map.Size.x && options.overridePosition.z + blueprint.height < map.Size.z))
                {
                    mapOriginX = options.overridePosition.x;
                    mapOriginZ = options.overridePosition.z;
                }
                else
                {
                    Debug.Warning(Debug.BlueprintTransfer, "Tried to override position, but map exceeded bounds and position was reverted due to corresponding options flag.");
                    Debug.Warning(Debug.BlueprintTransfer, "New position: {0}, {1}", mapOriginX, mapOriginZ);
                }
            }
        }
Example #2
0
        public override void Generate(Map map, GenStepParams parms)
        {
            Debug.Log(Debug.Scatter, "Medium generate");
            Find.TickManager.Pause();

            currentOptions = RealRuins_ModSettings.defaultScatterOptions.Copy();     //store as instance variable to keep accessible on subsequent ScatterAt calls

            currentOptions.minRadius               = 24;
            currentOptions.maxRadius               = 50;
            currentOptions.scavengingMultiplier    = 0.1f;
            currentOptions.deteriorationMultiplier = 0.1f;
            currentOptions.hostileChance           = 0.8f;
            currentOptions.itemCostLimit           = 800;

            currentOptions.minimumCostRequired        = 25000;
            currentOptions.minimumDensityRequired     = 0.01f;
            currentOptions.minimumAreaRequired        = 4000;
            currentOptions.deleteLowQuality           = false; //do not delete since we have much higher requirements for base ruins
            currentOptions.shouldKeepDefencesAndPower = true;

            ResolveParams rp = default(ResolveParams);

            BaseGen.globalSettings.map = map;
            rp.rect = new CellRect(0, 0, map.Size.x, map.Size.z);
            rp.SetCustom <ScatterOptions>(Constants.ScatterOptions, currentOptions);
            rp.faction = Find.FactionManager.OfAncientsHostile;
            BaseGen.symbolStack.Push("chargeBatteries", rp);
            BaseGen.symbolStack.Push("refuel", rp);
            BaseGen.symbolStack.Push("scatterRuins", rp);


            if (Rand.Chance(0.5f * Find.Storyteller.difficulty.threatScale))
            {
                float pointsCost = Math.Abs(Rand.Gaussian()) * 500 * Find.Storyteller.difficulty.threatScale;

                rp.faction        = Find.FactionManager.RandomEnemyFaction();
                rp.singlePawnLord = LordMaker.MakeNewLord(rp.faction,
                                                          new LordJob_AssaultColony(rp.faction, false, false, true, true), map, null);

                rp.pawnGroupKindDef = (rp.pawnGroupKindDef ?? PawnGroupKindDefOf.Settlement);

                if (rp.pawnGroupMakerParams == null)
                {
                    rp.pawnGroupMakerParams         = new PawnGroupMakerParms();
                    rp.pawnGroupMakerParams.tile    = map.Tile;
                    rp.pawnGroupMakerParams.faction = rp.faction;
                    PawnGroupMakerParms pawnGroupMakerParams = rp.pawnGroupMakerParams;
                    pawnGroupMakerParams.points = pointsCost;
                }

                BaseGen.symbolStack.Push("pawnGroup", rp);
            }


            BaseGen.Generate();
        }
Example #3
0
        public override void GenerateStartingParty(Map map, ResolveParams rp)
        {
            ScatterOptions currentOptions = rp.GetCustom <ScatterOptions>(Constants.ScatterOptions);
            float          uncoveredCost  = currentOptions.uncoveredCost;

            int points       = (int)(uncoveredCost / (10 * militaryPower));
            int initialGroup = 0;

            if (points > 10000)
            {
                initialGroup = Rand.Range(5000, 10000);
            }
            else
            {
                initialGroup = points;
            }
            Debug.Log(Debug.ForceGen, "Military gen: uncoveredCost {0}, military power: {1}, total points allowed: {2}", uncoveredCost, militaryPower, points);

            points -= initialGroup;
            SpawnGroup((int)ScalePointsToDifficulty(initialGroup), rp.rect, rp.faction, map);
            Debug.Log(Debug.ForceGen, "Initial group of {0} spawned, {1} points left for triggers", initialGroup, points);

            while (points > 0)
            {
                IntVec3 mapLocation = rp.rect.RandomCell;
                if (!mapLocation.InBounds(map))
                {
                    continue;
                }

                ThingDef    raidTriggerDef = ThingDef.Named("RaidTrigger");
                RaidTrigger trigger        = ThingMaker.MakeThing(raidTriggerDef) as RaidTrigger;

                trigger.faction = rp.faction;
                trigger.SetTimeouts(0, 300);

                int   raidMaxPoints = (int)(10000 / Math.Max(Math.Sqrt(d: militaryPower), 1.0));
                float raidValue     = Math.Abs(Rand.Gaussian()) * raidMaxPoints + Rand.Value * raidMaxPoints + 250.0f;
                if (raidValue > 10000)
                {
                    raidValue = Rand.Range(8000, 11000);                    //sanity cap. against some beta-poly bases.
                }
                points -= (int)raidValue;

                trigger.value = ScalePointsToDifficulty(points);

                GenSpawn.Spawn(trigger, mapLocation, map);
                Debug.Log(Debug.ForceGen, "Spawned trigger at {0}, {1} for {2} points, autofiring after {3} rare ticks", mapLocation.x, mapLocation.z, trigger.value, 0);
            }
        }
        public static void Process(Blueprint source, ScatterOptions options)
        {
            if (options.enableDeterioration)
            {
                DeteriorationProcessor dp = new DeteriorationProcessor();
                dp.options          = options;
                dp.blueprint        = source;
                dp.itemsIntegrity   = new float[source.width, source.height];
                dp.terrainIntegrity = new float[source.width, source.height];
                dp.ConstructRoomBasedIntegrityMap();

                //Debug.PrintNormalizedFloatMap(dp.terrainIntegrity);
                //Debug.PrintNormalizedFloatMap(dp.itemsIntegrity);

                dp.Deteriorate();
            }
        }
Example #5
0
        private void ResetSettings()
        {
            ScatterOptions defaultOptions = ScatterOptions.Default;

            RealRuins_ModSettings.defaultScatterOptions.claimableBlocks         = defaultOptions.claimableBlocks;
            RealRuins_ModSettings.defaultScatterOptions.decorationChance        = defaultOptions.decorationChance;
            RealRuins_ModSettings.defaultScatterOptions.deteriorationMultiplier = defaultOptions.deteriorationMultiplier;
            RealRuins_ModSettings.defaultScatterOptions.densityMultiplier       = defaultOptions.densityMultiplier;
            RealRuins_ModSettings.defaultScatterOptions.maxRadius                  = defaultOptions.maxRadius;
            RealRuins_ModSettings.defaultScatterOptions.minRadius                  = defaultOptions.minRadius;
            RealRuins_ModSettings.defaultScatterOptions.disableSpawnItems          = defaultOptions.disableSpawnItems;
            RealRuins_ModSettings.defaultScatterOptions.enableInstantCaravanReform = defaultOptions.enableInstantCaravanReform;
            RealRuins_ModSettings.defaultScatterOptions.enableProximity            = defaultOptions.enableProximity;
            RealRuins_ModSettings.defaultScatterOptions.hostileChance              = defaultOptions.hostileChance;
            RealRuins_ModSettings.defaultScatterOptions.itemCostLimit              = defaultOptions.itemCostLimit;
            RealRuins_ModSettings.defaultScatterOptions.scavengingMultiplier       = defaultOptions.scavengingMultiplier;
            RealRuins_ModSettings.defaultScatterOptions.trapChance                 = defaultOptions.trapChance;
            RealRuins_ModSettings.defaultScatterOptions.wallsDoorsOnly             = defaultOptions.wallsDoorsOnly;
        }
        public BlueprintTransferUtility(Blueprint blueprint, Map map, ResolveParams rp)
        {
            this.blueprint = blueprint;
            this.map       = map;
            this.rp        = rp;
            mapOriginX     = rp.rect.minX + rp.rect.Width / 2 - blueprint.width / 2;
            mapOriginZ     = rp.rect.minZ + rp.rect.Height / 2 - blueprint.height / 2;

            if (mapOriginX < 0)
            {
                mapOriginX = 0;
            }
            if (mapOriginZ < 0)
            {
                mapOriginZ = 0;
            }

            if (mapOriginX + blueprint.width >= map.Size.x)
            {
                mapOriginX = map.Size.x - blueprint.width - 1;
            }

            if (mapOriginZ + blueprint.height >= map.Size.z)
            {
                mapOriginZ = map.Size.z - blueprint.height - 1;
            }

            options = rp.GetCustom <ScatterOptions>(Constants.ScatterOptions);
            if (options.overridePosition != IntVec3.Zero)
            {
                if (!options.centerIfExceedsBounds || (options.overridePosition.x + blueprint.width < map.Size.x && options.overridePosition.z + blueprint.height < map.Size.z))
                {
                    mapOriginX = options.overridePosition.x;
                    mapOriginZ = options.overridePosition.z;
                }
                else
                {
                    Debug.Warning(Debug.BlueprintTransfer, "Tried to override position, but map exceeded bounds and position was reverted due to corresponding options flag.");
                    Debug.Warning(Debug.BlueprintTransfer, "New position: {0}, {1}", mapOriginX, mapOriginZ);
                }
            }
        }
Example #7
0
        public override void GenerateStartingParty(Map map, ResolveParams rp, ScatterOptions currentOptions)
        {
            float uncoveredCost = currentOptions.uncoveredCost;

            Faction faction = rp.faction;

            if (this.faction != null)
            {
                faction = this.faction;
            }
            if (faction == null)
            {
                faction = Find.FactionManager.RandomEnemyFaction(true, true, false);
            }

            Debug.Log(Debug.ForceGen, "Citizen force gen: uncoveredCost {0}. rect {1}", uncoveredCost, rp.rect);
            int maxPoints = Math.Min((int)(uncoveredCost / 10), 5000);

            SpawnGroup((int)ScalePointsToDifficulty(maxPoints), rp.rect, faction, map, Rand.Range(Math.Max(2, (int)(bedCount * 0.7)), (int)(bedCount * 1.5)));
            currentOptions.uncoveredCost -= maxPoints * 10;
        }
Example #8
0
        public ScatterOptions Copy()
        {
            ScatterOptions copy = new ScatterOptions {
                deteriorationMultiplier = deteriorationMultiplier,
                claimableBlocks         = claimableBlocks,
                decorationChance        = decorationChance,
                densityMultiplier       = densityMultiplier,
                hostileChance           = hostileChance,
                scavengingMultiplier    = scavengingMultiplier,
                trapChance                 = trapChance,
                disableSpawnItems          = disableSpawnItems,
                itemCostLimit              = itemCostLimit,
                minRadius                  = minRadius,
                maxRadius                  = maxRadius,
                wallsDoorsOnly             = wallsDoorsOnly,
                enableProximity            = enableProximity,
                minimumAreaRequired        = minimumAreaRequired,
                minimumDensityRequired     = minimumDensityRequired,
                minimumCostRequired        = minimumCostRequired,
                deleteLowQuality           = deleteLowQuality,
                shouldKeepDefencesAndPower = shouldKeepDefencesAndPower,
                shouldLoadPartOnly         = shouldLoadPartOnly,
                shouldAddRaidTriggers      = shouldAddRaidTriggers,
                uncoveredCost              = uncoveredCost,
                enableInstantCaravanReform = enableInstantCaravanReform,
                shouldAddFilth             = shouldAddFilth,
                roomMap               = roomMap,
                bottomLeft            = bottomLeft,
                blueprintRect         = blueprintRect,
                allowFriendlyRaids    = allowFriendlyRaids,
                enableDeterioration   = enableDeterioration,
                forceFullHitPoints    = forceFullHitPoints,
                canHaveFood           = canHaveFood,
                blueprintFileName     = blueprintFileName,
                centerIfExceedsBounds = centerIfExceedsBounds,
                overwritesEverything  = overwritesEverything
            };

            return(copy);
        }
Example #9
0
        public override void GenerateStartingParty(Map map, ResolveParams rp, ScatterOptions currentOptions)
        {
            float uncoveredCost = currentOptions.uncoveredCost;

            if (uncoveredCost > 0 || currentOptions.startingPartyPoints > 0)
            {
                float pointsCost = 0;
                if (currentOptions.startingPartyPoints > 0)
                {
                    pointsCost = currentOptions.startingPartyPoints;
                }
                else
                {
                    pointsCost = uncoveredCost / 10.0f;
                    FloatRange defaultPoints = new FloatRange(pointsCost * 0.7f,
                                                              Math.Min(12000.0f, pointsCost * 2.0f));
                    Debug.Log(Debug.ForceGen, "Adding starting party. Remaining points: {0}. Used points range: {1}",
                              currentOptions.uncoveredCost, defaultPoints);
                }
                pointsCost = ScalePointsToDifficulty(pointsCost);
                ScatterStartingParties((int)pointsCost, currentOptions.allowFriendlyRaids, map);
            }
        }
Example #10
0
        public override void GenerateForces(Map map, ResolveParams rp)
        {
            Debug.Log(Debug.ForceGen, "Generating mechanoid forces");

            ScatterOptions options = rp.GetCustom <ScatterOptions>(Constants.ScatterOptions);
            CellRect       rect    = rp.rect;

            /*if (rect.minX < 15 || rect.minZ < 15 || rect.maxX > map.Size.x - 15 || rect.maxZ > map.Size.z - 15) {
             *  return; //do not add enemies if we're on the map edge
             * }
             *
             * if (!CellFinder.TryFindRandomCellInsideWith(rect, (IntVec3 x) => x.Standable(map) && options.roomMap[x.x - rect.BottomLeft.x, x.z - rect.BottomLeft.z] > 1, out IntVec3 testCell)) {
             *  return; //interrupt if there are no closed cells available
             * }*/

            PawnKindDef pawnKindDef = null;

            if (powerMax == 0)
            {
                powerMax = rect.Area / 30.0f;
            }

            powerMax = ScalePointsToDifficulty(powerMax);

            float powerThreshold  = (Math.Abs(Rand.Gaussian(0.5f, 1)) * powerMax) + 1;
            float cumulativePower = 0;

            Faction faction = Faction.OfAncientsHostile;

            Lord lord = LordMaker.MakeNewLord(lordJob: new LordJob_DefendPoint(rect.CenterCell), faction: faction, map: map, startingPawns: null);
            int  tile = map.Tile;

            while (cumulativePower <= powerThreshold)
            {
                PawnKindDef currentPawnKindDef = (from kind in DefDatabase <PawnKindDef> .AllDefsListForReading
                                                  where kind.RaceProps.IsMechanoid
                                                  select kind).RandomElementByWeight((PawnKindDef kind) => 1f / kind.combatPower);

                PawnGenerationRequest request =
                    new PawnGenerationRequest(currentPawnKindDef, faction, PawnGenerationContext.NonPlayer, tile, true, false, false, //allowDead is last
                                              false, true, false, 1f,
                                              false, true, true, false,
                                              false, false, false,
                                              null, null, null, null,
                                              null, null, null, null);

                IntVec3 cell = IntVec3.Invalid;
//                if (!CellFinder.TryFindRandomCellInsideWith(rect, (IntVec3 x) => x.Standable(map) && options.roomMap[x.x - rect.minX, x.z - rect.minZ] > 1, out cell)) {
                CellFinder.TryFindRandomSpawnCellForPawnNear(rect.CenterCell, map, out cell);
//                }

                if (cell != IntVec3.Invalid)
                {
                    Pawn pawn = PawnGenerator.GeneratePawn(request);

                    FilthMaker.MakeFilth(cell, map, ThingDefOf.Filth_Blood, 5);
                    GenSpawn.Spawn(pawn, cell, map, WipeMode.Vanish);

                    lord.AddPawn(pawn);
                    cumulativePower += pawn.kindDef.combatPower;
                }
                else
                {
                    break; //no more suitable cells
                }
            }
        }
Example #11
0
        //ResolveParams's GetCustom/SetCustom is broken now, and it is a sealed (WHY??!) struct (WHY??!?!?) so I neither can fix it, nor make a dirty hack.
        //Seems like I have to abandon this approach and make direct calls.
        static public void Scatter(ResolveParams rp, ScatterOptions options, CoverageMap coverage, List <AbstractDefenderForcesGenerator> generators)
        {
            Debug.Log(Debug.Scatter, "Running stand-alone scatterer");
            if (options == null)
            {
                Debug.Warning(Debug.Scatter, "Scatter options are null, aborting");
                return;
            }

            DateTime start = DateTime.UtcNow;

            Debug.Log(Debug.Scatter, "[0 s]: Loading blueprint of size {0} - {1} to deploy at {2}, {3}", options.minRadius, options.maxRadius, rp.rect.minX, rp.rect.minZ);

            Blueprint bp  = null;
            Map       map = BaseGen.globalSettings.map;

            //probably should split scattering options into several distinct objects
            string filename = options.blueprintFileName;

            if (string.IsNullOrEmpty(filename) || !BlueprintLoader.CanLoadBlueprintAtPath(filename))
            {
                bp = BlueprintFinder.FindRandomBlueprintWithParameters(out filename, options.minimumAreaRequired, options.minimumDensityRequired, 15, removeNonQualified: options.deleteLowQuality);
                if (string.IsNullOrEmpty(filename))
                {
                    //still null = no suitable blueprints, fail.
                    Debug.Warning(Debug.Scatter, "Blueprint name was null and could not find another suitable blueprint, skipping");
                    return;
                }
            }

            if (!options.shouldLoadPartOnly) //should not cut => load whole
            {
                if (bp == null)              //if not loaded yet
                {
                    bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename);
                }
            }
            else
            {
                int radius = Rand.Range(options.minRadius, options.maxRadius);
                if (bp == null)
                {
                    bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename).RandomPartCenteredAtRoom(new IntVec3(radius, 0, radius));
                }
                else
                {
                    bp = bp.RandomPartCenteredAtRoom(new IntVec3(radius, 0, radius));
                }
            }

            if (bp == null)
            {
                Debug.Warning(Debug.Scatter, "Blueprint is still null after attempting to load any qualifying, returning");
                return;
            }


            Debug.Extra(Debug.Scatter, "Blueprint loaded, cutting and searching for rooms");
            bp.CutIfExceedsBounds(map.Size);

            // Here we have our blueprint loaded and ready to action. Doing stuff:
            BlueprintPreprocessor.ProcessBlueprint(bp, options); //Preprocess: remove missing and unnecessary items according to options
            bp.FindRooms();                                      //Traverse blueprint and construct rooms map
            options.roomMap = bp.wallMap;

            //Debug.PrintIntMap(bp.wallMap, delta: 1);
            Debug.Extra(Debug.Scatter, "Rooms traversed, initializing transfer utility");

            BlueprintTransferUtility btu = new BlueprintTransferUtility(bp, map, rp, options); //prepare blueprint transferrer

            Debug.Extra(Debug.Scatter, "Initialized, removing incompatible items...");

            btu?.RemoveIncompatibleItems(); //remove incompatible items
            Debug.Extra(Debug.Scatter, "Recalculating stats...");

            bp.UpdateBlueprintStats(true); //Update total cost, items count, etc

            Debug.Extra(Debug.Scatter, "Deteriorating...");
            DeteriorationProcessor.Process(bp, options); //create deterioration maps and do deterioration

            Debug.Extra(Debug.Scatter, "Scavenging...");
            ScavengingProcessor sp = new ScavengingProcessor();

            sp.RaidAndScavenge(bp, options); //scavenge remaining items according to scavenge options

            Debug.Extra(Debug.Scatter, "[{0} s] Prepared, about to start transferring.", DateTime.UtcNow.Subtract(start).TotalSeconds);
            try {
                btu.Transfer(coverage); //transfer blueprint
                Debug.Extra(Debug.Scatter, "[{0} s] Transferred.", DateTime.UtcNow.Subtract(start).TotalSeconds);
            } catch (Exception e) {
                Debug.Error(Debug.BlueprintTransfer, "Failed to transfer blueprint due to {0}", e);
            }

            if (generators != null)
            {
                foreach (AbstractDefenderForcesGenerator generator in generators)
                {
                    try {
                        generator.GenerateForces(map, rp, options);
                    } catch (Exception e) {
                        Debug.Error(Debug.BlueprintTransfer, "Failed to generate forces: {0}", e);
                    }
                }
            }
            Debug.Log(Debug.Scatter, "[{0} s] Generated forces.", DateTime.UtcNow.Subtract(start).TotalSeconds);

            if (options.shouldAddFilth)
            {
                try {
                    btu.AddFilthAndRubble(); //add filth and rubble
                } catch (Exception e) {
                    Debug.Warning(Debug.BlueprintTransfer, "Failed to add filth and rubble: {0}", e);
                }
            }
            Debug.Extra(Debug.Scatter, "[{0} s] Spiced up with rubble. Completed.", DateTime.UtcNow.Subtract(start).TotalSeconds);

            Debug.Log(Debug.Scatter, "Chunk scattering finished, moving");
        }
Example #12
0
        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);
                }
            }
        }
Example #13
0
        public static void ProcessBlueprint(Blueprint blueprint, ScatterOptions options)
        {
            if (blueprint == null)
            {
                return;
            }


            //Each item should be checked if it can be placed or not. This should help preventing situations when simulated scavenging removes things which anyway won't be placed.
            //For each placed item it's cost should be calculated
            for (int x = 0; x < blueprint.width; x++)
            {
                for (int z = 0; z < blueprint.height; z++)
                {
                    List <ItemTile> items      = blueprint.itemsMap[x, z];
                    TerrainTile     terrain    = blueprint.terrainMap[x, z];
                    TerrainDef      terrainDef = null;

                    if (terrain != null)
                    {
                        terrainDef = DefDatabase <TerrainDef> .GetNamed(terrain.defName, false);

                        if (terrainDef == null)
                        {
                            blueprint.terrainMap[x, z] = null; //remove unloadable terrain
                            terrain = null;
                        }
                    }



                    List <ItemTile> itemsToRemove = new List <ItemTile>();
                    if (items == null)
                    {
                        continue;
                    }

                    foreach (ItemTile item in items)
                    {
                        if (item.defName == "Corpse")
                        {
                            continue;                           //TODO: make some better way of handling corpses
                        }
                        //We can't move further with corpse item, because this item's thingDef is always null (actual corpse's def name depends on it's kind)

                        ThingDef thingDef = DefDatabase <ThingDef> .GetNamed(item.defName, false);

                        if (thingDef == null)
                        {
                            itemsToRemove.Add(item);
                            continue;
                        }

                        //remove items we don't want to see in the ruins
                        if (thingDef == ThingDefOf.Campfire || thingDef == ThingDefOf.TorchLamp)
                        {
                            itemsToRemove.Add(item);
                            continue;
                        }

                        if (options.wallsDoorsOnly)   //eleminate almost everything if "doors & walls" setting is active
                        {
                            if (!thingDef.IsDoor && !item.defName.ToLower().Contains("wall"))
                            {
                                itemsToRemove.Add(item);
                                continue;
                            }
                        }

                        if (options.disableSpawnItems)   //eleminate haulables if corresponding tick is set
                        {
                            if (thingDef.EverHaulable)
                            {
                                itemsToRemove.Add(item);
                                continue;
                            }
                        }

                        if (thingDef.defName.Contains("Animal") || thingDef.defName.Contains("Spot"))
                        {
                            itemsToRemove.Add(item);
                            continue; //remove animal sleeping beds and spots as wild animals tend to concentrate around. remove wedding, butchering and party spots, caravan spots as well
                        }


                        if (thingDef.IsCorpse || thingDef.Equals(ThingDefOf.MinifiedThing))   //check if corpses and minified things contain inner data, otherwise ignore
                        {
                            if ((item.innerItems?.Count() ?? 0) == 0 && item.itemXml == null)
                            {
                                itemsToRemove.Add(item);
                                continue;
                            }
                        }
                    }

                    foreach (ItemTile item in itemsToRemove)
                    {
                        if (item.isWall || item.isDoor)
                        {
                            blueprint.RemoveWall(item.location.x, item.location.z);
                        }

                        items.Remove(item);
                    }
                }
            }

            //Recalculate cost data after removing some items (should speed up, as cost calculation seems to be cpu-expensive process)
            blueprint.UpdateBlueprintStats(true);

            //Perform removing all items exceeding maximum cost
            for (int x = 0; x < blueprint.width; x++)
            {
                for (int z = 0; z < blueprint.height; z++)
                {
                    List <ItemTile> items   = blueprint.itemsMap[x, z];
                    TerrainTile     terrain = blueprint.terrainMap[x, z];

                    List <ItemTile> itemsToRemove = new List <ItemTile>();
                    if (terrain != null)
                    {
                        if (terrain.cost > options.itemCostLimit)
                        {
                            blueprint.terrainMap[x, z] = null;
                        }
                    }

                    if (items == null)
                    {
                        continue;
                    }
                    foreach (ItemTile item in items)
                    {
                        if (options.itemCostLimit > 0 && options.itemCostLimit < 1000) //filter too expensive items. limit of 1000 means "no limit" actually
                        {
                            if (item.cost > options.itemCostLimit)                     //removes only items where at least one item is more expensive than limit we have. limiting stacks is done later.
                            {
                                itemsToRemove.Add(item);
                            }
                        }
                    }

                    foreach (ItemTile item in itemsToRemove)
                    {
                        if (item.isWall || item.isDoor)
                        {
                            blueprint.RemoveWall(item.location.x, item.location.z);
                        }
                        items.Remove(item);
                    }
                }
            }
        }
Example #14
0
 public BlueprintAnalyzer(Blueprint blueprint, ScatterOptions options = null)
 {
     this.blueprint = blueprint;
     this.options   = options ?? ScatterOptions.asIs();
     itemStats      = new Dictionary <string, ItemStatRecord>();
 }
Example #15
0
        public override void GenerateForces(Map map, ResolveParams rp)
        {
            ScatterOptions options = rp.GetCustom <ScatterOptions>(Constants.ScatterOptions);

            if (options == null)
            {
                return;
            }

            int   addedTriggers = 0;
            float ratio         = 10;
            float remainingCost = options.uncoveredCost * (Rand.Value + 0.5f); //cost estimation as seen by other factions

            float initialCost = remainingCost;

            int triggersAbsoluteMaximum = 100;

            while (remainingCost > 0)
            {
                IntVec3 mapLocation = rp.rect.RandomCell;
                if (!mapLocation.InBounds(map))
                {
                    continue;
                }

                ThingDef    raidTriggerDef = ThingDef.Named("RaidTrigger");
                RaidTrigger trigger        = ThingMaker.MakeThing(raidTriggerDef) as RaidTrigger;

                if (options.allowFriendlyRaids)
                {
                    if (Rand.Chance(0.2f))
                    {
                        trigger.faction = Find.FactionManager.RandomNonHostileFaction();
                    }
                    else
                    {
                        trigger.faction = Find.FactionManager.RandomEnemyFaction();
                    }
                }
                else
                {
                    trigger.faction = Find.FactionManager.RandomEnemyFaction();
                }

                int   raidMaxPoints = (int)(remainingCost / ratio);
                float raidValue     = Math.Abs(Rand.Gaussian()) * raidMaxPoints + Rand.Value * raidMaxPoints + 250.0f;
                if (raidValue > 10000)
                {
                    raidValue = Rand.Range(8000, 11000);                    //sanity cap. against some beta-poly bases.
                }
                remainingCost -= raidValue * ratio;

                trigger.value = ScalePointsToDifficulty(raidValue);

                GenSpawn.Spawn(trigger, mapLocation, map);
                Debug.Log(Debug.ForceGen, "Spawned trigger at {0}, {1} for {2} points, autofiring after {3} rare ticks", mapLocation.x, mapLocation.z, trigger.value, 0);
                addedTriggers++;

                options.uncoveredCost = Math.Abs(remainingCost);

                if (addedTriggers > triggersAbsoluteMaximum)
                {
                    if (remainingCost < initialCost * 0.2f)
                    {
                        if (Rand.Chance(0.1f))
                        {
                            if (remainingCost > 100000)
                            {
                                remainingCost = Rand.Range(80000, 110000);
                            }
                            return;
                        }
                    }
                }
            }
        }
        public override void GenerateForces(Map map, ResolveParams rp, ScatterOptions options)
        {
            Debug.Log(Debug.ForceGen, "Animal forces generation");
            CellRect rect = rp.rect;

            /*if (rect.minX < 15 || rect.minZ < 15 || rect.maxX > map.Size.x - 15 || rect.maxZ > map.Size.z - 15) {
             *  return; //do not add enemies if we're on the map edge
             * }
             *
             * if (!CellFinder.TryFindRandomCellInsideWith(rect, (IntVec3 x) => x.Standable(map) && options.roomMap[x.x - rect.BottomLeft.x, x.z - rect.BottomLeft.z] > 1, out IntVec3 testCell)) {
             *  return; //interrupt if there are no closed cells available
             * }*/

            PawnKindDef pawnKindDef = null;


            pawnKindDef = map.Biome.AllWildAnimals.RandomElementByWeight((PawnKindDef def) => (def.RaceProps.foodType == FoodTypeFlags.CarnivoreAnimal || def.RaceProps.foodType == FoodTypeFlags.OmnivoreAnimal) ? 1 : 0);

            float powerMax = (float)Math.Sqrt(options.uncoveredCost / 10 * (rect.Area / 30.0f));

            Debug.Log(Debug.ForceGen, "Unscaled power is {0} based on cost of {1} and area of {2}", powerMax, options.uncoveredCost, rect.Area);
            powerMax = ScalePointsToDifficulty(powerMax);
            float powerThreshold = (Math.Abs(Rand.Gaussian(0.5f, 1)) * powerMax) + 1;

            float cumulativePower = 0;

            Faction faction = Faction.OfAncientsHostile;

            Lord lord = LordMaker.MakeNewLord(lordJob: new LordJob_DefendPoint(rect.CenterCell), faction: faction, map: map, startingPawns: null);
            int  tile = map.Tile;

            while (cumulativePower <= powerThreshold)
            {
                PawnKindDef           currentPawnKindDef = pawnKindDef;
                PawnGenerationRequest request            =
                    new PawnGenerationRequest(currentPawnKindDef, faction, PawnGenerationContext.NonPlayer, tile, true, false, false, //allowDead is last
                                              false, true, true, 1f,
                                              false, true, true, true,
                                              false, false, false,
                                              true, 0, null, 1, null, null, null,
                                              null, null, null, null);

                IntVec3 cell = IntVec3.Invalid;
                if (!CellFinder.TryFindRandomCellInsideWith(rect, (IntVec3 x) => x.Standable(map) && options.roomMap[x.x - rect.minX, x.z - rect.minZ] > 1, out cell))
                {
                    CellFinder.TryFindRandomSpawnCellForPawnNear(rect.CenterCell, map, out cell);
                }

                if (cell != IntVec3.Invalid)
                {
                    Pawn pawn = PawnGenerator.GeneratePawn(request);

                    FilthMaker.TryMakeFilth(cell, map, ThingDefOf.Filth_Blood, 5);
                    GenSpawn.Spawn(pawn, cell, map, WipeMode.Vanish);

                    lord.AddPawn(pawn);
                    cumulativePower += pawn.kindDef.combatPower;
                }
                else
                {
                    break; //no more suitable cells
                }
            }
        }
 public override void GenerateStartingParty(Map map, ResolveParams rp, ScatterOptions options)
 {
 }
        public abstract void GenerateForces(Map map, ResolveParams rp, ScatterOptions options); //called during map generation

        //There was some problem with pawns not created properly during basegen stack steps, but all working fine in genstep handler
        //Probably should investigate this later and combine all generation in one method
        public abstract void GenerateStartingParty(Map map, ResolveParams rp, ScatterOptions options);
Example #19
0
        public void RaidAndScavenge(Blueprint blueprint, ScatterOptions options)
        {
            //remove the most precious things. smash some other things.
            //word is spread, so each next raid is more destructive than the previous ones
            //to make calculations a bit easier we're going to calculate value per cell, not per item.

            this.options   = options;
            this.blueprint = blueprint;

            Debug.active = false;

            float scavengersActivity = Rand.Value * options.scavengingMultiplier + (options.scavengingMultiplier) / 3; //slight variation for scavengers activity for this particular blueprint
            float elapsedTime        = -blueprint.dateShift;

            int totalRemovedTiles    = 0;
            int totalRemovedTerrains = 0;
            int totalReplacedTiles   = 0;
            int processedTiles       = 0;
            int processedTerrains    = 0;

            for (int x = 0; x < blueprint.width; x++)
            {
                for (int z = 0; z < blueprint.height; z++)
                {
                    if (blueprint.terrainMap[x, z] != null)
                    {
                        tilesByCost.Add(blueprint.terrainMap[x, z]);
                        totalCost += blueprint.terrainMap[x, z].cost;
                        processedTerrains++;
                    }

                    foreach (ItemTile item in blueprint.itemsMap[x, z])
                    {
                        tilesByCost.Add(item);
                        totalCost += item.cost;
                        processedTiles++;
                    }
                }
            }

            tilesByCost.Sort(delegate(Tile t1, Tile t2) {
                return((t1.cost / t1.weight).CompareTo(t2.cost / t2.weight));
            });

            int ruinsArea = blueprint.width * blueprint.height;

            //Debug.Message("Scavenging blueprint of area {0}, age {1}, scavengers activity multiplier {2}", ruinsArea, elapsedTime, scavengersActivity);
            //Debug.Message("Enumerated {0} items", tilesByCost.Count());
            //Debug.PrintArray(tilesByCost.ToArray());

            int raidsCount = (int)(Math.Log(elapsedTime / 10 + 1) * scavengersActivity);

            if (raidsCount > 50)
            {
                raidsCount = 50;
            }
            if (options.scavengingMultiplier > 0.9f && raidsCount <= 0)
            {
                raidsCount = 1; //at least one raid for each ruins in case of normal scavenging activity
            }
            float baseRaidCapacity = ruinsArea / 10 * scavengersActivity;

            Debug.Log(Debug.BlueprintTransfer, "Performing {0} raids. Base capacity: {1}", raidsCount, baseRaidCapacity);

            for (int i = 0; i < raidsCount; i++)
            {
                float raidCapacity = baseRaidCapacity * (float)Math.Pow(1.1, i);
                bool  shouldStop   = false;
                Debug.Log(Debug.BlueprintTransfer, "Performing raid {0} of capacity {1}", i, raidCapacity);

                while (tilesByCost.Count > 0 && raidCapacity > 0 && !shouldStop)
                {
                    Tile   topTile = tilesByCost.Pop();
                    String msg     = string.Format("Inspecting tile \"{0}\" of cost {1} and weight {2}. ", topTile.defName, topTile.cost, topTile.weight);

                    if (topTile.cost / topTile.weight < 7)
                    {
                        shouldStop = true; //nothing to do here, everything valueable has already gone
                        msg       += "Too cheap, stopping.";
                    }
                    else
                    {
                        if (Rand.Chance(0.999f))   //there is still chance that even the most expensive thing will be left after raid. ("Big momma said ya shouldn't touch that golden chair, it's cursed")
                        {
                            raidCapacity -= topTile.weight;
                            if (topTile is TerrainTile)
                            {
                                blueprint.terrainMap[topTile.location.x, topTile.location.z] = null;
                                totalRemovedTerrains++;
                                totalCost -= topTile.cost;
                                msg       += "Terrain removed.";
                            }
                            else if (topTile is ItemTile)
                            {
                                ItemTile itemTile = topTile as ItemTile;
                                totalCost -= itemTile.cost;
                                blueprint.itemsMap[topTile.location.x, topTile.location.z].Remove(itemTile);
                                if (itemTile.isDoor)       //if door is removed it should be replaced with another door, raiders are very polite and always replace expensive doors with cheaper ones.
                                {
                                    if (Rand.Chance(0.8f)) //ok, not always.
                                    {
                                        ItemTile replacementTile = ItemTile.DefaultDoorItemTile(itemTile.location);
                                        blueprint.itemsMap[topTile.location.x, topTile.location.z].Add(replacementTile);
                                        msg += "Added " + replacementTile.defName + ", original ";
                                        totalReplacedTiles++;
                                    }
                                    else
                                    {
                                        totalRemovedTiles++;
                                        blueprint.RemoveWall(itemTile.location.x, itemTile.location.z);
                                    }
                                }
                                else if (itemTile.isWall)     //if something like a wall removed (vent or aircon) you usually want to cover the hole to keep wall integrity
                                {
                                    ItemTile replacementTile = ItemTile.WallReplacementItemTile(itemTile.location);
                                    blueprint.itemsMap[topTile.location.x, topTile.location.z].Add(replacementTile);
                                    msg += "Added " + replacementTile.defName + ", original ";
                                    totalReplacedTiles++;
                                }
                                else
                                {
                                    totalRemovedTiles++;
                                }
                                msg += "Tile removed.";
                            }
                        }
                    }
                    Debug.Log(Debug.BlueprintTransfer, msg);
                    if (shouldStop)
                    {
                        break;
                    }
                }
                if (shouldStop)
                {
                    break;
                }
            }

            //Check that there are no "hanging doors" left
            bool HasWallsIn(List <ItemTile> list)
            {
                foreach (ItemTile tile in list)
                {
                    if (tile.isWall)
                    {
                        return(true);
                    }
                }
                return(false);
            }

            for (int z = 1; z < blueprint.height - 1; z++)
            {
                for (int x = 1; x < blueprint.width - 1; x++)
                {
                    ItemTile tileToRemove = null;
                    foreach (ItemTile tile in blueprint.itemsMap[x, z])
                    {
                        if (tile.isDoor)   //check if a particular door tile has both two vertically adjacent walls (or similar) or two horizintally adjacent walls
                        {
                            if (!(HasWallsIn(blueprint.itemsMap[x - 1, z]) && HasWallsIn(blueprint.itemsMap[x + 1, z])) &&
                                !(HasWallsIn(blueprint.itemsMap[x, z - 1]) && HasWallsIn(blueprint.itemsMap[x, z + 1])))
                            {
                                tileToRemove = tile;
                                break;
                            }
                        }
                    }
                    if (tileToRemove != null)
                    {
                        blueprint.itemsMap[x, z].Remove(tileToRemove);
                        totalCost -= tileToRemove.cost;
                        blueprint.RemoveWall(x, z);
                    }
                }
            }
            Debug.active = true;
            //Debug.Message("Scavenging completed. Terrain removed: {0}/{1}, Tiles removed: {2}/{3}, tiles replaced: {4}.", totalRemovedTerrains, processedTerrains, totalRemovedTiles, processedTiles, totalReplacedTiles);

            if (options.costCap > 0)
            {
                LimitCostToCap();
            }
        }
 public abstract void GenerateForces(Map map, ResolveParams rp, ScatterOptions options); //called during map generation
Example #21
0
        public override void GenerateForces(Map map, ResolveParams rp, ScatterOptions options)
        {
            if (options == null)
            {
                return;
            }

            int   addedTriggers = 0;
            float ratio         = 10;
            float remainingCost = options.uncoveredCost * (Rand.Value + 0.5f); //cost estimation as seen by other factions

            Debug.Log(Debug.ForceGen, "Running citizen force generation with remaining cost of {0} (while uncovered is {1})", remainingCost, options.uncoveredCost);

            float initialCost = remainingCost;

            int triggersAbsoluteMaximum = 100;

            while (remainingCost > 0)
            {
                IntVec3 mapLocation = rp.rect.RandomCell;
                if (!mapLocation.InBounds(map))
                {
                    continue;
                }

                ThingDef    raidTriggerDef = ThingDef.Named("RaidTrigger");
                RaidTrigger trigger        = ThingMaker.MakeThing(raidTriggerDef) as RaidTrigger;

                trigger.faction = rp.faction;

                int   raidMaxPoints = (int)(remainingCost / ratio);
                float raidValue     = Math.Abs(Rand.Gaussian()) * raidMaxPoints + Rand.Value * raidMaxPoints + 250.0f;
                if (raidValue > 10000)
                {
                    raidValue = Rand.Range(8000, 11000);                    //sanity cap. against some beta-poly bases.
                }
                remainingCost -= raidValue * ratio;

                int timeout = (int)Math.Abs(Rand.Gaussian(0, 75));
                trigger.value = ScalePointsToDifficulty(raidValue);
                trigger.SetTimeouts(timeout, 200);

                GenSpawn.Spawn(trigger, mapLocation, map);
                Debug.Log(Debug.ForceGen, "Spawned trigger at {0}, {1} for {2} points, autofiring after {3} rare ticks", mapLocation.x, mapLocation.z, trigger.value, timeout);
                addedTriggers++;

                options.uncoveredCost = Math.Abs(remainingCost);

                if (addedTriggers > triggersAbsoluteMaximum)
                {
                    if (remainingCost < initialCost * 0.2f)
                    {
                        if (Rand.Chance(0.1f))
                        {
                            if (remainingCost > 100000)
                            {
                                remainingCost = Rand.Range(80000, 110000);
                            }
                            return;
                        }
                    }
                }
            }
        }
Example #22
0
        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);
                }
            }
        }
Example #23
0
        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();
                }
            }
        }
Example #24
0
        public override void Resolve(ResolveParams rp)
        {
            ScatterOptions options = rp.GetCustom <ScatterOptions>(Constants.ScatterOptions);

            if (options == null)
            {
                return;
            }

            //Debug.Message("Loading blueprint of size {0} - {1} to deploy at {2}, {3}", options.minRadius, options.maxRadius, rp.rect.minX, rp.rect.minZ);

            Blueprint bp  = null;
            Map       map = BaseGen.globalSettings.map;

            //probably should split scattering options into several distinct objects
            string filename = options.blueprintFileName;

            if (string.IsNullOrEmpty(filename))
            {
                bp = BlueprintFinder.FindRandomBlueprintWithParameters(out filename, options.minimumAreaRequired, options.minimumDensityRequired, 15, removeNonQualified: true);
                if (string.IsNullOrEmpty(filename))
                {
                    //still null = no suitable blueprints, fail.
                    return;
                }
            }

            if (!options.shouldLoadPartOnly) //should not cut => load whole
            {
                if (bp == null)              //if not loaded yet
                {
                    bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename);
                }
            }
            else
            {
                int radius = Rand.Range(options.minRadius, options.maxRadius);
                if (bp == null)
                {
                    bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename).RandomPartCenteredAtRoom(new IntVec3(radius, 0, radius));
                }
                else
                {
                    bp = bp.RandomPartCenteredAtRoom(new IntVec3(radius, 0, radius));
                }
            }

            if (bp == null)
            {
                Debug.Warning(Debug.Scatter, "Blueprint is still null after attempting to load any qualifying, returning");
                return;
            }
            bp.CutIfExceedsBounds(map.Size);

            // Here we have our blueprint loaded and ready to action. Doing stuff:
            BlueprintPreprocessor.ProcessBlueprint(bp, options); //Preprocess: remove missing and unnecessary items according to options
            bp.FindRooms();                                      //Traverse blueprint and construct rooms map
            options.roomMap = bp.wallMap;

            //Debug.PrintIntMap(bp.wallMap, delta: 1);

            BlueprintTransferUtility btu = new BlueprintTransferUtility(bp, map, rp); //prepare blueprint transferrer

            btu.RemoveIncompatibleItems();                                            //remove incompatible items
            bp.UpdateBlueprintStats(true);                                            //Update total cost, items count, etc

            DeteriorationProcessor.Process(bp, options);                              //create deterioration maps and do deterioration

            ScavengingProcessor sp = new ScavengingProcessor();

            sp.RaidAndScavenge(bp, options); //scavenge remaining items according to scavenge options

            btu.Transfer();                  //transfer blueprint

            List <AbstractDefenderForcesGenerator> generators = rp.GetCustom <List <AbstractDefenderForcesGenerator> >(Constants.ForcesGenerators);

            if (generators != null)
            {
                foreach (AbstractDefenderForcesGenerator generator in generators)
                {
                    generator.GenerateForces(map, rp);
                }
            }

            if (options.shouldAddFilth)
            {
                btu.AddFilthAndRubble(); //add filth and rubble
                                         //rp.GetCustom<CoverageMap>(Constants.CoverageMap).DebugPrint();
            }
        }