예제 #1
0
		State prev_state;                                // State during previous GPU frame update

		// pseudo-ctor
		public override void OnStart(StartState state)
		{
			// don't break tutorial scenarios
			if (Lib.DisableScenario(this)) return;

			// check if has Connected Living Space mod
			hasCLS = Lib.HasAssembly("ConnectedLivingSpace");

			// if part has Gravity Ring, find it.
			gravityRing = part.FindModuleImplementing<GravityRing>();
			hasGravityRing = gravityRing != null;

			// calculate habitat internal volume
			if (volume <= double.Epsilon) volume = Lib.PartVolume(part);

			// calculate habitat external surface
			if (surface <= double.Epsilon) surface = Lib.PartSurface(part);

			// set RMB UI status strings
			Volume = Lib.HumanReadableVolume(volume);
			Surface = Lib.HumanReadableSurface(surface);

			// hide toggle if specified
			Events["Toggle"].active = toggle;
			Actions["Action"].active = toggle;

			// create animators
			if (!hasGravityRing)
			{
				inflate_anim = new Animator(part, inflate);
			}

			perctDeployed = Lib.Level(part, "Atmosphere", true);

			if (perctDeployed == 1)
			{
				RefreshDialog();
				SetPassable(true);
			}

			// configure on start
			Configure(true);
		}
예제 #2
0
        public static void update(Vessel v, vessel_info vi, vessel_data vd, vessel_resources resources, double elapsed_s)
        {
            // get most used resource handlers
            resource_info ec = resources.Info(v, "ElectricCharge");

            // for each part
            foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
            {
                // a part can contain multiple resource converters
                int converter_index = 0;

                // get part prefab (required for module properties)
                Part part_prefab = PartLoader.getPartInfoByName(p.partName).partPrefab;

                // for each module
                foreach (ProtoPartModuleSnapshot m in p.modules)
                {
                    // get the module prefab
                    PartModule module_prefab = Lib.FindModule(part_prefab, m.moduleName);

                    // if the prefab doesn't contain this module, skip it
                    if (!module_prefab)
                    {
                        continue;
                    }

                    // process modules
                    switch (m.moduleName)
                    {
                    case "Reliability":                  Reliability.BackgroundUpdate(v, m, module_prefab as Reliability, elapsed_s);                 break;

                    case "Scrubber":                     Scrubber.BackgroundUpdate(v, m, module_prefab as Scrubber, vi, resources, elapsed_s);        break;

                    case "Recycler":                     Recycler.BackgroundUpdate(v, m, module_prefab as Recycler, resources, elapsed_s);            break;

                    case "Greenhouse":                   Greenhouse.BackgroundUpdate(v, p, m, module_prefab as Greenhouse, vi, resources, elapsed_s); break;

                    case "GravityRing":                  GravityRing.BackgroundUpdate(v, p, m, module_prefab as GravityRing, resources, elapsed_s);   break;

                    case "Emitter":                      Emitter.BackgroundUpdate(v, p, m, module_prefab as Emitter, ec, elapsed_s);                  break;

                    case "ModuleCommand":                ProcessCommand(v, p, m, module_prefab as ModuleCommand, resources, elapsed_s);               break;

                    case "ModuleDeployableSolarPanel":   ProcessPanel(v, p, m, module_prefab as ModuleDeployableSolarPanel, vi, ec, elapsed_s);       break;

                    case "ModuleGenerator":              ProcessGenerator(v, p, m, module_prefab as ModuleGenerator, resources, elapsed_s);           break;

                    case "ModuleResourceConverter":
                    case "ModuleKPBSConverter":
                    case "FissionReactor":               ProcessConverter(v, p, m, part_prefab, converter_index++, resources, elapsed_s);             break;

                    case "ModuleResourceHarvester":      ProcessHarvester(v, p, m, module_prefab as ModuleResourceHarvester, resources, elapsed_s);   break;

                    case "ModuleAsteroidDrill":          ProcessAsteroidDrill(v, p, m, module_prefab as ModuleAsteroidDrill, resources, elapsed_s);   break;

                    case "ModuleScienceConverter":       ProcessLab(v, p, m, module_prefab as ModuleScienceConverter, ec, elapsed_s);                 break;

                    case "ModuleLight":
                    case "ModuleColoredLensLight":
                    case "ModuleMultiPointSurfaceLight": ProcessLight(v, p, m, module_prefab as ModuleLight, ec, elapsed_s);                          break;

                    case "SCANsat":
                    case "ModuleSCANresourceScanner":    ProcessScanner(v, p, m, module_prefab, part_prefab, vd, ec, elapsed_s);                      break;

                    case "ModuleCurvedSolarPanel":       ProcessCurvedPanel(v, p, m, module_prefab, part_prefab, vi, ec, elapsed_s);                  break;

                    case "FissionGenerator":             ProcessFissionGenerator(v, p, m, module_prefab, ec, elapsed_s);                              break;

                    case "ModuleRadioisotopeGenerator":  ProcessRadioisotopeGenerator(v, p, m, module_prefab, ec, elapsed_s);                         break;

                    case "ModuleCryoTank":               ProcessCryoTank(v, p, m, module_prefab, resources, elapsed_s);                               break;
                    }
                }
            }
        }
