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); }
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; } } }
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); }
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) }); }
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); }
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); } } } } }
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)); }
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"))); }