예제 #1
0
        private void GeneratePawnGenOptions(IEnumerable <PawnKindDef> workList)
        {
            foreach (PawnKindDef def in workList)
            {
                //Log.Message(def.defaultFactionType.techLevel.ToString() + " == " + factionFc.techLevel.ToString() + " = " + (def.defaultFactionType.techLevel == factionFc.techLevel));
                //0 = combat, 1 = trader, 2 = settlement, 3 = peaceful
                PawnGenOption type = new PawnGenOption {
                    kind = def, selectionWeight = 1
                };
                faction.pawnGroupMakers[2].options.Add(type);
                if (def.label != "mercenary")
                {
                    faction.pawnGroupMakers[1].options.Add(type);
                    faction.pawnGroupMakers[3].options.Add(type);
                }

                if (def.isFighter)
                {
                    faction.pawnGroupMakers[1].guards.Add(type);
                    faction.pawnGroupMakers[0].options.Add(type);
                }

                if (def.trader)
                {
                    faction.pawnGroupMakers[1].traders.Add(type);
                }
            }
        }
        private static float HighestCost
        (
            PawnGroupMakerParms groupParms, PawnGenOption pawnGenOption, List <PawnGenOption> bestOptions, bool flag, float highestCost,
            List <PawnGenOption> candidates
        )
        {
            if (pawnGenOption.kind.isFighter)
            {
                // 16.08.2021 1.3 RW added required parameter to CanUsePawnGenOption for points
                // Using groupParms.points though unsure of effects
                if (groupParms.raidStrategy == null ||
                    groupParms.raidStrategy.Worker.CanUsePawnGenOption(groupParms.points, g: pawnGenOption, chosenGroups: bestOptions))
                {
                    if (!groupParms.dontUseSingleUseRocketLaunchers || !pawnGenOption.kind.weaponTags.Contains(item: "GunHeavy"))
                    {
                        if (MeleeConstraint(pawnGenOption: pawnGenOption))
                        {
                            if (!flag || !pawnGenOption.kind.factionLeader)
                            {
                                if (pawnGenOption.Cost > highestCost)
                                {
                                    highestCost = pawnGenOption.Cost;
                                }

                                candidates.Add(item: pawnGenOption);
                            }
                        }
                    }
                }
            }

            return(highestCost);
        }
예제 #3
0
 public override bool CanUsePawnGenOption(PawnGenOption opt, List <PawnGenOption> chosenOpts)
 {
     if (chosenOpts.Count == 0 && !opt.kind.canBeSapper)
     {
         return(false);
     }
     return(true);
 }
 public static bool MapAllowed(this PawnGroupMakerParms parms, PawnGenOption pawnOpt)
 {
     if (parms.tile >= 0 && MapExtensions.TileLookup.TryGetValue(parms.tile, out Map map))
     {
         return(map.PawnKindCanEnter(pawnOpt.kind));
     }
     return(true);
 }
 public static void Postfix(RaidStrategyWorker __instance, PawnGenOption g, List <PawnGenOption> chosenGroups, ref bool __result)
 {
     if (g.kind.factionLeader)
     {
         if (chosenGroups.Any(x => x.kind.factionLeader && x.kind == g.kind))
         {
             __result = false;
             //    Log.Warning(string.Format("Excess {0} detected:  there are {1} already in the raid, Disallowing", g.kind.LabelCap, chosenGroups.Where(x => x.kind == g.kind).Count()));
             return;
         }
     }
 }
예제 #6
0
 private static void AddPawn(this PawnGroupMaker pgm, PawnGenOption pgo, bool isTrader = false)
 {
     if (pgo.kind == null)
     {
         return;
     }
     ;
     if (isTrader)
     {
         pgm.guards.Add(pgo);
         return;
     }
     pgm.options.Add(pgo);
 }
        /* Validation Private Methods */



        private bool ValidateCarriers(PawnGroupMaker groupMaker)
        {
            PawnGenOption pawnGenOption = groupMaker.carriers.FirstOrDefault((PawnGenOption x) => !x.kind.RaceProps.packAnimal);

            if (pawnGenOption != null)
            {
                Log.Error(string.Concat(new object[]
                {
                    "Cannot generate arriving carnival for ",
                    "Carn_Faction_Roaming",
                    " because there is a pawn kind (",
                    pawnGenOption.kind.LabelCap,
                    ") who is not a carrier but is in a carriers list."
                }));
                return(false);
            }

            return(true);
        }
        private bool ValidateTradersList(PawnGroupMaker groupMaker)
        {
            // Returns false if there is an error in PawnGenOption XML (in Faction def)
            PawnGenOption pawnGenOption = groupMaker.traders.FirstOrDefault((PawnGenOption x) => !x.kind.trader);

            if (pawnGenOption != null)
            {
                Log.Error(string.Concat(new object[]
                {
                    "Cannot generate arriving carnival for ",
                    "Carn_Faction_Roaming",
                    " because there is a pawn kind (",
                    pawnGenOption.kind.LabelCap,
                    ") who is not a trader but is in a traders list."
                }));
                return(false);
            }

            return(true);
        }