예제 #3
0
        public static void update(Vessel v, vessel_info vi, VesselData vd, vessel_resources resources, double elapsed_s)
        {
            // get most used resource handlers
            resource_info ec = resources.Info(v, "ElectricCharge");

            // store data required to support multiple modules of same type in a part
            var PD = new Dictionary <string, Lib.module_prefab_data>();

            // for each part
            foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
            {
                // get part prefab (required for module properties)
                Part part_prefab = PartLoader.getPartInfoByName(p.partName).partPrefab;

                // get all module prefabs
                var module_prefabs = part_prefab.FindModulesImplementing <PartModule>();

                // clear module indexes
                PD.Clear();

                // for each module
                foreach (ProtoPartModuleSnapshot m in p.modules)
                {
                    // get module type
                    // if the type is unknown, skip it
                    module_type type = ModuleType(m.moduleName);
                    if (type == module_type.Unknown)
                    {
                        continue;
                    }

                    // get the module prefab
                    // if the prefab doesn't contain this module, skip it
                    PartModule module_prefab = Lib.ModulePrefab(module_prefabs, m.moduleName, PD);
                    if (!module_prefab)
                    {
                        continue;
                    }

                    // if the module is disabled, skip it
                    // note: this must be done after ModulePrefab is called, so that indexes are right
                    if (!Lib.Proto.GetBool(m, "isEnabled"))
                    {
                        continue;
                    }

                    // process modules
                    // note: this should be a fast switch, possibly compiled to a jump table
                    switch (type)
                    {
                    case module_type.Reliability:           Reliability.BackgroundUpdate(v, p, m, module_prefab as Reliability);                        break;

                    case module_type.Experiment:            Experiment.BackgroundUpdate(v, m, module_prefab as Experiment, ec, elapsed_s);              break;

                    case module_type.Greenhouse:            Greenhouse.BackgroundUpdate(v, m, module_prefab as Greenhouse, vi, resources, elapsed_s);   break;

                    case module_type.GravityRing:           GravityRing.BackgroundUpdate(v, p, m, module_prefab as GravityRing, ec, elapsed_s);         break;

                    case module_type.Emitter:               Emitter.BackgroundUpdate(v, p, m, module_prefab as Emitter, ec, elapsed_s);                 break;

                    case module_type.Harvester:             Harvester.BackgroundUpdate(v, m, module_prefab as Harvester, elapsed_s);                    break;

                    case module_type.Laboratory:            Laboratory.BackgroundUpdate(v, p, m, module_prefab as Laboratory, ec, elapsed_s);           break;

                    case module_type.Command:               ProcessCommand(v, p, m, module_prefab as ModuleCommand, resources, elapsed_s);              break;

                    case module_type.Panel:                 ProcessPanel(v, p, m, module_prefab as ModuleDeployableSolarPanel, vi, ec, elapsed_s);      break;

                    case module_type.Generator:             ProcessGenerator(v, p, m, module_prefab as ModuleGenerator, resources, elapsed_s);          break;

                    case module_type.Converter:             ProcessConverter(v, p, m, module_prefab as ModuleResourceConverter, resources, elapsed_s);  break;

                    case module_type.Drill:                 ProcessHarvester(v, p, m, module_prefab as ModuleResourceHarvester, resources, elapsed_s);  break;

                    case module_type.AsteroidDrill:         ProcessAsteroidDrill(v, p, m, module_prefab as ModuleAsteroidDrill, resources, elapsed_s);  break;

                    case module_type.StockLab:              ProcessStockLab(v, p, m, module_prefab as ModuleScienceConverter, ec, elapsed_s);           break;

                    case module_type.Light:                 ProcessLight(v, p, m, module_prefab as ModuleLight, ec, elapsed_s);                         break;

                    case module_type.Scanner:               ProcessScanner(v, p, m, module_prefab, part_prefab, vd, ec, elapsed_s);                     break;

                    case module_type.CurvedPanel:           ProcessCurvedPanel(v, p, m, module_prefab, part_prefab, vi, ec, elapsed_s);                 break;

                    case module_type.FissionGenerator:      ProcessFissionGenerator(v, p, m, module_prefab, ec, elapsed_s);                             break;

                    case module_type.RadioisotopeGenerator: ProcessRadioisotopeGenerator(v, p, m, module_prefab, ec, elapsed_s);                        break;

                    case module_type.CryoTank:              ProcessCryoTank(v, p, m, module_prefab, resources, elapsed_s);                              break;
                    }
                }
            }
        }
예제 #4
0
		public static void BackgroundUpdate(Vessel vessel, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, GravityRing ring, Resource_info ec, double elapsed_s)
		{
			// if the module is either non-deployable or deployed
			if (ring.deploy.Length == 0 || Lib.Proto.GetBool(m, "deployed"))
			{
				// consume ec
				ec.Consume(ring.ec_rate * elapsed_s);
			}
		}
예제 #5
0
        public Comforts(List <Part> parts, bool env_firm_ground, bool env_not_alone, bool env_call_home)
        {
            // environment factors
            firm_ground = env_firm_ground;
            not_alone   = env_not_alone;
            call_home   = env_call_home;

            // for each parts
            foreach (Part p in parts)
            {
                // for each modules in part
                foreach (PartModule m in p.Modules)
                {
                    // skip disabled modules
                    if (!m.isEnabled)
                    {
                        continue;
                    }

                    // comfort
                    if (m.moduleName == "Comfort")
                    {
                        Comfort c = m as Comfort;
                        switch (c.bonus)
                        {
                        case "firm-ground": firm_ground = true; break;

                        case "not-alone": not_alone = true; break;

                        case "call-home": call_home = true; break;

                        case "exercise": exercise = true; break;

                        case "panorama": panorama = true; break;

                        case "plants": plants = true; break;
                        }
                    }
                    // gravity ring
                    // - ignoring if ec is present or not here
                    else if (m.moduleName == "GravityRing")
                    {
                        GravityRing ring = m as GravityRing;
                        firm_ground |= ring.deployed;
                    }
                }
            }

            // calculate factor
            factor = 0.1;
            if (firm_ground)
            {
                factor += PreferencesComfort.Instance.firmGround;
            }
            if (not_alone)
            {
                factor += PreferencesComfort.Instance.notAlone;
            }
            if (call_home)
            {
                factor += PreferencesComfort.Instance.callHome;
            }
            if (exercise)
            {
                factor += PreferencesComfort.Instance.exercise;
            }
            if (panorama)
            {
                factor += PreferencesComfort.Instance.panorama;
            }
            factor = Lib.Clamp(factor, 0.1, 1.0);
        }
