Beispiel #1
0
        void VesselDestroyed(Vessel v)
        {
            DB.vessels.Remove(Lib.VesselID(v));

            // rescan the damn kerbals
            // - vessel crew is empty at destruction time
            // - we can't even use the flightglobal roster, because sometimes it isn't updated yet at this point
            HashSet <string> kerbals_alive = new HashSet <string>();
            HashSet <string> kerbals_dead  = new HashSet <string>();

            foreach (Vessel ov in FlightGlobals.Vessels)
            {
                foreach (ProtoCrewMember c in Lib.CrewList(ov))
                {
                    kerbals_alive.Add(c.name);
                }
            }
            foreach (KeyValuePair <string, KerbalData> p in DB.Kerbals())
            {
                if (!kerbals_alive.Contains(p.Key))
                {
                    kerbals_dead.Add(p.Key);
                }
            }
            foreach (string n in kerbals_dead)
            {
                // we don't know if the kerbal really is dead, or if it is just not currently assigned to a mission
                DB.KillKerbal(n, false);
            }


            // purge the caches
            ResourceCache.Purge(v);
            Drive.Purge(v);
            Cache.PurgeObjects(v);
        }
Beispiel #2
0
		public static void Update(CelestialBody body, double elapsed_s)
		{
			// do nothing if storms are disabled
			if (!Features.SpaceWeather) return;

			// skip the sun
			if (body.flightGlobalsIndex == 0) return;

			// skip moons
			// note: referenceBody is never null here
			if (body.referenceBody.flightGlobalsIndex != 0) return;

			// get body data
			BodyData bd = DB.Body(body.name);

			// generate storm time if necessary
			if (bd.storm_time <= double.Epsilon)
			{
				bd.storm_time = PreferencesStorm.Instance.StormMinTime + (PreferencesStorm.Instance.StormMaxTime - PreferencesStorm.Instance.StormMinTime) * Lib.RandomDouble();
			}

			// accumulate age
			bd.storm_age += elapsed_s * Storm_frequency(body.orbit.semiMajorAxis);

			// if storm is over
			if (bd.storm_age > bd.storm_time)
			{
				bd.storm_age = 0.0;
				bd.storm_time = 0.0;
				bd.storm_state = 0;
			}
			// if storm is in progress
			else if (bd.storm_age > bd.storm_time - PreferencesStorm.Instance.StormDuration)
			{
				bd.storm_state = 2;
			}
			// if storm is incoming
			else if (bd.storm_age > bd.storm_time - PreferencesStorm.Instance.StormDuration - Time_to_impact(body.orbit.semiMajorAxis))
			{
				bd.storm_state = 1;
			}

			// send messages
			// note: separed from state management to support the case when the user enter the SOI of a body under storm or about to be hit
			if (bd.msg_storm < 2 && bd.storm_state == 2)
			{
				if (Body_is_relevant(body))
				{
					Message.Post(Severity.danger, Lib.BuildString("The coronal mass ejection hit <b>", body.name, "</b> system"),
					  Lib.BuildString("Storm duration: ", Lib.HumanReadableDuration(TimeLeftCME(bd.storm_time, bd.storm_age))));
				}
				bd.msg_storm = 2;
			}
			else if (bd.msg_storm < 1 && bd.storm_state == 1)
			{
				if (Body_is_relevant(body))
				{
					Message.Post(Severity.warning, Lib.BuildString("Our observatories report a coronal mass ejection directed toward <b>", body.name, "</b> system"),
					  Lib.BuildString("Time to impact: ", Lib.HumanReadableDuration(TimeBeforeCME(bd.storm_time, bd.storm_age))));
				}
				bd.msg_storm = 1;
			}
			else if (bd.msg_storm > 1 && bd.storm_state == 0)
			{
				if (Body_is_relevant(body))
				{
					Message.Post(Severity.relax, Lib.BuildString("The solar storm at <b>", body.name, "</b> system is over"));
				}
				bd.msg_storm = 0;
			}
		}
Beispiel #3
0
        // kill a kerbal
        // note: you can't kill a kerbal while iterating over vessel crew list, do it outside the loop
        public static void Kill(Vessel v, ProtoCrewMember c)
        {
            // if on pod
            if (!v.isEVA)
            {
                // if vessel is loaded
                if (v.loaded)
                {
                    // find part
                    Part part = null;
                    foreach (Part p in v.parts)
                    {
                        if (p.protoModuleCrew.Find(k => k.name == c.name) != null)
                        {
                            part = p; break;
                        }
                    }

                    // remove kerbal from part
                    part.RemoveCrewmember(c);

                    // and from vessel
                    v.RemoveCrew(c);

                    // then kill it
                    c.Die();
                }
                // if vessel is not loaded
                else
                {
                    // find proto part
                    ProtoPartSnapshot part = null;
                    foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
                    {
                        if (p.HasCrew(c.name))
                        {
                            part = p; break;
                        }
                    }

                    // remove from part
                    part.RemoveCrew(c.name);

                    // and from vessel
                    v.protoVessel.RemoveCrew(c);

                    // flag as dead
                    c.rosterStatus = ProtoCrewMember.RosterStatus.Dead;
                }

                // forget kerbal data
                DB.KillKerbal(c.name, true);
            }
            // else it must be an eva death
            else
            {
                // flag as eva death
                DB.Kerbal(c.name).eva_dead = true;

                // rename vessel
                v.vesselName = c.name + "'s body";
            }

            // remove reputation
            if (HighLogic.CurrentGame.Mode == Game.Modes.CAREER)
            {
                Reputation.Instance.AddReputation(-PreferencesBasic.Instance.deathPenalty, TransactionReasons.Any);
            }
        }
