Beispiel #1
0
  // trigger malfunction for unloaded module
  public static void Break(Vessel v, ProtoPartModuleSnapshot m)
  {
    // get data
    uint malfunctions = Lib.GetProtoValue<uint>(m, "malfunctions");
    double lifetime = Lib.GetProtoValue<double>(m, "lifetime");
    double age = Lib.GetProtoValue<double>(m, "age");
    string malfunction_msg = m.moduleValues.GetValue("malfunction_msg");

    // limit number of malfunctions per-component
    if (malfunctions >= 2u) return;

    // increase malfunction
    ++malfunctions;

    // reset age and lifetime
    age = 0.0;
    lifetime = 0.0;

    // show message
    if (DB.Ready() && DB.VesselData(v.id).cfg_malfunction == 1)
    {
      Message.Post(Severity.warning, PrepareMsg(malfunction_msg, v, malfunctions));
    }

    // record first malfunction
    if (DB.Ready()) DB.NotificationData().first_malfunction = 1;

    // save data
    Lib.SetProtoValue<uint>(m, "malfunctions", malfunctions);
    Lib.SetProtoValue<double>(m, "lifetime", lifetime);
    Lib.SetProtoValue<double>(m, "age", age);
  }
Beispiel #2
0
 public static void ShowMessage(Vessel v, string type)
 {
     if (DB.Ready() && DB.VesselData(v.id).cfg_malfunction == 1)
     {
         Message.Post(Severity.warning, Lib.BuildString("<b>", type, "</b> malfunctioned on <b>", v.vesselName, "</b>"));
     }
 }
Beispiel #3
0
        // return true if the vessel is a resque mission
        public static bool IsResqueMission(Vessel v)
        {
            // if db isn't ready, assume a resque mission
            if (!DB.Ready())
            {
                return(true);
            }

            // avoid re-creating dead eva kerbals in the db
            // note: no extra cost if vessel is not eva
            if (EVA.IsDead(v))
            {
                return(true);
            }

            // if at least one of the crew is flagged as resque, consider it a resque mission
            var crew_members = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew();

            foreach (var c in crew_members)
            {
                kerbal_data kd = DB.KerbalData(c.name);
                if (kd.resque == 1)
                {
                    return(true);
                }
            }

            // not a resque mission
            return(false);
        }
Beispiel #4
0
  // called every frame twice, first to compute ui layout and then to draw the ui
  void OnGUI()
  {
    // re-enable camera mouse scrolling, as some of the following functions can
    // disable it on mouse-hover, but can't re-enable it again consistently
    // (eg: you mouse-hover and then close the window with the cursor still inside it)
    // note: we are ignoring user preference on mouse wheel
    GameSettings.AXIS_MOUSEWHEEL.primary.scale = 1.0f;

    // always render the launcher
    launcher.on_gui();

    // always render the messages
    message.on_gui();

    // do nothing else if DB isn't ready or if we are in the editor
    if (!DB.Ready() || !Lib.SceneIsGame()) return;

    // do nothing if GUI should be hidden
    if (launcher.must_hide_ui) return;

    // render subsystems
    info.on_gui();
    body_info.on_gui();
    console.on_gui();
    editor.on_gui();
  }
Beispiel #5
0
 // return time left until CME is over
 public static double TimeLeftCME(CelestialBody body)
 {
   if (body.flightGlobalsIndex == 0) return 0.0;
   if (!DB.Ready()) return 0.0;
   body_data bd = DB.BodyData(Lib.PlanetarySystem(body).name);
   return Math.Max(0.0, bd.storm_time - bd.storm_age);
 }
Beispiel #6
0
  public float height()
  {
    // note: this function is abused to determine if the filter must be shown

    // guess vessel count
    uint count = 0;
    show_filter = false;
    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 kerbals
      if (EVA.IsDead(v)) continue;

      // avoid problems if the DB isn't ready
      if (DB.Ready())
      {
        // get vessel data
        vessel_data vd = DB.VesselData(v.id);

        // determine if filter must be shown
        show_filter |= vd.group.Length > 0 && vd.group != "NONE";

        // if the panel is filtered, skip filtered vessels
        if (filtered() && vd.group != filter) continue;
      }

      // the vessel will be rendered
      ++count;
    }

    // deal with no vessels case
    count = Math.Max(1u, count);

    // calculate height
    float vessels_height = 10.0f + (float)count * (16.0f + 10.0f);
    uint config_entries = 0;
    if (configured_id != Guid.Empty)
    {
      config_entries = 3u; // group, info & notes
      if (Kerbalism.ec_rule != null) ++config_entries;
      if (Kerbalism.supply_rules.Count > 0) ++config_entries;
      if (Kerbalism.features.signal) config_entries += 2u;
      if (Kerbalism.features.malfunction) config_entries += 2u;
      if (Settings.StormDuration > double.Epsilon) ++config_entries;
      if (filtered()) ++config_entries;
    }
    float config_height = (float)config_entries * 16.0f;
    float filter_height = show_filter ? 16.0f + 10.0f : 0.0f;
    return Math.Min(vessels_height + config_height + filter_height, Screen.height * 0.5f);
  }
