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
  // return true if body is relevant to the player
  // - body: reference body of the planetary system
  bool body_is_relevant(CelestialBody body)
  {
    // special case: home system is always relevant
    // note: we deal with the case of a planet mod setting homebody as a moon
    if (body == Lib.PlanetarySystem(FlightGlobals.GetHomeBody())) return true;

    // for each vessel
    foreach(Vessel v in FlightGlobals.Vessels)
    {
      // if inside the system
      if (Lib.PlanetarySystem(v.mainBody) == body)
      {
        // 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;

        // obey message config
        if (DB.VesselData(v.id).cfg_storm == 0) continue;

        // body is relevant
        return true;
      }
    }
    return false;
  }
Beispiel #3
0
  // draw the window
  void render(int id)
  {
    // get vessel data
    vessel_data vd = DB.VesselData(vessel_id);

    // get vessel name
    string vessel_name = FlightGlobals.Vessels.Find(k => k.id == vessel_id).vesselName;

    // draw pseudo-title
    GUILayout.BeginHorizontal();
    GUILayout.Label(vessel_name, top_style);
    GUILayout.EndHorizontal();

    // draw top spacing
    GUILayout.Space(spacing);

    // draw text area
    scroll_pos = GUILayout.BeginScrollView(scroll_pos, HighLogic.Skin.horizontalScrollbar, HighLogic.Skin.verticalScrollbar);
    vd.notes = GUILayout.TextArea(vd.notes, txt_style, txt_options);
    GUILayout.EndScrollView();

    // draw bottom spacing
    GUILayout.Space(spacing);

    // draw footer
    GUILayout.BeginHorizontal();
    GUILayout.Label("close", bot_style);
    if (Lib.IsClicked()) Close();
    GUILayout.EndHorizontal();

    // enable dragging
    GUI.DragWindow(drag_rect);
  }
Beispiel #4
0
  // called every frame
  public void on_gui()
  {
    // forget vessel doesn't exist anymore
    if (vessel_id != Guid.Empty && FlightGlobals.Vessels.Find(k => k.id == vessel_id) == null)
    {
      vessel_id = Guid.Empty;
    }

    // forget file if it doesn't exist anymore
    if (vessel_id != Guid.Empty && !DB.VesselData(vessel_id).computer.files.ContainsKey(filename))
    {
      filename = string.Empty;
    }

    // do nothing if there isn't a vessel or a filename specified
    if (vessel_id == Guid.Empty || filename.Length == 0) return;

    // clamp the window to the screen, so it can't be dragged outside
    float offset_x = Math.Max(0.0f, -win_rect.xMin) + Math.Min(0.0f, Screen.width - win_rect.xMax);
    float offset_y = Math.Max(0.0f, -win_rect.yMin) + Math.Min(0.0f, Screen.height - win_rect.yMax);
    win_rect.xMin += offset_x;
    win_rect.xMax += offset_x;
    win_rect.yMin += offset_y;
    win_rect.yMax += offset_y;

    // draw the window
    win_rect = GUILayout.Window(win_id, win_rect, render, "", win_style);

    // disable camera mouse scrolling on mouse over
    if (win_rect.Contains(Event.current.mousePosition))
    {
      GameSettings.AXIS_MOUSEWHEEL.primary.scale = 0.0f;
    }
  }
Beispiel #5
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 #6
0
  // return true if body is relevant to the player
  // - body: reference body of the planetary system
  static bool body_is_relevant(CelestialBody body)
  {
    // [disabled]
    // special case: home system is always relevant
    // note: we deal with the case of a planet mod setting homebody as a moon
    //if (body == Lib.PlanetarySystem(FlightGlobals.GetHomeBody())) return true;

    // for each vessel
    foreach(Vessel v in FlightGlobals.Vessels)
    {
      // if inside the system
      if (Lib.PlanetarySystem(v.mainBody) == body)
      {
        // get info from the cache
        vessel_info vi = Cache.VesselInfo(v);

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

        // obey message config
        if (DB.VesselData(v.id).cfg_storm == 0) continue;

        // body is relevant
        return true;
      }
    }
    return false;
  }