Beispiel #4
0
        public override void OnLoad(ConfigNode node)
        {
            // deserialize data
            DB.Load(node);

            Communications.NetworkInitialized  = false;
            Communications.NetworkInitializing = false;

            // initialize everything just once
            if (!initialized)
            {
                // add supply resources to pods
                Profile.SetupPods();

                // initialize subsystems
                Cache.Init();
                ResourceCache.Init();
                Radiation.Init();
                Science.Init();
                LineRenderer.Init();
                ParticleRenderer.Init();
                Highlighter.Init();
                UI.Init();

                // prepare storm data
                foreach (CelestialBody body in FlightGlobals.Bodies)
                {
                    if (Storm.Skip_body(body))
                    {
                        continue;
                    }
                    Storm_data sd = new Storm_data
                    {
                        body = body
                    };
                    storm_bodies.Add(sd);
                }

                // various tweaks to the part icons in the editor
                Misc.TweakPartIcons();

                // setup callbacks
                callbacks = new Callbacks();

                // everything was initialized
                initialized = true;
            }

            // detect if this is a different savegame
            if (DB.uid != savegame_uid)
            {
                // clear caches
                Cache.Clear();
                ResourceCache.Clear();
                Message.all_logs.Clear();

                // sync main window pos from db
                UI.Sync();

                // remember savegame id
                savegame_uid = DB.uid;
            }
        }
Beispiel #5
0
        void FixedUpdate()
        {
            // remove control locks in any case
            Misc.ClearLocks();

            // do nothing if paused
            if (Lib.IsPaused())
            {
                return;
            }

            // maintain elapsed_s, converting to double only once
            // and detect warp blending
            double fixedDeltaTime = TimeWarp.fixedDeltaTime;

            if (Math.Abs(fixedDeltaTime - elapsed_s) > double.Epsilon)
            {
                warp_blending = 0;
            }
            else
            {
                ++warp_blending;
            }
            elapsed_s = fixedDeltaTime;

            // evict oldest entry from vessel cache
            Cache.Update();

            // store info for oldest unloaded vessel
            double           last_time      = 0.0;
            Vessel           last_v         = null;
            Vessel_info      last_vi        = null;
            VesselData       last_vd        = null;
            Vessel_resources last_resources = null;

            // for each vessel
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // get vessel info from the cache
                Vessel_info vi = Cache.VesselInfo(v);

                // set locks for active vessel
                if (v.isActiveVessel)
                {
                    Misc.SetLocks(v, vi);
                }

                // maintain eva dead animation and helmet state
                if (v.loaded && v.isEVA)
                {
                    EVA.Update(v);
                }

                // keep track of rescue mission kerbals, and gift resources to their vessels on discovery
                if (v.loaded && vi.is_vessel)
                {
                    // manage rescue mission mechanics
                    Misc.ManageRescueMission(v);
                }

                // do nothing else for invalid vessels
                if (!vi.is_valid)
                {
                    continue;
                }

                // get vessel data from db
                VesselData vd = DB.Vessel(v);

                // get resource cache
                Vessel_resources resources = ResourceCache.Get(v);

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

                    // show belt warnings
                    Radiation.BeltWarnings(v, vi, vd);

                    // update storm data
                    Storm.Update(v, vi, vd, elapsed_s);

                    Communications.Update(v, vi, vd, ec, elapsed_s);

                    // Habitat equalization
                    ResourceBalance.Equalizer(v);

                    // transmit science data
                    Science.Update(v, vi, vd, resources, elapsed_s);

                    // apply rules
                    Profile.Execute(v, vi, vd, resources, elapsed_s);

                    // apply deferred requests
                    resources.Sync(v, elapsed_s);

                    // call automation scripts
                    vd.computer.Automate(v, vi, resources);

                    // remove from unloaded data container
                    unloaded.Remove(vi.id);
                }
                // if unloaded
                else
                {
                    // get unloaded data, or create an empty one
                    Unloaded_data ud;
                    if (!unloaded.TryGetValue(vi.id, out ud))
                    {
                        ud = new Unloaded_data();
                        unloaded.Add(vi.id, ud);
                    }

                    // accumulate time
                    ud.time += elapsed_s;

                    // maintain oldest entry
                    if (ud.time > last_time)
                    {
                        last_time      = ud.time;
                        last_v         = v;
                        last_vi        = vi;
                        last_vd        = vd;
                        last_resources = resources;
                    }
                }
            }

            // at most one vessel gets background processing per physics tick
            // if there is a vessel that is not the currently loaded vessel, then
            // we will update the vessel whose most recent background update is the oldest
            if (last_v != null)
            {
                // get most used resource
                Resource_info last_ec = last_resources.Info(last_v, "ElectricCharge");

                // show belt warnings
                Radiation.BeltWarnings(last_v, last_vi, last_vd);

                // update storm data
                Storm.Update(last_v, last_vi, last_vd, last_time);

                Communications.Update(last_v, last_vi, last_vd, last_ec, last_time);

                // transmit science	data
                Science.Update(last_v, last_vi, last_vd, last_resources, last_time);

                // apply rules
                Profile.Execute(last_v, last_vi, last_vd, last_resources, last_time);

                // simulate modules in background
                Background.Update(last_v, last_vi, last_vd, last_resources, last_time);

                // apply deferred requests
                last_resources.Sync(last_v, last_time);

                // call automation scripts
                last_vd.computer.Automate(last_v, last_vi, last_resources);

                // remove from unloaded data container
                unloaded.Remove(last_vi.id);
            }

            // update storm data for one body per-step
            if (storm_bodies.Count > 0)
            {
                storm_bodies.ForEach(k => k.time += elapsed_s);
                Storm_data sd = storm_bodies[storm_index];
                Storm.Update(sd.body, sd.time);
                sd.time     = 0.0;
                storm_index = (storm_index + 1) % storm_bodies.Count;
            }
        }