예제 #9
0
        private static PawnGenOption MakePawnGenOption(PawnGenOption existing, string label)
        {
            string existingDefName = existing.kind.defName;

            PawnKindDef pkOld = PawnKindDef.Named(existingDefName);

            // if it is one of our defs then don't recreate it
            // if some alien race other than a Human then don't risk copying it
            if (existingDefName.Contains("StarWarsRaces") || pkOld.race != ThingDefOf.Human || pkOld.factionLeader)
            {
                return(null);
            }
            string defname = "StarWarsRaces_" + label + "_" + existingDefName;

            CreateNewPawnKind(pkOld, label, defname);
            return(new PawnGenOption
            {
                selectionWeight = existing.selectionWeight,
                kind = PawnKindDef.Named(defname)
            });
        }
예제 #10
0
 private static PawnGroupMaker AddPawnKindsToFactions(PawnGroupMaker pgm, string label)
 {
     // groups can be either an options or a guards for whatever reason, so check for both.
     PawnGenOption[] options = pgm.options.ToArray();
     for (int i = 0; i < options.Length; i++)
     {
         PawnGenOption pgo = MakePawnGenOption(options[i], label);
         if (pgo != null)
         {
             pgm.AddPawn(pgo, false);
         }
     }
     PawnGenOption[] guards = pgm.guards.ToArray();
     for (int j = 0; j < guards.Length; j++)
     {
         PawnGenOption pgo = MakePawnGenOption(guards[j], label);
         if (pgo != null)
         {
             pgm.AddPawn(pgo, true);
         }
     }
     return(pgm);
 }
