예제 #1
0
  public void Repair()
  {
    // do nothing if something is wrong, or the eva kerbal is dead
    Vessel v = FlightGlobals.ActiveVessel;
    if (v == null || !v.isEVA || EVA.IsDead(v)) return;

    // if the kerbal isn't an engineer, show a message and do nothing
    if (v.GetVesselCrew()[0].trait != "Engineer")
    {
      Message.Post("Only <b>Engineers</b> can repair parts");
      return;
    }

    // restore full functionality
    Apply(Math.Pow(2.0, (double)malfunctions));
    malfunctions = 0;

    // show a message
    Message.Post(Severity.relax, PrepareMsg(repair_msg, v, malfunctions));
  }
예제 #2
0
        public static void SetLocks(Vessel v, Vessel_Info vi)
        {
            // lock controls for EVA death
            if (EVA.IsDead(v))
            {
                InputLockManager.SetControlLock(ControlTypes.EVA_INPUT, "eva_dead_lock");
            }

            // lock controls for probes without signal
            if (vi.is_valid && !vi.connection.linked && vi.crew_count == 0 && Settings.UnlinkedControl != UnlinkedCtrl.full)
            {
                // choose no controls, or only full/zero throttle and staging
                ControlTypes ctrl = Settings.UnlinkedControl == UnlinkedCtrl.none
          ? ControlTypes.ALL_SHIP_CONTROLS
          : ControlTypes.PARTIAL_SHIP_CONTROLS;

                InputLockManager.SetControlLock(ctrl, "no_signal_lock");
                FlightInputHandler.state.mainThrottle = 0.0f;
            }
        }
예제 #3
0
        [KSPEvent(guiActive = false, guiActiveUnfocused = true, guiActiveUncommand = true, guiName = "#KERBALISM_HardDrive_TransferData", active = true, groupName = "Science", groupDisplayName = "#KERBALISM_Group_Science")]        //Science
        public void StoreData()
        {
            // disable for dead eva kerbals
            Vessel v = FlightGlobals.ActiveVessel;

            if (v == null || EVA.IsDead(v))
            {
                return;
            }

            // transfer data
            if (!Drive.Transfer(v, drive, PreferencesScience.Instance.sampleTransfer || Lib.CrewCount(v) > 0))
            {
                Message.Post
                (
                    Lib.Color(Lib.BuildString(Local.HardDrive_WARNING_title), Lib.Kolor.Red, true), //"WARNING: not evering copied"
                    Lib.BuildString(Local.HardDrive_WARNING)                                        //"Storage is at capacity"
                );
            }
        }
예제 #4
0
        public void TakeData()
        {
            // disable for dead eva kerbals
            Vessel v = FlightGlobals.ActiveVessel;

            if (v == null || EVA.IsDead(v))
            {
                return;
            }

            // transfer data
            if (!Drive.Transfer(drive, v, PreferencesScience.Instance.sampleTransfer || Lib.CrewCount(v) > 0))
            {
                Message.Post
                (
                    Lib.Color("red", Lib.BuildString("WARNING: not evering copied"), true),
                    Lib.BuildString("Storage is at capacity")
                );
            }
        }
예제 #5
0
		void ToEVA(GameEvents.FromToAction<Part, Part> data)
		{
			// get total crew in the origin vessel
			double tot_crew = (double)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);

			// 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];

				// determine quantity to take
				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);
			}

			// show warning if there isn't monoprop in the eva suit
			string prop_name = Lib.EvaPropellantName();
			if (Lib.Amount(data.to, prop_name) <= double.Epsilon && !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);
		}
예제 #6
0
        public void Update()
        {
            UpdateCapacity();

            if (Lib.IsFlight())
            {
                // show DATA UI button, with size info
                Events["ToggleUI"].guiName = Lib.StatusToggle("Data", drive.Empty() ? "empty" : drive.Size());
                Events["ToggleUI"].active  = true;

                // show TakeData eva action button, if there is something to take
                Events["TakeData"].active = !drive.Empty();

                // 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) && drive.FilesSize() > double.Epsilon;

                // hide TransferLocation button
                Events["TransferData"].active = true;
            }
        }
예제 #7
0
        public void Prepare()
        {
            // disable for dead eva kerbals
            Vessel v = FlightGlobals.ActiveVessel;

            if (v == null || EVA.IsDead(v))
            {
                return;
            }

            if (prepare_cs == null)
            {
                return;
            }

            // check trait
            if (!prepare_cs.Check(v))
            {
                Message.Post(
                    Lib.TextVariant
                    (
                        "I'm not qualified for this",
                        "I will not even know where to start",
                        "I'm afraid I can't do that"
                    ),
                    reset_cs.Warning()
                    );
            }

            didPrepare = true;

            Message.Post(
                "Preparation Complete",
                Lib.TextVariant
                (
                    "Ready to go",
                    "Let's start doing some science!"
                )
                );
        }
예제 #8
0
        public void Inspect()
        {
            // disable for dead eva kerbals
            Vessel v = FlightGlobals.ActiveVessel;

            if (v == null || EVA.IsDead(v))
            {
                return;
            }

            // get normalized time to failure
            double time_k = (Planetarium.GetUniversalTime() - last) / (next - last);

            // notify user
            if (time_k < 0.2)
            {
                Message.Post("It is practically new");
            }
            else if (time_k < 0.35)
            {
                Message.Post("It is in good shape");
            }
            else
            {
                needMaintenance = true;
                if (time_k < 0.6)
                {
                    Message.Post("It will keep working for some more time");
                }
                else if (time_k < 0.8)
                {
                    Message.Post("It is reaching its operational limits");
                }
                else
                {
                    Message.Post("It could fail at any moment now");
                }
            }
        }
예제 #9
0
        void manageResqueMission(Vessel v)
        {
            // skip eva dead kerbals
            // rationale: getting the kerbal data will create it again, leading to spurious resque mission detection
            if (EVA.IsDead(v))
            {
                return;
            }

            // deal with resque missions
            foreach (ProtoCrewMember c in v.GetVesselCrew())
            {
                // get kerbal data
                kerbal_data kd = DB.KerbalData(c.name);

                // flag the kerbal as not resque at prelaunch
                if (v.situation == Vessel.Situations.PRELAUNCH)
                {
                    kd.resque = 0;
                }

                // if the kerbal belong to a resque mission
                if (kd.resque == 1)
                {
                    // give the vessel some supply
                    Lib.RequestResource(v, v.isEVA ? "EVA Propellant" : "MonoPropellant", -Settings.ResqueMonoPropellant);
                    Lib.RequestResource(v, "ElectricCharge", -Settings.ResqueElectricCharge);
                    Lib.RequestResource(v, "Food", -Settings.ResqueFood);
                    Lib.RequestResource(v, "Oxygen", -Settings.ResqueOxygen);

                    // flag the kerbal as non-resque
                    // note: enable life support mechanics for the kerbal
                    kd.resque = 0;

                    // show a message
                    Message.Post("We found <b>" + c.name + "</b>", (c.gender == ProtoCrewMember.Gender.Male ? "He" : "She") + "'s still alive!");
                }
            }
        }