Beispiel #6
0
 public override void OnSave(ConfigNode node)
 {
     // serialize data
     DB.Save(node);
 }
Beispiel #7
0
        /// <summary>
        /// If short_strings parameter is true then the strings used for display of the data will be shorter when inflight.
        /// </summary>
        public static void Fileman(this Panel p, Vessel v, bool short_strings = false)
        {
            // avoid corner-case when this is called in a lambda after scene changes
            v = FlightGlobals.FindVessel(v.id);

            // if vessel doesn't exist anymore, leave the panel empty
            if (v == null)
            {
                return;
            }

            // get info from the cache
            Vessel_info vi = Cache.VesselInfo(v);

            // if not a valid vessel, leave the panel empty
            if (!vi.is_valid)
            {
                return;
            }

            // set metadata
            p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(40)), " <color=#cccccc>FILE MANAGER</color>"));
            p.Width(Styles.ScaleWidthFloat(465.0f));
            p.paneltype = Panel.PanelType.data;

            // time-out simulation
            if (p.Timeout(vi))
            {
                return;
            }

            foreach (var idDrivePair in DB.Vessel(v).drives)
            {
                var drive = idDrivePair.Value;

                if (drive.dataCapacity > double.Epsilon)
                {
                    // draw data section
                    p.AddSection(Lib.BuildString("DATA ", drive.name, " ", Lib.HumanReadableDataSize(drive.dataCapacity),
                                                 " (", Lib.HumanReadablePerc(drive.FilesSize() / drive.dataCapacity), ")"));
                    foreach (var pair in drive.files)
                    {
                        string filename = pair.Key;
                        File   file     = pair.Value;
                        Render_file(p, filename, file, drive, short_strings && Lib.IsFlight(), Cache.VesselInfo(v).connection.rate);
                    }
                    if (drive.files.Count == 0)
                    {
                        p.AddContent("<i>no files</i>", string.Empty);
                    }
                }

                if (drive.sampleCapacity > 0)
                {
                    double mass = 0;
                    foreach (var sample in drive.samples.Values)
                    {
                        mass += sample.mass;
                    }

                    // draw samples section
                    p.AddSection(Lib.BuildString("SAMPLES ", drive.name, " ",
                                                 Lib.HumanReadableSampleSize(drive.sampleCapacity),
                                                 " (", Lib.HumanReadablePerc(drive.SamplesSize() / drive.sampleCapacity), ") ",
                                                 Lib.HumanReadableMass(mass)));
                    foreach (var pair in drive.samples)
                    {
                        string filename = pair.Key;
                        Sample sample   = pair.Value;
                        Render_sample(p, filename, sample, drive, short_strings && Lib.IsFlight());
                    }
                    if (drive.samples.Count == 0)
                    {
                        p.AddContent("<i>no samples</i>", string.Empty);
                    }
                }
            }
        }