Beispiel #7
0
  void exec()
  {
    // get the computer
    Computer cpu = DB.VesselData(vessel_id).computer;

    // get the environment
    Vessel environment = FlightGlobals.Vessels.Find(k => k.id == vessel_id);

    // execute current prompt as a remote command
    cpu.execute(prompt, environment, true);

    // write the command string on the buffer
    buffer.Add(Lib.BuildString(">> ", prompt));

    // special outputs
    if (cpu.output.IndexOf('!') == 0)
    {
      var split = cpu.output.Substring(1).Split(' ');
      switch(split[0])
      {
        case "EDIT":
          Editor.Open(environment, split[1]);
          break;

        case "SWITCH":
          Open(FlightGlobals.Vessels.Find(k => k.id == new Guid(split[1])));
          break;

        case "CLEAR":
          buffer.Clear();
          break;

        case "EXIT":
          buffer.Clear();
          Close();
          break;
      }
    }
    // normal output
    else
    {
      // write the output on the buffer
      // note: we deal with multi-line success outputs
      var split = cpu.output.Split('\n');
      foreach(string s in split)
      {
        if (cpu.status) buffer.Add(s);
        else buffer.Add(Lib.BuildString("<color=red>", s, "</color>"));
      }
      if (cpu.output.Length > 0) buffer.Add(string.Empty);
    }

    // reset prompt
    prompt = string.Empty;

    // move the scroll bar at the bottom
    scroll_pos.y = 9999.0f;
  }
Beispiel #8
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 #9
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 #10
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 #11
0
  // show the console
  public static void Open(Vessel v, string filename)
  {
    // setting file show the window
    instance.vessel_id = v.id;
    instance.filename = filename;

    // create file if it doesn't exist
    var files = DB.VesselData(v.id).computer.files;
    File file;
    if (!files.TryGetValue(filename, out file))
    {
      file = new File();
      files.Add(filename, file);
    }
  }
Beispiel #12
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 #13
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 #14
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)
    {
      // get info from the cache
      vessel_info vi = Cache.VesselInfo(v);

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

      // 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 = 4u; // group, info, console, 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.reliability) 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 #15
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 #16
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 #17
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 #18
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 #19
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;
  }
Beispiel #20
0
  // draw vessel config
  void render_config(Vessel v)
  {
    // do nothing if db isn' ready
    if (!DB.Ready()) return;

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

    // draw the config
    GUILayout.BeginHorizontal(row_style);
    GUILayout.Label(new GUIContent(" EC MESSAGES", icon_toggle[vd.cfg_ec]), config_style);
    if (Lib.IsClicked()) vd.cfg_ec = (vd.cfg_ec == 0 ? 1u : 0);
    GUILayout.EndHorizontal();
    GUILayout.BeginHorizontal(row_style);
    GUILayout.Label(new GUIContent(" SUPPLY MESSAGES", icon_toggle[vd.cfg_supply]), config_style);
    if (Lib.IsClicked()) vd.cfg_supply = (vd.cfg_supply == 0 ? 1u : 0);
    GUILayout.EndHorizontal();
    GUILayout.BeginHorizontal(row_style);
    GUILayout.Label(new GUIContent(" MALFUNCTIONS MESSAGES", icon_toggle[vd.cfg_malfunction]), config_style);
    if (Lib.IsClicked()) vd.cfg_malfunction = (vd.cfg_malfunction == 0 ? 1u : 0);
    GUILayout.EndHorizontal();
    GUILayout.BeginHorizontal(row_style);
    GUILayout.Label(new GUIContent(" SIGNAL MESSAGES", icon_toggle[vd.cfg_signal]), config_style);
    if (Lib.IsClicked()) vd.cfg_signal = (vd.cfg_signal == 0 ? 1u : 0);
    GUILayout.EndHorizontal();
    if (!filtered())
    {
      GUILayout.BeginHorizontal(row_style);
      GUILayout.Label(new GUIContent(" GROUP: ", icon_group), config_style, new[]{GUILayout.Width(48.0f)});
      vd.group = Lib.TextFieldPlaceholder("Kerbalism_group", vd.group, "NONE", group_style).ToUpper();
      GUILayout.EndHorizontal();
    }
    GUILayout.BeginHorizontal(row_style);
    GUILayout.Label(new GUIContent(" NOTES", icon_notes), config_style);
    if (Lib.IsClicked()) Notepad.Toggle(v);
    GUILayout.EndHorizontal();
  }