예제 #6
0
        State prev_state;                              // State during previous GPU frame update

        // pseudo-ctor
        public override void OnStart(StartState state)
        {
            // don't break tutorial scenarios
            if (Lib.DisableScenario(this))
            {
                return;
            }

            // check if has Connected Living Space mod
            hasCLS = Lib.HasAssembly("ConnectedLivingSpace");

            // if part has Gravity Ring, find it.
            gravityRing    = part.FindModuleImplementing <GravityRing>();
            hasGravityRing = gravityRing != null;

            // calculate habitat internal volume
            if (volume <= double.Epsilon)
            {
                volume = Lib.PartVolume(part);
            }

            // calculate habitat external surface
            if (surface <= double.Epsilon)
            {
                surface = Lib.PartSurface(part);
            }

            // set RMB UI status strings
            Volume  = Lib.HumanReadableVolume(volume);
            Surface = Lib.HumanReadableSurface(surface);

            // hide toggle if specified
            Events["Toggle"].active  = toggle;
            Actions["Action"].active = toggle;

            // create animators
            if (!hasGravityRing)
            {
                inflate_anim = new Animator(part, inflate);
            }

            perctDeployed = Lib.Level(part, "Atmosphere", true);

            switch (this.state)
            {
            case State.enabled: Set_flow(true); break;

            case State.disabled: Set_flow(false); break;

            case State.pressurizing: Set_flow(true); break;

            case State.depressurizing: Set_flow(false); break;
            }

            if (Get_inflate_string().Length == 0)             // not inflatable
            {
                SetPassable(true);
                UpdateIVA(true);
            }
            else
            {
                SetPassable(Math.Truncate(Math.Abs((perctDeployed + ResourceBalance.precision) - 1.0) * 100000) / 100000 <= ResourceBalance.precision);
                UpdateIVA(Math.Truncate(Math.Abs((perctDeployed + ResourceBalance.precision) - 1.0) * 100000) / 100000 <= ResourceBalance.precision);
            }

            if (Lib.IsFlight())
            {
                // For fix IVA when crewTransfered occur, add event to define flag for FixedUpdate
                GameEvents.onCrewTransferred.Add(UpdateCrew);
            }

            // configure on start
            Configure(true);
        }
예제 #7
0
        // volume / surface evaluation at prefab compilation
        public override void OnLoad(ConfigNode node)
        {
            // volume/surface calcs are quite slow and memory intensive, so we do them only once on the prefab
            // then get the prefab values from OnStart. Moreover, we cache the results in the
            // Kerbalism\HabitatData.cache file and reuse those cached results on next game launch.
            if (HighLogic.LoadedScene == GameScenes.LOADING)
            {
                if (volume <= 0.0 || surface <= 0.0)
                {
                    if (habitatDatabase == null)
                    {
                        ConfigNode   dbRootNode   = ConfigNode.Load(HabitatDataCachePath);
                        ConfigNode[] habInfoNodes = dbRootNode?.GetNodes(habitatDataCacheNodeName);
                        habitatDatabase = new Dictionary <string, Lib.PartVolumeAndSurfaceInfo>();

                        if (habInfoNodes != null)
                        {
                            for (int i = 0; i < habInfoNodes.Length; i++)
                            {
                                string partName = habInfoNodes[i].GetValue("partName") ?? string.Empty;
                                if (!string.IsNullOrEmpty(partName) && !habitatDatabase.ContainsKey(partName))
                                {
                                    habitatDatabase.Add(partName, new Lib.PartVolumeAndSurfaceInfo(habInfoNodes[i]));
                                }
                            }
                        }
                    }

                    // SSTU specific support copypasted from the old system, not sure how well this works
                    foreach (PartModule pm in part.Modules)
                    {
                        if (pm.moduleName == "SSTUModularPart")
                        {
                            Bounds bb = Lib.ReflectionCall <Bounds>(pm, "getModuleBounds", new Type[] { typeof(string) }, new string[] { "CORE" });
                            if (bb != null)
                            {
                                if (volume <= 0.0)
                                {
                                    volume = Lib.BoundsVolume(bb) * 0.785398;                                                // assume it's a cylinder
                                }
                                if (surface <= 0.0)
                                {
                                    surface = Lib.BoundsSurface(bb) * 0.95493;                                                 // assume it's a cylinder
                                }
                            }
                            return;
                        }
                    }

                    string configPartName = part.name.Replace('.', '_');
                    Lib.PartVolumeAndSurfaceInfo partInfo;
                    if (!habitatDatabase.TryGetValue(configPartName, out partInfo))
                    {
                        // Find deploy/retract animations, either here on in the gravityring module
                        // then set the part to the deployed state before doing the volume/surface calcs
                        // if part has Gravity Ring, find it.
                        gravityRing    = part.FindModuleImplementing <GravityRing>();
                        hasGravityRing = gravityRing != null;

                        // create animators and set the model to the deployed state
                        if (hasGravityRing)
                        {
                            gravityRing.deploy_anim          = new Animator(part, gravityRing.deploy);
                            gravityRing.deploy_anim.reversed = gravityRing.animBackwards;

                            if (gravityRing.deploy_anim.IsDefined)
                            {
                                gravityRing.deploy_anim.Still(1.0);
                            }
                        }
                        else
                        {
                            inflate_anim          = new Animator(part, inflate);
                            inflate_anim.reversed = animBackwards;

                            if (inflate_anim.IsDefined)
                            {
                                inflate_anim.Still(1.0);
                            }
                        }

                        // get surface and volume
                        partInfo = Lib.GetPartVolumeAndSurface(part, Settings.VolumeAndSurfaceLogging);

                        habitatDatabase.Add(configPartName, partInfo);
                    }

                    partInfo.GetUsingMethod(
                        volumeAndSurfaceMethod != Lib.VolumeAndSurfaceMethod.Best ? volumeAndSurfaceMethod : partInfo.bestMethod,
                        out double infoVolume, out double infoSurface, substractAttachementNodesSurface);

                    if (volume <= 0.0)
                    {
                        volume = infoVolume;
                    }
                    if (surface <= 0.0)
                    {
                        surface = infoSurface;
                    }
                }
            }
        }
예제 #8
0
		public RingDevice(GravityRing ring)
		{
			this.ring = ring;
		}