Beispiel #8
0
        // constructor
        /// <summary> Creates a <see cref="ConnectionInfo"/> object for the specified vessel from it's antenna modules</summary>
        public ConnectionInfo(Vessel v, bool powered, bool storm)
        {
            // set RemoteTech powered and storm state
            if (RemoteTech.Enabled)
            {
                RemoteTech.SetPoweredDown(v.id, !powered);
                RemoteTech.SetCommsBlackout(v.id, storm);
            }

            // return no connection if there is no ec left
            if (!powered)
            {
                // hysteresis delay
                if ((DB.Vessel(v).hyspos_signal >= 5.0))
                {
                    DB.Vessel(v).hyspos_signal = 5.0;
                    DB.Vessel(v).hysneg_signal = 0.0;
                    return;
                }
                DB.Vessel(v).hyspos_signal += 0.1;
            }
            else
            {
                // hysteresis delay
                DB.Vessel(v).hysneg_signal += 0.1;
                if (!(DB.Vessel(v).hysneg_signal >= 5.0))
                {
                    return;
                }
                DB.Vessel(v).hysneg_signal = 5.0;
                DB.Vessel(v).hyspos_signal = 0.0;
            }

            // CommNet or simple signal system
            if (!RemoteTech.Enabled)
            {
                List <ModuleDataTransmitter> transmitters;

                // if vessel is loaded
                if (v.loaded)
                {
                    // find transmitters
                    transmitters = v.FindPartModulesImplementing <ModuleDataTransmitter>();

                    if (transmitters != null)
                    {
                        foreach (ModuleDataTransmitter t in transmitters)
                        {
                            if (t.antennaType == AntennaType.INTERNAL)                             // do not include internal data rate, ec cost only
                            {
                                internal_cost += t.DataResourceCost * t.DataRate;
                            }
                            else
                            {
                                // do we have an animation
                                ModuleDeployableAntenna animation = t.part.FindModuleImplementing <ModuleDeployableAntenna>();
                                if (animation != null)
                                {
                                    // only include data rate and ec cost if transmitter is extended
                                    if (animation.deployState == ModuleDeployablePart.DeployState.EXTENDED)
                                    {
                                        rate          += t.DataRate;
                                        external_cost += t.DataResourceCost * t.DataRate;
                                    }
                                }
                                // no animation
                                else
                                {
                                    rate          += t.DataRate;
                                    external_cost += t.DataResourceCost * t.DataRate;
                                }
                            }
                        }
                    }
                }

                // if vessel is not loaded
                else
                {
                    // find proto transmitters
                    foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
                    {
                        // get part prefab (required for module properties)
                        Part part_prefab = PartLoader.getPartInfoByName(p.partName).partPrefab;

                        transmitters = part_prefab.FindModulesImplementing <ModuleDataTransmitter>();

                        if (transmitters != null)
                        {
                            foreach (ModuleDataTransmitter t in transmitters)
                            {
                                if (t.antennaType == AntennaType.INTERNAL)                                 // do not include internal data rate, ec cost only
                                {
                                    internal_cost += t.DataResourceCost * t.DataRate;
                                }
                                else
                                {
                                    // do we have an animation
                                    ProtoPartModuleSnapshot m = p.FindModule("ModuleDeployableAntenna");
                                    if (m != null)
                                    {
                                        // only include data rate and ec cost if transmitter is extended
                                        string deployState = Lib.Proto.GetString(m, "deployState");
                                        if (deployState == "EXTENDED")
                                        {
                                            rate          += t.DataRate;
                                            external_cost += t.DataResourceCost * t.DataRate;
                                        }
                                    }
                                    // no animation
                                    else
                                    {
                                        rate          += t.DataRate;
                                        external_cost += t.DataResourceCost * t.DataRate;
                                    }
                                }
                            }
                        }
                    }
                }

                // if CommNet is enabled
                if (HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet)
                {
                    // are we connected to DSN
                    if (v.connection != null)
                    {
                        if (v.connection.IsConnected)
                        {
                            linked      = true;
                            status      = v.connection.ControlPath.First.hopType == CommNet.HopType.Home ? LinkStatus.direct_link : LinkStatus.indirect_link;
                            strength    = v.connection.SignalStrength;
                            rate        = rate * strength;
                            target_name = Lib.Ellipsis(Localizer.Format(v.connection.ControlPath.First.end.displayName).Replace("Kerbin", "DSN"), 20);
                            return;
                        }

                        // is loss of connection due to plasma blackout
                        else if (Lib.ReflectionValue <bool>(v.connection, "inPlasma"))                         // calling InPlasma causes a StackOverflow :(
                        {
                            status        = LinkStatus.plasma;
                            rate          = 0.0;
                            internal_cost = 0.0;
                            external_cost = 0.0;
                            return;
                        }
                    }

                    // no connection
                    rate          = 0.0;
                    internal_cost = 0.0;
                    external_cost = 0.0;
                    return;
                }

                // the simple stupid always connected signal system
                linked      = true;
                status      = LinkStatus.direct_link;
                strength    = 1;                 // 100 %
                target_name = "DSN: KSC";
                return;
            }

            // RemoteTech signal system
            else
            {
                // if vessel is loaded
                if (v.loaded)
                {
                    // find transmitters
                    foreach (Part p in v.parts)
                    {
                        foreach (PartModule m in p.Modules)
                        {
                            // calculate internal (passive) transmitter ec usage @ 0.5W each
                            if (m.moduleName == "ModuleRTAntennaPassive")
                            {
                                internal_cost += 0.0005;
                            }

                            // calculate external transmitters
                            else if (m.moduleName == "ModuleRTAntenna")
                            {
                                // only include data rate and ec cost if transmitter is active
                                if (Lib.ReflectionValue <bool>(m, "IsRTActive"))
                                {
                                    rate          += (Lib.ReflectionValue <float>(m, "RTPacketSize") / Lib.ReflectionValue <float>(m, "RTPacketInterval"));
                                    external_cost += m.resHandler.inputResources.Find(r => r.name == "ElectricCharge").rate;
                                }
                            }
                        }
                    }
                }

                // if vessel is not loaded
                else
                {
                    // find proto transmitters
                    foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
                    {
                        // get part prefab (required for module properties)
                        Part part_prefab = PartLoader.getPartInfoByName(p.partName).partPrefab;
                        int  index       = 0;                           // module index

                        foreach (ProtoPartModuleSnapshot m in p.modules)
                        {
                            // calculate internal (passive) transmitter ec usage @ 0.5W each
                            if (m.moduleName == "ModuleRTAntennaPassive")
                            {
                                internal_cost += 0.0005;
                            }

                            // calculate external transmitters
                            else if (m.moduleName == "ModuleRTAntenna")
                            {
                                // only include data rate and ec cost if transmitter is active skip if index is out of range
                                if (Lib.Proto.GetBool(m, "IsRTActive") && index < part_prefab.Modules.Count)
                                {
                                    // get module prefab
                                    PartModule pm = part_prefab.Modules.GetModule(index);

                                    if (pm != null)
                                    {
                                        rate          += (Lib.ReflectionValue <float>(pm, "RTPacketSize") / Lib.ReflectionValue <float>(pm, "RTPacketInterval"));
                                        external_cost += pm.resHandler.inputResources.Find(r => r.name == "ElectricCharge").rate;
                                    }
                                    else
                                    {
                                        Lib.DebugLog(String.Format("ConnectionInfo: Could not find PartModule ModuleRTAntenna for part {0} on unloaded vessel {1}, using default values as a workaround",
                                                                   p.partName, v.vesselName));
                                        rate          += 6.6666;                                            // 6.67 Mb/s
                                        external_cost += 0.025;                                             // 25 W/s
                                    }
                                }
                            }
                            index++;
                        }
                    }
                }

                // are we connected
                if (RemoteTech.Connected(v.id))
                {
                    linked      = RemoteTech.ConnectedToKSC(v.id);
                    status      = RemoteTech.TargetsKSC(v.id) ? LinkStatus.direct_link : LinkStatus.indirect_link;
                    strength    = RemoteTech.GetSignalDelay(v.id);
                    target_name = status == LinkStatus.direct_link ? Lib.Ellipsis("DSN: " + (RemoteTech.NameTargetsKSC(v.id) ?? ""), 20):
                                  Lib.Ellipsis(RemoteTech.NameFirstHopToKSC(v.id) ?? "", 20);
                    return;
                }

                // is loss of connection due to a blackout
                else if (RemoteTech.GetCommsBlackout(v.id))
                {
                    status        = storm ? LinkStatus.storm : LinkStatus.plasma;
                    rate          = 0.0;
                    internal_cost = 0.0;
                    external_cost = 0.0;
                    return;
                }

                // no connection
                rate          = 0.0;
                internal_cost = 0.0;
                external_cost = 0.0;
                return;
            }
        }