Beispiel #21
0
  // draw the window
  void render(int _)
  {
    // note: the id and the vessel are valid at this point, checked in on_gui()

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

    // get vessel
    Vessel v = FlightGlobals.Vessels.Find(k => k.id == vessel_id);

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

    // get crew
    var crew = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew();

    // draw pseudo-title
    GUILayout.BeginHorizontal();
    GUILayout.Label(v.vesselName, top_style);
    GUILayout.EndHorizontal();

    // draw the content
    render_environment(v, vi);
    render_supplies(v, vi);
    render_internal_space(v, vi, crew);
    render_crew(v, vi, crew);
    render_greenhouse(vi);

    // draw footer
    GUILayout.BeginHorizontal();
    GUILayout.Label("close", bot_style);
    if (Lib.IsClicked()) Close();
    GUILayout.EndHorizontal();

    // enable dragging
    GUI.DragWindow(drag_rect);
  }
Beispiel #22
0
  // draw the window
  void render(int id)
  {
    // draw pseudo-title
    GUILayout.BeginHorizontal();
    GUILayout.Label(close_left, icon_left_style);
    GUILayout.Label("EDITOR", top_style);
    GUILayout.Label(close_right, icon_right_style);
    if (Lib.IsClicked()) Close();
    GUILayout.EndHorizontal();

    // draw the text area
    // note: when user hit close, vessel/filename is not valid
    // note: file is guaranteed to exist at this point, if vessel/filename is valid
    if (vessel_id != Guid.Empty && filename.Length > 0)
    {
      File file = DB.VesselData(vessel_id).computer.files[filename];
      scroll_pos = GUILayout.BeginScrollView(scroll_pos, HighLogic.Skin.horizontalScrollbar, HighLogic.Skin.verticalScrollbar);
      file.content = GUILayout.TextArea(file.content, txt_style);
      GUILayout.EndScrollView();
    }

    // enable dragging
    GUI.DragWindow(drag_rect);
  }
