Spazmatism Posted October 18, 2013 Share Posted October 18, 2013 Is there a reason I can't find the debug setting in the launchpad part.cfg? Link to comment Share on other sites More sharing options...
taniwha Posted October 19, 2013 Share Posted October 19, 2013 Is there a reason I can't find the debug setting in the launchpad part.cfg?Yes. You don't need it. If you don't have Kethane installed, it will (or should) auto-enable. If you do have Kethane installed, then why would you want it unless actually debugging? Link to comment Share on other sites More sharing options...
greg12 Posted October 19, 2013 Share Posted October 19, 2013 So, I found a problem. I built a base on Minmus with Kethane and EL. I get all the resources to able to spawn my rocket on the launchpad. After I built the rocket all the resources stayed in the tanks. nothing get removed to fill up the spawned rocket. So now, I can spawn anything and I don`t need to go mining because the resources not going to be taken from the tanks. What should I do to fix this? Link to comment Share on other sites More sharing options...
impwarhamer Posted October 19, 2013 Share Posted October 19, 2013 So, I found a problem. I built a base on Minmus with Kethane and EL. I get all the resources to able to spawn my rocket on the launchpad. After I built the rocket all the resources stayed in the tanks. nothing get removed to fill up the spawned rocket. So now, I can spawn anything and I don`t need to go mining because the resources not going to be taken from the tanks. What should I do to fix this?purge the obviously possessed launch pad Link to comment Share on other sites More sharing options...
taniwha Posted October 20, 2013 Share Posted October 20, 2013 Yeah, it sounds like you've got a pad with debug enabled. just delete the line from the part.cfg. EL now checks for Kethane and sets the mode automatically if Kethane is not present, so third-party pads no longer need to include the debug setting. Link to comment Share on other sites More sharing options...
spiritplumber Posted October 20, 2013 Share Posted October 20, 2013 (edited) I have taken the liberty of adding orbital drydocks to this. Edited ExLaunchPad.cs follows:using System;using System.Collections.Generic;using System.Linq;//using System.IO; // needed for Path manipulation//using Uri;using UnityEngine;using KSP.IO;namespace ExLP {// edited by spiritplumber to add orbital launchpads public class ExLaunchPad : PartModule{ [KSPField] public bool debug = false; //public static bool kethane_present = CheckForKethane(); public static bool kethane_present; public enum crafttype { SPH, VAB }; public class Styles { public static GUIStyle normal; public static GUIStyle red; public static GUIStyle yellow; public static GUIStyle green; public static GUIStyle white; public static GUIStyle label; public static GUIStyle slider; public static GUIStyle sliderText; private static bool initialized; public static void Init() { if (initialized) return; initialized = true; normal = new GUIStyle(GUI.skin.button); normal.normal.textColor = normal.focused.textColor = Color.white; normal.hover.textColor = normal.active.textColor = Color.yellow; normal.onNormal.textColor = normal.onFocused.textColor = normal.onHover.textColor = normal.onActive.textColor = Color.green; normal.padding = new RectOffset(8, 8, 8, 8); red = new GUIStyle(GUI.skin.box); red.padding = new RectOffset(8, 8, 8, 8); red.normal.textColor = red.focused.textColor = Color.red; yellow = new GUIStyle(GUI.skin.box); yellow.padding = new RectOffset(8, 8, 8, 8); yellow.normal.textColor = yellow.focused.textColor = Color.yellow; green = new GUIStyle(GUI.skin.box); green.padding = new RectOffset(8, 8, 8, 8); green.normal.textColor = green.focused.textColor = Color.green; white = new GUIStyle(GUI.skin.box); white.padding = new RectOffset(8, 8, 8, 8); white.normal.textColor = white.focused.textColor = Color.white; label = new GUIStyle(GUI.skin.label); label.normal.textColor = label.focused.textColor = Color.white; label.alignment = TextAnchor.MiddleCenter; slider = new GUIStyle(GUI.skin.horizontalSlider); slider.margin = new RectOffset(0, 0, 0, 0); sliderText = new GUIStyle(GUI.skin.label); sliderText.alignment = TextAnchor.MiddleCenter; sliderText.margin = new RectOffset(0, 0, 0, 0); } } public class UIStatus { public Rect windowpos; public bool builduiactive = false; // Whether the build menu is open or closed public bool builduivisible = true; // Whether the build menu is allowed to be shown public bool showbuilduionload = false; public bool init = true; public bool linklfosliders = true; public bool showvab = true; public bool showsph = false; public bool canbuildcraft = false; public crafttype ct = crafttype.VAB; public string craftfile = null; public string flagname = null; public CraftBrowser craftlist = null; public bool showcraftbrowser = false; public ConfigNode craftnode = null; public bool craftselected = false; public Vector2 resscroll; public Dictionary<string, double> requiredresources = null; public double hullRocketParts = 0.0; public Dictionary<string, float> resourcesliders = new Dictionary<string, float>(); public float timer; public Vessel launchee, launcher; public Orbit currentorbit; } int padPartsCount; // the number of parts in the pad vessel (for docking detection) VesselResources padResources; // resources available to the pad [KSPField(isPersistant = false)] public float SpawnHeightOffset = 1.0f; // amount of pad between origin and open space private UIStatus uis = new UIStatus(); //private List<Vessel> bases; private static bool CheckForKethane() { if (AssemblyLoader.loadedAssemblies.Any(a => a.assembly.GetName().Name == "MMI_Kethane")) { Debug.Log("[EL] Kethane found"); return true; } Debug.Log("[EL] Kethane not found"); return false; } // ===================================================================================================================================================== // UI Functions private void UseResources(Vessel craft) { VesselResources craftResources = new VesselResources(craft); // Remove all resources that we might later fill (hull resources will not be touched) HashSet<string> resources_to_remove = new HashSet<string>(uis.requiredresources.Keys); craftResources.RemoveAllResources(resources_to_remove); // remove rocket parts required for the hull and solid fuel padResources.TransferResource("RocketParts", -uis.hullRocketParts); // use resources foreach (KeyValuePair<string, double> pair in uis.requiredresources) { // If resource is "JetFuel", rename to "LiquidFuel" string res = pair.Key; if (pair.Key == "JetFuel") { res = "LiquidFuel"; if (pair.Value == 0) continue; } if (!uis.resourcesliders.ContainsKey(pair.Key)) { Debug.Log(String.Format("[EL] missing slider {0}", pair.Key)); continue; } // Calculate resource cost based on slider position - note use pair.Key NOT res! we need to use the position of the dedicated LF slider not the LF component of LFO slider double tot = pair.Value * uis.resourcesliders[pair.Key]; // Transfer the resource from the vessel doing the building to the vessel being built padResources.TransferResource(res, -tot); craftResources.TransferResource(res, tot); } } private void FixCraftLock() { if (uis.launcher.situation == Vessel.Situations.ORBITING) { WarpShip(uis.launcher, uis.currentorbit); uis.currentorbit.epoch -= 0.1; WarpShip(uis.launchee, uis.currentorbit); PopupDialog.SpawnPopupDialog("Build completed!", "The new vessel has been assembled near the drydock." + situationdesc(uis.launcher.situation), "OK", false, HighLogic.Skin); } else PopupDialog.SpawnPopupDialog("Build completed!", "The new vessel has been assembled on the pad."+situationdesc(uis.launcher.situation), "OK", false, HighLogic.Skin); // Many thanks to Snjo (firespitter) uis.launchee.situation = Vessel.Situations.LANDED; uis.launchee.state = Vessel.State.ACTIVE; uis.launchee.Landed = false; uis.launchee.Splashed = false; uis.launchee.GoOnRails(); uis.launchee.rigidbody.WakeUp(); uis.launchee.ResumeStaging(); uis.launchee.landedAt = "External Launchpad"; uis.launchee.state = Vessel.State.ACTIVE; InputLockManager.ClearControlLocks(); uis.launcher.MakeActive(); uis.launchee.MakeActive(); //PopupDialog.SpawnPopupDialog("launcheE", " " + uis.launchee.orbit.inclination + " " + uis.launchee.orbit.altitude + " " + uis.launchee.orbit.argumentOfPeriapsis + " " + uis.launchee.orbit.eccentricity + " ", "OK", false, HighLogic.Skin); //PopupDialog.SpawnPopupDialog("launcheR", " " + uis.launcher.orbit.inclination + " " + uis.launcher.orbit.altitude + " " + uis.launcher.orbit.argumentOfPeriapsis + " " + uis.launcher.orbit.eccentricity + " ", "OK", false, HighLogic.Skin); } public static void ErrorPopup(string message) { PopupDialog.SpawnPopupDialog("Error", message, "Close", true, HighLogic.Skin); } private static void WarpShip(Vessel vessel, Orbit newOrbit) // from hyperedit { if (newOrbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()).magnitude > newOrbit.referenceBody.sphereOfInfluence) { ErrorPopup("Destination position was above the sphere of influence"); return; } vessel.Landed = false; vessel.Splashed = false; vessel.landedAt = string.Empty; var parts = vessel.parts; if (parts != null) { var clamps = parts.Where(p => p.Modules != null && p.Modules.OfType<LaunchClamp>().Any()).ToList(); foreach (var clamp in clamps) clamp.Die(); } try { OrbitPhysicsManager.HoldVesselUnpack(60); } catch (NullReferenceException) { } foreach (var v in (FlightGlobals.fetch == null ? (IEnumerable<Vessel>)new[] { vessel } : FlightGlobals.Vessels).Where(v => v.packed == false)) v.GoOnRails(); HardsetOrbit(vessel.orbit, newOrbit); vessel.orbitDriver.pos = vessel.orbit.pos.xzy; vessel.orbitDriver.vel = vessel.orbit.vel; } private static void HardsetOrbit(Orbit orbit, Orbit newOrbit) // from hyperedit { orbit.inclination = newOrbit.inclination; orbit.eccentricity = newOrbit.eccentricity; orbit.semiMajorAxis = newOrbit.semiMajorAxis; orbit.LAN = newOrbit.LAN; orbit.argumentOfPeriapsis = newOrbit.argumentOfPeriapsis; orbit.meanAnomalyAtEpoch = newOrbit.meanAnomalyAtEpoch; orbit.epoch = newOrbit.epoch; orbit.referenceBody = newOrbit.referenceBody; orbit.Init(); orbit.UpdateFromUT(Planetarium.GetUniversalTime()); } private void BuildAndLaunchCraft() { // build craft ShipConstruct nship = ShipConstruction.LoadShip(uis.craftfile); Vector3 offset = Vector3.up * SpawnHeightOffset; Transform t = this.part.transform; string landedAt = "External Launchpad"; string flag = uis.flagname; Game state = FlightDriver.FlightStateCache; VesselCrewManifest crew = new VesselCrewManifest (); GameObject launchPos = new GameObject (); launchPos.transform.position = t.position; launchPos.transform.position += t.TransformDirection(offset); launchPos.transform.rotation = t.rotation; ShipConstruction.CreateBackup(nship); ShipConstruction.PutShipToGround(nship, launchPos.transform); Destroy(launchPos); ShipConstruction.AssembleForLaunch(nship, landedAt, flag, state, crew); Vessel vsl = FlightGlobals.Vessels[FlightGlobals.Vessels.Count - 1]; vsl.Landed = false; if (kethane_present && !debug) UseResources(vsl); Staging.beginFlight(); uis.timer = 3.0f; uis.launchee = vsl; uis.launcher = this.vessel; uis.currentorbit = new Orbit(); HardsetOrbit(uis.currentorbit,this.vessel.GetOrbit());// PopupDialog.SpawnPopupDialog("DERP currentorbit", " " + uis.currentorbit.inclination + " " + uis.currentorbit.altitude + " " + uis.currentorbit.argumentOfPeriapsis + " " + uis.currentorbit.eccentricity + " ", "OK", false, HighLogic.Skin); } private float ResourceLine(string label, string resourceName, float fraction, double minAmount, double maxAmount, double available) { GUILayout.BeginHorizontal(); // Resource name GUILayout.Box(label, Styles.white, GUILayout.Width(120), GUILayout.Height(40)); // Fill amount GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); // limit slider to 0.5% increments if (minAmount == maxAmount) { GUILayout.Box("Must be 100%", GUILayout.Width(300), GUILayout.Height(20)); fraction = 1.0F; } else { fraction = (float)Math.Round(GUILayout.HorizontalSlider(fraction, 0.0F, 1.0F, Styles.slider, GUI.skin.horizontalSliderThumb, GUILayout.Width(300), GUILayout.Height(20)), 3); fraction = (Mathf.Floor(fraction * 200)) / 200; GUILayout.Box((fraction * 100).ToString() + "%", Styles.sliderText, GUILayout.Width(300), GUILayout.Height(20)); } GUILayout.FlexibleSpace(); GUILayout.EndVertical(); double required = minAmount * (1 - fraction) + maxAmount * fraction; // Calculate if we have enough resources to build GUIStyle requiredStyle = Styles.green; if (available < required) { requiredStyle = Styles.red; // prevent building unless debug mode is on, or kethane is not // installed (kethane is required for resource production) uis.canbuildcraft = (!kethane_present || debug); } // Required and Available GUILayout.Box((Math.Round(required, 2)).ToString(), requiredStyle, GUILayout.Width(75), GUILayout.Height(40)); GUILayout.Box((Math.Round(available, 2)).ToString(), Styles.white, GUILayout.Width(75), GUILayout.Height(40)); // Flexi space to make sure any unused space is at the right-hand edge GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); return fraction; } private void WindowGUI(int windowID) { Styles.Init(); /* * ToDo: * can extend FileBrowser class to see currently highlighted file? * rslashphish says: public myclass(arg1, arg2) : base(arg1, arg2); * KSPUtil.ApplicationRootPath - gets KSPO root * expose m_files and m_selectedFile? * fileBrowser = new FileBrowser(new Rect(Screen.width / 2, 100, 350, 500), title, callback, true); * * Style declarations messy - how do I dupe them easily? */ if (uis.init) { uis.init = false; } EditorLogic editor = EditorLogic.fetch; if (editor) return; if (!uis.builduiactive) return; if (padResources != null && padPartsCount != vessel.Parts.Count) { // something docked or undocked, so rebuild the pad's resouces info padResources = null; } if (padResources == null) { padPartsCount = vessel.Parts.Count; padResources = new VesselResources(vessel); } GUILayout.BeginVertical(); GUILayout.BeginHorizontal("box"); GUILayout.FlexibleSpace(); // VAB / SPH selection if (GUILayout.Toggle(uis.showvab, "VAB", GUILayout.Width(80))) { uis.showvab = true; uis.showsph = false; uis.ct = crafttype.VAB; } if (GUILayout.Toggle(uis.showsph, "SPH")) { uis.showvab = false; uis.showsph = true; uis.ct = crafttype.SPH; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); string strpath = HighLogic.SaveFolder; if (GUILayout.Button("Select Craft", Styles.normal, GUILayout.ExpandWidth(true))) { //GUILayout.Button is "true" when clicked uis.craftlist = new CraftBrowser(new Rect(Screen.width / 2, 100, 350, 500), uis.ct.ToString(), strpath, "Select a ship to load", craftSelectComplete, craftSelectCancel, HighLogic.Skin, EditorLogic.ShipFileImage, true); uis.showcraftbrowser = true; } if (uis.craftselected) { GUILayout.Box("Selected Craft: " + uis.craftnode.GetValue("ship"), Styles.white); // Resource requirements GUILayout.Label("Resources required to build:", Styles.label, GUILayout.Width(600)); // Link LFO toggle uis.linklfosliders = GUILayout.Toggle(uis.linklfosliders, "Link RocketFuel sliders for LiquidFuel and Oxidizer"); uis.resscroll = GUILayout.BeginScrollView(uis.resscroll, GUILayout.Width(600), GUILayout.Height(300)); GUILayout.BeginHorizontal(); // Headings GUILayout.Label("Resource", Styles.label, GUILayout.Width(120)); GUILayout.Label("Fill Percentage", Styles.label, GUILayout.Width(300)); GUILayout.Label("Required", Styles.label, GUILayout.Width(75)); GUILayout.Label("Available", Styles.label, GUILayout.Width(75)); GUILayout.EndHorizontal(); uis.canbuildcraft = true; // default to can build - if something is stopping us from building, we will set to false later if (!uis.requiredresources.ContainsKey("RocketParts")) { // if the craft to be built has no rocket parts storage, then the amount to use is not adjustable string resname = "RocketParts"; double available = padResources.ResourceAmount(resname); ResourceLine(resname, resname, 1.0F, uis.hullRocketParts, uis.hullRocketParts, available); } // Cycle through required resources foreach (KeyValuePair<string, double> pair in uis.requiredresources) { string resname = pair.Key; // Holds REAL resource name. May need to translate from "JetFuel" back to "LiquidFuel" string reslabel = resname; // Resource name for DISPLAY purposes only. Internally the app uses pair.Key if (reslabel == "JetFuel") { if (pair.Value == 0f) { // Do not show JetFuel line if not being used continue; } //resname = "JetFuel"; resname = "LiquidFuel"; } if (!uis.resourcesliders.ContainsKey(pair.Key)) { uis.resourcesliders.Add(pair.Key, 1); } // If in link LFO sliders mode, rename Oxidizer to LFO (Oxidizer) and LiquidFuel to LFO (LiquidFuel) if (reslabel == "Oxidizer") { reslabel = "RocketFuel (Ox)"; } if (reslabel == "LiquidFuel") { reslabel = "RocketFuel (LF)"; } double minAmount = 0.0; double maxAmount = uis.requiredresources[resname]; if (resname == "RocketParts") { minAmount += uis.hullRocketParts; maxAmount += uis.hullRocketParts; } double available = padResources.ResourceAmount(resname); // If LFO LiquidFuel exists and we are on LiquidFuel (Non-LFO), then subtract the amount used by LFO(LiquidFuel) from the available amount if (pair.Key == "JetFuel") { available -= uis.requiredresources["LiquidFuel"] * uis.resourcesliders["LiquidFuel"]; if (available < 0.0) available = 0.0; } uis.resourcesliders[pair.Key] = ResourceLine(reslabel, pair.Key, uis.resourcesliders[pair.Key], minAmount, maxAmount, available); if (uis.linklfosliders) { float tmp = uis.resourcesliders[pair.Key]; if (pair.Key == "Oxidizer") { uis.resourcesliders["LiquidFuel"] = tmp; } else if (pair.Key == "LiquidFuel") { uis.resourcesliders["Oxidizer"] = tmp; } } } GUILayout.EndScrollView(); // Build button if (uis.canbuildcraft) { if (GUILayout.Button("Build", Styles.normal, GUILayout.ExpandWidth(true))) { BuildAndLaunchCraft(); // Reset the UI uis.craftselected = false; uis.requiredresources = null; uis.resourcesliders = new Dictionary<string, float>();; // Close the UI HideBuildMenu(); } } else { GUILayout.Box("You do not have the resources to build this craft", Styles.red); } } else { GUILayout.Box("You must select a craft before you can build", Styles.red); } GUILayout.EndVertical(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close")) { HideBuildMenu(); } uis.showbuilduionload = GUILayout.Toggle(uis.showbuilduionload, "Show on StartUp"); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); //DragWindow makes the window draggable. The Rect specifies which part of the window it can by dragged by, and is //clipped to the actual boundary of the window. You can also pass no argument at all and then the window can by //dragged by any part of it. Make sure the DragWindow command is AFTER all your other GUI input stuff, or else //it may "cover up" your controls and make them stop responding to the mouse. GUI.DragWindow(new Rect(0, 0, 10000, 20)); } // called when the user selects a craft the craft browser private void craftSelectComplete(string filename, string flagname) { uis.showcraftbrowser = false; uis.craftfile = filename; uis.flagname = flagname; uis.craftnode = ConfigNode.Load(filename); ConfigNode[] nodes = uis.craftnode.GetNodes("PART"); // Get list of resources required to build vessel if ((uis.requiredresources = getBuildCost(nodes)) != null) uis.craftselected = true; } // called when the user clicks cancel in the craft browser private void craftSelectCancel() { uis.showcraftbrowser = false; uis.requiredresources = null; uis.craftselected = false; } // ===================================================================================================================================================== // Event Hooks // See http://docs.unity3d.com/Documentation/Manual/ExecutionOrder.html for some help on what fires when // Called each time the GUI is painted private void drawGUI() { GUI.skin = HighLogic.Skin; uis.windowpos = GUILayout.Window(1, uis.windowpos, WindowGUI, "Extraplanetary Launchpad: "+situationdesc(uis.launcher.situation), GUILayout.Width(600)); } // Called ONCE at start private void Start() { // If "Show GUI on StartUp" ticked, show the GUI if (uis.showbuilduionload) { ShowBuildMenu(); } } // Fired maybe multiple times a frame, maybe once every n frames public override void OnFixedUpdate() { // ToDo: Should not be checking this every frame - once per craft switch // OnVesselChange may be ideal but I cannot seem to get it to fire // Landed / Flying check should probably be with this code, but moved it elsewhere while this is firing so often this.Update(); // Does the UI want to be visible? if (uis.builduiactive) { // Decide if the build menu is allowed to be visible if (this.vessel == FlightGlobals.ActiveVessel) { // Yes - check if it is currently not visible if (!uis.builduivisible) { // Going from invisible to visible uis.builduivisible = true; RenderingManager.AddToPostDrawQueue(3, new Callback(drawGUI)); //start the GUI } } else { // No - check if it is currently visible if (uis.builduivisible) { // Going from visible to invisible uis.builduivisible = false; RenderingManager.RemoveFromPostDrawQueue(3, new Callback(drawGUI)); //stop the GUI } } } } /* // Called when you change vessel // ToDo: Cannot seem to get this code to fire... private void OnVesselChange() { if (this.vessel == FlightGlobals.ActiveVessel) { ShowBuildMenu(); } else { HideBuildMenu(); } } */ public void Update() { if ((uis.launchee != null) && (uis.timer >= 0)) { uis.timer -= Time.deltaTime; if (uis.timer <= 0) { FixCraftLock(); uis.launchee = null; } } } // Fired ONCE per frame public override void OnUpdate() { // Update state of context buttons depending on state of UI // ToDo: Move to something fired when the GUI is updated? Events["ShowBuildMenu"].active = !uis.builduiactive; Events["HideBuildMenu"].active = uis.builduiactive; this.Update(); } // Fired multiple times per frame in response to GUI events private void OnGUI() { if (uis.showcraftbrowser) { uis.craftlist.OnGUI(); } } /* // ToDo: What Does this Do? private void OnLoad() { bases = FlightGlobals.fetch.vessels; foreach (Vessel v in bases) { print(v.name); } } */ // Fired when KSP saves public override void OnSave(ConfigNode node) { PluginConfiguration config = PluginConfiguration.CreateForType<ExLaunchPad>(); config.SetValue("Window Position", uis.windowpos); config.SetValue("Show Build Menu on StartUp", uis.showbuilduionload); config.save(); } // Fired when KSP loads public override void OnLoad(ConfigNode node) { kethane_present = CheckForKethane(); LoadConfigFile(); } private void LoadConfigFile() { PluginConfiguration config = PluginConfiguration.CreateForType<ExLaunchPad>(); config.load(); uis.windowpos = config.GetValue<Rect>("Window Position"); uis.showbuilduionload = config.GetValue<bool>("Show Build Menu on StartUp"); } // ===================================================================================================================================================== // Flight UI and Action Group Hooks [KSPEvent(guiActive = true, guiName = "Show Build Menu", active = true)] public void ShowBuildMenu() { // Only allow enabling the menu if we are in a suitable place if (((this.vessel.situation == Vessel.Situations.LANDED) || (this.vessel.situation == Vessel.Situations.ORBITING) || (this.vessel.situation == Vessel.Situations.PRELAUNCH) || (this.vessel.situation == Vessel.Situations.SPLASHED))) { uis.launcher = this.vessel; RenderingManager.AddToPostDrawQueue(3, new Callback(drawGUI)); //start the GUI uis.builduiactive = true; } else { PopupDialog.SpawnPopupDialog("Sorry", "Can't build due to not being landed, splashed, or in a stable orbit\n\nCurrent state: " + situationdesc(this.vessel.situation), "OK", false, HighLogic.Skin); } } public String situationdesc(Vessel.Situations i) {switch (i){ case Vessel.Situations.DOCKED: return "Docked"; case Vessel.Situations.ESCAPING: return "Escaping"; case Vessel.Situations.FLYING: return "Flying"; case Vessel.Situations.LANDED: return "Landed"; case Vessel.Situations.ORBITING: return "Orbiting"; case Vessel.Situations.PRELAUNCH: return "Prelaunch"; case Vessel.Situations.SPLASHED: return "Splashed"; case Vessel.Situations.SUB_ORBITAL: return "Suborbital";}return "Not sure"; } [KSPEvent(guiActive = true, guiName = "Hide Build Menu", active = false)] public void HideBuildMenu() { RenderingManager.RemoveFromPostDrawQueue(3, new Callback(drawGUI)); //stop the GUI uis.builduiactive = false; } [KSPAction("Show Build Menu")] public void EnableBuildMenuAction(KSPActionParam param) { ShowBuildMenu(); } [KSPAction("Hide Build Menu")] public void DisableBuildMenuAction(KSPActionParam param) { HideBuildMenu(); } [KSPAction("Toggle Build Menu")] public void ToggleBuildMenuAction(KSPActionParam param) { if (uis.builduiactive) { HideBuildMenu(); } else { ShowBuildMenu(); } } // ===================================================================================================================================================== // Build Helper Functions private void MissingPopup(Dictionary<string, bool> missing_parts) { string text = ""; foreach (string mp in missing_parts.Keys) text += mp + "\n"; int ind = uis.craftfile.LastIndexOf("/") + 1; string craft = uis.craftfile.Substring (ind); craft = craft.Remove (craft.LastIndexOf(".")); PopupDialog.SpawnPopupDialog("Sorry", "Can't build " + craft + " due to the following missing parts\n\n" + text, "OK", false, HighLogic.Skin); } public Dictionary<string, double> getBuildCost(ConfigNode[] nodes) { float mass = 0.0f; Dictionary<string, double> resources = new Dictionary<string, double>(); Dictionary<string, double> hull_resources = new Dictionary<string, double>(); Dictionary<string, bool> missing_parts = new Dictionary<string, bool>(); foreach (ConfigNode node in nodes) { string part_name = node.GetValue("part"); part_name = part_name.Remove(part_name.LastIndexOf("_")); AvailablePart ap = PartLoader.getPartInfoByName(part_name); if (ap == null) { missing_parts[part_name] = true; continue; } Part p = ap.partPrefab; mass += p.mass; foreach (PartResource r in p.Resources) { if (r.resourceName == "IntakeAir" || r.resourceName == "KIntakeAir") { // Ignore intake Air continue; } Dictionary<string, double> res_dict = resources; PartResourceDefinition res_def; res_def = PartResourceLibrary.Instance.GetDefinition(r.resourceName); if (res_def.resourceTransferMode == ResourceTransferMode.NONE || res_def.resourceFlowMode == ResourceFlowMode.NO_FLOW) { res_dict = hull_resources; } if (!res_dict.ContainsKey(r.resourceName)) { res_dict[r.resourceName] = 0.0; } res_dict[r.resourceName] += r.maxAmount; } } if (missing_parts.Count > 0) { MissingPopup(missing_parts); return null; } // RocketParts for the hull is a separate entity to RocketParts in // storage containers PartResourceDefinition rp_def; rp_def = PartResourceLibrary.Instance.GetDefinition("RocketParts"); uis.hullRocketParts = mass / rp_def.density; // If non pumpable resources are used, convert to RocketParts foreach (KeyValuePair<string, double> pair in hull_resources) { PartResourceDefinition res_def; res_def = PartResourceLibrary.Instance.GetDefinition(pair.Key); double hull_mass = pair.Value * res_def.density; double hull_parts = hull_mass / rp_def.density; uis.hullRocketParts += hull_parts; } // If there is JetFuel (ie LF only tanks as well as LFO tanks - eg a SpacePlane) then split the Surplus LF off as "JetFuel" if (resources.ContainsKey("Oxidizer") && resources.ContainsKey("LiquidFuel")) { double jetFuel = 0.0; // The LiquidFuel:Oxidizer ratio is 9:11. Try to minimize rounding effects. jetFuel = (11 * resources["LiquidFuel"] - 9 * resources["Oxidizer"]) / 11; if (jetFuel < 0.01) { // Forget it. not getting far on that. Any discrepency this // small will be due to precision losses. jetFuel = 0.0; } resources["LiquidFuel"] -= jetFuel; resources["JetFuel"] = jetFuel; } return resources; }}public class Recycler : PartModule{ double busyTime; bool recyclerActive; [KSPField] public float RecycleRate = 1.0f; [KSPField (guiName = "State", guiActive = true)] public string status; public void OnTriggerStay(Collider col) { if (!recyclerActive || Planetarium.GetUniversalTime() <= busyTime || !col.CompareTag("Untagged") || col.gameObject.name == "MapOverlay collider") // kethane return; Part p = col.attachedRigidbody.GetComponent<Part>(); Debug.Log(String.Format("[EL] {0}", p)); if (p != null && p.vessel != null && p.vessel != vessel) { float mass; if (p.vessel.isEVA) { mass = RecycleKerbal(p.vessel); } else { mass = RecycleVessel(p.vessel); } busyTime = Planetarium.GetUniversalTime() + mass / RecycleRate; } } private float ReclaimResource(string resource, double amount, string vessel_name, string name=null) { PartResourceDefinition res_def; res_def = PartResourceLibrary.Instance.GetDefinition(resource); VesselResources recycler = new VesselResources(vessel); if (res_def == null) { return 0; } if (name == null) { name = resource; } double remain = amount; // any resources that can't be pumped or don't flow just "evaporate" // FIXME: should this be a little smarter and convert certain such // resources into rocket parts? if (res_def.resourceTransferMode != ResourceTransferMode.NONE && res_def.resourceFlowMode != ResourceFlowMode.NO_FLOW) { remain = recycler.TransferResource(resource, amount); } Debug.Log(String.Format("[EL] {0}-{1}: {2} taken {3} reclaimed, {4} lost", vessel_name, name, amount, amount - remain, remain)); return (float) (amount * res_def.density); } public float RecycleKerbal(Vessel v) { if (!v.isEVA) return 0; // idea and numbers taken from Kethane if (v.GetVesselCrew()[0].isBadass) { v.rootPart.explosionPotential = 10000; } FlightGlobals.ForceSetActiveVessel(this.vessel); v.rootPart.explode(); float mass = 0; mass += ReclaimResource("Kethane", 150, v.name); mass += ReclaimResource("Metal", 1, v.name); return mass; } public float RecycleVessel(Vessel v) { float ConversionEfficiency = 0.8f; double amount; VesselResources scrap = new VesselResources(v); PartResourceDefinition rp_def; rp_def = PartResourceLibrary.Instance.GetDefinition("RocketParts"); float mass = 0; foreach (string resource in scrap.resources.Keys) { amount = scrap.ResourceAmount (resource); mass += ReclaimResource(resource, amount, v.name); } float hull_mass = v.GetTotalMass(); amount = hull_mass * ConversionEfficiency / rp_def.density; mass += ReclaimResource("RocketParts", amount, v.name, "hull"); v.Die(); return mass; } [KSPEvent(guiActive = true, guiName = "Activate Recycler", active = true)] public void Activate() { recyclerActive = true; Events["Activate"].active = false; Events["Deactivate"].active = true; } [KSPEvent(guiActive = true, guiName = "Deactivate Recycler", active = false)] public void Deactivate() { recyclerActive = false; Events["Activate"].active = true; Events["Deactivate"].active = false; } public override void OnLoad(ConfigNode node) { Deactivate(); } public override void OnUpdate() { if (Planetarium.GetUniversalTime() <= busyTime) { status = "Busy"; } else if (recyclerActive) { status = "Active"; } else { status = "Inactive"; } }}} Edited October 20, 2013 by spiritplumber Link to comment Share on other sites More sharing options...
taniwha Posted October 20, 2013 Share Posted October 20, 2013 spiritplumber: Hmm, I'll have to take a look. Just the other day I'd worked out a possible method of doing orbital construction. Link to comment Share on other sites More sharing options...
spiritplumber Posted October 20, 2013 Share Posted October 20, 2013 This works more reliably.using System;using System.Collections.Generic;using System.Linq;//using System.IO; // needed for Path manipulation//using Uri;using UnityEngine;using KSP.IO;namespace ExLP {// edited by spiritplumber to add orbital launchpads public class ExLaunchPad : PartModule{ [KSPField] public bool debug = false; //public static bool kethane_present = CheckForKethane(); public static bool kethane_present; public enum crafttype { SPH, VAB }; public class Styles { public static GUIStyle normal; public static GUIStyle red; public static GUIStyle yellow; public static GUIStyle green; public static GUIStyle white; public static GUIStyle label; public static GUIStyle slider; public static GUIStyle sliderText; private static bool initialized; public static void Init() { if (initialized) return; initialized = true; normal = new GUIStyle(GUI.skin.button); normal.normal.textColor = normal.focused.textColor = Color.white; normal.hover.textColor = normal.active.textColor = Color.yellow; normal.onNormal.textColor = normal.onFocused.textColor = normal.onHover.textColor = normal.onActive.textColor = Color.green; normal.padding = new RectOffset(8, 8, 8, 8); red = new GUIStyle(GUI.skin.box); red.padding = new RectOffset(8, 8, 8, 8); red.normal.textColor = red.focused.textColor = Color.red; yellow = new GUIStyle(GUI.skin.box); yellow.padding = new RectOffset(8, 8, 8, 8); yellow.normal.textColor = yellow.focused.textColor = Color.yellow; green = new GUIStyle(GUI.skin.box); green.padding = new RectOffset(8, 8, 8, 8); green.normal.textColor = green.focused.textColor = Color.green; white = new GUIStyle(GUI.skin.box); white.padding = new RectOffset(8, 8, 8, 8); white.normal.textColor = white.focused.textColor = Color.white; label = new GUIStyle(GUI.skin.label); label.normal.textColor = label.focused.textColor = Color.white; label.alignment = TextAnchor.MiddleCenter; slider = new GUIStyle(GUI.skin.horizontalSlider); slider.margin = new RectOffset(0, 0, 0, 0); sliderText = new GUIStyle(GUI.skin.label); sliderText.alignment = TextAnchor.MiddleCenter; sliderText.margin = new RectOffset(0, 0, 0, 0); } } public class UIStatus { public Rect windowpos; public bool builduiactive = false; // Whether the build menu is open or closed public bool builduivisible = true; // Whether the build menu is allowed to be shown public bool showbuilduionload = false; public bool init = true; public bool linklfosliders = true; public bool showvab = true; public bool showsph = false; public bool canbuildcraft = false; public crafttype ct = crafttype.VAB; public string craftfile = null; public string flagname = null; public CraftBrowser craftlist = null; public bool showcraftbrowser = false; public ConfigNode craftnode = null; public bool craftselected = false; public Vector2 resscroll; public Dictionary<string, double> requiredresources = null; public double hullRocketParts = 0.0; public Dictionary<string, float> resourcesliders = new Dictionary<string, float>(); public float timer = 0.0f; public Vessel launchee, launcher; public Orbit currentorbit; } int padPartsCount; // the number of parts in the pad vessel (for docking detection) VesselResources padResources; // resources available to the pad [KSPField(isPersistant = false)] public float SpawnHeightOffset = 1.0f; // amount of pad between origin and open space private UIStatus uis = new UIStatus(); //private List<Vessel> bases; private static bool CheckForKethane() { if (AssemblyLoader.loadedAssemblies.Any(a => a.assembly.GetName().Name == "MMI_Kethane")) { Debug.Log("[EL] Kethane found"); return true; } Debug.Log("[EL] Kethane not found"); return false; } // ===================================================================================================================================================== // UI Functions private void UseResources(Vessel craft) { VesselResources craftResources = new VesselResources(craft); // Remove all resources that we might later fill (hull resources will not be touched) HashSet<string> resources_to_remove = new HashSet<string>(uis.requiredresources.Keys); craftResources.RemoveAllResources(resources_to_remove); // remove rocket parts required for the hull and solid fuel padResources.TransferResource("RocketParts", -uis.hullRocketParts); // use resources foreach (KeyValuePair<string, double> pair in uis.requiredresources) { // If resource is "JetFuel", rename to "LiquidFuel" string res = pair.Key; if (pair.Key == "JetFuel") { res = "LiquidFuel"; if (pair.Value == 0) continue; } if (!uis.resourcesliders.ContainsKey(pair.Key)) { Debug.Log(String.Format("[EL] missing slider {0}", pair.Key)); continue; } // Calculate resource cost based on slider position - note use pair.Key NOT res! we need to use the position of the dedicated LF slider not the LF component of LFO slider double tot = pair.Value * uis.resourcesliders[pair.Key]; // Transfer the resource from the vessel doing the building to the vessel being built padResources.TransferResource(res, -tot); craftResources.TransferResource(res, tot); } } private void FixCraftLock() { Double localepoch = uis.currentorbit.epoch; Double localdist = -0.1; //uis.launcher.state = Vessel.State.ACTIVE; FlightGlobals.ForceSetActiveVessel(uis.launcher); if (uis.launcher.situation == Vessel.Situations.ORBITING) { WarpShip(uis.launcher, uis.currentorbit); uis.currentorbit.epoch = localepoch + localdist; WarpShip(uis.launchee, uis.currentorbit); uis.currentorbit.epoch = localepoch; } if (uis.launcher.situation == Vessel.Situations.SUB_ORBITAL) { uis.currentorbit.epoch = localepoch; WarpShip(uis.launcher, uis.currentorbit); } if (uis.launchee.situation == Vessel.Situations.SUB_ORBITAL) { uis.currentorbit.epoch = localepoch + localdist; WarpShip(uis.launchee, uis.currentorbit); uis.currentorbit.epoch = localepoch; } //PopupDialog.SpawnPopupDialog("launcheE", " " + uis.launchee.orbit.inclination + " " + uis.launchee.orbit.altitude + " " + uis.launchee.orbit.argumentOfPeriapsis + " " + uis.launchee.orbit.eccentricity + " ", "OK", false, HighLogic.Skin); //PopupDialog.SpawnPopupDialog("launcheR", " " + uis.launcher.orbit.inclination + " " + uis.launcher.orbit.altitude + " " + uis.launcher.orbit.argumentOfPeriapsis + " " + uis.launcher.orbit.eccentricity + " ", "OK", false, HighLogic.Skin); if ((uis.launchee.situation == Vessel.Situations.SUB_ORBITAL) || (uis.launcher.situation == Vessel.Situations.SUB_ORBITAL)) { uis.timer = 1.0f; // try again } else { uis.currentorbit.epoch = localepoch; // Many thanks to Snjo (firespitter) uis.launchee.situation = uis.launcher.situation; //uis.launchee.state = Vessel.State.ACTIVE; uis.launchee.Landed = false; uis.launchee.Splashed = false; uis.launchee.GoOnRails(); uis.launchee.rigidbody.WakeUp(); uis.launchee.ResumeStaging(); uis.launchee.landedAt = "External Launchpad"; //uis.launchee.state = Vessel.State.ACTIVE; InputLockManager.ClearControlLocks(); PopupDialog.SpawnPopupDialog("Off-Kerbin Construction", "The vessel has been constructed successfully and is now " + situationdesc(uis.launchee.situation) + ".", "OK", false, HighLogic.Skin); FlightGlobals.ForceSetActiveVessel(uis.launchee); uis.timer = 9001.0f; // done } } public static void ErrorPopup(string message) { PopupDialog.SpawnPopupDialog("Error", message, "Close", true, HighLogic.Skin); } private static void WarpShip(Vessel vessel, Orbit newOrbit) // from hyperedit { if (newOrbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()).magnitude > newOrbit.referenceBody.sphereOfInfluence) { ErrorPopup("Destination position was above the sphere of influence"); return; } vessel.Landed = false; vessel.Splashed = false; vessel.landedAt = string.Empty; var parts = vessel.parts; if (parts != null) { var clamps = parts.Where(p => p.Modules != null && p.Modules.OfType<LaunchClamp>().Any()).ToList(); foreach (var clamp in clamps) clamp.Die(); } try { OrbitPhysicsManager.HoldVesselUnpack(60); } catch (NullReferenceException) { } foreach (var v in (FlightGlobals.fetch == null ? (IEnumerable<Vessel>)new[] { vessel } : FlightGlobals.Vessels).Where(v => v.packed == false)) v.GoOnRails(); HardsetOrbit(vessel.orbit, newOrbit); vessel.orbitDriver.pos = vessel.orbit.pos.xzy; vessel.orbitDriver.vel = vessel.orbit.vel; } private static void HardsetOrbit(Orbit orbit, Orbit newOrbit) // from hyperedit { orbit.inclination = newOrbit.inclination; orbit.eccentricity = newOrbit.eccentricity; orbit.semiMajorAxis = newOrbit.semiMajorAxis; orbit.LAN = newOrbit.LAN; orbit.argumentOfPeriapsis = newOrbit.argumentOfPeriapsis; orbit.meanAnomalyAtEpoch = newOrbit.meanAnomalyAtEpoch; orbit.epoch = newOrbit.epoch; orbit.referenceBody = newOrbit.referenceBody; orbit.Init(); orbit.UpdateFromUT(Planetarium.GetUniversalTime()); } private void BuildAndLaunchCraft() { // build craft ShipConstruct nship = ShipConstruction.LoadShip(uis.craftfile); Vector3 offset = Vector3.up * SpawnHeightOffset; Transform t = this.part.transform; string landedAt = "External Launchpad"; string flag = uis.flagname; Game state = FlightDriver.FlightStateCache; VesselCrewManifest crew = new VesselCrewManifest (); GameObject launchPos = new GameObject (); launchPos.transform.position = t.position; launchPos.transform.position += t.TransformDirection(offset); launchPos.transform.rotation = t.rotation; ShipConstruction.CreateBackup(nship); ShipConstruction.PutShipToGround(nship, launchPos.transform); Destroy(launchPos); ShipConstruction.AssembleForLaunch(nship, landedAt, flag, state, crew); Vessel vsl = FlightGlobals.Vessels[FlightGlobals.Vessels.Count - 1]; vsl.Landed = false; if (kethane_present && !debug) UseResources(vsl); Staging.beginFlight(); uis.timer = 3.0f; uis.launchee = vsl; uis.launcher = this.vessel; uis.currentorbit = new Orbit(); HardsetOrbit(uis.currentorbit,this.vessel.GetOrbit());// PopupDialog.SpawnPopupDialog("DERP currentorbit", " " + uis.currentorbit.inclination + " " + uis.currentorbit.altitude + " " + uis.currentorbit.argumentOfPeriapsis + " " + uis.currentorbit.eccentricity + " ", "OK", false, HighLogic.Skin); } private float ResourceLine(string label, string resourceName, float fraction, double minAmount, double maxAmount, double available) { GUILayout.BeginHorizontal(); // Resource name GUILayout.Box(label, Styles.white, GUILayout.Width(120), GUILayout.Height(40)); // Fill amount GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); // limit slider to 0.5% increments if (minAmount == maxAmount) { GUILayout.Box("Must be 100%", GUILayout.Width(300), GUILayout.Height(20)); fraction = 1.0F; } else { fraction = (float)Math.Round(GUILayout.HorizontalSlider(fraction, 0.0F, 1.0F, Styles.slider, GUI.skin.horizontalSliderThumb, GUILayout.Width(300), GUILayout.Height(20)), 3); fraction = (Mathf.Floor(fraction * 200)) / 200; GUILayout.Box((fraction * 100).ToString() + "%", Styles.sliderText, GUILayout.Width(300), GUILayout.Height(20)); } GUILayout.FlexibleSpace(); GUILayout.EndVertical(); double required = minAmount * (1 - fraction) + maxAmount * fraction; // Calculate if we have enough resources to build GUIStyle requiredStyle = Styles.green; if (available < required) { requiredStyle = Styles.red; // prevent building unless debug mode is on, or kethane is not // installed (kethane is required for resource production) uis.canbuildcraft = (!kethane_present || debug); } // Required and Available GUILayout.Box((Math.Round(required, 2)).ToString(), requiredStyle, GUILayout.Width(75), GUILayout.Height(40)); GUILayout.Box((Math.Round(available, 2)).ToString(), Styles.white, GUILayout.Width(75), GUILayout.Height(40)); // Flexi space to make sure any unused space is at the right-hand edge GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); return fraction; } private void WindowGUI(int windowID) { Styles.Init(); /* * ToDo: * can extend FileBrowser class to see currently highlighted file? * rslashphish says: public myclass(arg1, arg2) : base(arg1, arg2); * KSPUtil.ApplicationRootPath - gets KSPO root * expose m_files and m_selectedFile? * fileBrowser = new FileBrowser(new Rect(Screen.width / 2, 100, 350, 500), title, callback, true); * * Style declarations messy - how do I dupe them easily? */ if (uis.init) { uis.init = false; } EditorLogic editor = EditorLogic.fetch; if (editor) return; if (!uis.builduiactive) return; if (padResources != null && padPartsCount != vessel.Parts.Count) { // something docked or undocked, so rebuild the pad's resouces info padResources = null; } if (padResources == null) { padPartsCount = vessel.Parts.Count; padResources = new VesselResources(vessel); } GUILayout.BeginVertical(); GUILayout.BeginHorizontal("box"); GUILayout.FlexibleSpace(); // VAB / SPH selection if (GUILayout.Toggle(uis.showvab, "VAB", GUILayout.Width(80))) { uis.showvab = true; uis.showsph = false; uis.ct = crafttype.VAB; } if (GUILayout.Toggle(uis.showsph, "SPH")) { uis.showvab = false; uis.showsph = true; uis.ct = crafttype.SPH; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); string strpath = HighLogic.SaveFolder; if (GUILayout.Button("Select Craft", Styles.normal, GUILayout.ExpandWidth(true))) { //GUILayout.Button is "true" when clicked uis.craftlist = new CraftBrowser(new Rect(Screen.width / 2, 100, 350, 500), uis.ct.ToString(), strpath, "Select a ship to load", craftSelectComplete, craftSelectCancel, HighLogic.Skin, EditorLogic.ShipFileImage, true); uis.showcraftbrowser = true; } if (uis.craftselected) { GUILayout.Box("Selected Craft: " + uis.craftnode.GetValue("ship"), Styles.white); // Resource requirements GUILayout.Label("Resources required to build:", Styles.label, GUILayout.Width(600)); // Link LFO toggle uis.linklfosliders = GUILayout.Toggle(uis.linklfosliders, "Link RocketFuel sliders for LiquidFuel and Oxidizer"); uis.resscroll = GUILayout.BeginScrollView(uis.resscroll, GUILayout.Width(600), GUILayout.Height(300)); GUILayout.BeginHorizontal(); // Headings GUILayout.Label("Resource", Styles.label, GUILayout.Width(120)); GUILayout.Label("Fill Percentage", Styles.label, GUILayout.Width(300)); GUILayout.Label("Required", Styles.label, GUILayout.Width(75)); GUILayout.Label("Available", Styles.label, GUILayout.Width(75)); GUILayout.EndHorizontal(); uis.canbuildcraft = true; // default to can build - if something is stopping us from building, we will set to false later if (!uis.requiredresources.ContainsKey("RocketParts")) { // if the craft to be built has no rocket parts storage, then the amount to use is not adjustable string resname = "RocketParts"; double available = padResources.ResourceAmount(resname); ResourceLine(resname, resname, 1.0F, uis.hullRocketParts, uis.hullRocketParts, available); } // Cycle through required resources foreach (KeyValuePair<string, double> pair in uis.requiredresources) { string resname = pair.Key; // Holds REAL resource name. May need to translate from "JetFuel" back to "LiquidFuel" string reslabel = resname; // Resource name for DISPLAY purposes only. Internally the app uses pair.Key if (reslabel == "JetFuel") { if (pair.Value == 0f) { // Do not show JetFuel line if not being used continue; } //resname = "JetFuel"; resname = "LiquidFuel"; } if (!uis.resourcesliders.ContainsKey(pair.Key)) { uis.resourcesliders.Add(pair.Key, 1); } // If in link LFO sliders mode, rename Oxidizer to LFO (Oxidizer) and LiquidFuel to LFO (LiquidFuel) if (reslabel == "Oxidizer") { reslabel = "RocketFuel (Ox)"; } if (reslabel == "LiquidFuel") { reslabel = "RocketFuel (LF)"; } double minAmount = 0.0; double maxAmount = uis.requiredresources[resname]; if (resname == "RocketParts") { minAmount += uis.hullRocketParts; maxAmount += uis.hullRocketParts; } double available = padResources.ResourceAmount(resname); // If LFO LiquidFuel exists and we are on LiquidFuel (Non-LFO), then subtract the amount used by LFO(LiquidFuel) from the available amount if (pair.Key == "JetFuel") { available -= uis.requiredresources["LiquidFuel"] * uis.resourcesliders["LiquidFuel"]; if (available < 0.0) available = 0.0; } uis.resourcesliders[pair.Key] = ResourceLine(reslabel, pair.Key, uis.resourcesliders[pair.Key], minAmount, maxAmount, available); if (uis.linklfosliders) { float tmp = uis.resourcesliders[pair.Key]; if (pair.Key == "Oxidizer") { uis.resourcesliders["LiquidFuel"] = tmp; } else if (pair.Key == "LiquidFuel") { uis.resourcesliders["Oxidizer"] = tmp; } } } GUILayout.EndScrollView(); // Build button if (uis.canbuildcraft) { if (GUILayout.Button("Build", Styles.normal, GUILayout.ExpandWidth(true))) { BuildAndLaunchCraft(); // Reset the UI uis.craftselected = false; uis.requiredresources = null; uis.resourcesliders = new Dictionary<string, float>();; // Close the UI HideBuildMenu(); } } else { GUILayout.Box("You do not have the resources to build this craft", Styles.red); } } else { GUILayout.Box("You must select a craft before you can build", Styles.red); } GUILayout.EndVertical(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close")) { HideBuildMenu(); } uis.showbuilduionload = GUILayout.Toggle(uis.showbuilduionload, "Show on StartUp"); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); //DragWindow makes the window draggable. The Rect specifies which part of the window it can by dragged by, and is //clipped to the actual boundary of the window. You can also pass no argument at all and then the window can by //dragged by any part of it. Make sure the DragWindow command is AFTER all your other GUI input stuff, or else //it may "cover up" your controls and make them stop responding to the mouse. GUI.DragWindow(new Rect(0, 0, 10000, 20)); } // called when the user selects a craft the craft browser private void craftSelectComplete(string filename, string flagname) { uis.showcraftbrowser = false; uis.craftfile = filename; uis.flagname = flagname; uis.craftnode = ConfigNode.Load(filename); ConfigNode[] nodes = uis.craftnode.GetNodes("PART"); // Get list of resources required to build vessel if ((uis.requiredresources = getBuildCost(nodes)) != null) uis.craftselected = true; } // called when the user clicks cancel in the craft browser private void craftSelectCancel() { uis.showcraftbrowser = false; uis.requiredresources = null; uis.craftselected = false; } // ===================================================================================================================================================== // Event Hooks // See http://docs.unity3d.com/Documentation/Manual/ExecutionOrder.html for some help on what fires when // Called each time the GUI is painted private void drawGUI() { GUI.skin = HighLogic.Skin; uis.windowpos = GUILayout.Window(1, uis.windowpos, WindowGUI, "Extraplanetary Launchpad: "+situationdesc(uis.launcher.situation), GUILayout.Width(600)); } // Called ONCE at start private void Start() { // If "Show GUI on StartUp" ticked, show the GUI if (uis.showbuilduionload) { ShowBuildMenu(); } } // Fired maybe multiple times a frame, maybe once every n frames public override void OnFixedUpdate() { // ToDo: Should not be checking this every frame - once per craft switch // OnVesselChange may be ideal but I cannot seem to get it to fire // Landed / Flying check should probably be with this code, but moved it elsewhere while this is firing so often this.Update(); Update(); // Does the UI want to be visible? if (uis.builduiactive) { // Decide if the build menu is allowed to be visible if (this.vessel == FlightGlobals.ActiveVessel) { // Yes - check if it is currently not visible if (!uis.builduivisible) { // Going from invisible to visible uis.builduivisible = true; RenderingManager.AddToPostDrawQueue(3, new Callback(drawGUI)); //start the GUI } } else { // No - check if it is currently visible if (uis.builduivisible) { // Going from visible to invisible uis.builduivisible = false; RenderingManager.RemoveFromPostDrawQueue(3, new Callback(drawGUI)); //stop the GUI } } } } /* // Called when you change vessel // ToDo: Cannot seem to get this code to fire... private void OnVesselChange() { if (this.vessel == FlightGlobals.ActiveVessel) { ShowBuildMenu(); } else { HideBuildMenu(); } } */ public void Update() { if (uis.timer < 1000.0f) { uis.timer -= Time.deltaTime; if (uis.timer <= 0) { FixCraftLock(); } } } // Fired ONCE per frame public override void OnUpdate() { // Update state of context buttons depending on state of UI // ToDo: Move to something fired when the GUI is updated? Events["ShowBuildMenu"].active = !uis.builduiactive; Events["HideBuildMenu"].active = uis.builduiactive; this.Update(); Update(); } // Fired multiple times per frame in response to GUI events private void OnGUI() { if (uis.showcraftbrowser) { uis.craftlist.OnGUI(); } this.Update(); Update(); } /* // ToDo: What Does this Do? private void OnLoad() { bases = FlightGlobals.fetch.vessels; foreach (Vessel v in bases) { print(v.name); } } */ // Fired when KSP saves public override void OnSave(ConfigNode node) { PluginConfiguration config = PluginConfiguration.CreateForType<ExLaunchPad>(); config.SetValue("Window Position", uis.windowpos); config.SetValue("Show Build Menu on StartUp", uis.showbuilduionload); config.save(); } // Fired when KSP loads public override void OnLoad(ConfigNode node) { kethane_present = CheckForKethane(); LoadConfigFile(); } private void LoadConfigFile() { PluginConfiguration config = PluginConfiguration.CreateForType<ExLaunchPad>(); config.load(); uis.windowpos = config.GetValue<Rect>("Window Position"); uis.showbuilduionload = config.GetValue<bool>("Show Build Menu on StartUp"); } // ===================================================================================================================================================== // Flight UI and Action Group Hooks [KSPEvent(guiActive = true, guiName = "Show Build Menu", active = true)] public void ShowBuildMenu() { // Only allow enabling the menu if we are in a suitable place if (((this.vessel.situation == Vessel.Situations.LANDED) || (this.vessel.situation == Vessel.Situations.ORBITING) || (this.vessel.situation == Vessel.Situations.PRELAUNCH) || (this.vessel.situation == Vessel.Situations.SPLASHED))) { uis.launcher = this.vessel; RenderingManager.AddToPostDrawQueue(3, new Callback(drawGUI)); //start the GUI uis.builduiactive = true; } else { PopupDialog.SpawnPopupDialog("Sorry", "Can't build due to not being landed, splashed, or in a stable orbit\n\nCurrent state: " + situationdesc(this.vessel.situation), "OK", false, HighLogic.Skin); } } public String situationdesc(Vessel.Situations i) {switch (i){ case Vessel.Situations.DOCKED: return "Docked"; case Vessel.Situations.ESCAPING: return "Escaping"; case Vessel.Situations.FLYING: return "Flying"; case Vessel.Situations.LANDED: return "Landed"; case Vessel.Situations.ORBITING: return "Orbiting"; case Vessel.Situations.PRELAUNCH: return "Prelaunch"; case Vessel.Situations.SPLASHED: return "Splashed"; case Vessel.Situations.SUB_ORBITAL: return "Suborbital";}return "Not sure"; } [KSPEvent(guiActive = true, guiName = "Hide Build Menu", active = false)] public void HideBuildMenu() { RenderingManager.RemoveFromPostDrawQueue(3, new Callback(drawGUI)); //stop the GUI uis.builduiactive = false; } [KSPAction("Show Build Menu")] public void EnableBuildMenuAction(KSPActionParam param) { ShowBuildMenu(); } [KSPAction("Hide Build Menu")] public void DisableBuildMenuAction(KSPActionParam param) { HideBuildMenu(); } [KSPAction("Toggle Build Menu")] public void ToggleBuildMenuAction(KSPActionParam param) { if (uis.builduiactive) { HideBuildMenu(); } else { ShowBuildMenu(); } } // ===================================================================================================================================================== // Build Helper Functions private void MissingPopup(Dictionary<string, bool> missing_parts) { string text = ""; foreach (string mp in missing_parts.Keys) text += mp + "\n"; int ind = uis.craftfile.LastIndexOf("/") + 1; string craft = uis.craftfile.Substring (ind); craft = craft.Remove (craft.LastIndexOf(".")); PopupDialog.SpawnPopupDialog("Sorry", "Can't build " + craft + " due to the following missing parts\n\n" + text, "OK", false, HighLogic.Skin); } public Dictionary<string, double> getBuildCost(ConfigNode[] nodes) { float mass = 0.0f; Dictionary<string, double> resources = new Dictionary<string, double>(); Dictionary<string, double> hull_resources = new Dictionary<string, double>(); Dictionary<string, bool> missing_parts = new Dictionary<string, bool>(); foreach (ConfigNode node in nodes) { string part_name = node.GetValue("part"); part_name = part_name.Remove(part_name.LastIndexOf("_")); AvailablePart ap = PartLoader.getPartInfoByName(part_name); if (ap == null) { missing_parts[part_name] = true; continue; } Part p = ap.partPrefab; mass += p.mass; foreach (PartResource r in p.Resources) { if (r.resourceName == "IntakeAir" || r.resourceName == "KIntakeAir") { // Ignore intake Air continue; } Dictionary<string, double> res_dict = resources; PartResourceDefinition res_def; res_def = PartResourceLibrary.Instance.GetDefinition(r.resourceName); if (res_def.resourceTransferMode == ResourceTransferMode.NONE || res_def.resourceFlowMode == ResourceFlowMode.NO_FLOW) { res_dict = hull_resources; } if (!res_dict.ContainsKey(r.resourceName)) { res_dict[r.resourceName] = 0.0; } res_dict[r.resourceName] += r.maxAmount; } } if (missing_parts.Count > 0) { MissingPopup(missing_parts); return null; } // RocketParts for the hull is a separate entity to RocketParts in // storage containers PartResourceDefinition rp_def; rp_def = PartResourceLibrary.Instance.GetDefinition("RocketParts"); uis.hullRocketParts = mass / rp_def.density; // If non pumpable resources are used, convert to RocketParts foreach (KeyValuePair<string, double> pair in hull_resources) { PartResourceDefinition res_def; res_def = PartResourceLibrary.Instance.GetDefinition(pair.Key); double hull_mass = pair.Value * res_def.density; double hull_parts = hull_mass / rp_def.density; uis.hullRocketParts += hull_parts; } // If there is JetFuel (ie LF only tanks as well as LFO tanks - eg a SpacePlane) then split the Surplus LF off as "JetFuel" if (resources.ContainsKey("Oxidizer") && resources.ContainsKey("LiquidFuel")) { double jetFuel = 0.0; // The LiquidFuel:Oxidizer ratio is 9:11. Try to minimize rounding effects. jetFuel = (11 * resources["LiquidFuel"] - 9 * resources["Oxidizer"]) / 11; if (jetFuel < 0.01) { // Forget it. not getting far on that. Any discrepency this // small will be due to precision losses. jetFuel = 0.0; } resources["LiquidFuel"] -= jetFuel; resources["JetFuel"] = jetFuel; } return resources; }}public class Recycler : PartModule{ double busyTime; bool recyclerActive; [KSPField] public float RecycleRate = 1.0f; [KSPField (guiName = "State", guiActive = true)] public string status; public void OnTriggerStay(Collider col) { if (!recyclerActive || Planetarium.GetUniversalTime() <= busyTime || !col.CompareTag("Untagged") || col.gameObject.name == "MapOverlay collider") // kethane return; Part p = col.attachedRigidbody.GetComponent<Part>(); Debug.Log(String.Format("[EL] {0}", p)); if (p != null && p.vessel != null && p.vessel != vessel) { float mass; if (p.vessel.isEVA) { mass = RecycleKerbal(p.vessel); } else { mass = RecycleVessel(p.vessel); } busyTime = Planetarium.GetUniversalTime() + mass / RecycleRate; } } private float ReclaimResource(string resource, double amount, string vessel_name, string name=null) { PartResourceDefinition res_def; res_def = PartResourceLibrary.Instance.GetDefinition(resource); VesselResources recycler = new VesselResources(vessel); if (res_def == null) { return 0; } if (name == null) { name = resource; } double remain = amount; // any resources that can't be pumped or don't flow just "evaporate" // FIXME: should this be a little smarter and convert certain such // resources into rocket parts? if (res_def.resourceTransferMode != ResourceTransferMode.NONE && res_def.resourceFlowMode != ResourceFlowMode.NO_FLOW) { remain = recycler.TransferResource(resource, amount); } Debug.Log(String.Format("[EL] {0}-{1}: {2} taken {3} reclaimed, {4} lost", vessel_name, name, amount, amount - remain, remain)); return (float) (amount * res_def.density); } public float RecycleKerbal(Vessel v) { if (!v.isEVA) return 0; // idea and numbers taken from Kethane if (v.GetVesselCrew()[0].isBadass) { v.rootPart.explosionPotential = 10000; } FlightGlobals.ForceSetActiveVessel(this.vessel); v.rootPart.explode(); float mass = 0; mass += ReclaimResource("Kethane", 150, v.name); mass += ReclaimResource("Metal", 1, v.name); return mass; } public float RecycleVessel(Vessel v) { float ConversionEfficiency = 0.8f; double amount; VesselResources scrap = new VesselResources(v); PartResourceDefinition rp_def; rp_def = PartResourceLibrary.Instance.GetDefinition("RocketParts"); float mass = 0; foreach (string resource in scrap.resources.Keys) { amount = scrap.ResourceAmount (resource); mass += ReclaimResource(resource, amount, v.name); } float hull_mass = v.GetTotalMass(); amount = hull_mass * ConversionEfficiency / rp_def.density; mass += ReclaimResource("RocketParts", amount, v.name, "hull"); v.Die(); return mass; } [KSPEvent(guiActive = true, guiName = "Activate Recycler", active = true)] public void Activate() { recyclerActive = true; Events["Activate"].active = false; Events["Deactivate"].active = true; } [KSPEvent(guiActive = true, guiName = "Deactivate Recycler", active = false)] public void Deactivate() { recyclerActive = false; Events["Activate"].active = true; Events["Deactivate"].active = false; } public override void OnLoad(ConfigNode node) { Deactivate(); } public override void OnUpdate() { if (Planetarium.GetUniversalTime() <= busyTime) { status = "Busy"; } else if (recyclerActive) { status = "Active"; } else { status = "Inactive"; } }}} Link to comment Share on other sites More sharing options...
Patupi Posted October 21, 2013 Share Posted October 21, 2013 You mean it may be possible to use the ship selection from EPL in OSY instead of launching and teleporting the ship to the shipyard? That would be very cool! It somehow feels wrong to have to launch from KSC first, then catapult the vessels to your yard. I know there isn't much technical difference in result (other than the wait for the physics shift jumping back and forth) but I definitely would prefer this method used in OSY. Link to comment Share on other sites More sharing options...
Spazmatism Posted October 21, 2013 Share Posted October 21, 2013 Yes. You don't need it. If you don't have Kethane installed, it will (or should) auto-enable. If you do have Kethane installed, then why would you want it unless actually debugging?Can I still write it in with kethane installed? I want to keep kethane because I have some working ships using kethane that I don't want to despawn, and sometimes I play without cheating. Link to comment Share on other sites More sharing options...
Seawolf Posted October 21, 2013 Share Posted October 21, 2013 Hi,The center of mass and the center of thrust on the "launch pad 2" seem to be misaligned. When I try to fly it using its own rockets, it leans forward and eventually starts spinning, which makes it uncontrollable. No other part was connected to it when this happened.I didn't see another post about the same issue, so I wasn't sure if this was a bug or some problem with my installation.Can you guys help me out? Thanks. Link to comment Share on other sites More sharing options...
BigOto2 Posted October 21, 2013 Share Posted October 21, 2013 Sounds like an issue with the pad itself not having enough control authority. But attaching reaction wheels doesn't work well because of another issue, that also makes it seem to me that the Launch Pad 2 is impossible to use...It seems sensible to attach parts such as a docking port that would allow other modules to be connected, for example one with a Rocket Parts tank. But all of the parts move, and when I unfold it, none of the attached parts move with it. They just get weirdly suspended in the air where the attachment points used to be before the whole thing moved. So it's basically impossible to attach anything to it, which means transferring resources to it is also impossible without another addon for it.Am I overlooking something here? Link to comment Share on other sites More sharing options...
spiritplumber Posted October 22, 2013 Share Posted October 22, 2013 You mean it may be possible to use the ship selection from EPL in OSY instead of launching and teleporting the ship to the shipyard? That would be very cool! It somehow feels wrong to have to launch from KSC first, then catapult the vessels to your yard. I know there isn't much technical difference in result (other than the wait for the physics shift jumping back and forth) but I definitely would prefer this method used in OSY.That is the case. I am posting the modified dll. I am hoping skykooler will add this to the mod. It seems to work well. Replace the original dll with mine, and LaunchPadEx parts will function in orbit. However, there is a bug: you will have to "switch to" another spacecraft before having control.http://emlia.org/ksp_shared/Launchpad.dll Link to comment Share on other sites More sharing options...
taniwha Posted October 22, 2013 Share Posted October 22, 2013 Can I still write it in with kethane installed? I want to keep kethane because I have some working ships using kethane that I don't want to despawn, and sometimes I play without cheating.Indeed you can, for now anyway. Link to comment Share on other sites More sharing options...
KhaosCorp Posted October 22, 2013 Share Posted October 22, 2013 Sounds like an issue with the pad itself not having enough control authority. But attaching reaction wheels doesn't work well because of another issue, that also makes it seem to me that the Launch Pad 2 is impossible to use...It seems sensible to attach parts such as a docking port that would allow other modules to be connected, for example one with a Rocket Parts tank. But all of the parts move, and when I unfold it, none of the attached parts move with it. They just get weirdly suspended in the air where the attachment points used to be before the whole thing moved. So it's basically impossible to attach anything to it, which means transferring resources to it is also impossible without another addon for it.Am I overlooking something here?Yes you are =Puse a pancake tank as a base for LP2. OR just get KAS and land LP2 and then slap a pipe connector on it. Link to comment Share on other sites More sharing options...
Patupi Posted October 22, 2013 Share Posted October 22, 2013 That is the case. I am posting the modified dll. I am hoping skykooler will add this to the mod. It seems to work well. Replace the original dll with mine, and LaunchPadEx parts will function in orbit. However, there is a bug: you will have to "switch to" another spacecraft before having control.http://emlia.org/ksp_shared/Launchpad.dllAs long as you can switch ships within physics distance (ie the to the shipyard and back with '[', ']' ) to get control then that should be fine. If it needs unloading and loading physics by switching out of the area and back it'd be a pain with 0.21, 0.22's extra delays, but still workable. Link to comment Share on other sites More sharing options...
taniwha Posted October 22, 2013 Share Posted October 22, 2013 spiriteplumber: I've been looking at the code and I think the problem with switching is you copied a little too much from hyperedit: the spawned ship should already be active from when it is first created Link to comment Share on other sites More sharing options...
BigOto2 Posted October 22, 2013 Share Posted October 22, 2013 Yes you are =Puse a pancake tank as a base for LP2. OR just get KAS and land LP2 and then slap a pipe connector on it.Thanks, a seemingly odd solution but it sounds like it would work. I think I'll just use KAS for now so it won't be oddly propped up on the ground. Link to comment Share on other sites More sharing options...
Seawolf Posted October 22, 2013 Share Posted October 22, 2013 Hi,The center of mass and the center of thrust on the "launch pad 2" seem to be misaligned. When I try to fly it using its own rockets, it leans forward and eventually starts spinning, which makes it uncontrollable. No other part was connected to it when this happened.I didn't see another post about the same issue, so I wasn't sure if this was a bug or some problem with my installation.Can you guys help me out? Thanks.No one has a solution for this? Link to comment Share on other sites More sharing options...
BigOto2 Posted October 23, 2013 Share Posted October 23, 2013 Well, continuing off of Khaoscorp's idea, ASAS pancake on the bottom of the pad for better reaction wheel control? Link to comment Share on other sites More sharing options...
KhaosCorp Posted October 23, 2013 Share Posted October 23, 2013 LaunchPad2 was never really meant to 'fly' of its own power. The small engines it has can ASSIST in landing, OR are perfect for bunny-jumping the pad off of a more capable landing craft. A little bit of RCS or SAS and that more than fixes the tiny bit the CoM is offset. I have honestly had the best luck with landing the pad ontop of a more than capable lander, and then hopping the pad off...this method also leaves the lander to be recycled. Link to comment Share on other sites More sharing options...
Skyblue Posted October 23, 2013 Share Posted October 23, 2013 spiritplumber: Sorry if I'm asking a noob question but editting code is a first for me. I unpacked the mod and looked for the ExLaunchPad.cs file in order to edit it according to your very interesting suggestion. I am unable to find a file called ExLaunchPad.cs. Can you help? Link to comment Share on other sites More sharing options...
skykooler Posted October 23, 2013 Author Share Posted October 23, 2013 spiritplumber: Sorry if I'm asking a noob question but editting code is a first for me. I unpacked the mod and looked for the ExLaunchPad.cs file in order to edit it according to your very interesting suggestion. I am unable to find a file called ExLaunchPad.cs. Can you help?The source for the mod is not in the zip to save download size. You can find it on Github. Link to comment Share on other sites More sharing options...
spiritplumber Posted October 24, 2013 Share Posted October 24, 2013 If you do not wish to compile this yourself, I also linked a modified Launchpad.dll with the functionality. http://emlia.org/ksp_shared/Launchpad.dll I hope the creator of the mod is OK with this as a temporary solution. Link to comment Share on other sites More sharing options...
taniwha Posted October 24, 2013 Share Posted October 24, 2013 spiritplumber: The only problem you really should be distributing the "full"* source with your dll. (* just the source to the plugin itself, probably no need to distribute the models too so long as you provide a link).I don't include the source or link to my github reporsitory because I send my changes to skykooler and he merges them into his tree, which is linked on the front page, pretty quickly, and even that is pushing things.Once I get some time (I expect some this weekend), I'll integrate your patch into my tree (probably modified). Link to comment Share on other sites More sharing options...
Recommended Posts