예제 #10
0
        public void Toggle()
        {
            if (Lib.IsFlight())
            {
                // disable for dead eva kerbals
                Vessel v = FlightGlobals.ActiveVessel;
                if (v == null || EVA.IsDead(v))
                {
                    return;
                }
                if (!deploy_cs.Check(v))
                {
                    Message.Post
                    (
                        Lib.TextVariant
                        (
                            "I don't know how this works!"
                        ),
                        deploy_cs.Warning()
                    );
                    return;
                }
            }

            // switch status
            deployed = !deployed;

            // play animation
            deploy_anim.Play(!deployed, false);

            // refresh VAB/SPH ui
            if (Lib.IsEditor())
            {
                GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship);
            }
        }
예제 #11
0
  // implement quality-of-life mechanics
  public void FixedUpdate()
  {
    // avoid case when DB isn't ready for whatever reason
    if (!DB.Ready()) return;

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

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

    // get time elapsed from last update
    double elapsed_s = TimeWarp.fixedDeltaTime;

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

      // skip dead eva kerbals
      if (EVA.IsDead(v)) continue;

      // get crew
      List<ProtoCrewMember> crew = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew();

      // calculate quality-of-life bonus
      double qol = Bonus(v);

      // for each crew
      foreach(ProtoCrewMember c in crew)
      {
        // get kerbal data
        kerbal_data kd = DB.KerbalData(c.name);

        // skip resque kerbals
        if (kd.resque == 1) continue;

        // skip disabled kerbals
        if (kd.disabled == 1) continue;

        // accumulate stress
        kd.stressed += Settings.StressedDegradationRate * elapsed_s / (qol * Variance(c));

        // in case of breakdown
        if (kd.stressed >= Settings.StressedEventThreshold)
        {
          // trigger breakdown event
          Breakdown(v, c);

          // reset stress halfway between danger and event threshold
          kd.stressed = (Settings.StressedDangerThreshold + Settings.StressedEventThreshold) * 0.5;
        }
        // show warning messages
        else if (kd.stressed >= Settings.StressedDangerThreshold && kd.msg_stressed < 2)
        {
          Message.Post(Severity.danger, KerbalEvent.stress, v, c);
          kd.msg_stressed = 2;
        }
        else if (kd.stressed >= Settings.StressedWarningThreshold && kd.msg_stressed < 1)
        {
          Message.Post(Severity.warning, KerbalEvent.stress, v, c);
          kd.msg_stressed = 1;
        }
        // note: no recovery from stress
      }
    }
  }
예제 #12
0
        public Vessel_info(Vessel v, UInt64 vessel_id, UInt64 inc)
        {
            // NOTE: anything used here can't in turn use cache, unless you know what you are doing

            // NOTE: you can't cache vessel position
            // at any point in time all vessel/body positions are relative to a different frame of reference
            // so comparing the current position of a vessel, with the cached one of another make no sense

            // associate with an unique incremental id
            this.inc = inc;

            // determine if this is a valid vessel
            is_vessel = Lib.IsVessel(v);
            if (!is_vessel)
            {
                return;
            }

            // determine if this is a rescue mission vessel
            is_rescue = Misc.IsRescueMission(v);
            if (is_rescue)
            {
                return;
            }

            // dead EVA are not valid vessels
            if (EVA.IsDead(v))
            {
                return;
            }

            // shortcut for common tests
            is_valid = true;

            // generate id once
            id = vessel_id;

            // calculate crew info for the vessel
            crew_count    = Lib.CrewCount(v);
            crew_capacity = Lib.CrewCapacity(v);

            // get vessel position
            Vector3d position = Lib.VesselPosition(v);

            // this should never happen again
            if (Vector3d.Distance(position, v.mainBody.position) < 1.0)
            {
                throw new Exception("Shit hit the fan for vessel " + v.vesselName);
            }

            // determine if there is enough EC for a powered state
            powered = ResourceCache.Info(v, "ElectricCharge").amount > double.Epsilon;

            // determine if in sunlight, calculate sun direction and distance
            sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0;

            // environment stuff
            atmo_factor        = Sim.AtmosphereFactor(v.mainBody, position, sun_dir);
            gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude);
            underwater         = Sim.Underwater(v);
            breathable         = Sim.Breathable(v, underwater);
            landed             = Lib.Landed(v);
            zerog = !landed && (!v.mainBody.atmosphere || v.mainBody.atmosphereDepth < v.altitude);

            if (v.mainBody.flightGlobalsIndex != 0 && TimeWarp.CurrentRate > 1000.0f)
            {
                highspeedWarp(v);
            }

            // temperature at vessel position
            temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux);
            temp_diff   = Sim.TempDiff(temperature, v.mainBody, landed);

            // radiation
            radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out magnetosphere, out inner_belt, out outer_belt, out interstellar);

            // extended atmosphere
            thermosphere = Sim.InsideThermosphere(v);
            exosphere    = Sim.InsideExosphere(v);

            // malfunction stuff
            malfunction = Reliability.HasMalfunction(v);
            critical    = Reliability.HasCriticalFailure(v);

            // communications info
            connection   = new ConnectionInfo(v, powered, blackout);
            transmitting = Science.Transmitting(v, connection.linked && connection.rate > double.Epsilon);

            // habitat data
            volume          = Habitat.Tot_volume(v);
            surface         = Habitat.Tot_surface(v);
            pressure        = Habitat.Pressure(v);
            evas            = (uint)(Math.Max(0, ResourceCache.Info(v, "Nitrogen").amount - 330) / PreferencesLifeSupport.Instance.evaAtmoLoss);
            poisoning       = Habitat.Poisoning(v);
            humidity        = Habitat.Humidity(v);
            shielding       = Habitat.Shielding(v);
            living_space    = Habitat.Living_space(v);
            volume_per_crew = Habitat.Volume_per_crew(v);
            comforts        = new Comforts(v, landed, crew_count > 1, connection.linked && connection.rate > double.Epsilon);

            // data about greenhouses
            greenhouses = Greenhouse.Greenhouses(v);

            // other stuff
            gravioli = Sim.Graviolis(v);
        }