Beispiel #23
0
  // draw vessel config
  void render_config(Vessel v)
  {
    // do nothing if db isn' ready
    if (!DB.Ready()) return;

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

    // draw the config
    if (Kerbalism.ec_rule != null)
    {
      GUILayout.BeginHorizontal(row_style);
      GUILayout.Label(new GUIContent(" EC MESSAGES", icon_toggle[vd.cfg_ec]), config_style);
      if (Lib.IsClicked()) vd.cfg_ec = (vd.cfg_ec == 0 ? 1u : 0);
      GUILayout.EndHorizontal();
    }
    if (Kerbalism.supply_rules.Count > 0)
    {
      GUILayout.BeginHorizontal(row_style);
      GUILayout.Label(new GUIContent(" SUPPLY MESSAGES", icon_toggle[vd.cfg_supply]), config_style);
      if (Lib.IsClicked()) vd.cfg_supply = (vd.cfg_supply == 0 ? 1u : 0);
      GUILayout.EndHorizontal();
    }
    if (Kerbalism.features.signal)
    {
      GUILayout.BeginHorizontal(row_style);
      GUILayout.Label(new GUIContent(" SIGNAL MESSAGES", icon_toggle[vd.cfg_signal]), config_style);
      if (Lib.IsClicked()) vd.cfg_signal = (vd.cfg_signal == 0 ? 1u : 0);
      GUILayout.EndHorizontal();
    }
    if (Settings.StormDuration > double.Epsilon)
    {
      GUILayout.BeginHorizontal(row_style);
      GUILayout.Label(new GUIContent(" STORM MESSAGES", icon_toggle[vd.cfg_storm]), config_style);
      if (Lib.IsClicked()) vd.cfg_storm = (vd.cfg_storm == 0 ? 1u : 0);
      GUILayout.EndHorizontal();
    }
    if (Kerbalism.features.malfunction)
    {
      GUILayout.BeginHorizontal(row_style);
      GUILayout.Label(new GUIContent(" RELIABILITY MESSAGES", icon_toggle[vd.cfg_malfunction]), config_style);
      if (Lib.IsClicked()) vd.cfg_malfunction = (vd.cfg_malfunction == 0 ? 1u : 0);
      GUILayout.EndHorizontal();
      GUILayout.BeginHorizontal(row_style);
      GUILayout.Label(new GUIContent(" HIGHLIGHT MALFUNCTIONS", icon_toggle[vd.cfg_highlights]), config_style);
      if (Lib.IsClicked()) vd.cfg_highlights = (vd.cfg_highlights == 0 ? 1u : 0);
      GUILayout.EndHorizontal();
    }
    if (Kerbalism.features.signal)
    {
      GUILayout.BeginHorizontal(row_style);
      GUILayout.Label(new GUIContent(" SHOW LINK", icon_toggle[vd.cfg_showlink]), config_style);
      if (Lib.IsClicked()) vd.cfg_showlink = (vd.cfg_showlink == 0 ? 1u : 0);
      GUILayout.EndHorizontal();
    }
    if (!filtered())
    {
      GUILayout.BeginHorizontal(row_style);
      GUILayout.Label(new GUIContent(" GROUP: ", icon_group), config_style, new[]{GUILayout.Width(48.0f)});
      vd.group = Lib.TextFieldPlaceholder("Kerbalism_group", vd.group, "NONE", group_style).ToUpper();
      GUILayout.EndHorizontal();
    }
    GUILayout.BeginHorizontal(row_style);
    GUILayout.Label(new GUIContent(" NOTES", icon_notes), config_style);
    if (Lib.IsClicked()) Notepad.Toggle(v);
    GUILayout.EndHorizontal();
    GUILayout.BeginHorizontal(row_style);
    GUILayout.Label(new GUIContent(" DETAILS", icon_info), config_style);
    if (Lib.IsClicked()) Info.Toggle(v);
    GUILayout.EndHorizontal();
  }
Beispiel #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);
            }
        }
Beispiel #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;
  }
Beispiel #26
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;
                    }
                }
            }
        }
Beispiel #27
0
        public static void render()
        {
            // get home body position
            Vector3 home = ScaledSpace.LocalToScaledSpace(FlightGlobals.GetHomeBody().position);

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

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

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

                // skip vessels with showlink disabled
                if (vd.cfg_showlink == 0)
                {
                    continue;
                }

                // get link data
                link_data link = vi.link;

                // skip vessels with no antenna
                if (link.status == link_status.no_antenna)
                {
                    continue;
                }

                // start of the line
                Vector3 a = ScaledSpace.LocalToScaledSpace(v.GetWorldPos3D());

                // determine end of line and color
                Vector3 b;
                Color   color;
                if (link.status == link_status.no_link)
                {
                    b     = home;
                    color = Color.red;
                }
                else if (link.status == link_status.direct_link)
                {
                    b     = home;
                    color = Color.green;
                }
                else //< indirect link
                {
                    // get link path
                    var path = link.path;

                    // use relay position
                    b     = ScaledSpace.LocalToScaledSpace(path[path.Count - 1].GetWorldPos3D());
                    color = Color.yellow;
                }

                // commit the line
                LineRenderer.commit(a, b, color);
            }
        }