예제 #11
0
        public new bool SetAllow(ThingDef thingDef, bool allow)
        {
            if (faction == null)
            {
                faction = DefDatabase <FactionDef> .GetNamed("PColony");
            }

            if (allow)
            {
                //0 = combat, 1 = trader, 2 = settlement, 3 = peaceful
                foreach (PawnKindDef def in DefDatabase <PawnKindDef> .AllDefsListForReading.Where(
                             def => def.race.race.intelligence == Intelligence.Humanlike && def.race.BaseMarketValue != 0 &&
                             def.race.label == thingDef.label))
                {
                    PawnGenOption type = new PawnGenOption {
                        kind = def, selectionWeight = 1
                    };
                    faction.pawnGroupMakers[2].options.Add(type);
                    if (def.label != "mercenary")
                    {
                        faction.pawnGroupMakers[1].options.Add(type);
                        faction.pawnGroupMakers[3].options.Add(type);
                    }

                    if (def.isFighter)
                    {
                        faction.pawnGroupMakers[1].guards.Add(type);
                        faction.pawnGroupMakers[0].options.Add(type);
                    }

                    if (def.trader)
                    {
                        faction.pawnGroupMakers[1].traders.Add(type);
                    }
                }
            }
            else
            {
                faction.pawnGroupMakers.ForEach(
                    groupMaker =>
                {
                    groupMaker.options.RemoveAll(
                        type => type.kind.race.label.Equals(thingDef.label));
                    groupMaker.traders.RemoveAll(
                        type => type.kind.race.label.Equals(thingDef.label));
                    groupMaker.guards.RemoveAll(
                        type => type.kind.race.label.Equals(thingDef.label));
                });

                if (!faction.pawnGroupMakers[1].traders.Any() || !faction.pawnGroupMakers[0].options.Any() ||
                    !faction.pawnGroupMakers[3].options.Any())
                {
                    SetAllow(thingDef, true);
                    return(false);
                }

                WorldSettlementTraderTracker.reloadTraderKind();
                if (WorldSettlementTraderTracker.BaseTraderKinds == null ||
                    !WorldSettlementTraderTracker.BaseTraderKinds.Any())
                {
                    SetAllow(thingDef, true);
                    return(false);
                }

                base.SetAllow(thingDef, false);
                foreach (MercenarySquadFC mercenarySquadFc in militaryUtil.mercenarySquads)
                {
                    List <Mercenary> newMercs = new List <Mercenary>();
                    foreach (Mercenary mercenary in mercenarySquadFc.mercenaries)
                    {
                        if (!Allows(mercenary.pawn.kindDef.race))
                        {
                            Mercenary merc = mercenary;
                            mercenarySquadFc.createNewPawn(ref merc,
                                                           faction.pawnGroupMakers[0].options.RandomElement().kind);
                            newMercs.Add(merc);
                        }
                        else
                        {
                            newMercs.Add(mercenary);
                        }
                    }

                    mercenarySquadFc.mercenaries = newMercs;
                }

                return(true);
            }

            base.SetAllow(thingDef, allow);
            return(true);
        }
        public void InjectPawnKindDefsToFactions(List <FactionDef> FB_Factions)
        {
            Base FB = Base.Instance;

            // Clear out old settings, if any
            foreach (FactionDef FBfac in FB_Factions)
            {
                foreach (PawnGroupMaker maker in FBfac.pawnGroupMakers)
                {
                    foreach (var optList in new List <PawnGenOption>[] { maker.options, maker.traders, maker.carriers, maker.guards })
                    {
                        optList.RemoveAll(x => true);
                    }
                }
            }

            // Loop through each PawnKindDef
            foreach (PawnKindDef pawn in DefDatabase <PawnKindDef> .AllDefs.Where(pawn => FB.FilterPawnKindDef(pawn, "global")))
            {
                RaceProperties race = pawn.RaceProps;

                // Define weapon-like traits
                bool isRanged = race.ToolUser && pawn.weaponTags != null && pawn.weaponTags.Any(t =>
                                                                                                !(t.Contains("Melee") || t == "None") &&
                                                                                                Regex.IsMatch(t, "Gun|Ranged|Pistol|Rifle|Sniper|Carbine|Revolver|Bowman|Grenade|Artillery|Assault|MageAttack|DefensePylon|GlitterTech|^OC|Federator|Ogrenaut|Hellmaker")
                                                                                                );
                // Animals can shoot projectiles, too
                if (race.Animal && pawn.race.Verbs != null && pawn.race.Verbs.Any(v =>
                                                                                  v.burstShotCount >= 1 && v.range >= 10 && v.commonality >= 0.7 && v.defaultProjectile != null
                                                                                  ))
                {
                    isRanged = true;
                }

                bool isSniper = false;
                if (isRanged)
                {
                    // Using All here to be more strict about sniper weapon usage
                    isSniper = race.ToolUser && pawn.weaponTags != null && pawn.weaponTags.All(t =>
                                                                                               !(t.Contains("Melee") || t == "None") &&
                                                                                               Regex.IsMatch(t, "Sniper|Ranged(Strong|Mighty|Heavy|Chief)|ElderThingGun")
                                                                                               );
                    if (race.Animal && pawn.race.Verbs != null && pawn.race.Verbs.Any(v =>
                                                                                      v.burstShotCount >= 1 && v.range >= 40 && v.commonality >= 0.7 && v.defaultProjectile != null
                                                                                      ))
                    {
                        isSniper = true;
                    }
                }

                bool isHeavyWeapons = race.ToolUser && pawn.weaponTags != null && pawn.weaponTags.Any(t =>
                                                                                                      Regex.IsMatch(t, "Grenade|Flame|Demolition|GunHeavy|Turret|Pylon|Artillery|GlitterTech|OC(Heavy|Tank)|Bomb|Sentinel|FedHeavy")
                                                                                                      );
                // Include animals with BFGs and death explodey types
                if (race.Animal)
                {
                    if (isRanged && pawn.combatPower >= 500)
                    {
                        isHeavyWeapons = true;
                    }
                    if (
                        race.deathActionWorkerClass != null &&
                        Regex.IsMatch(race.deathActionWorkerClass.Name, "E?xplosion|Bomb")
                        )
                    {
                        isHeavyWeapons = true;
                    }
                }

                /*
                 * DEBUG
                 *
                 * string msg = pawn.defName;
                 * msg += " --> ";
                 * if (isRanged)        msg += "Ranged, ";
                 * if (!isRanged)       msg += "Melee, ";
                 * if (isSniper)        msg += "Sniper, ";
                 * if (isHeavyWeapons)  msg += "Heavy Weapons, ";
                 *
                 * if (pawn.defName.StartsWith(...)|| pawn.defName.Contains(...)) FB.ModLogger.Message(msg);
                 */

                foreach (FactionDef FBfac in FB_Factions)
                {
                    foreach (PawnGroupMaker maker in FBfac.pawnGroupMakers)
                    {
                        bool isPirate = FBfac.defName == "FactionBlender_Pirate";
                        bool isCombat = isPirate || (maker.kindDef.defName == "Combat");
                        bool isTrader = maker.kindDef.defName == "Trader";

                        // Allow "combat ready" animals
                        int origCP         = (int)((SettingHandle <float>)FB.config["FilterWeakerAnimalsRaids"]).Value;
                        int minCombatPower =
                            isPirate ? origCP :                                     // 100%
                            isCombat ? (int)System.Math.Round(origCP / 3f * 2f) :   // 66%
                            (int)System.Math.Round(origCP / 3f)                     // 33%
                        ;

                        // Create the pawn option
                        var newOpt = new PawnGenOption();
                        newOpt.kind            = pawn;
                        newOpt.selectionWeight =
                            race.Animal ? 1 :
                            race.Humanlike ? 10 : 2
                        ;

                        if (isCombat)
                        {
                            if (!FB.FilterPawnKindDef(pawn, "combat", minCombatPower))
                            {
                                continue;
                            }

                            // XXX: Unfortunately, there are no names for these pawnGroupMakers, so we have to use commonality
                            // to identify each type.

                            // Additional filters for specialized categories
                            bool addIt = true;
                            if (maker.commonality == 65)
                            {
                                addIt = isRanged;
                            }
                            else if (maker.commonality == 60)
                            {
                                addIt = !isRanged;
                            }
                            else if (maker.commonality == 40)
                            {
                                addIt = isSniper;
                            }
                            else if (maker.commonality == 25)
                            {
                                addIt = isHeavyWeapons;
                            }
                            else if (maker.commonality == 10)
                            {
                                newOpt.selectionWeight = race.Humanlike ? 1 : 10;
                            }

                            // Add it
                            if (addIt)
                            {
                                maker.options.Add(newOpt);
                            }
                        }
                        else if (isTrader)
                        {
                            if (!FB.FilterPawnKindDef(pawn, "trade"))
                            {
                                continue;
                            }

                            // Trader group makers split up their pawns into three buckets.  The pawn will go into one of those
                            // three, or none of them.
                            if (pawn.trader)
                            {
                                maker.traders.Add(newOpt);
                            }
                            else if (race.packAnimal)
                            {
                                maker.carriers.Add(newOpt);
                            }
                            else if (FB.FilterPawnKindDef(pawn, "combat", minCombatPower))
                            {
                                maker.guards.Add(newOpt);
                            }
                        }
                        else
                        {
                            // Peaceful or Settlement: Accept almost anybody
                            maker.options.Add(newOpt);
                        }
                    }
                }
            }
        }