Beispiel #9
0
        void ToEVA(GameEvents.FromToAction <Part, Part> data)
        {
            Cache.PurgeObjects(data.from.vessel);
            Cache.PurgeObjects(data.to.vessel);

            // get total crew in the origin vessel
            double tot_crew = Lib.CrewCount(data.from.vessel) + 1.0;

            // get vessel resources handler
            Vessel_resources resources = ResourceCache.Get(data.from.vessel);

            // setup supply resources capacity in the eva kerbal
            Profile.SetupEva(data.to);

            String prop_name = Lib.EvaPropellantName();

            // for each resource in the kerbal
            for (int i = 0; i < data.to.Resources.Count; ++i)
            {
                // get the resource
                PartResource res = data.to.Resources[i];

                // eva prop is handled differently
                if (res.resourceName == prop_name)
                {
                    continue;
                }

                double quantity = Math.Min(resources.Info(data.from.vessel, res.resourceName).amount / tot_crew, res.maxAmount);
                // remove resource from vessel
                quantity = data.from.RequestResource(res.resourceName, quantity);

                // add resource to eva kerbal
                data.to.RequestResource(res.resourceName, -quantity);
            }

            // take as much of the propellant as possible. just imagine: there are 1.3 units left, and 12 occupants
            // in the ship. you want to send out an engineer to fix the chemical plant that produces monoprop,
            // and have to get from one end of the station to the other with just 0.1 units in the tank...
            // nope.
            double evaPropQuantity = data.from.RequestResource(prop_name, Lib.EvaPropellantCapacity());

            // We can't just add the monoprop here, because that doesn't always work. It might be related
            // to the fact that stock KSP wants to add 5 units of monoprop to new EVAs. Instead of fighting KSP here,
            // we just let it do it's thing and set our amount later in EVA.cs - which seems to work just fine.
            // don't put that into Cache.VesselInfo because that can be deleted before we get there
            Cache.SetVesselObjectsCache(data.to.vessel, "eva_prop", evaPropQuantity);

            // Airlock loss
            resources.Consume(data.from.vessel, "Nitrogen", PreferencesLifeSupport.Instance.evaAtmoLoss, "airlock");

            // show warning if there is little or no EVA propellant in the suit
            if (evaPropQuantity <= 0.05 && !Lib.Landed(data.from.vessel))
            {
                Message.Post(Severity.danger,
                             Lib.BuildString("There isn't any <b>", prop_name, "</b> in the EVA suit"), "Don't let the ladder go!");
            }

            // turn off headlamp light, to avoid stock bug that show them for a split second when going on eva
            KerbalEVA kerbal = data.to.FindModuleImplementing <KerbalEVA>();

            EVA.HeadLamps(kerbal, false);

            // execute script
            DB.Vessel(data.from.vessel).computer.Execute(data.from.vessel, ScriptType.eva_out);
        }
