private void GenerateCarriers(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, List <Thing> wares, Caravan caravan) { List <Thing> list = wares.Where((Thing x) => !(x is Pawn)).ToList(); int i = 0; int num = Mathf.CeilToInt((float)list.Count / 8f); PawnKindDef kind = groupMaker.carriers.Where((PawnGenOption x) => parms.tile == -1 || Find.WorldGrid[parms.tile].biome.IsPackAnimalAllowed(x.kind.race)).RandomElementByWeight((PawnGenOption x) => x.selectionWeight).kind; List <Pawn> list2 = new List <Pawn>(); PawnGenerationRequest request = default(PawnGenerationRequest); for (int j = 0; j < num; j++) { PawnKindDef kind2 = kind; Faction faction = parms.faction; int tile = parms.tile; request = new PawnGenerationRequest(kind2, faction, PawnGenerationContext.NonPlayer, tile, forceGenerateNewPawn: false, newborn: false, allowDead: false, allowDowned: false, canGeneratePawnRelations: true, mustBeCapableOfViolence: false, 1f, forceAddFreeWarmLayerIfNeeded: false, allowGay: true, allowFood: true, parms.inhabitants); Pawn pawn = PawnGenerator.GeneratePawn(request); if (i < list.Count) { pawn.inventory.innerContainer.TryAdd(list[i]); i++; } list2.Add(pawn); Find.WorldPawns.PassToWorld(pawn); caravan.AddPawn(pawn, false); } for (; i < list.Count; i++) { list2.RandomElement().inventory.innerContainer.TryAdd(list[i]); } }
public static List <Pawn> GeneratePawns(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, bool errorOnZeroResults = true) { var list = new List <Pawn>(); PawnGroupKindWorker.pawnsBeingGeneratedNow.Add(item: list); try { GeneratePawns(parms: parms, groupMaker: groupMaker, outPawns: list, errorOnZeroResults: errorOnZeroResults); } catch (Exception arg) { Log.Error(text: "Exception while generating pawn group: " + arg); for (var i = 0; i < list.Count; i++) { list[index : i].Destroy(mode : DestroyMode.Vanish); } list.Clear(); } finally { PawnGroupKindWorker.pawnsBeingGeneratedNow.Remove(item: list); } return(list); }
public override float MinPointsToGenerateAnything(PawnGroupMaker groupMaker) { // NOTE: Just figured out that this would never be used for the // Carnival GroupKind. Leaving it here in case I can use it elsewhere. return(_DefOf.CarnyTrader.combatPower); }
public static void TryGetRandomPawnGroupMaker(PawnGroupMakerParms parms, out PawnGroupMaker pawnGroupMaker) { if (parms.faction.def.pawnGroupMakers.NullOrEmpty()) { Log.Error( text: string.Concat("Faction ", parms.faction, " of def ", parms.faction.def, " has no any PawnGroupMakers.") ); } if (parms.seed != null) { Rand.PushState(replacementSeed: parms.seed.Value); } IEnumerable <PawnGroupMaker> source = from gm in parms.faction.def.pawnGroupMakers where gm.kindDef == parms.groupKind && gm.CanGenerateFrom(parms: parms) select gm; bool result = source.TryRandomElementByWeight(weightSelector: gm => gm.commonality, result: out pawnGroupMaker); if (!source.Any()) { Log.Message($"Found no pawn groups fit for purpose"); } if (parms.seed != null) { Rand.PopState(); } }
//PawnGroupKindWorker_Trader public static void AddQuestGiverTwo(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, Pawn trader, List <Thing> wares, List <Pawn> outPawns) { LongEventHandler.QueueLongEvent(() => { var pawn = outPawns.FirstOrDefault(x => x.Spawned); Map map = pawn?.MapHeld; if (map != null) { List <Pawn> newPawnList = map.mapPawns.AllPawnsSpawned.FindAll(x => x.Faction == pawn.Faction && !x.IsPrisoner); var newQuestPawn = RimQuestUtility.GetNewQuestGiver(outPawns); if (newQuestPawn?.Faction == null) { return; } var questPawns = Find.World.GetComponent <RimQuestTracker>().questPawns; if (!questPawns.Any(x => x.pawn == newQuestPawn)) { var questPawn = new QuestPawn(newQuestPawn); if (questPawn != null) { questPawns.Add(questPawn); } } } }, "RQ_LoadingScreen".Translate(), true, null); }
public static void Prefix(PawnGroupMakerParms parms, ref PawnGroupMaker pawnGroupMaker) { Faction faction = parms.faction; HiveFactionEvolutionTracker evolutionTracker = Find.World.GetComponent <HiveFactionEvolutionTracker>(); if (faction != null) { HiveFactionExtension hive = faction.def.GetModExtension <HiveFactionExtension>(); if (evolutionTracker != null && hive != null) { if (evolutionTracker.HiveFactionStages.TryGetValue(faction.ToString(), out int stage)) { if (parms.seed != null) { Rand.PushState(parms.seed.Value); } if (!hive.CurStage.pawnGroupMakers.NullOrEmpty()) { string li = string.Empty; // Log.Message("TryGetRandomPawnGroupMaker HiveFaction using pawnGroupMaker from Stage: " + stage); } bool result = (from gm in hive.CurStage.pawnGroupMakers ?? parms.faction.def.pawnGroupMakers where gm.kindDef == parms.groupKind && gm.CanGenerateFrom(parms) select gm).TryRandomElementByWeight((PawnGroupMaker gm) => gm.commonality, out pawnGroupMaker); if (parms.seed != null) { Rand.PopState(); } // Log.Message("TryGetRandomPawnGroupMaker HiveFaction Stage: " + stage + " pawnGroupMaker: " + pawnGroupMaker.kindDef); } } } }
public override bool CanGenerateFrom(PawnGroupMakerParms parms, PawnGroupMaker groupMaker) { return(groupMaker.kindDef == _DefOf.Carnival && parms.faction.IsCarnival() && MinPointsToGenerateAnything(groupMaker) < parms.points && (parms.tile == -1 || groupMaker.carriers.Any((PawnGenOption x) => Find.WorldGrid[parms.tile].biome.IsPackAnimalAllowed(x.kind.race)))); }
public static void MinPointsTest(PawnGroupKindWorker_Normal __instance, PawnGroupMaker groupMaker) { // if (groupMaker?.options?.Count == null || // groupMaker.options.Count <= 0) // { // Log.Message("No options available."); // } // foreach (var x in groupMaker.options) // { // Log.Message(x.kind.defName + " " + x.kind.isFighter.ToString() + " " + x.Cost); // } }
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); }
/* Private Methods */ private Pawn GenerateVendor(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, TraderKindDef traderKind, bool subtractPoints) { if (subtractPoints) { if (parms.points < _DefOf.CarnyTrader.combatPower * 2) { return(null); } else { parms.points -= _DefOf.CarnyTrader.combatPower * 2; } } // Generate new vendor PawnGenerationRequest request = new PawnGenerationRequest( _DefOf.CarnyTrader, parms.faction, PawnGenerationContext.NonPlayer, parms.tile, false, false, false, false, true, false, 1f, true, // Force free warm layers if needed true, true, parms.inhabitants, false, null, // Consider adding predicate for backstory here null, null, null, null, null ); var vendor = PawnGenerator.GeneratePawn(request); vendor.mindState.wantsToTradeWithColony = true; PawnComponentsUtility.AddAndRemoveDynamicComponents(vendor, true); vendor.trader.traderKind = traderKind; return(vendor); }
private bool TryGetRandomPawnGroupMaker(PawnGroupMakerParms parms, out PawnGroupMaker pawnGroupMaker) { if (parms.seed.HasValue) { Rand.PushState(parms.seed.Value); } IEnumerable <PawnGroupMaker> source = parms.faction.def.pawnGroupMakers.Where((PawnGroupMaker gm) => gm.kindDef == parms.groupKind && gm.CanGenerateFrom(parms)); bool result = source.TryRandomElementByWeight((PawnGroupMaker gm) => gm.commonality, out pawnGroupMaker); if (parms.seed.HasValue) { Rand.PopState(); } return(result); }
private static void Postfix(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, Pawn trader, List <Thing> wares, ref List <Pawn> outPawns) { Log.Message("Postfix 3"); if (Rand.Chance(0.8f) && outPawns.Count > 0) { var candidates = outPawns.Where(x => x.def.race.Humanlike && x.AllComps.Where(y => y is CompQuestGiver).Count() == 0); if (candidates.Count() > 0) { Pawn pawn = candidates.RandomElement(); var questComp = Current.Game.GetComponent <QuestTracker>(); questComp.CreateQuestGiver(pawn); } } }
/* 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 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 override void PostWorldGenerate() { if (AMAMod.settings.ForceRelations) { int i = 0; Faction faction = null; FactionDef factionDef = null; ThingDef factionRace = null; Faction player = Faction.OfPlayer; FactionDef playerDef = player.def; ThingDef playerRace = playerDef.basicMemberKind.race; // Log.Message(string.Format("PWG Player: {0}\nDef: {1}\nRace: {2}", player, playerDef, playerRace)); base.PostWorldGenerate(); foreach (var f in Find.FactionManager.AllFactionsListForReading.FindAll(x => !x.IsPlayer && !x.def.permanentEnemy)) { faction = null; factionDef = null; factionRace = null; faction = f; factionDef = faction.def; factionRace = factionDef.basicMemberKind?.race; if (factionDef.basicMemberKind == null) { // Log.Message(string.Format("basicMemberKind: Missing, checking PGM for {0} def: {1}", f, factionDef)); if (!factionDef.pawnGroupMakers.NullOrEmpty()) { // Log.Message(string.Format("PGM: Found, checking options for {0} def: {1}", f, factionDef)); PawnGroupMaker maker = factionDef.pawnGroupMakers.RandomElement(); if (!maker.options.NullOrEmpty()) { // Log.Message(string.Format("options: Found, checking for {0} def: {1}", f, factionDef)); PawnGenOption genOption = maker.options.RandomElement(); if (genOption != null) { factionRace = genOption.kind.race; // Log.Message(string.Format("Race: {2}, checking for {0} def: {1}", f, factionDef, factionRace)); } else { // Log.Message(string.Format("Race: Not Found for {0} def: {1}", f, factionDef)); } } else { // Log.Message(string.Format("options: Not Found for {0} def: {1}", f, factionDef)); } } else { // Log.Message(string.Format("PGM: Missing for {0}", factionDef)); } } if (factionRace != null) { // Log.Message(string.Format("Race: {0}", factionRace)); if (factionRace != playerRace) { if ((factionDef.defName.Contains("OG_Mechanicus_") || factionDef.defName.Contains("OG_Militarum_") || factionDef.defName.Contains("OG_Astartes_") || factionDef.defName.Contains("OG_Sororitas_")) && (playerRace.defName.Contains("Human") || (playerRace.defName.Contains("OG_Mechanicus_") || playerRace.defName.Contains("OG_Militarum_") || playerRace.defName.Contains("OG_Astartes_") || playerRace.defName.Contains("OG_Sororitas_"))) && !playerRace.defName.Contains("OG_Chaos")) { // Log.Message(string.Format("Imperial Faction {0}: {1} should be friendly to {2}", f, factionDef, player)); if (f.GoodwillWith(player) < 0) { player.TrySetRelationKind(f, FactionRelationKind.Ally, false); } } else if ((factionDef.defName.Contains("OG_Eldar_") && (playerRace.defName.Contains("Alien_Eldar") || playerRace.defName.Contains("OG_Eldar_")))) { // Log.Message(string.Format("Eldar faction{0}: {1} should be friendly to {2}: {3}", f, factionDef, player, playerDef)); if (f.GoodwillWith(player) < 0) { player.TrySetRelationKind(f, FactionRelationKind.Ally, false); } } else if ((factionDef.defName.Contains("OG_Ork_")) && (playerRace.defName.Contains("Alien_Ork") || playerRace.defName.Contains("Alien_Grot") || playerRace.defName.Contains("OG_Ork_") || playerRace.defName.Contains("OG_Grot_"))) { // Log.Message(string.Format("Ork faction {0}: {1} should be friendly to {2}: {3}", f, f.def, player, playerDef)); if (f.GoodwillWith(player) < 0) { player.TrySetRelationKind(f, FactionRelationKind.Neutral, false); } } else if ((factionDef.defName.Contains("OG_Tau_") || factionDef.defName.Contains("OG_Kroot_") || factionDef.defName.Contains("OG_Vespid_")) && (playerRace.defName.Contains("Alien_Tau") || playerRace.defName.Contains("Alien_Kroot") || playerRace.defName.Contains("OG_Tau_") || playerRace.defName.Contains("OG_Kroot_"))) { // Log.Message(string.Format("Tau faction {0}: {1} should be friendly to {2}: {3}", f, factionDef, player, playerDef)); if (f.GoodwillWith(player) < 0) { player.TrySetRelationKind(f, FactionRelationKind.Ally, false); } } else if ((factionDef.defName.Contains("OG_Chaos_")) && (playerRace.defName.Contains("OG_Chaos"))) { // Log.Message(string.Format("Chaos faction {0}: {1} should be friendly to {2}: {3}", f, factionDef, player, playerDef)); if (f.GoodwillWith(player) < 0) { player.TrySetRelationKind(f, FactionRelationKind.Neutral, false); } } else { // Log.Message(string.Format("{0}: {1} should be hostile to {2}: {3}", f, factionDef, player, playerDef)); player.TrySetRelationKind(f, FactionRelationKind.Hostile, false); } } } } } }
static bool Prefix(ref PawnGroupKindWorker_Trader __instance, ref Pawn __result, PawnGroupMakerParms parms, PawnGroupMaker groupMaker, TraderKindDef traderKind) { if (parms.faction == FactionColonies.getPlayerColonyFaction()) { List <PawnKindDef> list = new List <PawnKindDef>(); foreach (ThingDef def in Find.World.GetComponent <FactionFC>().raceFilter.AllowedThingDefs) { list.Add(def.race.AnyPawnKind); } Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(list.RandomElement(), parms.faction, PawnGenerationContext.NonPlayer, parms.tile, false, false, false, false, true, false, 1f, false, true, true, true, parms.inhabitants, false, false, false, 0f, null, 1f, null, null, null, null, null, null, null, null, null, null, null, null)); pawn.mindState.wantsToTradeWithColony = true; PawnComponentsUtility.AddAndRemoveDynamicComponents(pawn, true); pawn.trader.traderKind = traderKind; parms.points -= pawn.kindDef.combatPower; __result = pawn; return(false); } else { return(true); } }
private static bool <PawnGroupGenSampled> m__2(PawnGroupMaker x) { return(x.kindDef == PawnGroupKindDefOf.Combat); }
private static bool Prefix(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, Pawn trader, List <Thing> wares, List <Pawn> outPawns) { Func <Thing, float> massTotaler = t => t.stackCount * t.GetStatValue(StatDefOf.Mass, true); List <Thing> list = wares.Where(t => !(t is Pawn)).ToList(); list.SortByDescending(massTotaler); float ttlMassThings = list.Sum(massTotaler); float ttlCapacity = 0f; float ttlBodySize = 0f; int numCarriers = 0; IEnumerable <PawnGenOption> carrierKinds = groupMaker.carriers.Where(p => { if (parms.tile != -1) { return(Find.WorldGrid[parms.tile].biome.IsPackAnimalAllowed(p.kind.race)); } return(true); }); PawnKindDef kind = carrierKinds.RandomElementByWeight(x => x.selectionWeight).kind; // No slow or small juveniles Predicate <Pawn> validator = (p => p.ageTracker.CurLifeStage.bodySizeFactor >= 1 && p.GetStatValue(StatDefOf.MoveSpeed, true) >= p.kindDef.race.GetStatValueAbstract(StatDefOf.MoveSpeed) ); // 50/50 chance of uniform carriers (like vanilla) or mixed carriers bool mixedCarriers = Rand.RangeInclusive(0, 1) == 1; // Generate all of the carrier pawns (empty). Either we spawn as many pawns as we need to cover // 120% of the weight of the items, or enough pawns before it seems "unreasonable" based on body // size. for (; ttlCapacity < ttlMassThings * 1.2 && ttlBodySize < 20; numCarriers++) { PawnGenerationRequest request = new PawnGenerationRequest( kind: kind, faction: parms.faction, tile: parms.tile, inhabitant: parms.inhabitants, validatorPreGear: validator ); Pawn pawn = PawnGenerator.GeneratePawn(request); outPawns.Add(pawn); ttlCapacity += MassUtility.Capacity(pawn); // Still can't have 100 chickenmuffalos. That might slow down some PCs. ttlBodySize += Mathf.Max(pawn.BodySize, 0.5f); if (mixedCarriers) { kind = carrierKinds.RandomElementByWeight(x => x.selectionWeight).kind; } } // Add items (in descending order of weight) to randomly chosen pack animals. This isn't the most // efficient routine, as we're trying to be a bit random. If I was trying to be efficient, I would // use something like SortByDescending(p.Capacity) against the existing thing list. foreach (Thing thing in list) { List <Pawn> validPawns = outPawns.FindAll(p => !MassUtility.WillBeOverEncumberedAfterPickingUp(p, thing, thing.stackCount)); if (validPawns.Count() != 0) { validPawns.RandomElement().inventory.innerContainer.TryAdd(thing, true); } else if (thing.stackCount > 1) { // No carrier can handle the full stack; split it up int countLeft = thing.stackCount; int c = 0; // safety counter (while loops can be dangerous) while (countLeft > 0) { validPawns = outPawns.FindAll(p => MassUtility.CountToPickUpUntilOverEncumbered(p, thing) >= 1); if (validPawns.Count() != 0 && c < thing.stackCount) { Pawn pawn = validPawns.RandomElement(); int countToAdd = Mathf.Min(MassUtility.CountToPickUpUntilOverEncumbered(pawn, thing), countLeft); countLeft -= pawn.inventory.innerContainer.TryAdd(thing, countToAdd, true); } else { // Either no carrier can handle a single item, or we're just in some bad while loop breakout. In // any case, force it in, evenly split among all carriers. int splitCount = Mathf.FloorToInt(countLeft / outPawns.Count()); if (splitCount > 0) { outPawns.ForEach(p => p.inventory.innerContainer.TryAdd(thing, splitCount, true)); countLeft -= splitCount * outPawns.Count(); } // Give the remainer to the ones with space (one at a time) while (countLeft > 0) { validPawns = new List <Pawn>(outPawns); validPawns.SortByDescending(p => MassUtility.FreeSpace(p)); validPawns.First().inventory.innerContainer.TryAdd(thing, 1, true); countLeft--; } break; } c++; } } else { // No way to split it; force it in validPawns = new List <Pawn>(outPawns); validPawns.SortByDescending(p => MassUtility.FreeSpace(p)); validPawns.First().inventory.innerContainer.TryAdd(thing, true); } } // Always skip the original method return(false); }
public static void GeneratePawns(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, List <Pawn> outPawns, bool errorOnZeroResults = true) { bool canBringFood = parms.raidStrategy?.pawnsCanBringFood ?? true; // 15.08.2021 RW1.3 added total points parameter to .CanUsePawn // For now just using parms.points however unsure if this will mess other things up Predicate <Pawn> postGear = parms.raidStrategy == null ? null : new Predicate <Pawn>(p => parms.raidStrategy.Worker.CanUsePawn(parms.points, p, otherPawns: outPawns)); var madeOnePawnIncap = false; PawnGenUtility.cachedConvertedPawnKindDefs = new Dictionary <string, PawnKindDef>(); foreach (PawnGenOption pawnGenOption in SolarRaidGroupMaker.ChoosePawnGenByConstraint( pointsTotal: parms.points, options: groupMaker.options, groupParms: parms )) { PawnKindDef kind = pawnGenOption.kind; Faction faction = parms.faction; int tile = parms.tile; bool allowFood = canBringFood; bool inhabitants = parms.inhabitants; Predicate <Pawn> validatorPostGear = postGear; var request = new PawnGenerationRequest( kind: PawnGenUtility.ConvertDefAndStoreOld(original: kind), faction: faction, context: PawnGenerationContext.NonPlayer, tile: tile, forceGenerateNewPawn: false, newborn: false, allowDead: false, allowDowned: false, canGeneratePawnRelations: true, mustBeCapableOfViolence: true, colonistRelationChanceFactor: 1f, forceAddFreeWarmLayerIfNeeded: true, allowGay: true, allowFood: allowFood, inhabitant: inhabitants, certainlyBeenInCryptosleep: false, forceRedressWorldPawnIfFormerColonist: false, worldPawnFactionDoesntMatter: false, validatorPreGear: pa => !pa.skills.GetSkill(skillDef: Defs_Rimworld.MeleeSkill).TotallyDisabled, validatorPostGear: validatorPostGear, minChanceToRedressWorldPawn: null, fixedBiologicalAge: null, fixedChronologicalAge: null, fixedGender: null, fixedMelanin: null, fixedLastName: null ); Pawn pawn = PawnGenerator.GeneratePawn(request: request); if (parms.forceOneIncap && !madeOnePawnIncap) { pawn.health.forceIncap = true; pawn.mindState.canFleeIndividual = false; madeOnePawnIncap = true; } PawnFinaliser(pawn: pawn); outPawns.Add(item: pawn); } }
private IEnumerable <Pawn> GenerateCarriers(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, List <Thing> wares) { var carrierList = new List <Pawn>(); var carrierKind = (from x in groupMaker.carriers where parms.tile == -1 || Find.WorldGrid[parms.tile].biome.IsPackAnimalAllowed(x.kind.race) select x).RandomElementByWeight(o => o.selectionWeight).kind; var waresSansPawns = new List <Thing>(); var numCarriers = 1; if (!wares.NullOrEmpty()) { var baseCapacity = carrierKind.RaceProps.baseBodySize * 34f; // Leaving some space for silvah, original calculation is 35f var totalWeight = 0f; for (int j = wares.Count - 1; j > -1; j--) { var thing = wares[j]; if (thing is Pawn) { continue; } var mass = thing.Mass(); if (thing.stackCount == 1 && mass > baseCapacity) { if (Prefs.DevMode) { Log.Warning("[Carnivale] " + thing + " is too big for any carrier and will be removed from wares. mass=" + mass + ", " + carrierKind.label + " capacity=" + baseCapacity ); } wares.RemoveAt(j); continue; } if (thing.def.stackLimit > 1) { while (thing.stackCount >= 2 && mass > baseCapacity) { thing.stackCount /= 2; mass = thing.Mass(); if (Prefs.DevMode) { Log.Message("\t[Carnivale] " + thing.LabelShort + " was to heavy for any carrier. Reducing its stack count to " + thing.stackCount + " and trying again."); } } if (mass > baseCapacity) { if (Prefs.DevMode) { Log.Warning("[Carnivale] " + thing.LabelShort + " is too heavy for any carrier and will be removed from wares. mass=" + mass + ", stackCount=" + thing.stackCount + ", carrierKind=" + carrierKind.label + ", capacity=" + baseCapacity ); } wares.RemoveAt(j); continue; } } totalWeight += mass; waresSansPawns.Add(thing); } numCarriers = Mathf.CeilToInt(totalWeight / baseCapacity); } else { var silver = ThingMaker.MakeThing(ThingDefOf.Silver); silver.stackCount = 100; waresSansPawns.Add(silver); } int i = 0; for (int j = 0; j < numCarriers; j++) { // Generate carrier PawnGenerationRequest request = new PawnGenerationRequest( carrierKind, parms.faction, PawnGenerationContext.NonPlayer, parms.tile, false, false, false, false, true, false, 1f, false, true, true, parms.inhabitants, false, null, null, null, null, null, null ); var carrier = PawnGenerator.GeneratePawn(request); if (i < waresSansPawns.Count) { // Add initial few items to carrier if (carrier.inventory.innerContainer.TryAdd(waresSansPawns[i], true)) { i++; } } carrierList.Add(carrier); yield return(carrier); } // Finally, fill up all the carriers' inventories while (i < waresSansPawns.Count) { var thing = waresSansPawns[i]; var mass = thing.Mass(); var carrier = carrierList.MaxBy(c => MassUtility.FreeSpace(c)); if (thing.stackCount > 1 && !carrier.HasSpaceFor(thing)) { while (thing.stackCount >= 2 && mass > MassUtility.FreeSpace(carrier)) { thing.stackCount /= 2; mass = thing.Mass(); if (Prefs.DevMode) { Log.Message("\t[Carnivale] " + thing.LabelShort + " was to heavy for any carrier. Reducing its stack count to " + thing.stackCount + " and trying again."); } } } if (carrier.inventory.innerContainer.TryAdd(thing)) { i++; } else { if (Prefs.DevMode) { Log.Warning("[Carnivale] " + thing.LabelShort + " is too heavy for any carrier and will be removed from wares. mass=" + mass + ", stackCount=" + thing.stackCount + ", carrierKind=" + carrierKind.label + ", freeSpace=" + MassUtility.FreeSpace(carrier) ); } wares.RemoveAt(i); } } if (i == waresSansPawns.Count) { yield break; } var remainingMass = waresSansPawns.Sum(w => w.Mass()); var remainingFreeSpace = carrierList.Sum(c => MassUtility.FreeSpace(c)); if (Prefs.DevMode) { Log.Warning("[Carnivale] Could not fit all wares in carriers. remainingMass=" + remainingMass + ", remainingFreeSpace=" + remainingFreeSpace); } while (i < waresSansPawns.Count) { var thing = waresSansPawns[i]; // Remove things that could not fit for whatever reason if (Prefs.DevMode) { Log.Warning("\t[Carnivale] removing " + thing); } wares.Remove(waresSansPawns[i]); i++; } }
protected override void GeneratePawns(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, List <Pawn> outPawns, bool errorOnZeroResults = true) { genderValidator = null; // Validation steps if (!CanGenerateFrom(parms, groupMaker) || !ValidateTradersList(groupMaker) || !ValidateCarriers(groupMaker)) { if (errorOnZeroResults) { Log.Error("Cannot generate carnival caravan for " + parms.faction + ". parms=" + parms); } return; } // End validation steps // Restrict gender of entertainers if it is in the name if (parms.faction.Name.EndsWith("Boys")) { genderValidator = delegate(Pawn p) { return(p.Is(CarnivalRole.Entertainer, false) && p.gender == Gender.Male); }; } else if (parms.faction.Name.EndsWith("Girls") || parms.faction.Name.EndsWith("Gals")) { genderValidator = delegate(Pawn p) { return(p.Is(CarnivalRole.Entertainer, false) && p.gender == Gender.Female); }; } // New approach // Spawn manager (costless) outPawns.Add(parms.faction.leader); // Generate vendors (first is costless) var allWares = new List <Thing>(); int numCarnies = 0; int maxVendors = Mathf.Clamp(groupMaker.traders.First().selectionWeight, 1, MaxVendors); for (int i = 0; i < maxVendors; i++) { TraderKindDef traderKind = null; int t = i % 3; switch (t) { case 0: traderKind = _DefOf.Carn_Trader_Food; break; case 1: traderKind = _DefOf.Carn_Trader_Surplus; break; case 2: traderKind = _DefOf.Carn_Trader_Curios; break; default: traderKind = _DefOf.Carn_Trader_Food; Log.Error("PawnGroupKindWorker_Carnival reached a bad place in code."); break; } // Subtracts points, first costless: var vendor = GenerateVendor(parms, groupMaker, traderKind, i > 0); if (vendor != null) { outPawns.Add(vendor); numCarnies++; } else { break; } // Generate wares var waresParms = default(ItemCollectionGeneratorParams); waresParms.traderDef = traderKind; waresParms.forTile = parms.tile; waresParms.forFaction = parms.faction; waresParms.validator = delegate(ThingDef def) { if (def.stackLimit > 1) { return(def.statBases.GetStatValueFromList(StatDefOf.Mass, 1f) * (def.stackLimit / 3f) < 68f); } else { return(def.statBases.GetStatValueFromList(StatDefOf.Mass, 1f) < 68f); } }; allWares.AddRange(ItemCollectionGeneratorDefOf.TraderStock.Worker.Generate(waresParms)); // Generate guards for each trader foreach (var guard in GenerateGroup(parms, groupMaker.guards, i > 0)) { outPawns.Add(guard); } // Generate carnies for each trader foreach (var carny in GenerateGroup(parms, groupMaker.options, i > 0)) { if (numCarnies++ > MaxCarnies) { break; } outPawns.Add(carny); } } // Spawn pawns that are for sale (if any) foreach (Pawn sellable in GetPawnsFromWares(parms, allWares)) { outPawns.Add(sellable); } // Generate carriers outPawns.AddRange( GenerateCarriers(parms, groupMaker, allWares) // carriers w/ traders' wares .Concat(GenerateCarriers(parms, groupMaker, null)) // carrier w/ 100 silver ); }
private void DrawFactionButtons(Rect inRect, int buttonSize) //Used to draw a list of buttons from the 'buttons' list { Text.Anchor = TextAnchor.MiddleCenter; Text.Font = GameFont.Small; for (int i = 0; i < buttons.Count; i++) { if (Widgets.ButtonText(new Rect(140, 110 + ((buttonSize + 5) * i), 170, buttonSize), buttons[i])) { if (buttons[i] == "FCOverview".Translate()) { //if click trade policy button //Log.Message(buttons[i]); Log.Message("Success"); Find.WindowStack.Add(new FCWindow_Overview()); } if (buttons[i] == "Military".Translate()) { if (FactionColonies.getPlayerColonyFaction() == null) { Messages.Message(new Message("NoFactionForMilitary".Translate(), MessageTypeDefOf.RejectInput)); } else { Find.WindowStack.Add(new militaryCustomizationWindowFC()); } } if (buttons[i] == "Actions".Translate()) { List <FloatMenuOption> list = new List <FloatMenuOption>(); list.Add(new FloatMenuOption("TaxDeliveryMap".Translate(), delegate { List <FloatMenuOption> list2 = new List <FloatMenuOption>(); list2.Add(new FloatMenuOption("SetMap".Translate(), delegate { List <FloatMenuOption> settlementList = new List <FloatMenuOption>(); foreach (Map map in Find.Maps) { if (map.IsPlayerHome) { settlementList.Add(new FloatMenuOption(map.Parent.LabelCap, delegate { faction.taxMap = map; Find.LetterStack.ReceiveLetter("Map Set!", "The tax delivery map has been set to the player colony of " + map.Parent.LabelCap + ".\n All taxes and other goods will be delivered there", LetterDefOf.NeutralEvent); } )); } } if (settlementList.Count == 0) { settlementList.Add(new FloatMenuOption("No valid settlements to use.", null)); } FloatMenu floatMenu2 = new FloatMenu(settlementList); floatMenu2.vanishIfMouseDistant = true; Find.WindowStack.Add(floatMenu2); })); FloatMenu floatMenu = new FloatMenu(list2); floatMenu.vanishIfMouseDistant = true; Find.WindowStack.Add(floatMenu); })); list.Add(new FloatMenuOption("SetCapital".Translate(), delegate { faction.setCapital(); })); list.Add(new FloatMenuOption("ActivateResearch".Translate(), delegate { faction.updateDailyResearch(); })); list.Add(new FloatMenuOption("ResearchLevel".Translate(), delegate { Messages.Message("CurrentResearchLevel".Translate(faction.techLevel.ToString(), faction.returnNextTechToLevel()), MessageTypeDefOf.NeutralEvent); })); if (faction.hasPolicy(FCPolicyDefOf.technocratic)) { list.Add(new FloatMenuOption("FCSendResearchItems".Translate(), delegate { if (Find.ColonistBar.GetColonistsInOrder().Count > 0) { Pawn playerNegotiator = Find.ColonistBar.GetColonistsInOrder()[0]; //Log.Message(playerNegotiator.Name + " Negotiator"); FCTrader_Research trader = new FCTrader_Research(); Find.WindowStack.Add(new Dialog_Trade(playerNegotiator, trader)); } else { Log.Message("Where are all the colonists?"); } })); } if (faction.hasPolicy(FCPolicyDefOf.feudal)) { list.Add(new FloatMenuOption("FCRequestMercenary".Translate(), delegate { if (faction.traitFeudalBoolCanUseMercenary) { faction.traitFeudalBoolCanUseMercenary = false; faction.traitFeudalTickLastUsedMercenary = Find.TickManager.TicksGame; List <PawnKindDef> listKindDef = new List <PawnKindDef>(); foreach (ThingDef def in Find.World.GetComponent <FactionFC>().raceFilter.AllowedThingDefs) { listKindDef.Add(def.race.AnyPawnKind); } PawnGroupMaker groupMaker = FactionColonies.getPlayerColonyFaction().def.pawnGroupMakers.RandomElement(); PawnGroupMakerParms group = new PawnGroupMakerParms(); group.groupKind = groupMaker.kindDef; group.faction = FactionColonies.getPlayerColonyFaction(); group.dontUseSingleUseRocketLaunchers = true; group.generateFightersOnly = true; group.points = 2000; group.raidStrategy = RaidStrategyDefOf.ImmediateAttackFriendly; PawnKindDef pawnkind = new PawnKindDef(); PawnKindDef kind = groupMaker.GeneratePawns(group).RandomElement().kindDef; pawnkind = listKindDef.RandomElement(); pawnkind.techHediffsTags = kind.techHediffsTags; pawnkind.apparelTags = kind.apparelTags; pawnkind.isFighter = kind.isFighter; pawnkind.combatPower = kind.combatPower; pawnkind.gearHealthRange = kind.gearHealthRange; pawnkind.weaponTags = kind.weaponTags; pawnkind.apparelMoney = kind.apparelMoney; pawnkind.weaponMoney = kind.weaponMoney; pawnkind.apparelAllowHeadgearChance = kind.apparelAllowHeadgearChance; pawnkind.techHediffsMoney = kind.techHediffsMoney; pawnkind.label = kind.label; Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(pawnkind, Find.FactionManager.OfPlayer, PawnGenerationContext.NonPlayer, -1, false, false, false, false, true, false, 20f)); IncidentParms parms = new IncidentParms(); parms.target = Find.CurrentMap; parms.faction = FactionColonies.getPlayerColonyFaction(); parms.points = 999; parms.raidArrivalModeForQuickMilitaryAid = true; parms.raidNeverFleeIndividual = true; parms.raidForceOneIncap = true; parms.raidArrivalMode = PawnsArrivalModeDefOf.CenterDrop; parms.raidStrategy = RaidStrategyDefOf.ImmediateAttackFriendly; parms.raidArrivalModeForQuickMilitaryAid = true; PawnsArrivalModeWorker_EdgeWalkIn worker = new PawnsArrivalModeWorker_EdgeWalkIn(); worker.TryResolveRaidSpawnCenter(parms); worker.Arrive(new List <Pawn> { pawn }, parms); Find.LetterStack.ReceiveLetter("FCMercenaryJoined".Translate(), "FCMercenaryJoinedText".Translate(pawn.NameFullColored), LetterDefOf.PositiveEvent, new LookTargets(pawn)); } else { Messages.Message("FCActionMercenaryOnCooldown".Translate(((faction.traitFeudalTickLastUsedMercenary + GenDate.TicksPerSeason) - Find.TickManager.TicksGame).ToStringTicksToDays()), MessageTypeDefOf.RejectInput); } })); } FloatMenu menu = new FloatMenu(list); Find.WindowStack.Add(menu); } } } }
static bool Prefix(ref PawnGroupKindWorker_Trader __instance, PawnGroupMakerParms parms, PawnGroupMaker groupMaker, Pawn trader, List <Thing> wares, List <Pawn> outPawns) { if (parms.faction == FactionColonies.getPlayerColonyFaction()) { List <PawnKindDef> list = new List <PawnKindDef>(); foreach (ThingDef def in Find.World.GetComponent <FactionFC>().raceFilter.AllowedThingDefs) { list.Add(def.race.AnyPawnKind); } if (!groupMaker.guards.Any <PawnGenOption>()) { return(false); } foreach (PawnGenOption pawnGenOption in PawnGroupMakerUtility.ChoosePawnGenOptionsByPoints(parms.points, groupMaker.guards, parms)) { PawnKindDef pawnkind = new PawnKindDef(); pawnkind = list.RandomElement(); pawnkind.techHediffsTags = pawnGenOption.kind.techHediffsTags; pawnkind.apparelTags = pawnGenOption.kind.apparelTags; pawnkind.isFighter = pawnGenOption.kind.isFighter; pawnkind.combatPower = pawnGenOption.kind.combatPower; pawnkind.gearHealthRange = pawnGenOption.kind.gearHealthRange; pawnkind.weaponTags = pawnGenOption.kind.weaponTags; pawnkind.apparelMoney = pawnGenOption.kind.apparelMoney; pawnkind.weaponMoney = pawnGenOption.kind.weaponMoney; pawnkind.apparelAllowHeadgearChance = pawnGenOption.kind.apparelAllowHeadgearChance; pawnkind.techHediffsMoney = pawnGenOption.kind.techHediffsMoney; pawnkind.label = pawnGenOption.kind.label; PawnGenerationRequest request = PawnGenerationRequest.MakeDefault(); request.KindDef = pawnkind; Log.Message(request.KindDef.ToString()); request.Faction = parms.faction; request.Tile = parms.tile; request.MustBeCapableOfViolence = true; request.Inhabitant = parms.inhabitants; request.RedressValidator = ((Pawn x) => x.royalty == null || !x.royalty.AllTitlesForReading.Any <RoyalTitle>()); Pawn item = PawnGenerator.GeneratePawn(request); outPawns.Add(item); } return(false); } else { return(true); } }
// RimWorld.PawnGroupKindWorker_Normal public static void GeneratePawns_PostFix(PawnGroupMakerParms parms, PawnGroupMaker groupMaker, bool errorOnZeroResults, ref List <Pawn> __result) { //Anyone special? if (__result.Any() && __result.FindAll(x => x.TryGetComp <CompAbilityUser>() is CompAbilityUser cu && cu.CombatPoints() > 0) is List <Pawn> specialPawns) { //Log.Message("Special Pawns Detected"); //Log.Message("------------------"); //Points var previousPoints = parms.points; //Log.Message("Points: " + previousPoints); //Log.Message("Average Characters"); //Log.Message("------------------"); //Anyone average? int avgPawns = 0; var avgCombatPoints = new Dictionary <Pawn, float>(); if (__result.FindAll(x => x.TryGetComp <CompAbilityUser>() == null) is List <Pawn> averagePawns) { avgPawns = averagePawns.Count; averagePawns.ForEach(x => { avgCombatPoints.Add(x, x.kindDef.combatPower); //Log.Message(x.LabelShort + " : " + x.kindDef.combatPower); }); } //Log.Message("------------------"); //Log.Message("Special Characters"); //Log.Message("------------------"); //What's your powers? var specCombatPoints = new Dictionary <Pawn, float>(); specialPawns.ForEach(x => { var combatValue = x.kindDef.combatPower; foreach (var thingComp in x.AllComps.FindAll(y => y is CompAbilityUser)) { //var compAbilityUser = (CompAbilityUser) thingComp; var val = Traverse.Create(thingComp).Method("CombatPoints").GetValue <float>(); combatValue += val; //compAbilityUser.CombatPoints(); } specCombatPoints.Add(x, combatValue); //Log.Message(x.LabelShort + " : " + combatValue); }); //Special case -- single raider/character should not be special to avoid problems (e.g. Werewolf raid destroys everyone). if (avgPawns == 0 && specCombatPoints.Sum(x => x.Value) > 0 && specialPawns.Count == 1) { //Log.Message("Special case called: Single character"); specialPawns.First().TryGetComp <CompAbilityUser>().DisableAbilityUser(); return; } //Should we rebalance? int tryLimit = avgPawns + specialPawns.Count + 1; int initTryLimit = tryLimit; var tempAvgCombatPoints = new Dictionary <Pawn, float>(avgCombatPoints); var tempSpecCombatPoints = new Dictionary <Pawn, float>(specCombatPoints); var removedCharacters = new List <Pawn>(); while (previousPoints < tempAvgCombatPoints.Sum(x => x.Value) + tempSpecCombatPoints.Sum(x => x.Value)) { //Log.Message("------------------"); //Log.Message("Rebalance Attempt # " + (initTryLimit - tryLimit + 1)); //Log.Message("------------------"); //Log.Message("Scenario Points: " + previousPoints + ". Total Points: " + tempAvgCombatPoints.Sum(x => x.Value) + tempSpecCombatPoints.Sum(x => x.Value)); //In-case some stupid stuff occurs --tryLimit; if (tryLimit < 0) { break; } //If special characters outnumber the avg characters, try removing some of the special characters instead. if (tempSpecCombatPoints.Count >= tempAvgCombatPoints.Count) { var toRemove = tempSpecCombatPoints.Keys.RandomElement(); //Log.Message("Removed: " + toRemove.LabelShort + " : " + tempSpecCombatPoints[toRemove]); removedCharacters.Add(toRemove); tempSpecCombatPoints.Remove(toRemove); } //If average characters outnumber special characters, then check if the combat value of avg is greater. else if (tempSpecCombatPoints.Count < tempAvgCombatPoints.Count) { //Remove a random average character if the average characters have more combat points for a score if (tempAvgCombatPoints.Sum(x => x.Value) > tempSpecCombatPoints.Sum(x => x.Value)) { var toRemove = tempAvgCombatPoints.Keys.RandomElement(); //Log.Message("Removed: " + toRemove.LabelShort + " : " + tempSpecCombatPoints[toRemove]); removedCharacters.Add(toRemove); tempAvgCombatPoints.Remove(toRemove); } else { var toRemove = tempSpecCombatPoints.Keys.RandomElement(); //Log.Message("Removed: " + toRemove.LabelShort + " : " + tempSpecCombatPoints[toRemove]); removedCharacters.Add(toRemove); tempSpecCombatPoints.Remove(toRemove); } } } avgCombatPoints = tempAvgCombatPoints; specCombatPoints = tempSpecCombatPoints; // Log.Message("------------"); // Log.Message("Final Report"); // Log.Message("------------"); // Log.Message("Scenario Points: " + previousPoints + ". Total Points: " + tempAvgCombatPoints.Sum(x => x.Value) + tempSpecCombatPoints.Sum(x => x.Value)); // Log.Message("------------"); // Log.Message("Characters"); // Log.Message("------------------"); __result.ForEach(x => { var combatValue = x.kindDef.combatPower + x?.TryGetComp <CompAbilityUser>()?.CombatPoints() ?? 0f; //Log.Message(x.LabelShort + " : " + combatValue); }); foreach (var x in removedCharacters) { if (x.TryGetComp <CompAbilityUser>() is CompAbilityUser cu && cu.CombatPoints() > 0) { cu.DisableAbilityUser(); }
static bool Prefix(ref PawnGroupKindWorker_Normal __instance, PawnGroupMakerParms parms, PawnGroupMaker groupMaker, List <Pawn> outPawns, bool errorOnZeroResults = true) { if (parms.faction == FactionColonies.getPlayerColonyFaction()) { List <PawnKindDef> list = new List <PawnKindDef>(); foreach (ThingDef def in Find.World.GetComponent <FactionFC>().raceFilter.AllowedThingDefs) { list.Add(def.race.AnyPawnKind); } if (!__instance.CanGenerateFrom(parms, groupMaker)) { if (errorOnZeroResults) { Log.Error(string.Concat(new object[] { "Cannot generate pawns for ", parms.faction, " with ", parms.points, ". Defaulting to a single random cheap group." }), false); } return(false); } bool allowFood = parms.raidStrategy == null || parms.raidStrategy.pawnsCanBringFood || (parms.faction != null && !parms.faction.HostileTo(Faction.OfPlayer)); Predicate <Pawn> validatorPostGear = (parms.raidStrategy != null) ? ((Pawn p) => parms.raidStrategy.Worker.CanUsePawn(p, outPawns)) : (Predicate <Pawn>)null; bool flag = false; foreach (PawnGenOption pawnGenOption in PawnGroupMakerUtility.ChoosePawnGenOptionsByPoints(parms.points, groupMaker.options, parms)) { PawnKindDef pawnkind = new PawnKindDef(); pawnkind = list.RandomElement(); pawnkind.techHediffsTags = pawnGenOption.kind.techHediffsTags; pawnkind.apparelTags = pawnGenOption.kind.apparelTags; pawnkind.isFighter = pawnGenOption.kind.isFighter; pawnkind.combatPower = pawnGenOption.kind.combatPower; pawnkind.gearHealthRange = pawnGenOption.kind.gearHealthRange; pawnkind.weaponTags = pawnGenOption.kind.weaponTags; pawnkind.apparelMoney = pawnGenOption.kind.apparelMoney; pawnkind.weaponMoney = pawnGenOption.kind.weaponMoney; pawnkind.apparelAllowHeadgearChance = pawnGenOption.kind.apparelAllowHeadgearChance; pawnkind.techHediffsMoney = pawnGenOption.kind.techHediffsMoney; pawnkind.label = pawnGenOption.kind.label; Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(pawnkind, parms.faction, PawnGenerationContext.NonPlayer, parms.tile, false, false, false, false, true, true, 1f, false, true, allowFood, true, parms.inhabitants, false, false, false, 0f, null, 1f, null, validatorPostGear, null, null, null, null, null, null, null, null, null, null)); if (parms.forceOneIncap && !flag) { pawn.health.forceIncap = true; pawn.mindState.canFleeIndividual = false; flag = true; } outPawns.Add(pawn); } return(false); } else { return(true); } }