예제 #13
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)
                {
                    // show belt warnings
                    Radiation.beltWarnings(v, vi, vd);

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

                    // show signal warnings
                    Signal.update(v, vi, vd, elapsed_s);

                    // consume ec for transmission, and 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;
                    }
                }
            }


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

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

                // show signal warnings
                Signal.update(last_v, last_vi, last_vd, last_time);

                // consume ec for transmission, and transmit science
                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;
            }
        }
예제 #14
0
        public void Update()
        {
            if (drive == null)
            {
                return;
            }

            if (Lib.IsEditor())
            {
                bool update = false;
                if (dataCapacities != null)
                {
                    foreach (var c in dataCapacities)
                    {
                        if (c.Key == dataCapacityUI)
                        {
                            update |= effectiveDataCapacity != c.Value;
                            effectiveDataCapacity = c.Value;
                        }
                    }
                }

                if (sampleCapacities != null)
                {
                    foreach (var c in sampleCapacities)
                    {
                        if (c.Key == sampleCapacityUI)
                        {
                            update |= effectiveSampleCapacity != c.Value;
                            effectiveSampleCapacity = c.Value;
                        }
                    }
                }

                drive.dataCapacity   = effectiveDataCapacity;
                drive.sampleCapacity = effectiveSampleCapacity;

                Fields["sampleCapacityUI"].guiActiveEditor = sampleCapacity > 0;
                Fields["dataCapacityUI"].guiActiveEditor   = dataCapacity > 0;

                if (update)
                {
                    GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship);
                    UpdateCapacity();
                }
            }

            if (Lib.IsFlight())
            {
                // show DATA UI button, with size info
                Events["ToggleUI"].guiName = Lib.StatusToggle("Data", drive.Empty() ? "empty" : drive.Size());
                Events["ToggleUI"].active  = !IsPrivate();

                // show TakeData eva action button, if there is something to take
                Events["TakeData"].active = !drive.Empty();

                // 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 = !IsPrivate() && v != null && v.isEVA && !EVA.IsDead(v);

                // hide TransferLocation button
                var transferVisible = !IsPrivate();
                if (transferVisible)
                {
                    transferVisible = Drive.GetDrives(vessel, true).Count > 1;
                }
                Events["TransferData"].active    = transferVisible;
                Events["TransferData"].guiActive = transferVisible;
            }
        }
예제 #15
0
        void FixedUpdate()
        {
            // remove control locks in any case
            Misc.ClearLocks();

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

            // convert elapsed time to double only once
            double fixedDeltaTime = TimeWarp.fixedDeltaTime;

            // and detect warp blending
            if (Math.Abs(fixedDeltaTime - elapsed_s) < 0.001)
            {
                warp_blending = 0;
            }
            else
            {
                ++warp_blending;
            }

            // update elapsed time
            elapsed_s = fixedDeltaTime;

            // store info for oldest unloaded vessel
            double          last_time      = 0.0;
            Guid            last_id        = Guid.Empty;
            Vessel          last_v         = null;
            VesselData      last_vd        = null;
            VesselResources last_resources = null;

            foreach (VesselData vd in DB.VesselDatas)
            {
                vd.EarlyUpdate();
            }

            // for each vessel
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // get vessel data
                VesselData vd = v.KerbalismData();

                // update the vessel data validity
                vd.Update(v);

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

                // 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 && vd.is_vessel)
                {
                    // manage rescue mission mechanics
                    Misc.ManageRescueMission(v);
                }

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

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

                // if loaded
                if (v.loaded)
                {
                    //UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.VesselDataEval");
                    // update the vessel info
                    vd.Evaluate(false, elapsed_s);
                    //UnityEngine.Profiling.Profiler.EndSample();

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

                    UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Radiation");
                    // show belt warnings
                    Radiation.BeltWarnings(v, vd);

                    // update storm data
                    Storm.Update(v, vd, elapsed_s);
                    UnityEngine.Profiling.Profiler.EndSample();

                    UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Comms");
                    Communications.Update(v, vd, ec, elapsed_s);
                    UnityEngine.Profiling.Profiler.EndSample();

                    // Habitat equalization
                    ResourceBalance.Equalizer(v);

                    UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Science");
                    // transmit science data
                    Science.Update(v, vd, ec, elapsed_s);
                    UnityEngine.Profiling.Profiler.EndSample();

                    UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Profile");
                    // apply rules
                    Profile.Execute(v, vd, resources, elapsed_s);
                    UnityEngine.Profiling.Profiler.EndSample();

                    UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Profile");
                    // part module resource updates
                    vd.ResourceUpdate(resources, elapsed_s);
                    UnityEngine.Profiling.Profiler.EndSample();

                    UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Resource");
                    // apply deferred requests
                    resources.Sync(v, vd, elapsed_s);
                    UnityEngine.Profiling.Profiler.EndSample();

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

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

                    // accumulate time
                    ud.time += elapsed_s;

                    // maintain oldest entry
                    if (ud.time > last_time)
                    {
                        last_time      = ud.time;
                        last_v         = v;
                        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)
            {
                //UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.VesselDataEval");
                // update the vessel info (high timewarp speeds reevaluation)
                last_vd.Evaluate(false, last_time);
                //UnityEngine.Profiling.Profiler.EndSample();

                // get most used resource
                ResourceInfo last_ec = last_resources.GetResource(last_v, "ElectricCharge");

                UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Radiation");
                // show belt warnings
                Radiation.BeltWarnings(last_v, last_vd);

                // update storm data
                Storm.Update(last_v, last_vd, last_time);
                UnityEngine.Profiling.Profiler.EndSample();

                UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Comms");
                Communications.Update(last_v, last_vd, last_ec, last_time);
                UnityEngine.Profiling.Profiler.EndSample();

                UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Profile");
                // apply rules
                Profile.Execute(last_v, last_vd, last_resources, last_time);
                UnityEngine.Profiling.Profiler.EndSample();

                UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Background");
                // simulate modules in background
                Background.Update(last_v, last_vd, last_resources, last_time);
                UnityEngine.Profiling.Profiler.EndSample();

                UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Science");
                // transmit science	data
                Science.Update(last_v, last_vd, last_ec, last_time);
                UnityEngine.Profiling.Profiler.EndSample();

                UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Resource");
                // apply deferred requests
                last_resources.Sync(last_v, last_vd, last_time);
                UnityEngine.Profiling.Profiler.EndSample();

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

                // remove from unloaded data container
                unloaded.Remove(last_vd.VesselId);
            }

            // 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;
            }
        }