예제 #9
0
        public static void Update(Vessel v, VesselData vd, VesselResources resources, double elapsed_s)
        {
            if (!Lib.IsVessel(v))
            {
                return;
            }

            // get most used resource handlers
            ResourceInfo ec = resources.GetResource(v, "ElectricCharge");

            List <ResourceInfo>         allResources       = resources.GetAllResources(v);
            Dictionary <string, double> availableResources = new Dictionary <string, double>();

            foreach (var ri in allResources)
            {
                availableResources[ri.ResourceName] = ri.Amount;
            }
            List <KeyValuePair <string, double> > resourceChangeRequests = new List <KeyValuePair <string, double> >();

            foreach (var e in Background_PMs(v))
            {
                switch (e.type)
                {
                case Module_type.Reliability: Reliability.BackgroundUpdate(v, e.p, e.m, e.module_prefab as Reliability, elapsed_s); break;

                case Module_type.Experiment: (e.module_prefab as Experiment).BackgroundUpdate(v, vd, e.m, ec, resources, elapsed_s); break;                         // experiments use the prefab as a singleton instead of a static method

                case Module_type.Greenhouse: Greenhouse.BackgroundUpdate(v, e.m, e.module_prefab as Greenhouse, vd, resources, elapsed_s); break;

                case Module_type.GravityRing: GravityRing.BackgroundUpdate(v, e.p, e.m, e.module_prefab as GravityRing, ec, elapsed_s); break;

                case Module_type.Harvester: Harvester.BackgroundUpdate(v, e.m, e.module_prefab as Harvester, elapsed_s); break;                         // Kerbalism ground and air harvester module

                case Module_type.Laboratory: Laboratory.BackgroundUpdate(v, e.p, e.m, e.module_prefab as Laboratory, ec, elapsed_s); break;

                case Module_type.Command: ProcessCommand(v, e.p, e.m, e.module_prefab as ModuleCommand, resources, elapsed_s); break;

                case Module_type.Generator: ProcessGenerator(v, e.p, e.m, e.module_prefab as ModuleGenerator, resources, elapsed_s); break;

                case Module_type.Converter: ProcessConverter(v, e.p, e.m, e.module_prefab as ModuleResourceConverter, resources, elapsed_s); break;

                case Module_type.Drill: ProcessDrill(v, e.p, e.m, e.module_prefab as ModuleResourceHarvester, resources, elapsed_s); break;                         // Stock ground harvester module

                // case Module_type.AsteroidDrill: ProcessAsteroidDrill(v, e.p, e.m, e.module_prefab as ModuleAsteroidDrill, resources, elapsed_s); break; // Stock asteroid harvester module
                case Module_type.StockLab: ProcessStockLab(v, e.p, e.m, e.module_prefab as ModuleScienceConverter, ec, elapsed_s); break;

                case Module_type.Light: ProcessLight(v, e.p, e.m, e.module_prefab as ModuleLight, ec, elapsed_s); break;

                case Module_type.Scanner: KerbalismScansat.BackgroundUpdate(v, e.p, e.m, e.module_prefab as KerbalismScansat, e.part_prefab, vd, ec, elapsed_s); break;

                case Module_type.FissionGenerator: ProcessFissionGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.RadioisotopeGenerator: ProcessRadioisotopeGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.CryoTank: ProcessCryoTank(v, e.p, e.m, e.module_prefab, resources, ec, elapsed_s); break;

                case Module_type.FNGenerator: ProcessFNGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.SolarPanelFixer: SolarPanelFixer.BackgroundUpdate(v, e.m, e.module_prefab as SolarPanelFixer, vd, ec, elapsed_s); break;

                case Module_type.KerbalismSentinel: KerbalismSentinel.BackgroundUpdate(v, e.m, e.module_prefab as KerbalismSentinel, vd, ec, elapsed_s); break;

                case Module_type.APIModule: ProcessApiModule(v, e.p, e.m, e.part_prefab, e.module_prefab, resources, availableResources, resourceChangeRequests, elapsed_s); break;
                }
            }
        }
