public string UWP(Planet.WorldType type = Planet.WorldType.NORMAL, double diameter = 0) { var builder = new StringBuilder(); switch (type) { case Planet.WorldType.LGG: builder.AppendFormat("LGG - diameter {0} km", diameter.ToString("F")); break; case Planet.WorldType.SGG: builder.AppendFormat("SGG - diameter {0} km", diameter.ToString("F")); break; case Planet.WorldType.SMALL: builder.AppendFormat("{0}-S{1}{2}{3}-{4}", Starport, Atmosphere.ToString(), Hydro.ToString(), SocialUWP(), TechLevel.ToString()); break; case Planet.WorldType.RING: builder.AppendFormat("{0}-R00{1}-{2}", Starport, SocialUWP(), TechLevel.ToString()); break; case Planet.WorldType.NORMAL: case Planet.WorldType.PLANETOID: builder.AppendFormat("{0}-{1}{2}-{3}", Starport, PhysicalUWP(), SocialUWP(), TechLevel.ToString()); break; case Planet.WorldType.STAR: builder.Append(Languages.CompanionStar); break; } return(builder.ToString()); }
public override void DefsLoaded() { //1. Preparing settings UpdateSettings(); //2. Adding Tech Tab to Pawns //ThingDef injection stolen from the work of notfood for Psychology var zombieThinkTree = DefDatabase <ThinkTreeDef> .GetNamedSilentFail("Zombie"); IEnumerable <ThingDef> things = (from def in DefDatabase <ThingDef> .AllDefs where def.race?.intelligence == Intelligence.Humanlike && (zombieThinkTree == null || def.race.thinkTreeMain != zombieThinkTree) select def); List <string> registered = new List <string>(); foreach (ThingDef t in things) { if (t.inspectorTabsResolved == null) { t.inspectorTabsResolved = new List <InspectTabBase>(1); } t.inspectorTabsResolved.Add(InspectTabManager.GetSharedInstance(typeof(ITab_PawnKnowledge))); if (t.comps == null) { t.comps = new List <CompProperties>(1); } t.comps.Add(new CompProperties_Knowledge()); registered.Add(t.defName); } InspectPaneUtility.Reset(); //3. Preparing knowledge support infrastructure //a. Things everyone knows UniversalWeapons.AddRange(DefDatabase <ThingDef> .AllDefs.Where(x => x.IsWeapon)); UniversalCrops.AddRange(DefDatabase <ThingDef> .AllDefs.Where(x => x.plant != null && x.plant.Sowable)); //b. Minus things unlocked on research ThingFilter lateFilter = new ThingFilter(); foreach (ResearchProjectDef tech in DefDatabase <ResearchProjectDef> .AllDefs) { tech.InferSkillBias(); tech.CreateStuff(lateFilter, unlocked); foreach (ThingDef weapon in tech.UnlockedWeapons()) { UniversalWeapons.Remove(weapon); } foreach (ThingDef plant in tech.UnlockedPlants()) { UniversalCrops.Remove(plant); } } ; //c. Also removing atipical weapons List <string> ForbiddenWeaponTags = TechDefOf.WeaponsNotBasic.weaponTags; UniversalWeapons.RemoveAll(x => SplitSimpleWeapons(x, ForbiddenWeaponTags)); List <ThingDef> garbage = new List <ThingDef>(); garbage.Add(TechDefOf.WeaponsNotBasic); //d. Classifying pawn backstories PawnBackgroundUtility.BuildCache(); //e. Telling humans what's going on ThingCategoryDef knowledgeCat = TechDefOf.Knowledge; IEnumerable <ThingDef> codifiedTech = DefDatabase <ThingDef> .AllDefs.Where(x => x.IsWithinCategory(knowledgeCat)); if (Prefs.LogVerbose || FullStartupReport) { Log.Message($"[HumanResources] Codified technologies: {codifiedTech.Select(x => x.label).ToStringSafeEnumerable()}"); Log.Message($"[HumanResources] Basic crops: {UniversalCrops.ToStringSafeEnumerable()}"); Log.Message($"[HumanResources] Basic weapons: {UniversalWeapons.ToStringSafeEnumerable()}"); Log.Message($"[HumanResources] Basic weapons that require training: {SimpleWeapons.ToStringSafeEnumerable()}"); Log.Warning($"[HumanResources] Basic weapons tags: {SimpleWeapons.Where(x => !x.weaponTags.NullOrEmpty()).SelectMany(x => x.weaponTags).Distinct().ToStringSafeEnumerable()}"); if (FullStartupReport) { Log.Warning("[HumanResources] Backstories classified by TechLevel:"); for (int i = 0; i < 8; i++) { TechLevel level = (TechLevel)i; IEnumerable <string> found = PawnBackgroundUtility.TechLevelByBackstory.Where(e => e.Value == level).Select(e => e.Key); if (!found.EnumerableNullOrEmpty()) { Log.Message($"- {level.ToString().CapitalizeFirst()} ({found.EnumerableCount()}): {found.ToStringSafeEnumerable()}"); } } Log.Warning("[HumanResources] Techs classified by associated skill:"); var skills = DefDatabase <SkillDef> .AllDefsListForReading.GetEnumerator(); while (skills.MoveNext()) { SkillDef skill = skills.Current; IEnumerable <string> found = TechTracker.FindTechs(skill).Select(x => x.Tech.label); Log.Message($"- {skill.LabelCap} ({found.EnumerableCount()}): {found.ToStringSafeEnumerable()}"); } } } else { Log.Message($"[HumanResources] This is what we know: {codifiedTech.EnumerableCount()} technologies processed, {UniversalCrops.Count()} basic crops, {UniversalWeapons.Count()} basic weapons + {SimpleWeapons.Count()} that require training."); } //4. Filling gaps on the database //a. TechBook dirty trick, but only now this is possible! TechDefOf.TechBook.stuffCategories = TechDefOf.UnfinishedTechBook.stuffCategories = TechDefOf.LowTechCategories.stuffCategories; TechDefOf.TechDrive.stuffCategories = TechDefOf.HiTechCategories.stuffCategories; garbage.Add(TechDefOf.LowTechCategories); garbage.Add(TechDefOf.HiTechCategories); //b. Filling main tech category with subcategories foreach (ThingDef t in lateFilter.AllowedThingDefs.Where(t => !t.thingCategories.NullOrEmpty())) { foreach (ThingCategoryDef c in t.thingCategories) { c.childThingDefs.Add(t); if (!knowledgeCat.childCategories.NullOrEmpty() && !knowledgeCat.childCategories.Contains(c)) { knowledgeCat.childCategories.Add(c); } } } //c. Populating knowledge recipes and book shelves foreach (RecipeDef r in DefDatabase <RecipeDef> .AllDefs.Where(x => x.ingredients.Count == 1 && x.fixedIngredientFilter.AnyAllowedDef == null)) { r.fixedIngredientFilter.ResolveReferences(); r.defaultIngredientFilter.ResolveReferences(); } foreach (ThingDef t in DefDatabase <ThingDef> .AllDefs.Where(x => x.thingClass == typeof(Building_BookStore))) { t.building.fixedStorageSettings.filter.ResolveReferences(); t.building.defaultStorageSettings.filter.ResolveReferences(); } //d. Removing temporary defs from database. foreach (ThingDef def in garbage) { AccessTools.Method(typeof(DefDatabase <ThingDef>), "Remove").Invoke(this, new object[] { def }); } }
internal static void _ReapplyAllMods(this ResearchManager _this) //new ReapplyAllMods Method { if (Faction.OfPlayerSilentFail?.def?.techLevel == null || Faction.OfPlayer.def.techLevel == TechLevel.Undefined) // if some mod does something funky again.... { return; } if (firstpass || facName != Faction.OfPlayer.def.defName) { startedAt = DateTime.Now; facName = Faction.OfPlayer.def.defName; try { GetAndReloadTL(); //store the default value for the techlevel because we will modify it later and we need the one from right now isTribe = factionDefault == TechLevel.Neolithic; LoadCfgValues(); firstpass = false; //Debug LogOutput.WriteLogMessage(Errorlevel.Debug, "Con A val= " + TechAdvancing_Config_Tab.Conditionvalue_A + "|||Con B Val= " + TechAdvancing_Config_Tab.Conditionvalue_B); } catch (Exception ex) { LogOutput.WriteLogMessage(Errorlevel.Error, "Caught error in Reapply All Mods: " + ex.ToString()); } } var researchProjectStoreTotal = new Dictionary <TechLevel, int>(); var researchProjectStoreFinished = new Dictionary <TechLevel, int>(); for (int i = 0; i < Enum.GetValues(typeof(TechLevel)).Length; i++) { researchProjectStoreTotal.Add((TechLevel)i, 0); researchProjectStoreFinished.Add((TechLevel)i, 0); } foreach (var researchProjectDef in DefDatabase <ResearchProjectDef> .AllDefs) { //skip the research if it contains the disabled-tag: #region tagDesc /* * <ResearchProjectDef> * <defName>Firefoam</defName> * <label>firefoam</label> * <description>Allows the construction of firefoam poppers; fire-safety buildings which spread fire-retardant foam in response to encroaching flames.</description> * <baseCost>800</baseCost> * <techLevel>Industrial</techLevel> * <prerequisites> * <li>MicroelectronicsBasics</li> * </prerequisites> * ! <tags> * Important ! <li>ta-ignore</li> * ! </tags> * <requiredResearchBuilding>HiTechResearchBench</requiredResearchBuilding> * <researchViewX>7</researchViewX> * <researchViewY>4</researchViewY> * </ResearchProjectDef> * */ #endregion if (researchProjectDef.tags?.Any(x => x.defName == "ta-ignore") != true) { researchProjectStoreTotal[researchProjectDef.techLevel]++; //total projects for techlevel if (researchProjectDef.IsFinished) { // TODO filter out undefined later researchProjectStoreFinished[researchProjectDef.techLevel]++; //finished projects for techlevel researchProjectDef.ReapplyAllMods(); // TODO always run it? } } else { LogOutput.WriteLogMessage(Errorlevel.Debug, "Found ta-ignore tag in:" + researchProjectDef.defName); } } TechAdvancing.Rules.researchProjectStoreTotal = researchProjectStoreTotal; TechAdvancing.Rules.researchProjectStoreFinished = researchProjectStoreFinished; TechLevel newLevel = TechAdvancing.Rules.GetNewTechLevel(); if (newLevel != TechLevel.Undefined) { if (firstNotificationHidden && DateTime.Now.Subtract(TimeSpan.FromSeconds(5)) > startedAt) //hiding the notification on world start { if (Faction.OfPlayer.def.techLevel < newLevel) { Find.LetterStack.ReceiveLetter("newTechLevelLetterTitle".Translate(), "newTechLevelLetterContents".Translate(isTribe ? "configTribe".Translate() : "configColony".Translate()) + " " + newLevel.ToString() + ".", LetterDefOf.PositiveEvent); } } else { firstNotificationHidden = true; } Faction.OfPlayer.def.techLevel = newLevel; } /*** * how techlevel increases: * player researched all techs of techlevel X and below. the techlevel rises to X+1 * * player researched more than 50% of the techlevel Y then the techlevel rises to Y **/ RecalculateTechlevel(false); }
static RemoveModernStuff() { DebugString.AppendLine("Lord of the Rings - The Third Age - Start Removal Log"); DebugString.AppendLine("Tech Limiter Active: Max Level = " + MAX_TECHLEVEL.ToString()); giveApproppriateTechLevels(); removedDefs = 0; IEnumerable <ResearchProjectDef> projects = DefDatabase <ResearchProjectDef> .AllDefs.Where(rpd => rpd.techLevel > MAX_TECHLEVEL); things = new HashSet <ThingDef>(DefDatabase <ThingDef> .AllDefs.Where(td => td.techLevel > MAX_TECHLEVEL || (td.researchPrerequisites?.Any(rpd => projects.Contains(rpd)) ?? false) || new[] { "Gun_Revolver", "VanometricPowerCell", "PsychicEmanator", "InfiniteChemreactor", "Joywire", "Painstopper" }.Contains(td.defName))); DebugString.AppendLine("RecipeDef Removal List"); var recipeDefsToRemove = DefDatabase <RecipeDef> .AllDefs.Where(rd => rd.products.Any(tcc => things.Contains(tcc.thingDef)) || rd.AllRecipeUsers.All(td => things.Contains(td)) || projects.Contains(rd.researchPrerequisite)).Cast <Def>().ToList(); recipeDefsToRemove?.RemoveAll(x => x.defName == "ExtractMetalFromSlag" || x.defName == "SmeltWeapon" || x.defName == "DestroyWeapon" || x.defName == "OfferingOfPlants_Meagre" || x.defName == "OfferingOfPlants_Decent" || x.defName == "OfferingOfPlants_Sizable" || x.defName == "OfferingOfPlants_Worthy" || x.defName == "OfferingOfPlants_Impressive" || x.defName == "OfferingOfMeat_Meagre" || x.defName == "OfferingOfMeat_Decent" || x.defName == "OfferingOfMeat_Sizable" || x.defName == "OfferingOfMeat_Worthy" || x.defName == "OfferingOfMeat_Impressive" || x.defName == "OfferingOfMeals_Meagre" || x.defName == "OfferingOfMeals_Decent" || x.defName == "OfferingOfMeals_Sizable" || x.defName == "OfferingOfMeals_Worthy" || x.defName == "OfferingOfMeals_Impressive" || x.defName == "ROMV_ExtractBloodVial" || x.defName == "ROMV_ExtractBloodPack" ); RemoveStuffFromDatabase(typeof(DefDatabase <RecipeDef>), recipeDefsToRemove); DebugString.AppendLine("ResearchProjectDef Removal List"); RemoveStuffFromDatabase(typeof(DefDatabase <ResearchProjectDef>), projects.Cast <Def>()); DebugString.AppendLine("Scenario Part Removal List"); FieldInfo getThingInfo = typeof(ScenPart_ThingCount).GetField("thingDef", BindingFlags.NonPublic | BindingFlags.Instance); foreach (ScenarioDef def in DefDatabase <ScenarioDef> .AllDefs) { foreach (ScenPart sp in def.scenario.AllParts) { if (sp is ScenPart_ThingCount && things.Contains((ThingDef)getThingInfo?.GetValue(sp))) { def.scenario.RemovePart(sp); DebugString.AppendLine("- " + sp.Label + " " + ((ThingDef)getThingInfo?.GetValue(sp)).label + " from " + def.label); } } } foreach (ThingCategoryDef thingCategoryDef in DefDatabase <ThingCategoryDef> .AllDefs) { thingCategoryDef.childThingDefs.RemoveAll(things.Contains); } DebugString.AppendLine("Stock Generator Part Cleanup"); foreach (TraderKindDef tkd in DefDatabase <TraderKindDef> .AllDefs) { for (int i = tkd.stockGenerators.Count - 1; i >= 0; i--) { StockGenerator stockGenerator = tkd.stockGenerators[i]; switch (stockGenerator) { case StockGenerator_SingleDef sd when things.Contains(Traverse.Create(sd).Field("thingDef") .GetValue <ThingDef>()): ThingDef def = Traverse.Create(sd).Field("thingDef") .GetValue <ThingDef>(); tkd.stockGenerators.Remove(stockGenerator); DebugString.AppendLine("- " + def.label + " from " + tkd.label + "'s StockGenerator_SingleDef"); break; case StockGenerator_MultiDef md: Traverse thingListTraverse = Traverse.Create(md).Field("thingDefs"); List <ThingDef> thingList = thingListTraverse.GetValue <List <ThingDef> >(); var removeList = thingList.FindAll(things.Contains); removeList?.ForEach(x => DebugString.AppendLine("- " + x.label + " from " + tkd.label + "'s StockGenerator_MultiDef")); thingList.RemoveAll(things.Contains); if (thingList.NullOrEmpty()) { tkd.stockGenerators.Remove(stockGenerator); } else { thingListTraverse.SetValue(thingList); } break; } } } DebugString.AppendLine("IncidentDef Removal List"); IEnumerable <IncidentDef> incidents = DefDatabase <IncidentDef> .AllDefs .Where(id => new[] { typeof (IncidentWorker_ShipChunkDrop ), AccessTools .TypeByName( "IncidentWorker_ShipPartCrash"), typeof (IncidentWorker_QuestJourneyOffer ), typeof (IncidentWorker_ResourcePodCrash ), //typeof(IncidentWorker_RefugeePodCrash), typeof(IncidentWorker_TransportPodCrash), typeof (IncidentWorker_PsychicDrone ), typeof (IncidentWorker_RansomDemand ), typeof (IncidentWorker_ShortCircuit ), typeof (IncidentWorker_OrbitalTraderArrival ), typeof (IncidentWorker_PsychicSoothe ) }.SelectMany( it => it .AllSubclassesNonAbstract() .Concat( it)) .ToArray() .Contains( id .workerClass) || new[] { "Disease_FibrousMechanites", "Disease_SensoryMechanites", "RaidEnemyEscapeShip", "StrangerInBlackJoin" }.Contains( id .defName)).ToList(); foreach (IncidentDef incident in incidents) { incident.targetTags?.Clear(); incident.baseChance = 0f; incident.allowedBiomes?.Clear(); incident.earliestDay = int.MaxValue; } RemoveStuffFromDatabase(typeof(DefDatabase <IncidentDef>), incidents.Cast <Def>()); DebugString.AppendLine("Replaced Ancient Asphalt Road / Ancient Asphalt Highway with Stone Road"); RoadDef[] targetRoads = { RoadDefOf.AncientAsphaltRoad, RoadDefOf.AncientAsphaltHighway }; RoadDef originalRoad = DefDatabase <RoadDef> .GetNamed("StoneRoad"); List <string> fieldNames = AccessTools.GetFieldNames(typeof(RoadDef)); fieldNames.Remove("defName"); foreach (FieldInfo fi in fieldNames.Select(name => AccessTools.Field(typeof(RoadDef), name))) { object fieldValue = fi.GetValue(originalRoad); foreach (RoadDef targetRoad in targetRoads) { fi.SetValue(targetRoad, fieldValue); } } DebugString.AppendLine("Special Hediff Removal List"); RemoveStuffFromDatabase(typeof(DefDatabase <HediffDef>), (hediffs = new[] { HediffDefOf.Gunshot }).Cast <Def>()); DebugString.AppendLine("RaidStrategyDef Removal List"); RemoveStuffFromDatabase(typeof(DefDatabase <RaidStrategyDef>), DefDatabase <RaidStrategyDef> .AllDefs .Where(rs => typeof(ScenPart_ThingCount).IsAssignableFrom(rs.workerClass)).Cast <Def>()); // ItemCollectionGeneratorUtility.allGeneratableItems.RemoveAll(match: things.Contains); // // foreach (Type type in typeof(ItemCollectionGenerator_Standard).AllSubclassesNonAbstract()) // type.GetMethod(name: "Reset")?.Invoke(obj: null, parameters: null); DebugString.AppendLine("ThingDef Removal List"); RemoveStuffFromDatabase(typeof(DefDatabase <ThingDef>), things.ToArray()); DebugString.AppendLine("ThingSetMaker Reset"); ThingSetMakerUtility.Reset(); DebugString.AppendLine("TraitDef Removal List"); RemoveStuffFromDatabase(typeof(DefDatabase <TraitDef>), // { nameof(TraitDefOf.Prosthophobe), "Prosthophile" } ? DefDatabase <TraitDef> .AllDefs .Where(td => new[] { nameof(TraitDefOf.BodyPurist), "Transhumanist" }.Contains(td.defName)) .Cast <Def>()); DebugString.AppendLine("Designators Resolved Again"); MethodInfo resolveDesignatorsAgain = typeof(DesignationCategoryDef).GetMethod("ResolveDesignators", BindingFlags.NonPublic | BindingFlags.Instance); foreach (DesignationCategoryDef dcd in DefDatabase <DesignationCategoryDef> .AllDefs) { resolveDesignatorsAgain?.Invoke(dcd, null); } DebugString.AppendLine("PawnKindDef Removal List"); RemoveStuffFromDatabase(typeof(DefDatabase <PawnKindDef>), DefDatabase <PawnKindDef> .AllDefs .Where(pkd => (!pkd.defaultFactionType?.isPlayer ?? false) && (pkd.race.techLevel > MAX_TECHLEVEL || pkd.defaultFactionType?.techLevel > MAX_TECHLEVEL) && !pkd.defName.EqualsIgnoreCase("Villager") && !pkd.defName.EqualsIgnoreCase("SpaceRefugee")) .Cast <Def>()); DebugString.AppendLine("FactionDef Removal List"); RemoveStuffFromDatabase(typeof(DefDatabase <FactionDef>), DefDatabase <FactionDef> .AllDefs.Where(fd => !fd.isPlayer && fd.techLevel > MAX_TECHLEVEL).Cast <Def>()); DebugString.AppendLine("BackstoryDef Removal List"); BackstoryHandler.RemoveIncompatibleBackstories(DebugString); DebugString.AppendLine("MapGeneratorDef Removal List"); DebugString.AppendLine("- GenStep_SleepingMechanoids"); DebugString.AppendLine("- GenStep_Turrets"); DebugString.AppendLine("- GenStep_Power"); foreach (MapGeneratorDef mgd in DefDatabase <MapGeneratorDef> .AllDefs) { mgd.genSteps.RemoveAll(gs => gs.genStep is GenStep_SleepingMechanoids || gs.genStep is GenStep_Turrets || gs.genStep is GenStep_Power); } DebugString.AppendLine("RuleDef Removal List"); DebugString.AppendLine("- SymbolResolver_AncientCryptosleepCasket"); DebugString.AppendLine("- SymbolResolver_ChargeBatteries"); DebugString.AppendLine("- SymbolResolver_EdgeMannedMortor"); DebugString.AppendLine("- SymbolResolver_FirefoamPopper"); DebugString.AppendLine("- SymbolResolver_MannedMortar"); DebugString.AppendLine("- SymbolResolver_"); foreach (RuleDef rd in DefDatabase <RuleDef> .AllDefs) { rd.resolvers.RemoveAll(sr => sr is SymbolResolver_AncientCryptosleepCasket || sr is SymbolResolver_ChargeBatteries || sr is SymbolResolver_EdgeMannedMortar || sr is SymbolResolver_FirefoamPopper || sr is SymbolResolver_MannedMortar || sr is SymbolResolver_OutdoorLighting); if (rd.resolvers.Count == 0) { rd.resolvers.Add(new SymbolResolver_AddWortToFermentingBarrels()); } } Log.Message("Removed " + removedDefs + " modern defs"); PawnWeaponGenerator.Reset(); PawnApparelGenerator.Reset(); Debug.Log(DebugString.ToString()); DebugString = new StringBuilder(); }
static void Postfix() { if (Faction.OfPlayerSilentFail?.def?.techLevel == null || Faction.OfPlayer.def.techLevel == TechLevel.Undefined) // abort if our techlevel is undefined for some reason { LogOutput.WriteLogMessage(Errorlevel.Debug, "Aborted reasearch manager postfix!"); return; } LogOutput.WriteLogMessage(Errorlevel.Debug, "Research Manager called"); if (Find.CurrentMap == null) { //LogOutput.WriteLogMessage(Errorlevel.Information, "Research Manager called while loading a new map. Flushing old values."); FlushCfg(); } if (firstpass || facName != Faction.OfPlayer.def.defName) { startedAt = DateTime.Now; LogOutput.WriteLogMessage(Errorlevel.Debug, "Research Manager restarted"); facName = Faction.OfPlayer.def.defName; try { GetAndReloadTL(); //store the default value for the techlevel because we will modify it later and we need the one from right now isTribe = factionDefault == TechLevel.Neolithic; //LoadCfgValues(); firstpass = false; } catch (Exception ex) { LogOutput.WriteLogMessage(Errorlevel.Error, "Caught error in Reapply All Mods: " + ex.ToString()); } } UpdateFinishedProjectCounts(); TechLevel newLevel = TechAdvancing.Rules.GetNewTechLevel(); if (newLevel != TechLevel.Undefined) { if (firstNotificationHidden && DateTime.Now.Subtract(TimeSpan.FromSeconds(5)) > startedAt) //hiding the notification on world start { if (Faction.OfPlayer.def.techLevel < newLevel) { Find.LetterStack.ReceiveLetter("newTechLevelLetterTitle".Translate(), "newTechLevelLetterContents".Translate(isTribe ? "configTribe".Translate() : "configColony".Translate()) + " " + newLevel.ToString() + ".", LetterDefOf.PositiveEvent); } } else { firstNotificationHidden = true; } LogOutput.WriteLogMessage(Errorlevel.Debug, $"Factiondeflevel was changed from {Faction.OfPlayer.def.techLevel} to {newLevel} via call #1."); Faction.OfPlayer.def.techLevel = newLevel; } /*** * how techlevel increases: * player researched all techs of techlevel X and below. the techlevel rises to X+1 * * player researched more than 50% of the techlevel Y then the techlevel rises to Y **/ RecalculateTechlevel(false); }
public IEnumerable <ResearchProjectDef> GetExpertiseDefsFor(Pawn pawn, FactionDef faction) { //1. Gather info on that pawn //a. tech level TechLevel factionTechLevel = faction?.techLevel ?? 0; TechLevel childhoodLevel = 0; SkillDef childhoodSkill = null; bool isPlayer = pawn.Faction?.IsPlayer ?? false; techLevel = TechPoolIncludesBackground || !isPlayer?FindBGTechLevel(pawn, out childhoodLevel, out childhoodSkill) : factionTechLevel; TechLevel workingTechLevel = startingTechLevel = techLevel; //b. higest skills SkillRecord highestSkillRecord = pawn.skills.skills.Aggregate(AccessHighestSkill); SkillDef highestSkill = highestSkillRecord.def; IEnumerable <SkillRecord> secondCandidates = pawn.skills.skills.Except(highestSkillRecord).Where(x => SkillIsRelevant(x.def, techLevel)); SkillDef secondSkill = secondCandidates.Aggregate(AccessHighestSkill).def; //c. age float middleAge = pawn.RaceProps.lifeExpectancy / 2; int matureAge = pawn.RaceProps.lifeStageAges.FindLastIndex(x => x.minAge < middleAge); //not always the last possible age because there are mods with an "eldery" stage int growthAdjust = 0; int oldBonus = 0; if (pawn.ageTracker.CurLifeStageIndex < matureAge) { growthAdjust = matureAge - pawn.ageTracker.CurLifeStageIndex; } else if (pawn.ageTracker.AgeBiologicalYears > middleAge) { oldBonus = 1; } //d. special cases isFighter = highestSkill == SkillDefOf.Melee; isShooter = highestSkill == SkillDefOf.Shooting; int fighterHandicap = (isFighter | isShooter) ? 1 : 0; bool guru = techLevel < TechLevel.Archotech && highestSkill == SkillDefOf.Intellectual && highestSkillRecord.Level >= Rand.Range(7, 10); //2. Calculate how many techs he should know int minSlots = techLevel > TechLevel.Medieval ? 1 : oldBonus; int slots = Mathf.Max(minSlots, FactionExpertiseRange(techLevel) - growthAdjust + oldBonus - fighterHandicap); if (slots == 0) { if (Prefs.LogVerbose) { Log.Warning($"... No slots for {pawn.gender.GetObjective()}, returning null. (StartingTechLevel is {techLevel}, CurLifeStageIndex is {pawn.ageTracker.CurLifeStageIndex}, fighterHandicap is {fighterHandicap})"); } return(null); } //3. Info for debugging. if (Prefs.LogVerbose) { StringBuilder stringBuilder = new StringBuilder(); string factionName = faction.label.ToLower() ?? pawn.Possessive().ToLower() + faction; if (TechPoolIncludesStarting) { stringBuilder.Append($"default for {factionName}"); } if (TechPoolIncludesTechLevel) { stringBuilder.AppendWithComma($"{factionTechLevel.ToString().ToLower()} age"); } if (TechPoolIncludesScenario) { stringBuilder.AppendWithComma($"{Find.Scenario.name.ToLower()} scenario"); } if (TechPoolIncludesBackground) { stringBuilder.AppendWithComma($"{childhoodLevel.ToString().ToLower()} childhood & {techLevel.ToString().ToLower()} background"); } Log.Message($"... Including technologies from: " + stringBuilder.ToString() + "."); stringBuilder.Clear(); string guruText = guru ? " (allowing advanced knowledge)" : ""; stringBuilder.Append($"... As {pawn.ageTracker.CurLifeStage.label}, {pawn.ProSubj()} gets {slots} slots. {pawn.Possessive().CapitalizeFirst()} highest relevant skills are {highestSkill.label}{guruText} & {secondSkill.label}."); Log.Message(stringBuilder.ToString()); } //4. Finally, Distribute knowledge bool strict = false; bool useChildhood = childhoodSkill != null && TechPoolIncludesBackground && SkillIsRelevant(childhoodSkill, childhoodLevel) && slots > 1; var filtered = TechTracker.FindTechs(x => TechPool(isPlayer, x, workingTechLevel, strict)); int pass = 0; List <ResearchProjectDef> result = new List <ResearchProjectDef>(); if (guru) { workingTechLevel++; } while (result.Count() < slots) { pass++; filtered.ExecuteEnumerable(); if (filtered.EnumerableNullOrEmpty()) { Log.Warning("[HumanResources] Empty technology pool!"); } var remaining = filtered.Where(x => !result.Contains(x)); if (remaining.EnumerableNullOrEmpty()) { break; } SkillDef skill = null; if (pass == 1 && remaining.Any(x => x.Skills.Contains(highestSkill))) { skill = highestSkill; } else if (pass == 2 && remaining.Any(x => x.Skills.Contains(secondSkill))) { skill = useChildhood ? childhoodSkill : secondSkill; } ResearchProjectDef selected = remaining.RandomElementByWeightWithDefault(x => TechLikelihoodForSkill(pawn, x.Skills, slots, pass, skill), 1f) ?? remaining.RandomElement(); result.Add(selected); //prepare next pass: strict = false; if ((guru && pass == 1) | result.NullOrEmpty()) { workingTechLevel--; } if (useChildhood) { if (pass == 1) { strict = true; workingTechLevel = childhoodLevel; } if (pass == 2) { workingTechLevel = techLevel; } } if (workingTechLevel == 0) { break; } } if (!result.NullOrEmpty()) { return(result); } Log.Error($"[HumanResources] Couldn't calculate any expertise for {pawn}"); return(null); }
public override void DoWindowContents(Rect canvas) { // zooming in seems to cause Text.Font to start at Tiny, make sure it's set to Small for our panels. Text.Font = GameFont.Small; float drawpos = 0; DrawText(canvas, description, ref drawpos); AddSpace(ref drawpos, 10f); if (Widgets.RadioButtonLabeled(new Rect(canvas.x + 20, drawpos, 100f, 60f), "configRadioBtnNeolithic".Translate(), baseTechlvlCfg == 0)) //translation default: Neolithic / Tribal { baseTechlvlCfg = 0; } if (Widgets.RadioButtonLabeled(new Rect(canvas.x + 200f, drawpos, 100f, 60f), "configRadioBtnAutoDetect".Translate(), baseTechlvlCfg == 1)) //translation default: Auto-Detect (default) { baseTechlvlCfg = 1; } if (Widgets.RadioButtonLabeled(new Rect(canvas.x + 400f, drawpos, 100f, 60f), "configRadioBtnIndustrial".Translate(), baseTechlvlCfg == 2)) //translation default: Industrial / Colony { baseTechlvlCfg = 2; } AddSpace(ref drawpos, 70f); DrawText(canvas, "configBaseTechLvl".Translate() + " (" + ((baseTechlvlCfg == 1) ? ((_ResearchManager.isTribe) ? "configTribe".Translate() : "configColony".Translate()) : ((baseTechlvlCfg == 0) ? "configSetToTribe".Translate() : "configSetToColony".Translate())) + "): " + ((baseTechlvlCfg == 1) ? _ResearchManager.factionDefault.ToString().TranslateOrDefault(null, "TA_TL_") : ((baseTechlvlCfg == 0) ? "configNeolithic".Translate() : "configIndustrial".Translate())), ref drawpos); AddSpace(ref drawpos, 20f); baseFactionTechLevel = _ResearchManager.factionDefault; if (baseTechlvlCfg != 1) { baseFactionTechLevel = (baseTechlvlCfg == 0) ? TechLevel.Neolithic : TechLevel.Industrial; } DrawText(canvas, descriptionA2 + " (" + "configWordDefault".Translate() + Conditionvalue_A_Default + ")", ref drawpos); string bufferA = null; string bufferB = null; Widgets.TextFieldNumeric(new Rect(canvas.x + Verse.Text.CalcSize(descriptionA2_calc + " (" + "configWordDefault".Translate() + Conditionvalue_A_Default + ")").x - 25f, canvas.y + drawpos - 22f, 50f, Verse.Text.CalcSize("Text").y), ref Conditionvalue_A, ref bufferA, -100, 100); AddSpace(ref drawpos, 10f); DrawText(canvas, "configExpectedTechLvl".Translate() + " " + ((TechLevel)Math.Min((int)TechLevel.Archotech, (int)previewTechLevels[0])).ToString().TranslateOrDefault(null, "TA_TL_"), ref drawpos); AddSpace(ref drawpos, 20f); DrawText(canvas, descriptionB2.Replace("50", Conditionvalue_B_s.ToString()) + " (" + "configWordDefault".Translate() + Conditionvalue_B_Default + ")", ref drawpos); Widgets.TextFieldNumeric(new Rect(canvas.x + Verse.Text.CalcSize(descriptionB2_calc + " (" + "configWordDefault".Translate() + Conditionvalue_B_Default + ")").x - 25f, canvas.y + drawpos - 22f, 50f, Verse.Text.CalcSize("Text").y), ref Conditionvalue_B, ref bufferB, -100, 100); AddSpace(ref drawpos, 10f); DrawText(canvas, "configExpectedTechLvl".Translate() + " " + ((TechLevel)Math.Min((int)TechLevel.Archotech, (int)previewTechLevels[1])).ToString().TranslateOrDefault(null, "TA_TL_"), ref drawpos); AddSpace(ref drawpos, 20f); DrawText(canvas, descriptionB2_s + " (" + "configWordDefault".Translate() + Conditionvalue_B_s_Default + ")", ref drawpos); AddSpace(ref drawpos, 10f); Conditionvalue_B_s = (int)Widgets.HorizontalSlider(new Rect(canvas.x, canvas.y + drawpos, 500, 15), Conditionvalue_B_s, 1, 100, true, "50%", "1%", "100%", 1); DrawText(new Rect(canvas.x + 530, canvas.y - 5, canvas.width, canvas.height), $"{Conditionvalue_B_s}%", ref drawpos); AddSpace(ref drawpos, 20f); //if (b_configCheckboxNeedTechColonists != (configCheckboxNeedTechColonists == 1)) //{ // previewTechLevels[2] = (Util.ColonyHasHiTechPeople()) ? TechLevel.Archotech : TechAdvancing_Config_Tab.maxTechLevelForTribals; //} b_configCheckboxNeedTechColonists = configCheckboxNeedTechColonists == 1; Widgets.CheckboxLabeled(new Rect(canvas.x, drawpos, Verse.Text.CalcSize("configCheckboxNeedTechColonists".Translate(maxTechLevelForTribals.ToString().TranslateOrDefault(null, "TA_TL_"))).x + 40f, 40f), "configCheckboxNeedTechColonists".Translate(maxTechLevelForTribals.ToString().TranslateOrDefault(null, "TA_TL_")), ref b_configCheckboxNeedTechColonists, false); configCheckboxNeedTechColonists = (b_configCheckboxNeedTechColonists) ? 1 : 0; AddSpace(ref drawpos, 32f); if (previewTechLevels[2] == maxTechLevelForTribals && b_configCheckboxNeedTechColonists) { DrawText(canvas, "configCheckboxNeedTechColonists_CappedAt".Translate(maxTechLevelForTribals.ToString().TranslateOrDefault(null, "TA_TL_")), ref drawpos, false, Color.red); } AddSpace(ref drawpos, 50f); DrawText(canvas, "configResultingTechLvl".Translate() + " " + Rules.GetNewTechLevel().ToString().TranslateOrDefault(null, "TA_TL_"), ref drawpos); AddSpace(ref drawpos, 30f); DrawText(canvas, "availableTechLvls".Translate(), ref drawpos); AddSpace(ref drawpos, 10f); string[] techLevels = Enum.GetNames(typeof(TechLevel)); for (int i = 0; i < techLevels.Length; i++) { DrawText(canvas, techLevels[i].ToString().TranslateOrDefault(null, "TA_TL_") + " = " + i, ref drawpos); } }
static void Postfix() { if (Settings.AllowTechAdvance == true) { TechLevel currentTechLevel = Faction.OfPlayer.def.techLevel; #if DEBUG Log.Warning("Tech Level: " + currentTechLevel); #endif int totalCurrentAndPast = 0; int finishedResearch = 0; foreach (ResearchProjectDef def in DefDatabase <ResearchProjectDef> .AllDefs) { if (def.IsFinished) { ++finishedResearch; //if (def.techLevel <= currentTechLevel) // ++finishedCurrentAndPast; //else // ++finishedFuture; } if (def.techLevel <= currentTechLevel) { ++totalCurrentAndPast; } } int neededTechsToAdvance = 0; bool useStatisPerTier = Settings.StaticNumberResearchPerTier; if (useStatisPerTier) { switch (Faction.OfPlayer.def.techLevel) { case TechLevel.Neolithic: neededTechsToAdvance = Settings.NeolithicNeeded; break; case TechLevel.Medieval: neededTechsToAdvance = Settings.MedievalNeeded; break; case TechLevel.Industrial: neededTechsToAdvance = Settings.IndustrialNeeded; break; case TechLevel.Spacer: neededTechsToAdvance = Settings.SpacerNeeded; break; } } #if DEBUG Log.Warning("Current Tech Level: " + Faction.OfPlayer.def.techLevel); Log.Warning("neededTechsToAdvance: " + neededTechsToAdvance); Log.Warning("totalCurrentAndPast: " + totalCurrentAndPast); Log.Warning("finishedResearch: " + finishedResearch); #endif if ((useStatisPerTier && neededTechsToAdvance < finishedResearch) || (!useStatisPerTier && totalCurrentAndPast + 1 < finishedResearch)) { if (Faction.OfPlayer.def.techLevel < TechLevel.Spacer) { if (Scribe.mode == LoadSaveMode.Inactive) { // Only display this message is not loading Messages.Message( "Advancing Tech Level from [" + currentTechLevel.ToString() + "] to [" + (currentTechLevel + 1).ToString() + "].", MessageTypeDefOf.PositiveEvent); } Faction.OfPlayer.def.techLevel = currentTechLevel + 1; } } else { int needed = (useStatisPerTier) ? neededTechsToAdvance - finishedResearch : totalCurrentAndPast + 1 - finishedResearch; Log.Message("Tech Advance: Need to research [" + needed + "] more technologies"); } } if (Settings.ChangeBaseCosts) { foreach (var cost in Settings.ResearchBaseCosts) { var techDef = ResearchTimeUtil.GetResearchDef(cost.Key); if (techDef != null) { techDef.baseCost = cost.Value; } } } }