예제 #16
0
파일: Cache.cs 프로젝트: zajc3w/Kerbalism
  public vessel_info(Vessel v, uint vessel_id, UInt64 inc)
  {
    // NOTE: anything used here can't in turn use cache, unless you know what you are doing

    // associate with an unique incremental id
    this.inc = inc;

    // determine if this is a valid vessel
    is_vessel = Lib.IsVessel(v);
    if (!is_vessel) return;

    // determine if this is a resque mission vessel
    is_resque = Lib.IsResqueMission(v);
    if (is_resque) return;

    // dead EVA are not valid vessels
    if (v.isEVA && EVA.KerbalData(v).eva_dead) return;

    // shortcut for common tests
    is_valid = true;

    // generate id once
    id = vessel_id;

    // calculate crew info for the vessel
    crew_count = Lib.CrewCount(v);
    crew_capacity = Lib.CrewCapacity(v);

    // get vessel position once
    position = Lib.VesselPosition(v);

    // determine if in sunlight, calculate sun direction and distance
    sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0;

    // if the orbit length vs simulation step is lower than an acceptable threshold, use discrete sun visibility
    if (v.mainBody.flightGlobalsIndex != 0)
    {
      double orbit_period = Sim.OrbitalPeriod(v);
      if (orbit_period / Kerbalism.elapsed_s < 16.0) sunlight = 1.0 - Sim.ShadowPeriod(v) / orbit_period;
    }

    // calculate environment stuff
    atmo_factor = Sim.AtmosphereFactor(v.mainBody, position, sun_dir);
    gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude);
    breathable = Sim.Breathable(v);
    landed = Lib.Landed(v);

    // calculate temperature at vessel position
    temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux);

    // calculate radiation
    radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out inside_pause, out inside_belt);

    // calculate malfunction stuff
    max_malfunction = Reliability.MaxMalfunction(v);
    avg_quality = Reliability.AverageQuality(v);

    // calculate signal info
    antenna = new antenna_data(v);
    avoid_inf_recursion.Add(v.id);
    link = Signal.Link(v, position, antenna, blackout, avoid_inf_recursion);
    avoid_inf_recursion.Remove(v.id);

    // partial data about modules, used by vessel info/monitor
    scrubbers = Scrubber.PartialData(v);
    recyclers = Recycler.PartialData(v);
    greenhouses = Greenhouse.PartialData(v);

    // woot relativity
    time_dilation = Sim.TimeDilation(v);
  }
예제 #17
0
        public void Update()
        {
            var exp = Science.Experiment(experiment_id);

            // in flight
            if (Lib.IsFlight())
            {
                Vessel v = FlightGlobals.ActiveVessel;
                if (v == null || EVA.IsDead(v))
                {
                    return;
                }

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

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

                var sampleSize = exp.max_amount;
                var eta        = data_rate < double.Epsilon || Done(exp, dataSampled) ? " done" : " " + Lib.HumanReadableCountdown((sampleSize - dataSampled) / data_rate);

                // update ui
                var title = Lib.Ellipsis(exp.name, Styles.ScaleStringLength(24));
                if (scienceValue > 0.1)
                {
                    title += " •<b>" + scienceValue.ToString("F1") + "</b>";
                }

                string statusString = string.Empty;
                switch (state)
                {
                case State.ISSUE: statusString = Lib.Color("yellow", issue); break;

                case State.RUNNING: statusString = Lib.HumanReadablePerc(dataSampled / sampleSize) + eta; break;

                case State.WAITING: statusString = "waiting" + eta; break;

                case State.STOPPED: statusString = "stopped"; break;
                }

                Events["Toggle"].guiName = Lib.StatusToggle(title, statusString);
                Events["Toggle"].active  = (prepare_cs == null || didPrepare);

                Events["Prepare"].guiName = Lib.BuildString("Prepare <b>", exp.name, "</b>");
                Events["Prepare"].active  = !didPrepare && prepare_cs != null && string.IsNullOrEmpty(last_subject_id);

                Events["Reset"].guiName = Lib.BuildString("Reset <b>", exp.name, "</b>");
                // we need a reset either if we have recorded data or did a setup
                bool resetActive = (reset_cs != null || prepare_cs != null) && !string.IsNullOrEmpty(last_subject_id);
                Events["Reset"].active = resetActive;

                if (issue.Length > 0 && hide_when_unavailable && issue != insufficient_storage)
                {
                    Events["Toggle"].active = false;
                }
            }
            // in the editor
            else if (Lib.IsEditor())
            {
                // update ui
                Events["Toggle"].guiName = Lib.StatusToggle(exp.name, recording ? "recording" : "stopped");
                Events["Reset"].active   = false;
                Events["Prepare"].active = false;
            }
        }
예제 #18
0
        // implement radiation mechanics
        public void FixedUpdate()
        {
            // avoid case when DB isn't ready for whatever reason
            if (!DB.Ready())
            {
                return;
            }

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

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

            // get time elapsed from last update
            double elapsed_s = TimeWarp.fixedDeltaTime;

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

                // skip dead eva kerbals
                if (EVA.IsDead(v))
                {
                    continue;
                }

                // get crew
                List <ProtoCrewMember> crew = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew();

                // get crew count
                int crew_count = Lib.CrewCount(v);

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

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


                // belt warnings
                // note: we only show it for manned vesssels, but the first time we also show it for probes
                if (crew_count > 0 || DB.NotificationData().first_belt_crossing == 0)
                {
                    if (InsideBelt(v) && vd.msg_belt < 1)
                    {
                        Message.Post("<b>" + v.vesselName + "</b> is crossing <i>" + v.mainBody.bodyName + " radiation belt</i>", "Exposed to extreme radiation");
                        vd.msg_belt = 1;
                        DB.NotificationData().first_belt_crossing = 1; //< record first belt crossing
                    }
                    else if (!InsideBelt(v) && vd.msg_belt > 0)
                    {
                        // no message after crossing the belt
                        vd.msg_belt = 0;
                    }
                }


                // for each crew
                foreach (ProtoCrewMember c in crew)
                {
                    // get kerbal data
                    kerbal_data kd = DB.KerbalData(c.name);

                    // skip resque kerbals
                    if (kd.resque == 1)
                    {
                        continue;
                    }

                    // skip disabled kerbals
                    if (kd.disabled == 1)
                    {
                        continue;
                    }

                    // accumulate radiation
                    kd.radiation += info.radiation * elapsed_s;

                    // kill kerbal if necessary
                    if (kd.radiation >= Settings.RadiationFatalThreshold)
                    {
                        Message.Post(Severity.fatality, KerbalEvent.radiation, v, c);
                        Kerbalism.Kill(v, c);
                    }
                    // show warnings
                    else if (kd.radiation >= Settings.RadiationDangerThreshold && kd.msg_radiation < 2)
                    {
                        Message.Post(Severity.danger, KerbalEvent.radiation, v, c);
                        kd.msg_radiation = 2;
                    }
                    else if (kd.radiation >= Settings.RadiationWarningThreshold && kd.msg_radiation < 1)
                    {
                        Message.Post(Severity.danger, KerbalEvent.radiation, v, c);
                        kd.msg_radiation = 1;
                    }
                    // note: no recovery from radiations
                }
            }
        }