Beispiel #10
0
        public static void Devman(this Panel p, Vessel v)
        {
            // avoid corner-case when this is called in a lambda after scene changes
            v = FlightGlobals.FindVessel(v.id);

            // if vessel doesn't exist anymore, leave the panel empty
            if (v == null)
            {
                return;
            }

            // get info from the cache
            Vessel_info vi = Cache.VesselInfo(v);

            // if not a valid vessel, leave the panel empty
            if (!vi.is_valid)
            {
                return;
            }

            // set metadata
            p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(20)), " <color=#cccccc>" + Localizer.Format("#KERBALISM_UI_devman") + "</color>"));
            p.Width(Styles.ScaleWidthFloat(355.0f));
            p.paneltype = Panel.PanelType.scripts;

            // time-out simulation
            if (p.Timeout(vi))
            {
                return;
            }

            // get devices
            Dictionary <uint, Device> devices = Computer.Boot(v);
            int deviceCount = 0;

            // direct control
            if (script_index == 0)
            {
                // draw section title and desc
                p.AddSection
                (
                    Localizer.Format("#KERBALISM_UI_devices"),
                    Description(),
                    () => p.Prev(ref script_index, (int)ScriptType.last),
                    () => p.Next(ref script_index, (int)ScriptType.last),
                    true
                );

                // for each device
                foreach (var pair in devices)
                {
                    // render device entry
                    Device dev = pair.Value;
                    if (!dev.IsVisible())
                    {
                        continue;
                    }
                    p.AddContent(dev.Name(), dev.Info(), string.Empty, dev.Toggle, () => Highlighter.Set(dev.Part(), Color.cyan));
                    deviceCount++;
                }
            }
            // script editor
            else
            {
                // get script
                ScriptType script_type = (ScriptType)script_index;
                string     script_name = script_type.ToString().Replace('_', ' ').ToUpper();
                Script     script      = DB.Vessel(v).computer.Get(script_type);

                // draw section title and desc
                p.AddSection
                (
                    script_name,
                    Description(),
                    () => p.Prev(ref script_index, (int)ScriptType.last),
                    () => p.Next(ref script_index, (int)ScriptType.last),
                    true
                );

                // for each device
                foreach (var pair in devices)
                {
                    Device dev = pair.Value;
                    if (!dev.IsVisible())
                    {
                        continue;
                    }

                    // determine tribool state
                    int state = !script.states.ContainsKey(pair.Key)
                                          ? -1
                                          : !script.states[pair.Key]
                                          ? 0
                                          : 1;

                    // render device entry
                    p.AddContent
                    (
                        dev.Name(),
                        state == -1 ? "<color=#999999>" + Localizer.Format("#KERBALISM_UI_dontcare") + " </color>" : state == 0 ? "<color=red>" + Localizer.Format("#KERBALISM_Generic_OFF") + "</color>" : "<color=cyan>" + Localizer.Format("#KERBALISM_Generic_ON") + "</color>",
                        string.Empty,
                        () =>
                    {
                        switch (state)
                        {
                        case -1: script.Set(dev, true); break;

                        case 0: script.Set(dev, null); break;

                        case 1: script.Set(dev, false); break;
                        }
                    },
                        () => Highlighter.Set(dev.Part(), Color.cyan)
                    );
                    deviceCount++;
                }
            }

            // no devices case
            if (deviceCount == 0)
            {
                p.AddContent("<i>no devices</i>");
            }
        }
