public bool ContributeResearch(TieredResource source, string atBody, double timespentInKerbalSeconds)
 {
     if (source.ResearchCategory == hydroponicResearchCategory)
     {
         this.AgroponicResearchProgress += timespentInKerbalSeconds;
         if (this.AgroponicResearchProgress > KerbalTime.KerbalYearsToSeconds(source.ResearchCategory.KerbalYearsToNextTier(this.AgroponicsMaxTier)))
         {
             this.AgroponicResearchProgress = 0;
             ++this.AgroponicsMaxTier;
             return(true);
         }
     }
     else if (source.ResearchCategory == farmingResearchCategory)
     {
         this.AgricultureResearchProgress += timespentInKerbalSeconds;
     }
     else if (source.ResearchCategory == productionResearchCategory)
     {
         this.ProductionResearchProgress += timespentInKerbalSeconds;
     }
     return(false);
 }
        public void TieredProduction_FirstBaseSimulation()
        {
            var enRouteModules = new List <ITieredProducer>()
            {
                // 20% of food capacity  1 module oversupplies our crew of 4
                new StubHydroponic
                {
                    Tier                = TechTier.Tier0, // An agroponics lab that can work with the junky fertilizer we get from Duna
                    ProductionRate      = 1,
                    IsProductionEnabled = true,
                    IsResearchEnabled   = false
                },
                // 55%-20% = 35% of production capacity comes from this - we need two to be over
                new StubHydroponic
                {
                    Tier                = TechTier.Tier2,
                    ProductionRate      = 2,
                    IsProductionEnabled = true,
                    IsResearchEnabled   = true
                },
            };
            var colonizationResearchScenario      = new StubColonizationResearchScenario(TechTier.Tier2);
            Dictionary <string, double> available = new Dictionary <string, double>();
            Dictionary <string, double> noStorage = new Dictionary <string, double>();

            // Kerbal->Duna scenario - plenty of maxtier stuff
            available["Fertilizer-Tier4"] = 1.0;
            available["Snacks-Tier4"]     = 1.0;
            TieredProduction.CalculateResourceUtilization(
                4 /* kerbals */, 1.0 /* seconds*/, enRouteModules, new List <ITieredCombiner>(),
                colonizationResearchScenario, available, noStorage,
                out double timePassedInSeconds, out List <TieredResource> breakthroughs,
                out Dictionary <string, double> consumptionPerSecond,
                out Dictionary <string, double> productionPerSecond,
                out IEnumerable <string> limitingResources,
                out Dictionary <string, double> unusedProduction);
            Assert.AreEqual(timePassedInSeconds, 1.0);
            Assert.AreEqual(false, breakthroughs.Any());
            Assert.AreEqual(4 * (1 - Tier2AgroponicMaxDietRatio), consumptionPerSecond["Snacks-Tier4"] * SecondsPerKerbanDay, TestTolerance);
            Assert.AreEqual(4 * Tier2AgroponicMaxDietRatio, consumptionPerSecond["Fertilizer-Tier4"] * SecondsPerKerbanDay, TestTolerance);
            Assert.AreEqual(4 * (Tier2AgroponicMaxDietRatio - Tier0AgroponicMaxDietRatio), colonizationResearchScenario.AgroponicResearchProgress, TestTolerance);
            Assert.IsFalse(limitingResources.Any());
            Assert.AreEqual(0.2, unusedProduction["HydroponicSnacks-Tier0"], TestTolerance);
            Assert.AreEqual(0.6, unusedProduction["HydroponicSnacks-Tier2"], TestTolerance);


            // Duna return scenario - still got the max-tier stuff, but added some local stuff
            available["Fertilizer-Tier0"] = 1.0;
            available["Snacks-Tier0"]     = 1.0;
            // Just about ready to tick over the research counter
            colonizationResearchScenario.AgroponicResearchProgress =
                KerbalTime.KerbalYearsToSeconds(StubColonizationResearchScenario.hydroponicResearchCategory.KerbalYearsToNextTier(TechTier.Tier2)) - 0.00001;
            TieredProduction.CalculateResourceUtilization(
                4 /* kerbals */, 1.0 /* seconds*/, enRouteModules, new List <ITieredCombiner>(),
                colonizationResearchScenario, available, noStorage,
                out timePassedInSeconds, out breakthroughs, out consumptionPerSecond,
                out productionPerSecond, out limitingResources, out unusedProduction);
            Assert.AreEqual(timePassedInSeconds, 1.0);
            Assert.AreEqual(1, breakthroughs.Count);
            // We're burning T0 fertilizer in the T0 agro lab
            Assert.AreEqual(4 * Tier0AgroponicMaxDietRatio,
                            consumptionPerSecond["Fertilizer-Tier0"] * SecondsPerKerbanDay, TestTolerance);
            // And burning reduced maxtier ferilizer
            Assert.AreEqual(4 * (Tier2AgroponicMaxDietRatio - Tier0AgroponicMaxDietRatio),
                            consumptionPerSecond["Fertilizer-Tier4"] * SecondsPerKerbanDay, TestTolerance);
            // And snacking a few local things
            Assert.AreEqual(4 * (Tier0AgricultureMaxDietRatio - Tier2AgroponicMaxDietRatio),
                            consumptionPerSecond["Snacks-Tier0"] * SecondsPerKerbanDay, TestTolerance);
            // And making up the rest from the snack stores.
            Assert.AreEqual(4 * (1 - Tier0AgricultureMaxDietRatio),
                            consumptionPerSecond["Snacks-Tier4"] * SecondsPerKerbanDay, TestTolerance);
            Assert.AreEqual(0.2, unusedProduction["HydroponicSnacks-Tier0"], TestTolerance);
            Assert.AreEqual(0.6, unusedProduction["HydroponicSnacks-Tier2"], TestTolerance);

            Assert.AreEqual(0.0, colonizationResearchScenario.AgroponicResearchProgress);    // Progress is reset
            Assert.AreEqual(TechTier.Tier3, colonizationResearchScenario.AgroponicsMaxTier); // Next tier is up

            // And we run out of our KSP-provided fertilizer
            available.Remove("Fertilizer-Tier4");
            TieredProduction.CalculateResourceUtilization(
                4 /* kerbals */, 1.0 /* seconds*/, enRouteModules, new List <ITieredCombiner>(),
                colonizationResearchScenario, available, noStorage,
                out timePassedInSeconds, out breakthroughs, out consumptionPerSecond,
                out productionPerSecond, out limitingResources, out unusedProduction);
            Assert.AreEqual(timePassedInSeconds, 1.0);
            Assert.AreEqual(false, breakthroughs.Any());
            // We're burning T0 fertilizer in the T0 agro lab
            Assert.AreEqual(4 * Tier0AgroponicMaxDietRatio,
                            consumptionPerSecond["Fertilizer-Tier0"] * SecondsPerKerbanDay, TestTolerance);
            // And snacking on more local things now that the T2-agro-lab is offline
            Assert.AreEqual(4 * (Tier0AgricultureMaxDietRatio - Tier0AgroponicMaxDietRatio),
                            consumptionPerSecond["Snacks-Tier0"] * SecondsPerKerbanDay, TestTolerance);
            // And making up the rest from the snack stores.
            Assert.AreEqual(4 * (1 - Tier0AgricultureMaxDietRatio),
                            consumptionPerSecond["Snacks-Tier4"] * SecondsPerKerbanDay, TestTolerance);

            Assert.AreEqual(0.0, colonizationResearchScenario.AgroponicResearchProgress); // no gear for next tier (and no T2 progress anyway)

            Assert.AreEqual("Fertilizer-Tier2", limitingResources.Single());
            Assert.AreEqual(2.0, unusedProduction["HydroponicSnacks-Tier2"], TestTolerance);
            Assert.AreEqual(0.2, unusedProduction["HydroponicSnacks-Tier0"], TestTolerance);
        }