private static bool TryFindScrounger(TechTier scannerTier, Vessel candidate, TieredResource stuffResource, out TechTier highestScroungerTier) { highestScroungerTier = TechTier.Tier0; // Don't trust KSP to actually always have these things populated; if (candidate.protoVessel == null || candidate.protoVessel.protoPartSnapshots == null) { return(false); } bool hasScrounger = false; foreach (var protoPart in candidate.protoVessel.protoPartSnapshots) { if (protoPart.modules == null) { continue; } // Unloaded vessels have modules, but they're not truly populated - that is, the class for // the module is created, but the members have their default values... So we can find the // stuff that's coded in the part description (in this case) the "output" field here: if (protoPart.partPrefab.Modules.OfType <PksTieredResourceConverter>().Any(c => c.Output == stuffResource)) { hasScrounger = true; // ...But to get hold of the this that are set in the VAB (like the tier), you have // to parse it out of the config nodes. foreach (var protoModule in protoPart.modules.Where(m => m.moduleName == nameof(PksTieredResourceConverter))) { TechTier tier = PksTieredResourceConverter.GetTechTierFromConfig(protoModule.moduleValues); if (tier > scannerTier) { // There's no practical use of finding stuff near this base - even if it has lower // tier scroungers somewhere, the higher tier ones should be taking priority. return(false); } else if (tier > highestScroungerTier) { highestScroungerTier = tier; } } } } return(hasScrounger && stuffResource.MadeFrom(highestScroungerTier) != null); }
internal static TierSuitability GetTierSuitability( IColonizationResearchScenario colonizationResearchScenario, TieredResource tieredResource, TechTier tier, TechTier partMaxTier, string body) { if (body == null && tieredResource.ResearchCategory.Type != ProductionRestriction.Space) { return(TierSuitability.BodyNotSelected); } if (tier > partMaxTier) { return(TierSuitability.PartDoesntSupportTier); } var maxTier = colonizationResearchScenario.GetMaxUnlockedTier(tieredResource, body); if (tier > maxTier) { return(TierSuitability.NotResearched); } bool subordinateTechIsCapping = false; for (TieredResource requiredResource = tieredResource.MadeFrom(tier); requiredResource != null; requiredResource = requiredResource.MadeFrom(tier)) { if (requiredResource.ResearchCategory.Type != tieredResource.ResearchCategory.Type) { // This would be a case where the made-from is produced in one situation (e.g. landed) and consumed // in another (in space). We don't know where the stuff is produced, so we'll just have to assume // we can get the stuff from somewhere. break; } var t = colonizationResearchScenario.GetMaxUnlockedTier(requiredResource, body); if (tier > t) { return(TierSuitability.LacksSubordinateResearch); } else if (tier == t) { subordinateTechIsCapping = true; } } TechTier maxScanningTier = string.IsNullOrEmpty(body) ? TechTier.Tier4 : colonizationResearchScenario.GetMaxUnlockedScanningTier(body); if (tier > maxScanningTier) { return(TierSuitability.LacksScanner); } if (tier < maxTier && !subordinateTechIsCapping && (string.IsNullOrEmpty(body) || tier < maxScanningTier)) { return(TierSuitability.UnderTier); } return(TierSuitability.Ideal); }