Beispiel #11
0
 public override void OnSave(ConfigNode node)
 {
     // serialize data
     Science.CreditAllDeferred();
     DB.Save(node);
 }
Beispiel #12
0
        public Drive(ConfigNode node)
        {
            // parse science  files
            files = new Dictionary <SubjectData, File>();
            if (node.HasNode("files"))
            {
                foreach (var file_node in node.GetNode("files").GetNodes())
                {
                    string subject_id = DB.From_safe_key(file_node.name);
                    File   file       = File.Load(subject_id, file_node);
                    if (file != null)
                    {
                        if (files.ContainsKey(file.subjectData))
                        {
                            Lib.Log("Warning: discarding duplicate subject " + file.subjectData);
                        }
                        else
                        {
                            files.Add(file.subjectData, file);
                            file.subjectData.AddDataCollectedInFlight(file.size);
                        }
                    }
                    else
                    {
                        file = File.LoadOldFormat(subject_id, file_node);
                        if (file != null)
                        {
                            Lib.Log("Drive file load : converted '" + subject_id + "' to new format");
                            if (files.ContainsKey(file.subjectData))
                            {
                                Lib.Log("Warning: discarding duplicate converted subject " + file.subjectData);
                            }
                            else
                            {
                                files.Add(file.subjectData, file);
                                file.subjectData.AddDataCollectedInFlight(file.size);
                            }
                        }
                    }
                }
            }

            // parse science samples
            samples = new Dictionary <SubjectData, Sample>();
            if (node.HasNode("samples"))
            {
                foreach (var sample_node in node.GetNode("samples").GetNodes())
                {
                    string subject_id = DB.From_safe_key(sample_node.name);
                    Sample sample     = Sample.Load(subject_id, sample_node);
                    if (sample != null)
                    {
                        samples.Add(sample.subjectData, sample);
                        sample.subjectData.AddDataCollectedInFlight(sample.size);
                    }
                    else
                    {
                        sample = Sample.LoadOldFormat(subject_id, sample_node);
                        if (sample != null)
                        {
                            Lib.Log("Drive sample load : converted '" + subject_id + "' to new format");
                            samples.Add(sample.subjectData, sample);
                            sample.subjectData.AddDataCollectedInFlight(sample.size);
                        }
                    }
                }
            }

            name       = Lib.ConfigValue(node, "name", "DRIVE");
            is_private = Lib.ConfigValue(node, "is_private", false);

            // parse capacities. be generous with default values for backwards
            // compatibility (drives had unlimited storage before this)
            dataCapacity   = Lib.ConfigValue(node, "dataCapacity", 100000.0);
            sampleCapacity = Lib.ConfigValue(node, "sampleCapacity", 1000);

            fileSendFlags = new Dictionary <string, bool>();
            string fileNames = Lib.ConfigValue(node, "sendFileNames", string.Empty);

            foreach (string fileName in Lib.Tokenize(fileNames, ','))
            {
                Send(fileName, true);
            }
        }
Beispiel #13
0
 public void TransferData()
 {
     DB.Vessel(vessel).drive.location = part.flightID;
 }
Beispiel #14
0
        public void Update()
        {
            if (Lib.IsFlight())
            {
                Drive drive = DB.Vessel(vessel).drive;

                // if no location was ever specified, set it here
                if (drive.location == 0)
                {
                    drive.location = part.flightID;
                }

                // if this is the location the data is stored
                if (drive.location == part.flightID)
                {
                    // get data size
                    double size = drive.Size();

                    // show DATA UI button, with size info
                    Events["ToggleUI"].guiName = Lib.StatusToggle("Data", size > double.Epsilon ? Lib.HumanReadableDataSize(size) : "empty");
                    Events["ToggleUI"].active  = true;

                    // show TakeData eva action button, if there is something to take
                    Events["TakeData"].active = size > double.Epsilon;

                    // show StoreData eva action button, if active vessel is an eva kerbal and there is something to store from it
                    Vessel v = FlightGlobals.ActiveVessel;
                    Events["StoreData"].active = v != null && v.isEVA && !EVA.IsDead(v) && DB.Vessel(v).drive.Size() > double.Epsilon;

                    // hide TransferLocation button
                    Events["TransferData"].active = false;
                }
                // if this is not the location the data is stored
                else
                {
                    // hide DATA UI button
                    Events["ToggleUI"].active = false;

                    // hide EVA actions
                    Events["TakeData"].active  = false;
                    Events["StoreData"].active = false;

                    // show TransferData button
                    Events["TransferData"].active = true;
                }
            }
        }