예제 #10
0
        public static void Update(Vessel v, Vessel_info vi, VesselData vd, Vessel_resources resources, double elapsed_s)
        {
            if (!Lib.IsVessel(v))
            {
                return;
            }

            // get most used resource handlers
            Resource_info ec = resources.Info(v, "ElectricCharge");

            // This is basically handled in cache. However, when accelerating time warp while
            // the vessel is in shadow, the cache logic doesn't kick in soon enough. So we double-check here
            if (TimeWarp.CurrentRate > 1000.0f || elapsed_s > 150)              // we're time warping fast...
            {
                vi.highspeedWarp(v);
            }

            foreach (var e in Background_PMs(v))
            {
                switch (e.type)
                {
                case Module_type.Reliability: Reliability.BackgroundUpdate(v, e.p, e.m, e.module_prefab as Reliability); break;

                case Module_type.Experiment: Experiment.BackgroundUpdate(v, e.m, e.module_prefab as Experiment, ec, resources, elapsed_s); break;

                case Module_type.Greenhouse: Greenhouse.BackgroundUpdate(v, e.m, e.module_prefab as Greenhouse, vi, resources, elapsed_s); break;

                case Module_type.GravityRing: GravityRing.BackgroundUpdate(v, e.p, e.m, e.module_prefab as GravityRing, ec, elapsed_s); break;

                case Module_type.Emitter: Emitter.BackgroundUpdate(v, e.p, e.m, e.module_prefab as Emitter, ec, elapsed_s); break;

                case Module_type.Harvester: Harvester.BackgroundUpdate(v, e.m, e.module_prefab as Harvester, elapsed_s); break;                         // Kerbalism ground and air harvester module

                case Module_type.Laboratory: Laboratory.BackgroundUpdate(v, e.p, e.m, e.module_prefab as Laboratory, ec, elapsed_s); break;

                case Module_type.Command: ProcessCommand(v, e.p, e.m, e.module_prefab as ModuleCommand, resources, elapsed_s); break;

                case Module_type.Panel: ProcessPanel(v, e.p, e.m, e.module_prefab as ModuleDeployableSolarPanel, vi, ec, elapsed_s); break;

                case Module_type.Generator: ProcessGenerator(v, e.p, e.m, e.module_prefab as ModuleGenerator, resources, elapsed_s); break;

                case Module_type.Converter: ProcessConverter(v, e.p, e.m, e.module_prefab as ModuleResourceConverter, resources, elapsed_s); break;

                case Module_type.Drill: ProcessDrill(v, e.p, e.m, e.module_prefab as ModuleResourceHarvester, resources, elapsed_s); break;                         // Stock ground harvester module

                case Module_type.AsteroidDrill: ProcessAsteroidDrill(v, e.p, e.m, e.module_prefab as ModuleAsteroidDrill, resources, elapsed_s); break;             // Stock asteroid harvester module

                case Module_type.StockLab: ProcessStockLab(v, e.p, e.m, e.module_prefab as ModuleScienceConverter, ec, elapsed_s); break;

                case Module_type.Light: ProcessLight(v, e.p, e.m, e.module_prefab as ModuleLight, ec, elapsed_s); break;

                case Module_type.Scanner: KerbalismScansat.BackgroundUpdate(v, e.p, e.m, e.module_prefab as KerbalismScansat, e.part_prefab, vd, ec, elapsed_s); break;

                case Module_type.CurvedPanel: ProcessCurvedPanel(v, e.p, e.m, e.module_prefab, e.part_prefab, vi, ec, elapsed_s); break;

                case Module_type.FissionGenerator: ProcessFissionGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.RadioisotopeGenerator: ProcessRadioisotopeGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.CryoTank: ProcessCryoTank(v, e.p, e.m, e.module_prefab, resources, ec, elapsed_s); break;

                case Module_type.FNGenerator: ProcessFNGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.NonRechargeBattery: ProcessNonRechargeBattery(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.KerbalismProcess: KerbalismProcess.BackgroundUpdate(v, e.m, e.module_prefab as KerbalismProcess, ec, resources, elapsed_s); break;
                }
            }
        }
예제 #11
0
  // called at every simulation step
  public void FixedUpdate()
  {
    // do nothing if paused
    if (Lib.IsPaused()) return;

    // do nothing if DB isn't ready
    if (!DB.Ready()) return;

    // for each vessel
    foreach(Vessel vessel in FlightGlobals.Vessels)
    {
      // skip invalid vessels
      if (!Lib.IsVessel(vessel)) continue;

      // skip loaded vessels
      if (vessel.loaded) continue;

      // get vessel data from the db
      vessel_data vd = DB.VesselData(vessel.id);

      // get vessel info from the cache
      vessel_info info = Cache.VesselInfo(vessel);

      // calculate atmospheric factor (proportion of flux not blocked by atmosphere)
      double atmo_factor = Sim.AtmosphereFactor(vessel.mainBody, info.position, info.sun_dir);

      // for each part
      foreach(ProtoPartSnapshot part in vessel.protoVessel.protoPartSnapshots)
      {
        // get part prefab (required for module properties)
        Part part_prefab = PartLoader.getPartInfoByName(part.partName).partPrefab;

        // store index of ModuleResourceConverter to process
        // rationale: a part can contain multiple resource converters
        int converter_index = 0;

        // for each module
        foreach(ProtoPartModuleSnapshot module in part.modules)
        {
          // something weird is going on, skip this
          if (!part_prefab.Modules.Contains(module.moduleName)) continue;

          // command module
          if (module.moduleName == "ModuleCommand")
          {
            // get module from prefab
            ModuleCommand command = part_prefab.Modules.GetModules<ModuleCommand>()[0];

            // do not consume if this is a MCM with no crew
            // rationale: for consistency, the game doesn't consume resources for MCM without crew in loaded vessels
            //            this make some sense: you left a vessel with some battery and nobody on board, you expect it to not consume EC
            if (command.minimumCrew == 0 || part.protoModuleCrew.Count > 0)
            {
              // for each input resource
              foreach(ModuleResource ir in command.inputResources)
              {
                // consume the resource
                Lib.RequestResource(vessel, ir.name, ir.rate * TimeWarp.fixedDeltaTime);
              }
            }
          }
          // solar panel
          else if (module.moduleName == "ModuleDeployableSolarPanel")
          {
            // determine if extended
            bool extended = module.moduleValues.GetValue("stateString") == ModuleDeployableSolarPanel.panelStates.EXTENDED.ToString();

            // if in sunlight and extended
            if (info.sunlight && extended)
            {
              // get module from prefab
              ModuleDeployableSolarPanel panel = part_prefab.Modules.GetModules<ModuleDeployableSolarPanel>()[0];

              // produce electric charge
              Lib.RequestResource(vessel, "ElectricCharge", -PanelOutput(vessel, part, panel, info.sun_dir, info.sun_dist, atmo_factor) * TimeWarp.fixedDeltaTime * Malfunction.Penalty(part));
            }
          }
          // generator
          // note: assume generators require all input
          else if (module.moduleName == "ModuleGenerator")
          {
            // determine if active
            bool activated = Convert.ToBoolean(module.moduleValues.GetValue("generatorIsActive"));

            // if active
            if (activated)
            {
              // get module from prefab
              ModuleGenerator generator = part_prefab.Modules.GetModules<ModuleGenerator>()[0];

              // determine if vessel is full of all output resources
              bool full = true;
              foreach(var or in generator.outputList)
              {
                double amount = Lib.GetResourceAmount(vessel, or.name);
                double capacity = Lib.GetResourceCapacity(vessel, or.name);
                double perc = capacity > 0.0 ? amount / capacity : 0.0;
                full &= (perc >= 1.0 - double.Epsilon);
              }

              // if not full
              if (!full)
              {
                // calculate worst required resource percentual
                double worst_input = 1.0;
                foreach(var ir in generator.inputList)
                {
                  double required = ir.rate * TimeWarp.fixedDeltaTime;
                  double amount = Lib.GetResourceAmount(vessel, ir.name);
                  worst_input = Math.Min(worst_input, amount / required);
                }

                // for each input resource
                foreach(var ir in generator.inputList)
                {
                  // consume the resource
                  Lib.RequestResource(vessel, ir.name, ir.rate * worst_input * TimeWarp.fixedDeltaTime);
                }

                // for each output resource
                foreach(var or in generator.outputList)
                {
                  // produce the resource
                  Lib.RequestResource(vessel, or.name, -or.rate * worst_input * TimeWarp.fixedDeltaTime * Malfunction.Penalty(part));
                }
              }
            }
          }
          // converter
          // note: support multiple resource converters
          // note: ignore stock temperature mechanic of converters
          // note: ignore autoshutdown
          // note: ignore crew experience bonus (seem that stock ignore it too)
          // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation)
          // note: support PlanetaryBaseSystem converters
          // note: support NearFuture reactors
          else if (module.moduleName == "ModuleResourceConverter" || module.moduleName == "ModuleKPBSConverter" || module.moduleName == "FissionReactor")
          {
            // get module from prefab
            ModuleResourceConverter converter = part_prefab.Modules.GetModules<ModuleResourceConverter>()[converter_index++];

            // determine if active
            bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated"));

            // if active
            if (activated)
            {
              // determine if vessel is full of all output resources
              bool full = true;
              foreach(var or in converter.outputList)
              {
                double amount = Lib.GetResourceAmount(vessel, or.ResourceName);
                double capacity = Lib.GetResourceCapacity(vessel, or.ResourceName);
                double perc = capacity > 0.0 ? amount / capacity : 0.0;
                full &= (perc >= converter.FillAmount - double.Epsilon);
              }

              // if not full
              if (!full)
              {
                // calculate worst required resource percentual
                double worst_input = 1.0;
                foreach(var ir in converter.inputList)
                {
                  double required = ir.Ratio * TimeWarp.fixedDeltaTime;
                  double amount = Lib.GetResourceAmount(vessel, ir.ResourceName);
                  worst_input = Math.Min(worst_input, amount / required);
                }

                // for each input resource
                foreach(var ir in converter.inputList)
                {
                  // consume the resource
                  Lib.RequestResource(vessel, ir.ResourceName, ir.Ratio * worst_input * TimeWarp.fixedDeltaTime);
                }

                // for each output resource
                foreach(var or in converter.outputList)
                {
                  // produce the resource
                  Lib.RequestResource(vessel, or.ResourceName, -or.Ratio * worst_input * TimeWarp.fixedDeltaTime * Malfunction.Penalty(part));
                }
              }

              // undo stock behaviour by forcing last_update_time to now
              module.moduleValues.SetValue("lastUpdateTime", Planetarium.GetUniversalTime().ToString());
            }
          }
          // drill
          // note: ignore stock temperature mechanic of harvesters
          // note: ignore autoshutdown
          // note: ignore depletion (stock seem to do the same)
          // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation)
          else if (module.moduleName == "ModuleResourceHarvester")
          {
            // determine if active
            bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated"));

            // if active
            if (activated)
            {
              // get module from prefab
              ModuleResourceHarvester harvester = part_prefab.Modules.GetModules<ModuleResourceHarvester>()[0];

              // [disabled] reason: not working
              // deduce crew bonus
              /*double experience_bonus = 0.0;
              if (harvester.UseSpecialistBonus)
              {
                foreach(ProtoCrewMember c in vessel.protoVessel.GetVesselCrew())
                {
                  experience_bonus = Math.Max(experience_bonus, (c.trait == harvester.Specialty) ? (double)c.experienceLevel : 0.0);
                }
              }*/
              const double crew_bonus = 1.0; //harvester.SpecialistBonusBase + (experience_bonus + 1.0) * harvester.SpecialistEfficiencyFactor;

              // detect amount of ore in the ground
              AbundanceRequest request = new AbundanceRequest
              {
                Altitude = vessel.altitude,
                BodyId = vessel.mainBody.flightGlobalsIndex,
                CheckForLock = false,
                Latitude = vessel.latitude,
                Longitude = vessel.longitude,
                ResourceType = (HarvestTypes)harvester.HarvesterType,
                ResourceName = harvester.ResourceName
              };
              double abundance = ResourceMap.Instance.GetAbundance(request);

              // if there is actually something (should be if active when unloaded)
              if (abundance > harvester.HarvestThreshold)
              {
                // calculate worst required resource percentual
                double worst_input = 1.0;
                foreach(var ir in harvester.inputList)
                {
                  double required = ir.Ratio * TimeWarp.fixedDeltaTime;
                  double amount = Lib.GetResourceAmount(vessel, ir.ResourceName);
                  worst_input = Math.Min(worst_input, amount / required);
                }

                // for each input resource
                foreach(var ir in harvester.inputList)
                {
                  // consume the resource
                  Lib.RequestResource(vessel, ir.ResourceName, ir.Ratio * worst_input * TimeWarp.fixedDeltaTime);
                }

                // determine resource produced
                double res = abundance * harvester.Efficiency * crew_bonus * worst_input * Malfunction.Penalty(part);

                // accumulate ore
                Lib.RequestResource(vessel, harvester.ResourceName, -res * TimeWarp.fixedDeltaTime);
              }

              // undo stock behaviour by forcing last_update_time to now
              module.moduleValues.SetValue("lastUpdateTime", Planetarium.GetUniversalTime().ToString());
            }
          }
          // asteroid drill
          // note: untested
          // note: ignore stock temperature mechanic of asteroid drills
          // note: ignore autoshutdown
          // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation)
          else if (module.moduleName == "ModuleAsteroidDrill")
          {
            // determine if active
            bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated"));

            // if active
            if (activated)
            {
              // get module from prefab
              ModuleAsteroidDrill asteroid_drill = part_prefab.Modules.GetModules<ModuleAsteroidDrill>()[0];

              // [disabled] reason: not working
              // deduce crew bonus
              /*double experience_bonus = 0.0;
              if (asteroid_drill.UseSpecialistBonus)
              {
                foreach(ProtoCrewMember c in vessel.protoVessel.GetVesselCrew())
                {
                  experience_bonus = Math.Max(experience_bonus, (c.trait == asteroid_drill.Specialty) ? (double)c.experienceLevel : 0.0);
                }
              }*/
              const double crew_bonus = 1.0; //asteroid_drill.SpecialistBonusBase + (experience_bonus + 1.0) * asteroid_drill.SpecialistEfficiencyFactor;

              // get asteroid data
              ProtoPartModuleSnapshot asteroid_info = null;
              ProtoPartModuleSnapshot asteroid_resource = null;
              foreach(ProtoPartSnapshot p in vessel.protoVessel.protoPartSnapshots)
              {
                if (asteroid_info == null) asteroid_info = p.modules.Find(k => k.moduleName == "ModuleAsteroidInfo");
                if (asteroid_resource == null) asteroid_resource = p.modules.Find(k => k.moduleName == "ModuleAsteroidResource");
              }

              // if there is actually an asteroid attached to this active asteroid drill (it should)
              if (asteroid_info != null && asteroid_resource != null)
              {
                // get some data
                double mass_threshold = Convert.ToDouble(asteroid_info.moduleValues.GetValue("massThresholdVal"));
                double mass = Convert.ToDouble(asteroid_info.moduleValues.GetValue("currentMassVal"));
                double abundance = Convert.ToDouble(asteroid_resource.moduleValues.GetValue("abundance"));
                string res_name = asteroid_resource.moduleValues.GetValue("resourceName");
                double res_density = PartResourceLibrary.Instance.GetDefinition(res_name).density;

                // if asteroid isn't depleted
                if (mass > mass_threshold && abundance > double.Epsilon)
                {
                  // consume EC
                  double ec_required = asteroid_drill.PowerConsumption * TimeWarp.fixedDeltaTime;
                  double ec_consumed = Lib.RequestResource(vessel, "ElectricCharge", ec_required);
                  double ec_ratio = ec_consumed / ec_required;

                  // determine resource extracted
                  double res_amount = abundance * asteroid_drill.Efficiency * crew_bonus * ec_ratio * TimeWarp.fixedDeltaTime;

                  // produce mined resource
                  Lib.RequestResource(vessel, res_name, -res_amount);

                  // consume asteroid mass
                  asteroid_info.moduleValues.SetValue("currentMassVal", (mass - res_density * res_amount).ToString());
                }
              }

              // undo stock behaviour by forcing last_update_time to now
              module.moduleValues.SetValue("lastUpdateTime", Planetarium.GetUniversalTime().ToString());
            }
          }
          // science lab
          // note: we are only simulating the EC consumption
          // note: there is no easy way to 'stop' the lab when there isn't enough EC
          else if (module.moduleName == "ModuleScienceConverter")
          {
            // get module from prefab
            ModuleScienceConverter lab = part_prefab.Modules.GetModules<ModuleScienceConverter>()[0];

            // determine if active
            bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated"));

            // if active
            if (activated)
            {
              Lib.RequestResource(vessel, "ElectricCharge", lab.powerRequirement * TimeWarp.fixedDeltaTime);
            }
          }
          // SCANSAT support
          else if (module.moduleName == "SCANsat" || module.moduleName == "ModuleSCANresourceScanner")
          {
            // get ec consumption rate
            PartModule scansat = part_prefab.Modules[module.moduleName];
            double power = Lib.ReflectionValue<float>(scansat, "power");
            double ec_required = power * TimeWarp.fixedDeltaTime;
            bool is_scanning = Lib.GetProtoValue<bool>(module, "scanning");
            bool was_disabled = vd.scansat_id.Contains(part.flightID);

            // if its scanning
            if (Lib.GetProtoValue<bool>(module, "scanning"))
            {
              // consume ec
              double ec_consumed = Lib.RequestResource(vessel, "ElectricCharge", ec_required);

              // if there isn't enough ec
              if (ec_consumed < ec_required * 0.99 && ec_required > double.Epsilon)
              {
                // unregister scanner
                SCANsat.stopScanner(vessel, module, part_prefab);

                // remember disabled scanner
                vd.scansat_id.Add(part.flightID);

                // give the user some feedback
                if (DB.VesselData(vessel.id).cfg_ec == 1)
                  Message.Post("SCANsat sensor was disabled on <b>" + vessel.vesselName + "</b>");
              }
            }
            // if it was disabled
            else if (vd.scansat_id.Contains(part.flightID))
            {
              // if there is enough ec
              double ec_amount = Lib.GetResourceAmount(vessel, "ElectricCharge");
              double ec_capacity = Lib.GetResourceCapacity(vessel, "ElectricCharge");
              if (ec_capacity > double.Epsilon && ec_amount / ec_capacity > 0.25) //< re-enable at 25% EC
              {
                // re-enable the scanner
                SCANsat.resumeScanner(vessel, module, part_prefab);

                // give the user some feedback
                if (DB.VesselData(vessel.id).cfg_ec == 1)
                  Message.Post("SCANsat sensor resumed operations on <b>" + vessel.vesselName + "</b>");
              }
            }

            // forget active scanners
            if (Lib.GetProtoValue<bool>(module, "scanning")) vd.scansat_id.Remove(part.flightID);
          }
          // NearFutureSolar support
          // note: we assume deployed, this is a current limitation
          else if (module.moduleName == "ModuleCurvedSolarPanel")
          {
            // if in sunlight
            if (info.sunlight)
            {
              PartModule curved_panel = part_prefab.Modules[module.moduleName];
              double output = CurvedPanelOutput(vessel, part, part_prefab, curved_panel, info.sun_dir, info.sun_dist, atmo_factor) * Malfunction.Penalty(part);
              Lib.RequestResource(vessel, "ElectricCharge", -output * TimeWarp.fixedDeltaTime);
            }
          }
          // NearFutureElectrical support
          // note: fission generator ignore heat
          // note: radioisotope generator doesn't support easy mode
          else if (module.moduleName == "FissionGenerator")
          {
            PartModule generator = part_prefab.Modules[module.moduleName];
            double power = Lib.ReflectionValue<float>(generator, "PowerGeneration");

            // get fission reactor tweakable, will default to 1.0 for other modules
            var reactor = part.modules.Find(k => k.moduleName == "FissionReactor");
            double tweakable = reactor == null ? 1.0 : Lib.ConfigValue(reactor.moduleValues, "CurrentPowerPercent", 100.0) * 0.01;
            Lib.RequestResource(vessel, "ElectricCharge", -power * tweakable * TimeWarp.fixedDeltaTime);
          }
          else if (module.moduleName == "ModuleRadioisotopeGenerator")
          {
            double mission_time = vessel.missionTime / (3600.0 * Lib.HoursInDay() * Lib.DaysInYear());
            PartModule generator = part_prefab.Modules[module.moduleName];
            double half_life = Lib.ReflectionValue<float>(generator, "HalfLife");
            double remaining = Math.Pow(2.0, (-mission_time) / half_life);
            double power = Lib.ReflectionValue<float>(generator, "BasePower");
            Lib.RequestResource(vessel, "ElectricCharge", -power * remaining * TimeWarp.fixedDeltaTime);
          }
          // KERBALISM modules
          else if (module.moduleName == "Scrubber") { Scrubber.BackgroundUpdate(vessel, part.flightID); }
          else if (module.moduleName == "Greenhouse") { Greenhouse.BackgroundUpdate(vessel, part.flightID); }
          else if (module.moduleName == "GravityRing") { GravityRing.BackgroundUpdate(vessel, part.flightID); }
          else if (module.moduleName == "Malfunction") { Malfunction.BackgroundUpdate(vessel, part.flightID); }
        }
      }
    }
  }
예제 #12
0
        public Comforts(List <Part> parts, bool firm_ground, bool not_alone, bool call_home)
        {
            // environment factors
            this.firm_ground = firm_ground;
            this.not_alone   = not_alone;
            this.call_home   = call_home;

            // for each parts
            foreach (Part p in parts)
            {
                // for each modules in part
                foreach (PartModule m in p.Modules)
                {
                    // skip disabled modules
                    if (!m.isEnabled)
                    {
                        continue;
                    }

                    // comfort
                    if (m.moduleName == "Comfort")
                    {
                        Comfort c = m as Comfort;
                        switch (c.bonus)
                        {
                        case "firm-ground": this.firm_ground = true; break;

                        case "not-alone":   this.not_alone = true;   break;

                        case "call-home":   this.call_home = true;   break;

                        case "exercise":    this.exercise = true;    break;

                        case "panorama":    this.panorama = true;    break;
                        }
                    }
                    // gravity ring
                    // - ignoring if ec is present or not here
                    else if (m.moduleName == "GravityRing")
                    {
                        GravityRing ring = m as GravityRing;
                        this.firm_ground |= ring.deployed;
                    }
                }
            }

            // calculate factor
            factor = 0.1;
            if (firm_ground)
            {
                factor += Settings.ComfortFirmGround;
            }
            if (not_alone)
            {
                factor += Settings.ComfortNotAlone;
            }
            if (call_home)
            {
                factor += Settings.ComfortCallHome;
            }
            if (exercise)
            {
                factor += Settings.ComfortExercise;
            }
            if (panorama)
            {
                factor += Settings.ComfortPanorama;
            }
            factor = Lib.Clamp(factor, 0.1, 1.0);
        }
예제 #13
0
  // implement gravity ring mechanics for unloaded vessels
  public static void BackgroundUpdate(Vessel vessel, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, GravityRing ring, vessel_resources resources, double elapsed_s)
  {
    // get protomodule data
    float speed = Lib.Proto.GetFloat(m, "speed");

    // get resource handler
    resource_info ec = resources.Info(vessel, "ElectricCharge");

    // consume ec
    ec.Consume(ring.ec_rate * speed * elapsed_s * Reliability.Penalty(p, "GravityRing", 2.0));

    // reset speed if there isn't enough ec
    // note: comparing against amount in previous simulation step
    if (ec.amount <= double.Epsilon)
    {
      speed = 0.0f;
      Lib.Proto.Set(m, "speed", speed);
    }

    // set entertainment
    // note: entertainmnent is only recomputed for loaded vessels,
    // so changing rate here does nothing until vessel is reloaded
    double rate = 1.0 + (ring.entertainment_rate - 1.0) * speed;
    Lib.Proto.Set(m, "rate", rate);
  }
예제 #14
0
        // pseudo-ctor
        public override void OnStart(StartState state)
        {
            // don't break tutorial scenarios
            if (Lib.DisableScenario(this))
            {
                return;
            }

            // check if has Connected Living Space mod
            hasCLS = Lib.HasAssembly("ConnectedLivingSpace");

            // if part has Gravity Ring, find it.
            gravityRing    = part.FindModuleImplementing <GravityRing>();
            hasGravityRing = gravityRing != null;

            if (volume <= 0.0 || surface <= 0.0)
            {
                Habitat prefab = part.partInfo.partPrefab.FindModuleImplementing <Habitat>();
                if (volume <= 0.0)
                {
                    volume = prefab.volume;
                }
                if (surface <= 0.0)
                {
                    surface = prefab.surface;
                }
            }

            // set RMB UI status strings
            Volume  = Lib.HumanReadableVolume(volume);
            Surface = Lib.HumanReadableSurface(surface);

            // hide toggle if specified
            Events["Toggle"].active = toggle;
            //Actions["Action"].active = toggle;

#if DEBUG
            Events["LogVolumeAndSurface"].active = true;
#else
            Events["LogVolumeAndSurface"].active = Settings.VolumeAndSurfaceLogging;
#endif
            // create animators
            if (!hasGravityRing)
            {
                inflate_anim = new Animator(part, inflate);
            }

            // add the cost of shielding to the base part cost
            shieldingCost = (float)surface * PartResourceLibrary.Instance.GetDefinition("Shielding").unitCost;

            // configure on start
            Configure();

            perctDeployed = Lib.Level(part, "Atmosphere", true);

            switch (this.state)
            {
            case State.enabled: Set_flow(true); break;

            case State.disabled: Set_flow(false); break;

            case State.pressurizing: Set_flow(true); break;

            case State.depressurizing: Set_flow(false); break;
            }

            if (Get_inflate_string().Length == 0) // not inflatable
            {
                SetPassable(true);
                UpdateIVA(true);
            }
            else
            {
                SetPassable(Math.Truncate(Math.Abs((perctDeployed + ResourceBalance.precision) - 1.0) * 100000) / 100000 <= ResourceBalance.precision);
                UpdateIVA(Math.Truncate(Math.Abs((perctDeployed + ResourceBalance.precision) - 1.0) * 100000) / 100000 <= ResourceBalance.precision);
            }

            if (Lib.IsFlight())
            {
                // For fix IVA when crewTransfered occur, add event to define flag for FixedUpdate
                GameEvents.onCrewTransferred.Add(UpdateCrew);
            }
        }