예제 #19
0
        public void Update()
        {
            if (drive == null)
            {
                return;
            }

            if (Lib.IsFlight())
            {
                // show DATA UI button, with size info
                Events["ToggleUI"].guiName = Lib.StatusToggle("Data", drive.Empty() ? "empty" : drive.Size());
                Events["ToggleUI"].active  = !IsPrivate();

                // show TakeData eva action button, if there is something to take
                Events["TakeData"].active = !drive.Empty();

                // 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 = !IsPrivate() && v != null && v.isEVA && !EVA.IsDead(v);

                // hide TransferLocation button
                var transferVisible = !IsPrivate();
                if (transferVisible)
                {
                    transferVisible = Drive.GetDrives(vessel, true).Count > 1;
                }
                Events["TransferData"].active    = transferVisible;
                Events["TransferData"].guiActive = transferVisible;
            }
        }
예제 #20
0
  public vessel_info(Vessel v, uint vessel_id, UInt64 inc)
  {
    // NOTE: anything used here can't in turn use cache, unless you know what you are doing

    // NOTE: you can't cache vessel position
    // at any point in time all vessel/body positions are relative to a different frame of reference
    // so comparing the current position of a vessel, with the cached one of another make no sense

    // associate with an unique incremental id
    this.inc = inc;

    // determine if this is a valid vessel
    is_vessel = Lib.IsVessel(v);
    if (!is_vessel) return;

    // determine if this is a rescue mission vessel
    is_rescue = Misc.IsRescueMission(v);
    if (is_rescue) return;

    // dead EVA are not valid vessels
    if (EVA.IsDead(v)) return;

    // shortcut for common tests
    is_valid = true;

    // generate id once
    id = vessel_id;

    // calculate crew info for the vessel
    crew_count = Lib.CrewCount(v);
    crew_capacity = Lib.CrewCapacity(v);

    // get vessel position
    Vector3d position = Lib.VesselPosition(v);

    // this should never happen again
    if (Vector3d.Distance(position, v.mainBody.position) < 1.0)
    {
      throw new Exception("Shit hit the fan for vessel " + v.vesselName);
    }

    // determine if in sunlight, calculate sun direction and distance
    sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0;

    // at the two highest timewarp speed, the number of sun visibility samples drop to the point that
    // the quantization error first became noticeable, and then exceed 100%
    // to solve this, we switch to an analytical estimation of the portion of orbit that was in sunlight
    // - we check against timewarp rate, instead of index, to avoid issues during timewarp blending
    if (v.mainBody.flightGlobalsIndex != 0 && TimeWarp.CurrentRate > 1000.0f)
    {
      sunlight = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v);
    }

    // environment stuff
    atmo_factor = Sim.AtmosphereFactor(v.mainBody, position, sun_dir);
    gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude);
    underwater = Sim.Underwater(v);
    breathable = Sim.Breathable(v, underwater);
    landed = Lib.Landed(v);

    // temperature at vessel position
    temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux);
    temp_diff = Sim.TempDiff(temperature, v.mainBody, landed);

    // radiation
    radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out magnetosphere, out inner_belt, out outer_belt, out interstellar);

    // extended atmosphere
    thermosphere = Sim.InsideThermosphere(v);
    exosphere = Sim.InsideExosphere(v);

    // malfunction stuff
    malfunction = Reliability.HasMalfunction(v);
    critical = Reliability.HasCriticalFailure(v);

    // signal info
    antenna = new AntennaInfo(v);
    avoid_inf_recursion.Add(v.id);
    connection = Signal.connection(v, position, antenna, blackout, avoid_inf_recursion);
    transmitting = Science.transmitting(v, connection.linked);
    relaying = Signal.relaying(v, avoid_inf_recursion);
    avoid_inf_recursion.Remove(v.id);

    // habitat data
    volume = Habitat.tot_volume(v);
    surface = Habitat.tot_surface(v);
    pressure = Habitat.pressure(v);
    poisoning = Habitat.poisoning(v);
    shielding = Habitat.shielding(v);
    living_space = Habitat.living_space(v);
    comforts = new Comforts(v, landed, crew_count > 1, connection.linked);

    // data about greenhouses
    greenhouses = Greenhouse.Greenhouses(v);

    // other stuff
    gravioli = Sim.Graviolis(v);
  }
예제 #21
0
        public void Repair()
        {
            // disable for dead eva kerbals
            Vessel v = FlightGlobals.ActiveVessel;

            if (v == null || EVA.IsDead(v))
            {
                return;
            }

            // check trait
            if (!repair_cs.Check(v))
            {
                Message.Post
                (
                    Lib.TextVariant
                    (
                        "I'm not qualified for this",
                        "I will not even know where to start",
                        "I'm afraid I can't do that"
                    ),
                    repair_cs.Warning()
                );
                return;
            }

            // flag as not broken
            broken = false;

            // reset times
            last = 0.0;
            next = 0.0;

            // re-enable module
            foreach (PartModule m in modules)
            {
                m.isEnabled = true;
                m.enabled   = true;
            }

            // we need to reconfigure the module here, because if all modules of a type
            // share the broken state, and these modules are part of a configure setup,
            // then repairing will enable all of them, messing up with the configuration
            part.FindModulesImplementing <Configure>().ForEach(k => k.DoConfigure());

            // type-specific hacks
            Apply(false);

            // notify user
            Message.Post
            (
                Lib.BuildString("<b>", title, "</b> repaired"),
                Lib.TextVariant
                (
                    "A powerkick did the trick",
                    "Duct tape, is there something it can't fix?",
                    "Fully operational again",
                    "We are back in business"
                )
            );
        }
예제 #22
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();

            // vvvv------- This code tests for a theroy that could cause #313
            // If KSP itself has the same vessel more than once in the
            // FlightGlobals.Vessels list, it would cause processes to run too many times.
            // The other possible cause was a Vessel ID collision in Lib.VesselID(), which
            // only used 4 bytes of a 16 byte GUID to create an ID from.
            //
            // If the BUG TRIGGERED message is never observed in the wild,
            // it is safe to remove this chunk of code.
            Dictionary <UInt64, Vessel> vessels = new Dictionary <UInt64, Vessel>();

            foreach (Vessel v in FlightGlobals.Vessels)
            {
                if (vessels.ContainsKey(Lib.VesselID(v)))
                {
                    Lib.Log("THIS SHOULD NOT BE HAPPENING: Vessel " + v.name + " already seen in FlightGlobals.Vessels");
                    Message.Post(Lib.BuildString(Lib.Color("red", "BUG TRIGGERED", true), "\n",
                                                 v.name + " duplicated in FlightGlobals.Vessels. Please report this on GitHub."));
                }
                else
                {
                    vessels.Add(Lib.VesselID(v), v);
                }
            }
            // ^^^^-------- end theory test code

            // 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)
            foreach (Vessel v in vessels.Values)
            {
                // 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;
            }
        }