Beispiel #15
0
  // called every simulation step
  void FixedUpdate()
  {
    // do nothing if paused
    if (Lib.IsPaused()) return;

    // do nothing in the editors and the menus
    if (!Lib.SceneIsGame()) return;

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

    // get elapsed time
    double elapsed_s = Kerbalism.elapsed_s;

    // evict oldest entry from vessel cache
    cache.update();

    // store info for oldest unloaded vessel
    double last_time = 0.0;
    Vessel last_v = null;
    vessel_info last_vi = null;
    vessel_data last_vd = null;
    vessel_resources last_resources = null;

    // for each vessel
    foreach(Vessel v in FlightGlobals.Vessels)
    {
      // get vessel info from the cache
      vessel_info vi = Cache.VesselInfo(v);

      // skip invalid vessels
      if (!vi.is_valid) continue;

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

      // get resource cache
      vessel_resources resources = ResourceCache.Get(v);

      // if loaded
      if (v.loaded)
      {
        // show belt warnings
        Radiation.beltWarnings(v, vi, vd);

        // update storm data
        storm.update(v, vi, vd, elapsed_s);

        // consume relay EC and show signal warnings
        signal.update(v, vi, vd, resources, elapsed_s * vi.time_dilation);

        // apply rules
        Rule.applyRules(v, vi, vd, resources, elapsed_s * vi.time_dilation);

        // apply deferred requests
        resources.Sync(v, elapsed_s);

        // update computer
        vd.computer.update(v, elapsed_s);

        // remove from unloaded data container
        unloaded.Remove(vi.id);
      }
      // if unloaded
      else
      {
        // get unloaded data, or create an empty one
        unloaded_data ud;
        if (!unloaded.TryGetValue(vi.id, out ud))
        {
          ud = new unloaded_data();
          unloaded.Add(vi.id, ud);
        }

        // accumulate time
        ud.time += elapsed_s;

        // maintain oldest entry
        if (ud.time > last_time)
        {
          last_time = ud.time;
          last_v = v;
          last_vi = vi;
          last_vd = vd;
          last_resources = resources;
        }
      }
    }


    // if the oldest unloaded vessel was selected
    if (last_v != null)
    {
      // show belt warnings
      Radiation.beltWarnings(last_v, last_vi, last_vd);

      // decay unloaded vessels inside atmosphere
      Kerbalism.atmosphereDecay(last_v, last_vi, last_time);

      // update storm data
      storm.update(last_v, last_vi, last_vd, last_time);

      // consume relay EC and show signal warnings
      signal.update(last_v, last_vi, last_vd, last_resources, last_time * last_vi.time_dilation);

      // apply rules
      Rule.applyRules(last_v, last_vi, last_vd, last_resources, last_time * last_vi.time_dilation);

      // simulate modules in background
      Background.update(last_v, last_vi, last_vd, last_resources, last_time * last_vi.time_dilation);

      // apply deferred requests
      last_resources.Sync(last_v, last_time);

      // update computer
      last_vd.computer.update(last_v, last_time);

      // remove from unloaded data container
      unloaded.Remove(last_vi.id);
    }


    // update storm data for one body per-step
    storm_bodies.ForEach(k => k.time += elapsed_s);
    storm_data sd = storm_bodies[storm_index];
    storm.update(sd.body, sd.time);
    sd.time = 0.0;
    storm_index = (storm_index + 1) % storm_bodies.Count;
  }
Beispiel #16
0
        public void FixedUpdate()
        {
            // do nothing in the editor
            if (Lib.IsEditor())
            {
                return;
            }

            // do nothing if vessel is invalid
            if (!Cache.VesselInfo(vessel).is_valid)
            {
                return;
            }

            // get ec handler
            Resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

            // if experiment is active
            if (recording)
            {
                // detect conditions
                // - comparing against amount in previous step
                bool   has_ec       = ec.amount > double.Epsilon;
                bool   has_operator = operator_cs.Check(vessel);
                string sit          = Science.Situation(vessel, situations);

                // deduce issues
                issue = string.Empty;
                if (sit.Length == 0)
                {
                    issue = "invalid situation";
                }
                else if (!has_operator)
                {
                    issue = "no operator";
                }
                else if (!has_ec)
                {
                    issue = "missing <b>EC</b>";
                }

                // if there are no issues
                if (issue.Length == 0)
                {
                    // generate subject id
                    string subject_id = Science.Generate_subject(experiment, vessel.mainBody, sit, Science.Biome(vessel, sit), Science.Multiplier(vessel, sit));

                    // record in drive
                    if (transmissible)
                    {
                        DB.Vessel(vessel).drive.Record_file(subject_id, data_rate * Kerbalism.elapsed_s);
                    }
                    else
                    {
                        DB.Vessel(vessel).drive.Record_sample(subject_id, data_rate * Kerbalism.elapsed_s);
                    }

                    // consume ec
                    ec.Consume(ec_rate * Kerbalism.elapsed_s);
                }
            }
        }