public static String VesselConnectionTransmitting(Vessel v) { var vi = Cache.VesselInfo(v); if (!vi.is_valid) { return(string.Empty); } return(vi.transmitting); }
// --- VESSEL -------------------------------------------------------------- public static double VesselConnectionRate(Vessel v) { var vi = Cache.VesselInfo(v); if (!vi.is_valid) { return(0.0); } return(vi.connection.rate); }
public static bool VesselConnectionLinked(Vessel v) { var vi = Cache.VesselInfo(v); if (!vi.is_valid) { return(false); } return(vi.connection.linked); }
// --- RADIATION ------------------------------------------------------------ // return amount of environment radiation at the position of the specified vessel public static double Radiation(Vessel v) { if (!Features.Radiation) { return(0.0); } Vessel_info vi = Cache.VesselInfo(v); return(vi.radiation); }
// remove a file from a vessel public static void RemoveFile(Vessel v, string subject_id, double amount) { if (!Cache.VesselInfo(v).is_valid) { return; } Drive drive = DB.Vessel(v).drive; drive.Delete_file(subject_id, amount); }
// store a sample on a vessel public static void StoreSample(Vessel v, string subject_id, double amount) { if (!Cache.VesselInfo(v).is_valid) { return; } Drive drive = DB.Vessel(v).drive; drive.Record_sample(subject_id, amount); }
bool render_vessel(Panel p, Vessel v) { // get vessel info vessel_info vi = Cache.VesselInfo(v); // skip invalid vessels if (!vi.is_valid) return false; // get data from db VesselData vd = DB.Vessel(v); // determine if filter must be shown show_filter |= vd.group.Length > 0 && vd.group != "NONE"; // skip filtered vessels if (filtered() && vd.group != filter) return false; // get resource handler vessel_resources resources = ResourceCache.Get(v); // get vessel crew List<ProtoCrewMember> crew = Lib.CrewList(v); // get vessel name string vessel_name = v.isEVA ? crew[0].name : v.vesselName; // get body name string body_name = v.mainBody.name.ToUpper(); // render entry p.header ( Lib.BuildString("<b>", Lib.Ellipsis(vessel_name, 20), "</b> <size=9><color=#cccccc>", Lib.Ellipsis(body_name, 8), "</color></size>"), string.Empty, () => { selected_id = selected_id != v.id ? v.id : Guid.Empty; } ); // problem indicator indicator_problems(p, v, vi, crew); // battery indicator indicator_ec(p, v, vi); // supply indicator if (Features.Supplies) indicator_supplies(p, v, vi); // reliability indicator if (Features.Reliability) indicator_reliability(p, v, vi); // signal indicator if (Features.Signal) indicator_signal(p, v, vi); // done return true; }
public void update(Vessel v, vessel_info vi, vessel_data vd, vessel_resources resources, double elapsed_s) { // do nothing if signal mechanic is disabled if (!Kerbalism.features.signal) { return; } // get link data link_data link = vi.link; // consume relay ec // note: this is the only way to do it with new signal and resource systems if (vi.antenna.relay_range > 0.0) { foreach (Vessel w in FlightGlobals.Vessels) { vessel_info wi = Cache.VesselInfo(w); if (wi.is_valid) { if (wi.link.path.Contains(v)) { resources.Consume(v, "ElectricCharge", vi.antenna.relay_cost * elapsed_s); break; } } } } // maintain and send messages // - do nothing if db isn't ready // - do not send messages for vessels without an antenna if (link.status != link_status.no_antenna) { if (vd.msg_signal < 1 && !link.linked) { vd.msg_signal = 1; if (vd.cfg_signal == 1 && !vi.blackout) //< do not send message during storms { Message.Post(Severity.warning, Lib.BuildString("Signal lost with <b>", v.vesselName, "</b>"), vi.crew_count == 0 && Settings.RemoteControlLink ? "Remote control disabled" : "Data transmission disabled"); } } else if (vd.msg_signal > 0 && link.linked) { vd.msg_signal = 0; if (vd.cfg_signal == 1 && !Storm.JustEnded(v, elapsed_s)) //< do not send messages after a storm { var path = link.path; Message.Post(Severity.relax, Lib.BuildString("<b>", v.vesselName, "</b> signal is back"), path.Count == 0 ? "We got a direct link with the space center" : Lib.BuildString("Relayed by <b>", path[path.Count - 1].vesselName, "</b>")); } } } }
// execute a command on the computer public void execute(string cmd, string arg0, string arg1, Vessel environment, bool remote = false) { // do nothing if cmd is empty if (cmd.Length == 0) return; // check if there is EC on the vessel if (ResourceCache.Info(environment, "ElectricCharge").amount <= double.Epsilon) { error("no electric charge"); return; } // check if there is signal in case the command is remote vessel_info vi = Cache.VesselInfo(environment); if (remote && !vi.link.linked && vi.crew_count == 0) { error("no signal"); return; } // add 'device files' from all the drivers if (environment != null) { boot_crew(environment); boot_network(environment); boot_devices(environment); } // execute the command switch(cmd) { case "list": list(arg0); break; case "info": info(arg0); break; case "ctrl": ctrl(arg0, arg1); break; case "run": /* do nothing */ break; case "send": send(arg0, arg1); break; case "copy": copy(arg0, arg1); break; case "move": move(arg0, arg1); break; case "del": del(arg0); break; case "switch": switch_(arg0); break; case "edit": edit(arg0); break; case "log": log(arg0); break; case "msg": msg(arg0, arg1); break; case "help": help(arg0); break; case "clear": clear(); break; case "exit": exit(); break; default: error("unknown command"); break; } // remove all device files cleanup(); // execute script in a clear environment if (cmd == "run") run(arg0, environment); }
// implement scrubber mechanics public void FixedUpdate() { // do nothing in the editor if (HighLogic.LoadedSceneIsEditor) return; // do nothing until tech tree is ready if (!Lib.TechReady()) return; // deduce quality from technological level if necessary if (efficiency <= double.Epsilon) efficiency = DeduceEfficiency(); // get vessel info from the cache vessel_info vi = Cache.VesselInfo(vessel); // do nothing if vessel is invalid if (!vi.is_valid) return; // get resource cache vessel_resources resources = ResourceCache.Get(vessel); // get elapsed time double elapsed_s = Kerbalism.elapsed_s * vi.time_dilation; // if inside breathable atmosphere if (vi.breathable) { // produce oxygen from the intake resources.Produce(vessel, resource_name, intake_rate * elapsed_s); // set status Status = "Intake"; } // if outside breathable atmosphere and enabled else if (is_enabled) { // transform waste + ec into resource resource_recipe recipe = new resource_recipe(resource_recipe.scrubber_priority); recipe.Input(waste_name, co2_rate * elapsed_s); recipe.Input("ElectricCharge", ec_rate * elapsed_s); recipe.Output(resource_name, co2_rate * co2_ratio * efficiency * elapsed_s); resources.Transform(recipe); // set status Status = "Running"; } // if outside breathable atmosphere and disabled else { // set status Status = "Off"; } // add efficiency to status Status += Lib.BuildString(" (Efficiency: ", (efficiency * 100.0).ToString("F0"), "%)"); }
// remove a file from a vessel public static void RemoveFile(Vessel v, string subject_id, double amount) { if (!Cache.VesselInfo(v).is_valid) { return; } foreach (var d in Drive.GetDrives(v, true)) { d.Delete_file(subject_id, amount, v.protoVessel); } }
public void FixedUpdate() { // if part is manned (even in the editor), force enabled if (Lib.IsManned(part) && state != State.enabled) state = State.equalizing; perctDeployed = Lib.Level(part, "Atmosphere", true); // state machine switch (state) { case State.enabled: set_flow(true); break; case State.disabled: set_flow(false); break; case State.equalizing: set_flow(true); state = equalize(); break; case State.venting: set_flow(false); // Just do Venting when has no gravityRing or when the gravity ring is not spinning. if(hasGravityRing) { if(gravityRing.rotateIsTransform) { if (!gravityRing.rotate_transf.IsRotating()) state = venting(); } else { if (!gravityRing.rotate_anim.playing()) state = venting(); } } else state = venting(); break; } // if there is an inflate animation, set still animation from pressure if (animBackwards) inflate_anim.still(Math.Abs(Lib.Level(part, "Atmosphere", true)-1)); else inflate_anim.still(Lib.Level(part, "Atmosphere", true)); // instant pressurization and scrubbing inside breathable atmosphere if (!Lib.IsEditor() && Cache.VesselInfo(vessel).breathable && inflate.Length == 0) { var atmo = part.Resources["Atmosphere"]; var waste = part.Resources["WasteAtmosphere"]; if (Features.Pressure) atmo.amount = atmo.maxAmount; if (Features.Poisoning) waste.amount = 0.0; } }
protected virtual void Init() { if (!antennaInfo.powered || v.connection == null) { antennaInfo.linked = false; antennaInfo.status = (int)LinkStatus.no_link; return; } // force CommNet update of unloaded vessels if (!v.loaded) { Lib.ReflectionValue(v.connection, "unloadedDoOnce", true); } // are we connected to DSN if (v.connection.IsConnected) { antennaInfo.linked = true; var link = v.connection.ControlPath.First; antennaInfo.status = link.hopType == CommNet.HopType.Home ? (int)LinkStatus.direct_link : (int)LinkStatus.indirect_link; antennaInfo.strength = link.signalStrength; antennaInfo.rate *= Math.Pow(link.signalStrength, Settings.DataRateDampingExponent); antennaInfo.target_name = Lib.Ellipsis(Localizer.Format(v.connection.ControlPath.First.end.displayName).Replace("Kerbin", "DSN"), 20); if (antennaInfo.status != (int)LinkStatus.direct_link) { Vessel firstHop = Lib.CommNodeToVessel(v.Connection.ControlPath.First.end); // Get rate from the firstHop, each Hop will do the same logic, then we will have the min rate for whole path antennaInfo.rate = Math.Min(Cache.VesselInfo(FlightGlobals.FindVessel(firstHop.id)).connection.rate, antennaInfo.rate); } } // is loss of connection due to plasma blackout else if (Lib.ReflectionValue <bool>(v.connection, "inPlasma")) // calling InPlasma causes a StackOverflow :( { antennaInfo.status = (int)LinkStatus.plasma; } antennaInfo.control_path = new List <string[]>(); foreach (CommLink link in v.connection.ControlPath) { double antennaPower = link.end.isHome ? link.start.antennaTransmit.power + link.start.antennaRelay.power : link.start.antennaTransmit.power; double signalStrength = 1 - ((link.start.position - link.end.position).magnitude / Math.Sqrt(antennaPower * link.end.antennaRelay.power)); signalStrength = (3 - (2 * signalStrength)) * Math.Pow(signalStrength, 2); string name = Lib.Ellipsis(Localizer.Format(link.end.name).Replace("Kerbin", "DSN"), 35); string value = Lib.HumanReadablePerc(Math.Ceiling(signalStrength * 10000) / 10000, "F2"); string tooltip = "Distance: " + Lib.HumanReadableRange((link.start.position - link.end.position).magnitude) + "\nMax Distance: " + Lib.HumanReadableRange(Math.Sqrt((link.start.antennaTransmit.power + link.start.antennaRelay.power) * link.end.antennaRelay.power)); antennaInfo.control_path.Add(new string[] { name, value, tooltip }); } }
// remove a sample from a vessel public static void RemoveSample(Vessel v, string subject_id, double amount) { if (!Cache.VesselInfo(v).is_valid) { return; } foreach (var d in DB.Vessel(v).drives.Values) { d.Delete_sample(subject_id, amount); } }
// return size of a sample in a vessel drive public static double SampleSize(Vessel v, string subject_id) { if (!Cache.VesselInfo(v).is_valid) { return(0.0); } Drive drive = DB.Vessel(v).drive; Sample sample; return(drive.samples.TryGetValue(subject_id, out sample) ? sample.size : 0.0); }
public static void TelemetryPanel(this Panel p, Vessel v) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) { return; } // get info from the cache Vessel_info vi = Cache.VesselInfo(v); // if not a valid vessel, leave the panel empty if (!vi.is_valid) { return; } // set metadata p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(20)), " <color=#cccccc>TELEMETRY</color>")); p.Width(Styles.ScaleWidthFloat(355.0f)); p.paneltype = Panel.PanelType.telemetry; // time-out simulation if (p.Timeout(vi)) { return; } // get vessel data VesselData vd = DB.Vessel(v); // get resources Vessel_resources resources = ResourceCache.Get(v); // get crew var crew = Lib.CrewList(v); // draw the content Render_crew(p, crew); Render_greenhouse(p, vi); Render_supplies(p, v, vi, resources); Render_habitat(p, v, vi); Render_environment(p, v, vi); // collapse eva kerbal sections into one if (v.isEVA) { p.Collapse("EVA SUIT"); } }
public void Update() { // do nothing if tech tree is not ready if (!Lib.TechReady()) return; // get range double range = Signal.Range(scope, Signal.ECC()); // update rmb ui status RangeStatus = Lib.HumanReadableRange(range); RelayStatus = relay ? "Active" : "Disabled"; // when in flight if (HighLogic.LoadedSceneIsFlight) { // remove incomplete data toggle Events["TransmitIncompleteToggle"].active = false; // get vessel info from the cache vessel_info info = Cache.VesselInfo(vessel); // proper antenna mechanics for valid vessels if (info.is_valid) { // shortcut link_data link = info.link; // enable/disable science transmission can_transmit = link.linked; // determine currect packet cost // note: we set it to max float if out of range, to indirectly specify antenna score if (link.distance <= range) { this.packetResourceCost = (float)(min_transmission_cost + (max_transmission_cost - min_transmission_cost) * link.distance / range); CostStatus = Lib.BuildString(this.packetResourceCost.ToString("F2"), " EC/Mbit"); } else { this.packetResourceCost = float.MaxValue; CostStatus = ""; } } // sane defaults for invalid vessels else { can_transmit = false; this.packetResourceCost = float.MaxValue; CostStatus = ""; } } }
// implement gravity ring mechanics public void FixedUpdate() { // reset speed when not open if (!opened) speed = 0.0f; // hide the tweakable if not open this.Fields["speed"].guiActive = opened; this.Fields["speed"].guiActiveEditor = opened; // manage animation if (rotate != null) { // set rotating animation speed rotate[rotate_animation].speed = speed; // if its open but no animations are playing, start rotating if (opened) { bool playing = false; foreach(var anim in this.part.FindModelAnimators()) { playing |= anim.isPlaying; } if (!playing) rotate.Play(rotate_animation); } } // do nothing else in the editor if (HighLogic.LoadedSceneIsEditor) return; // get vessel info from the cache vessel_info vi = Cache.VesselInfo(vessel); // do nothing if vessel is invalid if (!vi.is_valid) return; // get resource cache vessel_resources resources = ResourceCache.Get(vessel); // get resource handler resource_info ec = resources.Info(vessel, "ElectricCharge"); // consume ec ec.Consume(ec_rate * speed * Kerbalism.elapsed_s * vi.time_dilation); // reset speed if there isn't enough ec // note: comparing against amount in previous simulation step if (ec.amount <= double.Epsilon) speed = 0.0f; // set entertainment rate = 1.0 + (entertainment_rate - 1.0) * speed; }
public static void Update(Vessel v) { // do nothing if not an eva kerbal if (!v.isEVA) return; // get KerbalEVA module KerbalEVA kerbal = Lib.FindModules<KerbalEVA>(v)[0]; Vessel_info vi = Cache.VesselInfo(v); // Stock KSP adds 5 units of monoprop to EVAs. We want to limit that amount // to whatever was available in the ship, so we don't magically create EVA prop out of nowhere if(Cache.HasVesselObjectsCache(v, "eva_prop")) { Lib.Log("### have eva_prop for " + v); var quantity = Cache.VesselObjectsCache<double>(v, "eva_prop"); Cache.RemoveVesselObjectsCache(v, "eva_prop"); Lib.Log("### adding " + quantity + " eva prop"); Lib.SetResource(kerbal.part, Lib.EvaPropellantName(), quantity, Lib.EvaPropellantCapacity()); } // get resource handler Resource_info ec = ResourceCache.Info(v, "ElectricCharge"); // determine if headlamps need ec // - not required if there is no EC capacity in eva kerbal (no ec supply in profile) // - not required if no EC cost for headlamps is specified (set by the user) bool need_ec = ec.capacity > double.Epsilon && Settings.HeadLampsCost > double.Epsilon; // consume EC for the headlamps if (need_ec && kerbal.lampOn) { ec.Consume(Settings.HeadLampsCost * Kerbalism.elapsed_s, "headlamp"); } // force the headlamps on/off HeadLamps(kerbal, kerbal.lampOn && (!need_ec || ec.amount > double.Epsilon)); // if dead if (IsDead(v)) { // enforce freezed state Freeze(kerbal); // disable modules DisableModules(kerbal); // remove plant flag action kerbal.flagItems = 0; } }
// remove a sample from a vessel public static double RemoveSample(Vessel v, string subject_id, double amount) { if (!Cache.VesselInfo(v).is_valid) { return(0); } double massRemoved = 0; foreach (var d in Drive.GetDrives(v, true)) { massRemoved += d.Delete_sample(subject_id, amount); } return(massRemoved); }
// implement recycler mechanics public void FixedUpdate() { // do nothing in the editor if (HighLogic.LoadedSceneIsEditor) return; // do nothing until tech tree is ready if (!Lib.TechReady()) return; if (use_efficiency) { // deduce quality from technological level if necessary if (efficiency <= double.Epsilon) efficiency = Scrubber.DeduceEfficiency(); } if (is_enabled) { // get vessel info from the cache vessel_info vi = Cache.VesselInfo(vessel); // do nothing if vessel is invalid if (!vi.is_valid) return; // get elapsed time double elapsed_s = Kerbalism.elapsed_s * vi.time_dilation; // get resource cache vessel_resources resources = ResourceCache.Get(vessel); // recycle EC+waste+filter into resource resource_recipe recipe = new resource_recipe(resource_recipe.scrubber_priority); recipe.Input(waste_name, waste_rate * elapsed_s); recipe.Input("ElectricCharge", ec_rate * elapsed_s); if (filter_name.Length > 0 && filter_rate > double.Epsilon) { recipe.Input(filter_name, filter_rate * elapsed_s); } recipe.Output(resource_name, waste_rate * waste_ratio * efficiency * elapsed_s); resources.Transform(recipe); // set status Status = "Running"; } else { Status = "Off"; } // add efficiency to status if (use_efficiency) Status += Lib.BuildString(" (Efficiency: ", (efficiency * 100.0).ToString("F0"), "%)"); }
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); }
// implement scrubber 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) efficiency = DeduceEfficiency(); // if for some reason efficiency wasn't set, default to 50% // note: for example, resque vessels never get to prelaunch if (efficiency <= double.Epsilon) efficiency = 0.5; // get time elapsed from last update double elapsed_s = TimeWarp.fixedDeltaTime; // if inside breathable atmosphere if (Cache.VesselInfo(this.vessel).breathable) { // produce oxygen from the intake this.part.RequestResource(resource_name, -intake_rate * elapsed_s); // set status Status = "Intake"; } // if outside breathable atmosphere and enabled else if (is_enabled) { // recycle CO2+EC into oxygen double co2_required = co2_rate * elapsed_s; double co2 = this.part.RequestResource(waste_name, co2_required); double ec_required = ec_rate * elapsed_s * (co2 / co2_required); double ec = this.part.RequestResource("ElectricCharge", ec_required); this.part.RequestResource(resource_name, -co2 * efficiency); // set status Status = co2 <= double.Epsilon ? "No " + waste_name : ec <= double.Epsilon ? "No Power" : "Running"; } // if outside breathable atmosphere and disabled else { // set status Status = "Off"; } // add efficiency to status Status += " (Efficiency: " + (efficiency * 100.0).ToString("F0") + "%)"; }
public void FixedUpdate() { // if part is manned (even in the editor), force enabled if (Lib.IsManned(part) && state != State.enabled) state = State.equalizing; perctDeployed = Lib.Level(part, "Atmosphere", true); // instant pressurization and scrubbing inside breathable atmosphere if (!Lib.IsEditor() && Cache.VesselInfo(vessel).breathable) { var atmo = part.Resources["Atmosphere"]; var waste = part.Resources["WasteAtmosphere"]; var moist = part.Resources["MoistAtmosphere"]; if (Get_inflate_string().Length == 0) // not inflatable { if ((state == State.equalizing) || (state == State.enabled)) { if (Features.Pressure) atmo.amount = atmo.maxAmount; } } if (Features.Poisoning) waste.amount = 0.0; if (Features.Humidity) moist.amount = 0.0; } // state machine switch (state) { case State.enabled: Set_flow(true); break; case State.disabled: Set_flow(false); break; case State.equalizing: Set_flow(true); state = Equalize(); break; case State.venting: Set_flow(false); // Just do Venting when has no gravityRing or when the gravity ring is not spinning. if (hasGravityRing && !gravityRing.Is_rotating()) state = Venting(); else if (!hasGravityRing) state = Venting(); break; } }
// called every frame public void Update() { if (HighLogic.LoadedSceneIsEditor) return; vessel_info vi = Cache.VesselInfo(this.vessel); switch(type) { case "temperature": Status = Lib.HumanReadableTemp(vi.temperature); break; case "radiation": Status = vi.env_radiation > double.Epsilon ? Lib.HumanReadableRadiationRate(vi.env_radiation) : "nominal"; break; } if (pinanim != null && type == "radiation") { pinanim["pinanim"].normalizedTime = pinfc.Evaluate((float)vi.env_radiation); } }
// trigger an undesiderable event for the kerbal specified public static void Breakdown(Vessel v, ProtoCrewMember c) { if (!Cache.VesselInfo(v).is_valid) { return; } if (!DB.vessels.ContainsKey(Lib.RootID(v))) { return; } if (!DB.ContainsKerbal(c.name)) { return; } Misc.Breakdown(v, c); }
// return size of a sample in a vessel drive public static double SampleSize(Vessel v, string subject_id) { if (!Cache.VesselInfo(v).is_valid) { return(0.0); } foreach (var d in DB.Vessel(v).drives.Values) { if (d.samples.ContainsKey(subject_id)) { return(d.samples[subject_id].size); } } return(0.0); }
// hook: LinkStatus() public static uint hook_LinkStatus(Vessel v) { vessel_info vi = Cache.VesselInfo(v); if (!vi.is_valid) { return(0); } switch (vi.link.status) { case link_status.direct_link: return(2u); case link_status.indirect_link: return(1u); default: return(0); // no_antenna, no_link } }
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; } } }
// called every frame public void on_gui() { // if there is a vessel id specified if (vessel_id != Guid.Empty) { // try to get the vessel Vessel v = FlightGlobals.Vessels.Find(k => k.id == vessel_id); // if the vessel still exist if (v != null) { // get info from cache vessel_info vi = Cache.VesselInfo(v); // if vessel is valid if (vi.is_valid) { // set automatic height win_rect.height = height(v, vi); // 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); } // if the vessel is invalid else { // forget it vessel_id = Guid.Empty; } } // if the vessel doesn't exist anymore else { // forget it vessel_id = Guid.Empty; } } }