예제 #23
0
        void ToEVA(GameEvents.FromToAction <Part, Part> data)
        {
            OnVesselModified(data.from.vessel);
            OnVesselModified(data.to.vessel);

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

            // get vessel resources handler
            VesselResources 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.GetResource(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", Settings.LifeSupportAtmoLoss, ResourceBroker.Generic);

            // 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,
                             Local.CallBackMsg_EvaNoMP.Format("<b>" + prop_name + "</b>"), Local.CallBackMsg_EvaNoMP2);       //Lib.BuildString("There isn't any <<1>> 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
            data.from.vessel.KerbalismData().computer.Execute(data.from.vessel, ScriptType.eva_out);
        }
예제 #24
0
        void toEVA(GameEvents.FromToAction <Part, Part> data)
        {
            // use Hydrazine instead of MonoPropellant if RealFuel is installed
            string monoprop_name = detected_mods.RealFuels ? "Hydrazine" : "MonoPropellant";

            // determine if inside breathable atmosphere
            // note: the user can force the helmet + oxygen by pressing shift when going on eva
            bool breathable = Sim.Breathable(data.from.vessel) && !(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift));

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

            // EVA vessels start with 5 units of eva fuel, remove them
            data.to.RequestResource("EVA Propellant", 5.0);

            // determine how much MonoPropellant to get
            // note: never more that the 'share' of this kerbal
            double monoprop = Math.Min(ResourceCache.Info(data.from.vessel, monoprop_name).amount / tot_crew, Settings.MonoPropellantOnEVA);

            // get monoprop from the vessel
            monoprop = data.from.RequestResource(monoprop_name, monoprop);

            // transfer monoprop to the EVA kerbal
            data.to.RequestResource("EVA Propellant", -monoprop);

            // show warning if there isn't monoprop in the eva suit
            if (monoprop <= double.Epsilon && !Lib.Landed(data.from.vessel))
            {
                Message.Post(Severity.danger, Lib.BuildString("There isn't any <b>", monoprop_name, "</b> in the EVA suit", "Don't let the ladder go!"));
            }

            // manage resources from rules
            foreach (Rule r in rules)
            {
                if (r.resource_name.Length == 0 || r.on_eva <= double.Epsilon)
                {
                    continue;
                }

                // determine amount to take, never more that his own share
                double amount = Math.Min(ResourceCache.Info(data.from.vessel, r.resource_name).amount / tot_crew, r.on_eva);

                // deal with breathable modifier
                if (breathable && r.modifier.Contains("breathable"))
                {
                    continue;
                }

                // remove resource from the vessel
                amount = data.from.RequestResource(r.resource_name, amount);

                // create new resource in the eva kerbal
                Lib.SetupResource(data.to, r.resource_name, amount, r.on_eva);
            }

            // get KerbalEVA
            KerbalEVA kerbal = data.to.FindModuleImplementing <KerbalEVA>();

            // turn off headlamp light, to avoid stock bug that show the light for a split second when going on eva
            EVA.SetHeadlamp(kerbal, false);
            EVA.SetFlares(kerbal, false);

            // remove the helmet if inside breathable atmosphere
            // note: done in EVA::FixedUpdate(), but also done here avoid 'popping' of the helmet when going on eva
            EVA.SetHelmet(kerbal, !breathable);

            // remember if the kerbal has an helmet
            EVA.KerbalData(data.to.vessel).has_helmet = !breathable;

            // execute script on vessel computer
            if (DB.Ready())
            {
                DB.VesselData(data.from.vessel.id).computer.execute("run", "auto/eva_out", string.Empty, data.from.vessel);
            }

            // mute messages for a couple seconds to avoid warning messages from the vessel resource amounts
            Message.MuteInternal();
            base.StartCoroutine(CallbackUtil.DelayedCallback(2.0f, Message.UnmuteInternal));

            // if vessel info is open, switch to the eva kerbal
            // note: for a single tick, the EVA vessel is not valid (sun_dist is zero)
            // this make IsVessel() return false, that in turn close the vessel info instantly
            // for this reason, we wait a small amount of time before switching the info window
            if (Info.IsOpen())
            {
                Info.Open(data.to.vessel);
            }
        }
예제 #25
0
  // draw a vessel in the monitor
  // - return: 1 if vessel wasn't skipped
  uint render_vessel(Vessel v)
  {
    // avoid case when DB isn't ready for whatever reason
    if (!DB.Ready()) return 0;

    // skip invalid vessels
    if (!Lib.IsVessel(v)) return 0;

    // skip resque missions
    if (Lib.IsResqueMission(v)) return 0;

    // skip dead eva kerbals
    if (EVA.IsDead(v)) return 0;

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

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

    // skip filtered vessels
    if (filtered() && vd.group != filter) return 0;

    // get vessel crew
    List<ProtoCrewMember> crew = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew();

    // get vessel name
    string vessel_name = v.isEVA ? crew[0].name : v.vesselName;

    // get body name
    string body_name = v.mainBody.name.ToUpper();

    // get list of scrubbers
    List<Scrubber> scrubbers = Scrubber.GetScrubbers(v);

    // get list of greenhouses
    List<Greenhouse> greenhouses = Greenhouse.GetGreenhouses(v);

    // store problems icons & tooltips
    List<Texture> problem_icons = new List<Texture>();
    List<string> problem_tooltips = new List<string>();

    // detect problems
    problem_sunlight(vi, ref problem_icons, ref problem_tooltips);
    problem_storm(v, ref problem_icons, ref problem_tooltips);
    if (crew.Count > 0)
    {
      problem_kerbals(crew, ref problem_icons, ref problem_tooltips);
      problem_radiation(vi, ref problem_icons, ref problem_tooltips);
      problem_scrubbers(v, scrubbers, ref problem_icons, ref problem_tooltips);
    }
    problem_greenhouses(v, greenhouses, ref problem_icons, ref problem_tooltips);

    // choose problem icon
    const UInt64 problem_icon_time = 3;
    Texture problem_icon = icon_empty;
    if (problem_icons.Count > 0)
    {
      UInt64 problem_index = (Convert.ToUInt64(Time.realtimeSinceStartup) / problem_icon_time) % (UInt64)(problem_icons.Count);
      problem_icon = problem_icons[(int)problem_index];
    }

    // generate problem tooltips
    string problem_tooltip = String.Join("\n", problem_tooltips.ToArray());

    // render vessel name & icons
    GUILayout.BeginHorizontal(row_style);
    GUILayout.Label(new GUIContent("<b>" + Lib.Epsilon(vessel_name, 20) + "</b>", vessel_name.Length > 20 ? vessel_name : ""), name_style);
    GUILayout.Label(new GUIContent(Lib.Epsilon(body_name, 8), body_name.Length > 8 ? body_name : ""), body_style);
    GUILayout.Label(new GUIContent(problem_icon, problem_tooltip), icon_style);
    GUILayout.Label(indicator_ec(v), icon_style);
    GUILayout.Label(indicator_supplies(v, scrubbers, greenhouses), icon_style);
    GUILayout.Label(indicator_reliability(v), icon_style);
    GUILayout.Label(indicator_signal(v), icon_style);
    GUILayout.EndHorizontal();

    // remember last vessel clicked
    if (Lib.IsClicked()) last_clicked_id = v.id;

    // render vessel config
    if (configured_id == v.id) render_config(v);

    // spacing between vessels
    GUILayout.Space(10.0f);

    // signal that the vessel wasn't skipped for whatever reason
    return 1;
  }
