public override void DefsLoaded() { hasAlienRace = GenTypes.GetTypeInAnyAssembly("AlienRace.RaceSettings", "AlienRace") != null; FB_Factions.RemoveAll(x => true); FB_Factions.Add(FactionDef.Named("FactionBlender_Pirate")); FB_Factions.Add(FactionDef.Named("FactionBlender_Civil")); ProcessSettings(); DefInjector.InjectMiscToFactions(FB_Factions); Logger.Message("Injecting pawn groups to our factions"); FillFilterLists(); DefInjector.InjectPawnKindDefsToFactions(FB_Factions); if (hasAlienRace) { Logger.Message("Injecting pawn groups to our race settings"); DefInjector.InjectPawnKindEntriesToRaceSettings(); } else { Logger.Message("AlienRace not loaded; no race settings for us!"); } }
public override void SettingsChanged() { lastSettingChanged = ""; Logger.Message("Re-injecting pawn groups to our factions"); DefInjector.InjectPawnKindDefsToFactions(FB_Factions); if (hasAlienRace) { Logger.Message("Re-injecting pawn groups to our race settings"); DefInjector.InjectPawnKindEntriesToRaceSettings(); } }
public override void DefsLoaded() { ProcessSettings(); // Set the debug flag IsDebug = ((SettingHandle <bool>)config["MoreDebug"]).Value; // Curate the surgery worker class list before building allSurgeryDefs Dictionary <string, Type[]> searchConfigMapper = new Dictionary <string, Type[]> { { "Adminster", new[] { typeof(Recipe_AdministerIngestible), typeof(Recipe_AdministerUsableItem) } }, { "InstallNaturalBodyPart", new[] { typeof(Recipe_InstallNaturalBodyPart) } }, { "InstallArtificialBodyPart", new[] { typeof(Recipe_InstallArtificialBodyPart) } }, { "InstallImplant", new[] { typeof(Recipe_InstallImplant), typeof(Recipe_ChangeImplantLevel) } }, { "VanillaRemoval", new[] { typeof(Recipe_RemoveHediff), AccessTools.TypeByName("RimWorld.Recipe_RemoveBodyPart"), typeof(Recipe_RemoveImplant) } }, }; foreach (string cName in searchConfigMapper.Keys) { if (((SettingHandle <bool>)config["Search" + cName + "Recipes"]).Value) { surgeryWorkerClassesFilter.AddRange(searchConfigMapper[cName]); } } // Add additional search types for modded surgery classes if (((SettingHandle <bool>)config["SearchModdedSurgeryClasses"]).Value) { List <string> moddedWorkerClassNames = new List <string> { // (EPOE doesn't have any custom worker classes) // EPOE Forked "EPIA.Recipe_RemoveImplant", "EPIA.Recipe_RemoveScarHediff", "EPIA.Recipe_RemoveBrainScarHediff", // Rah's Bionics and Surgery Expansion "ScarRemoving.Recipe_RemoveHediff_noBrain", // Medical Surgery Expansion "OrenoMSE.Recipe_InstallBodyPartModule", "OrenoMSE.Recipe_InstallImplantSystem", "OrenoMSE.Recipe_RemoveImplantSystem", // Medical Surgery Expansion 2.0 "MSE2.Recipe_InstallModule", "MSE2.Recipe_RemoveModules", "MSE2.Recipe_InstallNaturalBodyPartWithChildren", "MSE2.Recipe_InstallArtificialBodyPartWithChildren", // Cyber Fauna "SurgeryCF_Simple", "SurgeryCF_Bionic", "SurgeryCF_Archo", "SurgeryCF_Battle", // Chj's Androids "Androids.Recipe_Disassemble", "Androids.Recipe_RepairKit", // Android Tiers "MOARANDROIDS.Recipe_AndroidRewireSurgery", "MOARANDROIDS.Recipe_RemoveSentience", "MOARANDROIDS.Recipe_RerollTraits", "MOARANDROIDS.Recipe_InstallImplantAndroid", "MOARANDROIDS.Recipe_InstallArtificialBodyPartAndroid", "MOARANDROIDS.Recipe_InstallArtificialBrain", "MOARANDROIDS.Recipe_ApplyHydraulicNaniteBank", "MOARANDROIDS.Recipe_ApplyHealFrameworkSystem", "MOARANDROIDS.Recipe_ApplyHealCoolingSystem", "MOARANDROIDS.Recipe_ApplyHealCPUSerum", // Alien vs. Predator "RRYautja.Recipe_Remove_Gauntlet", "RRYautja.Recipe_RemoveHugger", // Questionable Ethics "QEthics.RecipeWorker_CreateBrainScan", "QEthics.RecipeWorker_GenomeSequencing", "QEthics.RecipeWorker_InstallNaturalBodyPart", "QEthics.RecipeWorker_NerveStapling", // Harpies "SyrHarpy.Recipe_InstallPart", // A RimWorld of Magic "TorannMagic.Recipe_RegrowBodyPart", "TorannMagic.Recipe_RegrowUniversalBodyPart", // PolarisBloc "Polarisbloc.Recipe_MakeCartridgeSurgery", "Polarisbloc.Recipe_InstallCombatChip", "Polarisbloc.Recipe_RemoveHediffIsOld", "Polarisbloc.Recipe_RestoreMissingPart", "Polarisbloc.Recipe_RemoveImplant", "Polarisbloc.Recipe_TransgenderSurgery", "Polarisbloc.Recipe_SurgeryChangeBioAge", "Polarisbloc.Recipe_ExtractAbility", // What the Hack "WhatTheHack.Recipes.Recipe_ExtractBrainData", // The rest of them are really only for mechanoids // CyberNet "CyberNet.Recipe_InstallCyberNetBrainImplant", // Cybernetic Organism and Neural Network "CONN.Recipe_InstallArtificialBodyPartAndClearPawnFromCache", // Vanilla Factions Expanded: Insectoids "VFEI.Other.Recipe_AddMutationHediff", // Deathrattle "DeathRattle.Recipe_AdministerComaDrug", // Rim of Madness: Vampires has blood recipes, but who knows which blood is compatible to a vampire? // Just leave them alone. /* * "Vampire.Recipe_ExtractBloodVial", * "Vampire.Recipe_ExtractBloodPack", * "Vampire.Recipe_ExtractBloodWine", * "Vampire.Recipe_TransferBlood", */ }; foreach (string workerName in moddedWorkerClassNames) { Type worker = Helpers.SafeTypeByName(workerName); if (worker != null) { surgeryWorkerClassesFilter.Add(worker); } } } Stopwatch stopwatch = Stopwatch.StartNew(); string beforeMsg = "Injecting {0} surgical recipes into {1}"; string afterMsg = "Injected {0} surgical recipes into {1} (took {2:F4}s; {3:N0} combinations)"; // Start with a few global lists List <ThingDef> allPawnDefs = DefDatabase <ThingDef> .AllDefs.Where( thing => Helpers.IsSupertypeOf(typeof(Pawn), thing.thingClass) ).ToList(); List <RecipeDef> allSurgeryDefs = DefDatabase <RecipeDef> .AllDefs.Where( recipe => recipe.IsSurgery && surgeryWorkerClassesFilter.Any(t => Helpers.IsSupertypeOf(t, recipe.workerClass)) ).ToList(); // Because we use pawn.recipes so often for surgery checks, and not the other side (surgery.recipeUsers), // merge the latter into the former. Our new additions will be sure to add it in both sides to keep // pawn.recipes complete. stopwatch.Start(); foreach (ThingDef pawn in allPawnDefs) { if (pawn.recipes == null) { pawn.recipes = new List <RecipeDef> { } } ; pawn.recipes.AddRange( allSurgeryDefs.Where(s => s.recipeUsers != null && s.recipeUsers.Contains(pawn)) ); pawn.recipes.RemoveDuplicates(); } // Pre-caching allSurgeryDefs.ForEach(s => Helpers.GetSurgeryBioType(s)); allPawnDefs.ForEach(p => Helpers.GetPawnBioType(p)); stopwatch.Stop(); Logger.Message("Prep work / pre-caching (took {0:F4}s; {1:N0} defs)", stopwatch.ElapsedMilliseconds / 1000f, allSurgeryDefs.Count() + allPawnDefs.Count()); stopwatch.Reset(); // Animal/Animal if (((SettingHandle <bool>)config["PatchAnimalToAnimal"]).Value) { if (IsDebug) { Logger.Message(beforeMsg, "animal", "other animals"); } var surgeryList = allSurgeryDefs.Where(s => Helpers.GetSurgeryBioType(s) == "animal").ToList(); var pawnList = allPawnDefs.Where(p => Helpers.GetPawnBioType(p) == "animal").ToList(); stopwatch.Start(); DefInjector.InjectSurgeryRecipes(surgeryList, pawnList); stopwatch.Stop(); Logger.Message(afterMsg, "animal", "other animals", stopwatch.ElapsedMilliseconds / 1000f, surgeryList.Count() * pawnList.Count()); } stopwatch.Reset(); // Humanlike/Humanlike if (((SettingHandle <bool>)config["PatchHumanlikeToHumanlike"]).Value) { if (IsDebug) { Logger.Message(beforeMsg, "humanlike", "other humanlikes"); } var surgeryList = allSurgeryDefs.Where(s => Helpers.GetSurgeryBioType(s) == "humanlike").ToList(); var pawnList = allPawnDefs.Where(p => Helpers.GetPawnBioType(p) == "humanlike").ToList(); stopwatch.Start(); DefInjector.InjectSurgeryRecipes(surgeryList, pawnList); stopwatch.Stop(); Logger.Message(afterMsg, "humanlike", "other humanlikes", stopwatch.ElapsedMilliseconds / 1000f, surgeryList.Count() * pawnList.Count()); } stopwatch.Reset(); // */Mech (artificial+mech only) if (((SettingHandle <bool>)config["PatchArtificialToMech"]).Value) { if (IsDebug) { Logger.Message(beforeMsg, "artificial part", "mechs"); } var surgeryList = allSurgeryDefs.Where(s => Helpers.IsSupertypeOf(typeof(Recipe_InstallArtificialBodyPart), s.workerClass) || Helpers.IsSupertypeOf("OrenoMSE.Recipe_InstallBodyPartModule", s.workerClass) || Helpers.GetSurgeryBioType(s) == "mech" ).ToList(); var pawnList = allPawnDefs.Where(p => Helpers.GetPawnBioType(p) == "mech").ToList(); stopwatch.Start(); DefInjector.InjectSurgeryRecipes(surgeryList, pawnList); stopwatch.Stop(); Logger.Message(afterMsg, "artificial part", "mechs", stopwatch.ElapsedMilliseconds / 1000f, surgeryList.Count() * pawnList.Count()); } stopwatch.Reset(); // Animal/Humanlike if (((SettingHandle <bool>)config["PatchAnimalToHumanlike"]).Value) { if (IsDebug) { Logger.Message(beforeMsg, "animal", "humanlikes"); } var surgeryList = allSurgeryDefs.Where(s => Helpers.GetSurgeryBioType(s) == "animal").ToList(); var pawnList = allPawnDefs.Where(p => Helpers.GetPawnBioType(p) == "humanlike").ToList(); stopwatch.Start(); DefInjector.InjectSurgeryRecipes(surgeryList, pawnList); stopwatch.Stop(); Logger.Message(afterMsg, "animal", "humanlikes", stopwatch.ElapsedMilliseconds / 1000f, surgeryList.Count() * pawnList.Count()); } stopwatch.Reset(); // Humanlike/Animal if (((SettingHandle <bool>)config["PatchHumanlikeToAnimal"]).Value) { if (IsDebug) { Logger.Message(beforeMsg, "humanlike", "animals"); } var surgeryList = allSurgeryDefs.Where(s => Helpers.GetSurgeryBioType(s) == "humanlike").ToList(); var pawnList = allPawnDefs.Where(p => Helpers.GetPawnBioType(p) == "animal").ToList(); stopwatch.Start(); DefInjector.InjectSurgeryRecipes(surgeryList, pawnList); stopwatch.Stop(); Logger.Message(afterMsg, "humanlike", "animals", stopwatch.ElapsedMilliseconds / 1000f, surgeryList.Count() * pawnList.Count()); } stopwatch.Reset(); // Any Fleshlike to any Fleshlike (only if all other similar ones are on) if ( ((SettingHandle <bool>)config["PatchAnimalToAnimal"]).Value && ((SettingHandle <bool>)config["PatchHumanlikeToHumanlike"]).Value && ((SettingHandle <bool>)config["PatchAnimalToHumanlike"]).Value && ((SettingHandle <bool>)config["PatchHumanlikeToAnimal"]).Value ) { if (IsDebug) { Logger.Message(beforeMsg, "fleshlike", "fleshlikes"); } var surgeryList = allSurgeryDefs.Where(s => Regex.IsMatch(Helpers.GetSurgeryBioType(s), "animal|(?:human|flesh)like|mixed")).ToList(); var pawnList = allPawnDefs.Where(p => Helpers.GetPawnBioType(p) != "mech").ToList(); stopwatch.Start(); DefInjector.InjectSurgeryRecipes(surgeryList, pawnList); stopwatch.Stop(); Logger.Message(afterMsg, "fleshlike", "fleshlikes", stopwatch.ElapsedMilliseconds / 1000f, surgeryList.Count() * pawnList.Count()); } stopwatch.Reset(); // Humanlike/Mech if (((SettingHandle <bool>)config["PatchHumanlikeToMech"]).Value) { if (IsDebug) { Logger.Message(beforeMsg, "humanlike", "mechs"); } var surgeryList = allSurgeryDefs.Where(s => Helpers.GetSurgeryBioType(s) == "humanlike").ToList(); var pawnList = allPawnDefs.Where(p => Helpers.GetPawnBioType(p) == "mech").ToList(); stopwatch.Start(); DefInjector.InjectSurgeryRecipes(surgeryList, pawnList); stopwatch.Stop(); Logger.Message(afterMsg, "humanlike", "mechs", stopwatch.ElapsedMilliseconds / 1000f, surgeryList.Count() * pawnList.Count()); } stopwatch.Reset(); // Mech-like/Humanlike if (((SettingHandle <bool>)config["PatchMechlikeToHumanlike"]).Value) { if (IsDebug) { Logger.Message(beforeMsg, "mech-like", "humanlikes"); } var surgeryList = allSurgeryDefs.Where(s => Helpers.GetSurgeryBioType(s) == "mech").ToList(); var pawnList = allPawnDefs.Where(p => Helpers.GetPawnBioType(p) == "humanlike").ToList(); stopwatch.Start(); DefInjector.InjectSurgeryRecipes(surgeryList, pawnList); stopwatch.Stop(); Logger.Message(afterMsg, "mech-like", "humanlikes", stopwatch.ElapsedMilliseconds / 1000f, surgeryList.Count() * pawnList.Count()); } stopwatch.Reset(); // Hand/foot clean up if (((SettingHandle <bool>)config["CleanupHandFootSurgeries"]).Value) { if (IsDebug) { Logger.Message("Cleaning up hand/foot surgical recipes"); } var surgeryList = allSurgeryDefs.Where( s => s.label.ToLower() is string sl && (sl.Contains("hand") || sl.Contains("foot")) ).ToList(); stopwatch.Start(); DefInjector.CleanupHandFootSurgeryRecipes(surgeryList); stopwatch.Stop(); Logger.Message("Cleaning up hand/foot surgical recipes (took {0:F4}s)", stopwatch.ElapsedMilliseconds / 1000f); } stopwatch.Reset(); // Clean up if (IsDebug) { Logger.Message("Merging duplicate surgical recipes, hyperlinking, and sorting"); } stopwatch.Start(); DefInjector.CleanupSurgeryRecipes(allSurgeryDefs, allPawnDefs); stopwatch.Stop(); Logger.Message("Merged duplicate surgical recipes, hyperlinking, and sorting (took {0:F4}s)", stopwatch.ElapsedMilliseconds / 1000f); stopwatch.Reset(); // No need to occupy all of this memory Helpers.ClearCaches(); }