Beispiel #7
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;
            }

            // if there is an active vessel
            Vessel v = FlightGlobals.ActiveVessel;

            if (v != null && Lib.IsVessel(v))
            {
                // set control locks if necessary
                setLocks(v);

                // update thermometer readings
                updateThermometers(v);

                // manage resque mission mechanics
                manageResqueMission(v);
            }

            // show vessel resource warnings
            resourceWarnings();

            // decay debris orbits
            atmosphereDecay();


            // FIXME: forcing warp rate here essentially stop the 'slow warp change' done in Lib.StopWarp(), temporarely disabled
            // [disabled] detect if there are any serious warnings active
            // note: we consider serious only the ones that have a time-to-death shorther than 1 day
            //bool warnings = false;
            //foreach(var p in DB.Kerbals())
            //{
            //  kerbal_data kd = p.Value;
            //  warnings |= kd.msg_freezing > 0;
            //  warnings |= kd.msg_burning > 0;
            //  warnings |= kd.msg_deprived > 0;
            //}
            // if there is a warning active, do not allow the user to warp at high speed
            // rationale: at high warp speed, even stopping warping don't give the user time to react, kerbals just die
            //if (warnings && TimeWarp.CurrentRateIndex > 4) TimeWarp.SetRate(4, true);
        }
Beispiel #8
0
 public override bool MeetRequirements()
 {
   // stop checking when requirements are met
   if (!meet_requirements)
   {
     meet_requirements =
       Kerbalism.rad_rule != null // a radiation rule is present
       && ProgressTracking.Instance != null && ProgressTracking.Instance.reachSpace.IsComplete // first suborbit flight completed
       && DB.Ready() && DB.Landmarks().belt_crossing == 0; // belt never crossed before
   }
   return meet_requirements;
 }
Beispiel #9
0
 public override bool MeetRequirements()
 {
   // stop checking when requirements are met
   if (!meet_requirements)
   {
     meet_requirements =
       PartLoader.getPartInfoByName("Greenhouse") != null  // greenhouse part is present
       && Lib.TechReady() && Lib.HasTech("scienceTech")    // greenhouse unlocked
       && DB.Ready() && DB.Landmarks().space_harvest == 0; // greenhouse never harvested in space before
   }
   return meet_requirements;
 }
Beispiel #10
0
 public override bool MeetRequirements()
 {
   // stop checking when requirements are met
   if (!meet_requirements)
   {
     meet_requirements =
       (Kerbalism.ec_rule != null || Kerbalism.supply_rules.Count > 0) // some resource-related life support rule is present
       && ProgressTracking.Instance != null && ProgressTracking.Instance.celestialBodyHome.orbit.IsComplete // first orbit completed
       && DB.Ready() && DB.Landmarks().manned_orbit== 0; // contract never completed
   }
   return meet_requirements;
 }
Beispiel #11
0
 // hook: DisableKerbal()
 public static void hook_DisableKerbal(string k_name, bool disabled)
 {
     if (!DB.Ready())
     {
         return;
     }
     if (!DB.Kerbals().ContainsKey(k_name))
     {
         return;
     }
     DB.KerbalData(k_name).disabled = disabled ? 1u : 0;
 }
Beispiel #12
0
 // hook: LivingSpace()
 public static double hook_LivingSpace(string k_name)
 {
     if (!DB.Ready())
     {
         return(1.0);
     }
     if (!DB.Kerbals().ContainsKey(k_name))
     {
         return(1.0);
     }
     return(DB.KerbalData(k_name).living_space);
 }
Beispiel #13
0
 // hook: Entertainment()
 public static double hook_Entertainment(string k_name)
 {
     if (!DB.Ready())
     {
         return(1.0);
     }
     if (!DB.Kerbals().ContainsKey(k_name))
     {
         return(1.0);
     }
     return(DB.KerbalData(k_name).entertainment);
 }