Beispiel #28
0
        // called at every frame
        public void Update()
        {
            // FIXME: can't double-click on vessel to switch active one, if line is rendered

            // hide all lines
            foreach (var l in lines)
            {
                l.Value.Show(false);
            }

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

            // do nothing if signal is disabled
            if (!Kerbalism.features.signal)
            {
                return;
            }

            // do nothing if not in map view or tracking station
            if (!MapView.MapIsEnabled)
            {
                return;
            }

            // get homebody position
            Vector3d home = FlightGlobals.GetHomeBody().position;

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

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

                // skip EVA kerbals
                if (v.isEVA)
                {
                    continue;
                }

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

                // do nothing if showlink is disabled
                if (vd.cfg_showlink == 0)
                {
                    continue;
                }

                // get link status
                link_data ld = Signal.Link(v);

                // if there is an antenna
                if (ld.status != link_status.no_antenna)
                {
                    // get line renderer from the cache
                    Line line = getLine(v.id);

                    // start of the line
                    Vector3d a = Lib.VesselPosition(v);

                    // determine end of line and color
                    Vector3d b;
                    Color    clr;
                    if (ld.status == link_status.direct_link)
                    {
                        b   = home;
                        clr = Color.green;
                    }
                    else if (ld.status == link_status.indirect_link)
                    {
                        Vessel relay = FlightGlobals.Vessels.Find(k => k.id == ld.path_id[ld.path.Count - 1]);
                        if (relay == null)
                        {
                            line.Show(false); continue;
                        }                                    //< skip if it doesn't exist anymore
                        b   = Lib.VesselPosition(relay);
                        clr = Color.yellow;
                    }
                    else // no link
                    {
                        b   = home;
                        clr = Color.red;
                    }

                    // setup the line and show it
                    line.UpdatePoints(a, b, clr);
                    line.Show(true);
                }
            }
        }
Beispiel #29
0
  // implement malfunction mechanics
  public void FixedUpdate()
  {
    // do nothing in the editor
    if (HighLogic.LoadedSceneIsEditor) return;

    // deduce quality from technological level if necessary
    // note: done at prelaunch to avoid problems with start()/load() and the tech tree being not consistent
    if (vessel.situation == Vessel.Situations.PRELAUNCH) quality = DeduceQuality();

    // if for some reason quality wasn't set, default to 1.0
    // note: for example, resque vessels never get to prelaunch
    if (quality <= double.Epsilon) quality = 1.0;

    // update rmb ui
    var av = FlightGlobals.ActiveVessel;
    Events["Repair"].active = malfunctions > 0 && av != null && av.isEVA;
    Events["Inspect"].active = malfunctions == 0 && av != null && av.isEVA;
    Fields["Status"].guiActive = malfunctions > 0;
    Status = malfunctions == 0 ? "" : PrepareMsg(status_msg, vessel, malfunctions);

    // generate lifetime if necessary
    if (lifetime <= double.Epsilon)
    {
      lifetime = min_lifetime + (max_lifetime - min_lifetime) * Lib.RandomDouble();
    }

    // accumulate age
    age += TimeWarp.fixedDeltaTime
         * AgingCurve(age, min_lifetime, max_lifetime)
         / quality;

    // check age and malfunction if needed
    if (age > lifetime) Break();

    // set highlighting
    if (DB.Ready() && DB.VesselData(this.vessel.id).cfg_highlights > 0)
    {
      switch(malfunctions)
      {
        case 0:
          part.SetHighlightDefault();
          break;

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

        default:
          part.SetHighlightType(Part.HighlightType.AlwaysOn);
          part.SetHighlightColor(Color.red);
          part.SetHighlight(true, false);
          break;
      }
    }
    else
    {
      part.SetHighlightDefault();
    }
  }
Beispiel #30
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
                }
            }
        }