예제 #26
0
        void toEVA(GameEvents.FromToAction <Part, Part> data)
        {
            // determine if inside breathable atmosphere
            bool breathable = LifeSupport.BreathableAtmosphere(data.from.vessel);

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

            // add resource definitions to EVA vessel part
            Lib.SetupResource(data.to, "ElectricCharge", 0.0, Settings.ElectricChargeOnEVA);
            if (!breathable)
            {
                Lib.SetupResource(data.to, "Oxygen", 0.0, Settings.OxygenOnEVA);
            }


            // determine how much MonoPropellant to get
            // note: never more that the 'share' of this kerbal
            double monoprop = Math.Min(Lib.GetResourceAmount(data.from.vessel, "MonoPropellant") / tot_crew, Settings.MonoPropellantOnEVA);

            // determine how much ElectricCharge to get
            // note: never more that the 'share' of this kerbal
            // note: always keep half the ec in the vessel
            double ec = Math.Min(Lib.GetResourceAmount(data.from.vessel, "ElectricCharge") / (tot_crew * 2.0), Settings.ElectricChargeOnEVA);


            // EVA vessels start with 5 units of eva fuel, remove them
            data.to.RequestResource("EVA Propellant", 5.0);

            // transfer monoprop
            data.to.RequestResource("EVA Propellant", -data.from.RequestResource("MonoPropellant", monoprop));

            // transfer ec
            data.to.RequestResource("ElectricCharge", -data.from.RequestResource("ElectricCharge", ec));


            // if outside breathable atmosphere
            if (!breathable)
            {
                // determine how much Oxygen to get
                // note: never more that the 'share' of this kerbal
                double oxygen = Math.Min(Lib.GetResourceAmount(data.from.vessel, "Oxygen") / tot_crew, Settings.OxygenOnEVA);

                // transfer oxygen
                data.to.RequestResource("Oxygen", -data.from.RequestResource("Oxygen", oxygen));
            }


            // get KerbalEVA
            KerbalEVA kerbal = data.to.FindModuleImplementing <KerbalEVA>();

            // turn off headlamp light, to avoid stock bug that show the light for a split second when going on eva
            EVA.SetHeadlamp(kerbal, false);
            EVA.SetFlares(kerbal, false);

            // remove the helmet if inside breathable atmosphere
            // note: done in EVA::FixedUpdate(), but also done here avoid 'popping' of the helmet when going on eva
            EVA.SetHelmet(kerbal, !breathable);

            // remember if the kerbal has an helmet in the EVA module
            data.to.FindModuleImplementing <EVA>().has_helmet = !breathable;


            // show warning if there isn't monoprop in the eva suit
            if (monoprop <= double.Epsilon && !Lib.Landed(data.from.vessel))
            {
                Message.Post(Severity.danger, "There isn't any <b>MonoPropellant</b> in the EVA suit", "Don't let the ladder go!");
            }
        }
예제 #27
0
        public void Update()
        {
            // in flight
            if (Lib.IsFlight())
            {
                Vessel v = FlightGlobals.ActiveVessel;
                if (v == null || EVA.IsDead(v))
                {
                    return;
                }

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

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

                var sampleSize      = (exp.scienceCap * exp.dataScale);
                var recordedPercent = Lib.HumanReadablePerc(dataSampled / sampleSize);
                var eta             = data_rate < double.Epsilon || dataSampled >= sampleSize ? " done" : " T-" + Lib.HumanReadableDuration((sampleSize - dataSampled) / data_rate);

                // update ui
                Events["Toggle"].guiName = Lib.StatusToggle(exp.experimentTitle, !recording ? "stopped"
                                                                            : Lib.Color(issue.Length > 0 ? "#ffff00":"", Lib.HumanReadablePerc(dataSampled / sampleSize) + "..."));
                Events["Toggle"].active = (prepare_cs == null || didPrepare);

                Events["Prepare"].guiName = Lib.BuildString("Prepare <b>", exp.experimentTitle, "</b>");
                Events["Prepare"].active  = !didPrepare && prepare_cs != null && string.IsNullOrEmpty(last_subject_id);

                Events["Reset"].guiName = Lib.BuildString("Reset <b>", exp.experimentTitle, "</b>");
                // we need a reset either if we have recorded data or did a setup
                bool resetActive = sample_mass < float.Epsilon && (reset_cs != null || prepare_cs != null) && !string.IsNullOrEmpty(last_subject_id);
                Events["Reset"].active = resetActive;

                Fields["ExperimentStatus"].guiName   = exp.experimentTitle;
                Fields["ExperimentStatus"].guiActive = true;

                if (issue.Length > 0)
                {
                    ExperimentStatus = Lib.BuildString("<color=#ffff00>", issue, "</color>");
                }
                else if (dataSampled > 0)
                {
                    string a = string.Empty;
                    string b = string.Empty;

                    if (sample_mass < float.Epsilon)
                    {
                        a = Lib.HumanReadableDataSize(dataSampled);
                        b = Lib.HumanReadableDataSize(sampleSize);
                    }
                    else
                    {
                        a = Lib.SampleSizeToSlots(dataSampled).ToString();
                        b = Lib.HumanReadableSampleSize(sampleSize);

                        if (remainingSampleMass > double.Epsilon)
                        {
                            b += " " + Lib.HumanReadableMass(remainingSampleMass) + " left";
                        }
                    }

                    ExperimentStatus = Lib.BuildString(a, "/", b, eta);
                }
                else
                {
                    var size = sample_mass < double.Epsilon ? Lib.HumanReadableDataSize(sampleSize) : Lib.HumanReadableSampleSize(sampleSize);
                    ExperimentStatus = Lib.BuildString("ready ", size, " in ", Lib.HumanReadableDuration(sampleSize / data_rate));
                }
            }
            // in the editor
            else if (Lib.IsEditor())
            {
                // update ui
                Events["Toggle"].guiName = Lib.StatusToggle(exp.experimentTitle, recording ? "recording" : "stopped");
                Events["Reset"].active   = false;
                Events["Prepare"].active = false;
            }
        }