Beispiel #14
0
 // hook: Shielding()
 public static double hook_Shielding(string k_name)
 {
     if (!DB.Ready())
     {
         return(0.0);
     }
     if (!DB.Kerbals().ContainsKey(k_name))
     {
         return(0.0);
     }
     return(DB.KerbalData(k_name).shielding);
 }
Beispiel #15
0
        public void BuildLinks()
        {
            // clear links container
            links.Clear();

            // clear active relays container
            active_relays.Clear();

            // iterate over all vessels
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // skip invalid vessels
                if (!Lib.IsVessel(v))
                {
                    continue;
                }

                // generate and store link status
                link_data ld = ComputeLink(v, new HashSet <Guid>());
                links.Add(v.id, ld);

                // maintain and send messages
                // - do nothing if db isn't ready
                // - do not send messages for vessels without an antenna
                if (DB.Ready() && ld.status != link_status.no_antenna)
                {
                    vessel_data vd = DB.VesselData(v.id);
                    if (vd.msg_signal < 1 && !ld.linked)
                    {
                        vd.msg_signal = 1;
                        if (DB.Ready())
                        {
                            DB.NotificationData().first_signal_loss = 1; //< record first signal loss
                        }
                        if (vd.cfg_signal == 1 && !Blackout(v))          //< do not send message during storms
                        {
                            bool is_probe = (v.loaded ? v.GetCrewCount() == 0 : v.protoVessel.GetVesselCrew().Count == 0);
                            Message.Post(Severity.warning, "Signal lost with <b>" + v.vesselName + "</b>", is_probe ? "Remote control disabled" : "Data transmission disabled");
                        }
                    }
                    else if (vd.msg_signal > 0 && ld.linked)
                    {
                        vd.msg_signal = 0;
                        if (vd.cfg_signal == 1 && !Storm.JustEnded(v.mainBody, TimeWarp.deltaTime)) //< do not send messages after a storm
                        {
                            Message.Post(Severity.relax, "<b>" + v.vesselName + "</b> signal is back",
                                         ld.path.Count == 0 ? "We got a direct link with the space center" : "Relayed by <b>" + ld.path[ld.path.Count - 1] + "</b>");
                        }
                    }
                }
            }
        }
Beispiel #16
0
  // called every frame
  public void OnGUI()
  {
    // avoid case when DB isn't ready for whatever reason
    if (!DB.Ready()) return;

    // check only when at the space center
    if (HighLogic.LoadedScene != GameScenes.SPACECENTER) return;

    // check once in a while
    float time = Time.realtimeSinceStartup;
    if (last_check + check_interval > time) return;
    last_check = time;

    // get notification data
    notification_data nd = DB.NotificationData();

    // if there are tutorials left to show
    if (nd.next_tutorial < tutorials.Length)
    {
      // check tutorial condition
      if (tutorial_condition(nd.next_tutorial))
      {
        // check if the relative feature is enabled
        if (tutorial_feature(nd.next_tutorial))
        {
          // show notification
          Entry e = tutorials[nd.next_tutorial];
          Notification(e.title, e.msg, "INFO");
        }

        // move to next tutorial
        ++nd.next_tutorial;
      }
    }

    // if there is one or more new deaths
    if (nd.death_counter > nd.last_death_counter)
    {
      // show notification
      Entry e = death_report[nd.next_death_report];
      Notification(e.title, e.msg, "ALERT");

      // move to next tutorial, cycle throwgh all of them repetatedly
      // note: done this way because modulo didn't work...
      ++nd.next_death_report;
      if (nd.next_death_report >= death_report.Length) nd.next_death_report -= (uint)death_report.Length;
    }

    // remember number of death kerbals
    nd.last_death_counter = nd.death_counter;
  }
Beispiel #17
0
        // hook: InjectRadiation()
        public static void hook_InjectRadiation(string k_name, double amount)
        {
            if (!DB.Ready())
            {
                return;
            }
            if (!DB.Kerbals().ContainsKey(k_name))
            {
                return;
            }
            kerbal_data kd = DB.KerbalData(k_name);

            kd.radiation = Math.Max(kd.radiation + amount, 0.0);
        }