예제 #13
0
        public static int SpawnSinglePawn(this CorpseProduct CP, Pawn ParentPawn, IntVec3 SpawnPos, Map map, bool MyDebug = false)
        {
            string DebugStr = MyDebug ? "SpawnSinglePawn " : null;

            PawnGenOption PGO = CP.pawnKind.RandomElementByWeight(p => p.selectionWeight);

            if (PGO == null)
            {
                if (MyDebug)
                {
                    Log.Warning(DebugStr + " No PawnGenOption found");
                }
                return(0);
            }

            PawnKindDef PKD           = PGO.kind;
            Faction     RandomFaction = CP.HasWeightedFaction ? CP.forcedFaction?.GetFaction(ParentPawn) : null;

            if (PKD == null)
            {
                if (MyDebug)
                {
                    Log.Warning(DebugStr + " No PKD found");
                }
                return(0);
            }
            if (MyDebug)
            {
                Log.Warning(DebugStr + "PKD:" + PKD.label + " faction:" + RandomFaction);
            }

            bool wantNewBorn = Rand.Chance(CP.newBornChance);

            float combatPowerMultiplier = wantNewBorn ? CP.newBornCombatPowerRatio : 1;

            PawnGenerationRequest request =
                new PawnGenerationRequest(
                    kind: PKD, faction: RandomFaction, context: PawnGenerationContext.NonPlayer, tile: -1, forceGenerateNewPawn: false,
                    newborn: wantNewBorn, colonistRelationChanceFactor: 0, allowAddictions: false, allowFood: false, relationWithExtraPawnChanceFactor: 0
                    );
            Pawn NewPawn = PawnGenerator.GeneratePawn(request);

            GenSpawn.Spawn(NewPawn, SpawnPos, map, WipeMode.Vanish);

            if (CP.HasRelevantManhunterChance && Rand.Chance(CP.manhunterChance))
            {
                NewPawn.MakeManhunter(MyDebug);
            }

            if (CP.inheritSettingsFromParent && NewPawn.InheritParentSettings(ParentPawn, RandomFaction) && MyDebug)
            {
                Log.Warning(DebugStr + "applied parent settings");
            }

            if (CP.setRelationsWithParent && NewPawn.AddParentRelations(ParentPawn) && MyDebug)
            {
                Log.Warning(DebugStr + "added relations");
            }

            return((int)(combatPowerMultiplier * NewPawn.kindDef.combatPower));
        }