예제 #28
0
        // kill a kerbal
        public static void Kill(Vessel v, ProtoCrewMember c)
        {
            // forget kerbal data
            DB.ForgetKerbal(c.name);

            // 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 and kill it
                    part.RemoveCrewmember(c);
                    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 vessel
                    part.RemoveCrew(c.name);

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

                    // register background death manually for death report notifications
                    Notifications.RegisterDeath();
                }
            }
            // else it must be an eva death
            else
            {
                // flag as eva death
                EVA.Kill(v);

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

                // register eva death manually for death report notifications
                Notifications.RegisterDeath();
            }

            // remove reputation
            if (HighLogic.CurrentGame.Mode == Game.Modes.CAREER)
            {
                Reputation.Instance.AddReputation(-Settings.DeathReputationPenalty, TransactionReasons.Any);
            }
        }
예제 #29
0
        public void FixedUpdate()
        {
            // remove control locks in any case
            clearLocks();

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

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

            // 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;

            // for each vessel
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // skip unloaded vessels
                if (!v.loaded)
                {
                    continue;
                }

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

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

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

                // keep track of resque mission kerbals, and gift resources to their vessels on discovery
                if (vi.is_vessel)
                {
                    // manage resque mission mechanics
                    manageResqueMission(v);
                }

                // update connected spaces using CLS, for QoL and Radiation mechanics
                if (vi.is_valid)
                {
                    updateConnectedSpaces(v, vi);
                }
            }
        }
예제 #30
0
        void resourceWarnings()
        {
            // for each vessel
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // skip invalid vessels
                if (!Lib.IsVessel(v))
                {
                    continue;
                }

                // skip resque missions
                if (Lib.IsResqueMission(v))
                {
                    continue;
                }

                // skip dead eva kerbal
                if (EVA.IsDead(v))
                {
                    continue;
                }

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

                // get EC amount and capacity
                double ec_amount   = Lib.GetResourceAmount(v, "ElectricCharge");
                double ec_capacity = Lib.GetResourceCapacity(v, "ElectricCharge");
                double ec_perc     = ec_capacity > 0.0 ? ec_amount / ec_capacity : 0.0;

                // if it has EC capacity
                if (ec_capacity > 0.0)
                {
                    // check EC thresholds and show messages
                    if (ec_perc <= Settings.ResourceDangerThreshold && vd.msg_ec < 2)
                    {
                        if (vd.cfg_ec == 1)
                        {
                            Message.Post(Severity.danger, VesselEvent.ec, v);
                        }
                        vd.msg_ec = 2;
                    }
                    else if (ec_perc <= Settings.ResourceWarningThreshold && vd.msg_ec < 1)
                    {
                        if (vd.cfg_ec == 1)
                        {
                            Message.Post(Severity.warning, VesselEvent.ec, v);
                        }
                        vd.msg_ec = 1;
                    }
                    else if (ec_perc > Settings.ResourceWarningThreshold && vd.msg_ec > 0)
                    {
                        if (vd.cfg_ec == 1)
                        {
                            Message.Post(Severity.relax, VesselEvent.ec, v);
                        }
                        vd.msg_ec = 0;
                    }
                }

                // get food amount and capacity
                double food_amount   = Lib.GetResourceAmount(v, "Food");
                double food_capacity = Lib.GetResourceCapacity(v, "Food");
                double food_perc     = food_capacity > 0.0 ? food_amount / food_capacity : 0.0;

                // if it has food capacity
                if (food_capacity > 0.0)
                {
                    // check food thresholds and show messages
                    // note: no warnings at prelaunch
                    if (food_perc <= Settings.ResourceDangerThreshold && vd.msg_food < 2)
                    {
                        if (vd.cfg_supply == 1 && v.situation != Vessel.Situations.PRELAUNCH)
                        {
                            Message.Post(Severity.danger, VesselEvent.food, v);
                        }
                        vd.msg_food = 2;
                    }
                    else if (food_perc <= Settings.ResourceWarningThreshold && vd.msg_food < 1)
                    {
                        if (vd.cfg_supply == 1 && v.situation != Vessel.Situations.PRELAUNCH)
                        {
                            Message.Post(Severity.warning, VesselEvent.food, v);
                        }
                        vd.msg_food = 1;
                    }
                    else if (food_perc > Settings.ResourceWarningThreshold && vd.msg_food > 0)
                    {
                        if (vd.cfg_supply == 1 && v.situation != Vessel.Situations.PRELAUNCH)
                        {
                            Message.Post(Severity.relax, VesselEvent.food, v);
                        }
                        vd.msg_food = 0;
                    }
                }

                // get oxygen amount and capacity
                double oxygen_amount   = Lib.GetResourceAmount(v, "Oxygen");
                double oxygen_capacity = Lib.GetResourceCapacity(v, "Oxygen");
                double oxygen_perc     = oxygen_capacity > 0.0 ? oxygen_amount / oxygen_capacity : 0.0;

                // if it has oxygen capacity
                if (oxygen_capacity > 0.0)
                {
                    // check oxygen thresholds and show messages
                    // note: no warnings at prelaunch
                    if (oxygen_perc <= Settings.ResourceDangerThreshold && vd.msg_oxygen < 2)
                    {
                        if (vd.cfg_supply == 1 && v.situation != Vessel.Situations.PRELAUNCH)
                        {
                            Message.Post(Severity.danger, VesselEvent.oxygen, v);
                        }
                        vd.msg_oxygen = 2;
                    }
                    else if (oxygen_perc <= Settings.ResourceWarningThreshold && vd.msg_oxygen < 1)
                    {
                        if (vd.cfg_supply == 1 && v.situation != Vessel.Situations.PRELAUNCH)
                        {
                            Message.Post(Severity.warning, VesselEvent.oxygen, v);
                        }
                        vd.msg_oxygen = 1;
                    }
                    else if (oxygen_perc > Settings.ResourceWarningThreshold && vd.msg_oxygen > 0)
                    {
                        if (vd.cfg_supply == 1 && v.situation != Vessel.Situations.PRELAUNCH)
                        {
                            Message.Post(Severity.relax, VesselEvent.oxygen, v);
                        }
                        vd.msg_oxygen = 0;
                    }
                }
            }
        }