Beispiel #18
0
        void fromEVA(GameEvents.FromToAction <Part, Part> data)
        {
            // use Hydrazine instead of MonoPropellant if RealFuel is installed
            string monoprop_name = detected_mods.RealFuels ? "Hydrazine" : "MonoPropellant";

            // get any leftover EVA Fuel from EVA vessel
            double monoprop = data.from.Resources.list[0].amount;

            // add the leftover monoprop back to the pod
            data.to.RequestResource(monoprop_name, -monoprop);

            // manage resources in rules
            foreach (Rule r in rules)
            {
                if (r.resource_name.Length == 0 || r.on_eva <= double.Epsilon)
                {
                    continue;
                }
                double leftover = ResourceCache.Info(data.from.vessel, r.resource_name).amount;
                data.to.RequestResource(r.resource_name, -leftover);
            }

            // merge EVA computer files into vessel
            Computer a = DB.VesselData(data.from.vessel.id).computer;
            Computer b = DB.VesselData(data.to.vessel.id).computer;

            b.merge(a);

            // forget vessel data
            DB.ForgetVessel(data.from.vessel.id);

            // purge vessel from resource cache
            ResourceCache.Purge(data.from.vessel.id);

            // execute script on vessel computer
            if (DB.Ready())
            {
                DB.VesselData(data.to.vessel.id).computer.execute("run", "auto/eva_in", string.Empty, data.to.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 vessel
            if (Info.IsOpen())
            {
                Info.Open(data.to.vessel);
            }
        }
Beispiel #19
0
  // return true if a storm just ended
  // used to avoid sending 'signal is back' messages en-masse after the storm is over
  // - delta_time: time between calls to this function
  public static bool JustEnded(Vessel v, double delta_time)
  {
    if (!DB.Ready()) return false;

    // if in interplanetary space
    if (v.mainBody.flightGlobalsIndex == 0)
    {
      return DB.VesselData(v.id).storm_age < delta_time * 2.0;
    }
    // if inside a planetary system
    else
    {
      return DB.BodyData(Lib.PlanetarySystem(v.mainBody).name).storm_age < delta_time * 2.0;
    }
  }
Beispiel #20
0
  // return true if a storm is in progress
  public static bool InProgress(Vessel v)
  {
    if (!DB.Ready()) return false;

    // if in interplanetary space
    if (v.mainBody.flightGlobalsIndex == 0)
    {
      return DB.VesselData(v.id).storm_state == 2;
    }
    // if inside a planetary system
    else
    {
      return DB.BodyData(Lib.PlanetarySystem(v.mainBody).name).storm_state == 2;
    }
  }
Beispiel #21
0
  void OnPostRender()
  {
    // do nothing if DB isn't ready for whatever reason
    if (!DB.Ready()) return;

    // do nothing when not in map view
    if (!MapView.MapIsEnabled) return;

    // commit all geometry
    Signal.render();
    Radiation.render();

    // render all committed geometry
    LineRenderer.render();
    ParticleRenderer.render();
  }
Beispiel #22
0
        void vesselDock(GameEvents.FromToAction <Part, Part> e)
        {
            // this need to happen when db is in a valid state
            if (DB.Ready())
            {
                // merge computer data from vessel A to vessel B on docking
                Computer a = DB.VesselData(e.from.vessel.id).computer;
                Computer b = DB.VesselData(e.to.vessel.id).computer;
                b.merge(a);

                // forget vessel being docked
                DB.ForgetVessel(e.from.vessel.id);
            }

            // purge vessel from resource cache
            ResourceCache.Purge(e.from.vessel.id);
        }
Beispiel #23
0
  // return time left until CME is over
  public static double TimeLeftCME(Vessel v)
  {
    if (!DB.Ready()) return 0.0;

    // if in interplanetary space
    if (v.mainBody.flightGlobalsIndex == 0)
    {
      vessel_data vd = DB.VesselData(v.id);
      return TimeLeftCME(vd.storm_time, vd.storm_age);
    }
    // if inside a planetary system
    else
    {
      body_data bd = DB.BodyData(Lib.PlanetarySystem(v.mainBody).name);
      return TimeLeftCME(bd.storm_time, bd.storm_age);
    }
  }
Beispiel #24
0
 protected override void OnUpdate()
 {
   foreach(Vessel v in FlightGlobals.Vessels)
   {
     vessel_info vi = Cache.VesselInfo(v);
     if (!vi.is_valid) continue;
     bool manned = v.loaded ? v.GetCrewCount() > 0 : v.protoVessel.GetVesselCrew().Count > 0;
     bool in_orbit = Sim.Apoapsis(v) > v.mainBody.atmosphereDepth && Sim.Periapsis(v) > v.mainBody.atmosphereDepth;
     bool for_30days = v.missionTime > 60.0 * 60.0 * Lib.HoursInDay() * 30.0;
     if (manned && in_orbit && for_30days && DB.Ready())
     {
       base.SetComplete();
       DB.Landmarks().manned_orbit = 1; //< remember that contract was completed
       break;
     }
   }
 }
Beispiel #25
0
  public void EmergencyHarvest()
  {
    // calculate reduced harvest size
    double reduced_harvest = harvest_size * growth * 0.5;

    // produce reduced quantity of food, proportional to current growth
    ResourceCache.Produce(vessel, resource_name, reduced_harvest);

    // reset growth
    growth = 0.0;

    // show message
    Message.Post(Lib.BuildString("On <color=FFFFFF>", vessel.vesselName, "</color> an emergency harved produced <color=FFFFFF>",
      reduced_harvest.ToString("F0"), " ", resource_name, "</color>"));

    // record first harvest
    if (!Lib.Landed(vessel) && DB.Ready()) DB.Landmarks().space_harvest = 1;
  }
Beispiel #26
0
  public float height()
  {
    // note: this function is abused to determine if the filter must be shown

    // guess vessel count
    uint count = 0;
    show_filter = false;
    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 kerbals
      if (EVA.IsDead(v)) continue;

      // avoid problems if the DB isn't ready
      if (DB.Ready())
      {
        // get vessel data
        vessel_data vd = DB.VesselData(v.id);

        // determine if filter must be shown
        show_filter |= vd.group.Length > 0 && vd.group != "NONE";

        // if the panel is filtered, skip filtered vessels
        if (filtered() && vd.group != filter) continue;
      }

      // the vessel will be rendered
      ++count;
    }

    // deal with no vessels case
    count = Math.Max(1u, count);

    // calculate height
    float vessels_height = 10.0f + (float)count * (16.0f + 10.0f);
    float config_height = configured_id == Guid.Empty ? 0.0f : filtered() ? 80.0f : 96.0f;
    float filter_height = show_filter ? 16.0f + 10.0f : 0.0f;
    return Math.Min(vessels_height + config_height + filter_height, Screen.height * 0.5f);
  }
Beispiel #27
0
        // set highlighting
        public static void SetHighlight(Part p)
        {
            // get max malfunction among all reliability components in the part
            uint max_malfunctions = 0;

            foreach (Reliability m in p.FindModulesImplementing <Reliability>())
            {
                max_malfunctions = Math.Max(max_malfunctions, m.malfunctions);
            }

            // note: when solar panels break (the stock mechanic), this throw exceptions inside KSP
            try
            {
                if (DB.Ready() && DB.VesselData(p.vessel.id).cfg_highlights > 0)
                {
                    switch (max_malfunctions)
                    {
                    case 0:
                        p.SetHighlightDefault();
                        break;

                    case 1:
                        p.SetHighlightType(Part.HighlightType.AlwaysOn);
                        p.SetHighlightColor(Color.yellow);
                        p.SetHighlight(true, false);
                        break;

                    default:
                        p.SetHighlightType(Part.HighlightType.AlwaysOn);
                        p.SetHighlightColor(Color.red);
                        p.SetHighlight(true, false);
                        break;
                    }
                }
                else
                {
                    p.SetHighlightDefault();
                }
            }
            catch {}
        }
Beispiel #28
0
        // hook: InjectRadiation()
        public static void hook_InjectRadiation(string k_name, double amount)
        {
            if (!DB.Ready())
            {
                return;
            }
            if (!DB.Kerbals().ContainsKey(k_name))
            {
                return;
            }
            kerbal_data kd = DB.KerbalData(k_name);

            foreach (Rule r in Kerbalism.rules)
            {
                if (r.modifier.Contains("radiation"))
                {
                    var kmon = DB.KmonData(k_name, r.name);
                    kmon.problem = Math.Max(kmon.problem + amount, 0.0);
                }
            }
        }
Beispiel #29
0
        // hook: Breakdown
        public static void hook_Breakdown(Vessel v, ProtoCrewMember c)
        {
            if (!Cache.VesselInfo(v).is_valid)
            {
                return;
            }
            if (!DB.Ready())
            {
                return;
            }
            if (!DB.Vessels().ContainsKey(v.id))
            {
                return;
            }
            if (!DB.Kerbals().ContainsKey(c.name))
            {
                return;
            }

            Breakdown(v, c);
        }
Beispiel #30
0
  // trigger malfunction
  public void Break()
  {
    // reset age and lifetime
    age = 0.0;
    lifetime = 0.0;

    // apply malfunction penalty immediately
    Apply(0.5);

    // increase malfunction
    ++malfunctions;

    // show message
    if (DB.Ready() && DB.VesselData(vessel.id).cfg_malfunction == 1)
    {
      Message.Post(Severity.warning, PrepareMsg(malfunction_msg, vessel, malfunctions));
    }

    // record first malfunction
    if (DB.Ready()) DB.NotificationData().first_malfunction = 1;
  }