예제 #14
0
 public virtual bool CanUsePawnGenOption(PawnGenOption g, List <PawnGenOption> chosenGroups)
 {
     return(true);
 }
        public static IEnumerable <PawnGenOption> ChoosePawnGenByConstraint
            (float pointsTotal, List <PawnGenOption> options, PawnGroupMakerParms groupParms)
        {
            if (groupParms.seed != null)
            {
                Rand.PushState(replacementSeed: groupParms.seed.Value);
            }

            float maxPawnCost = MaxPawnCostMultiplier
                                * PawnGroupMakerUtility.MaxPawnCost(
                faction: groupParms.faction,
                totalPoints: pointsTotal,
                raidStrategy: groupParms.raidStrategy,
                groupKind: groupParms.groupKind
                );

            var   candidates  = new List <PawnGenOption>();
            var   bestOptions = new List <PawnGenOption>();
            float remTotal    = pointsTotal * PointMultiplier;
            var   foundLeader = false;
            float highestCost = -1f;

            for (; ;)
            {
                candidates.Clear();

                for (var i = 0; i < options.Count; i++)
                {
                    PawnGenOption pawnGenOption = options[index : i];

                    if (pawnGenOption.Cost <= remTotal)
                    {
                        if (pawnGenOption.Cost <= maxPawnCost)
                        {
                            highestCost = HighestCost(
                                groupParms: groupParms,
                                pawnGenOption: pawnGenOption,
                                bestOptions: bestOptions,
                                flag: foundLeader,
                                highestCost: highestCost,
                                candidates: candidates
                                );
                        }
                    }
                }

                if (candidates.Count == 0)
                {
                    break;
                }

                Func <PawnGenOption, float> weightSelector = delegate(PawnGenOption gr)
                {
                    float selectionWeight = gr.selectionWeight;

                    return(selectionWeight * WeightingPreferPawnsCloseToHighestCost.Evaluate(x: gr.Cost / highestCost));
                };

                PawnGenOption pawnGenOption2 = candidates.RandomElementByWeight(weightSelector: weightSelector);
                bestOptions.Add(item: pawnGenOption2);
                remTotal -= pawnGenOption2.Cost;

                if (pawnGenOption2.kind.factionLeader)
                {
                    foundLeader = true;
                }
            }

            if (bestOptions.Count == 1 && remTotal > pointsTotal / 2f)
            {
                Log.Warning(
                    text: string.Concat("Used only ", pointsTotal - remTotal, " / ", pointsTotal, " points generating for ", groupParms.faction)
                    );
            }

            if (groupParms.seed != null)
            {
                Rand.PopState();
            }

            return(bestOptions);
        }
 private static bool MeleeConstraint(PawnGenOption pawnGenOption)
 {
     return(pawnGenOption.kind.weaponTags.Count > 0 &&
            pawnGenOption.kind.weaponTags.Any(predicate: str => str.Contains(value: "Melee") || str.Contains(value: "melee")));
 }