Example #1
0
        // Creates a new ship with the given parameters for this mission. The code however seems unnecessarily convoluted and
        // error-prone, but there are no better examples available on the internet.
        private void CreateShip()
        {
            try
            {
                // The ShipConstruct-object can only savely exist while not in flight, otherwise it will spam Null-Pointer Exceptions every tick:
                if (HighLogic.LoadedScene == GameScenes.FLIGHT)
                {
                    throw new Exception("unable to run CreateShip while in flight");
                }

                // Load the parts form the saved vessel:
                if (!File.Exists(shipTemplateFilename))
                {
                    throw new Exception("file '" + shipTemplateFilename + "' not found");
                }

                var shipConstruct = ShipConstruction.LoadShip(shipTemplateFilename);

                // Maybe adjust the orbit:
                var vesselHeight = Math.Max(Math.Max(shipConstruct.shipSize.x, shipConstruct.shipSize.y), shipConstruct.shipSize.z);
                if (missionType == MissionType.DEPLOY)
                {
                    // Make sure that there won't be any collisions, when the vessel is created at the given orbit:
                    orbit = GUIOrbitEditor.ApplySafetyDistance(orbit, vesselHeight);
                }
                else if (missionType == MissionType.CONSTRUCT)
                {
                    // Deploy the new ship next to the space-dock:
                    var spaceDock = TargetVessel.GetVesselById((Guid)targetVesselId);
                    orbit = GUIOrbitEditor.CreateFollowingOrbit(spaceDock.orbit, TargetVessel.GetVesselSize(spaceDock) + vesselHeight);
                    orbit = GUIOrbitEditor.ApplySafetyDistance(orbit, vesselHeight);
                }
                else
                {
                    throw new Exception("invalid mission-type '" + missionType + "'");
                }

                var game     = FlightDriver.FlightStateCache ?? HighLogic.CurrentGame;
                var profile  = GetProfile();
                var duration = profile.missionDuration;
                AssembleForLaunchUnlanded(shipConstruct, crewToDeliver ?? Enumerable.Empty <string>(), duration, orbit, flagURL, game);
                var newVessel = FlightGlobals.Vessels[FlightGlobals.Vessels.Count - 1];
                newVessel.vesselName = shipName;
                Debug.Log("[KSTS] deployed new ship '" + shipName + "' as '" + newVessel.protoVessel.vesselRef.id + "'");
                ScreenMessages.PostScreenMessage("Vessel '" + shipName + "' deployed"); // Popup message to notify the player

                // Notify other mods about the new vessel:
                GameEvents.onVesselCreate.Fire(newVessel);
            }
            catch (Exception e)
            {
                Debug.LogError("[KSTS] Mission.CreateShip(): " + e);
            }
        }
Example #2
0
        // Generates a description for displaying on the GUI:
        public string GetDescription()
        {
            var description = "<color=#F9FA86><b>" + profileName + "</b></color> <color=#FFFFFF>(" + GetMissionTypeName(missionType) + ")\n";

            var shipTemplate = GetShipTemplate();

            if (shipTemplate != null)
            {
                description += "<b>Ship:</b> " + shipName + " (" + shipTemplate.shipName.ToString() + ")\n";
            }

            if (orbit != null)
            {
                description += "<b>Orbit:</b> " + orbit.referenceBody.bodyName.ToString() + " @ " + GUI.FormatAltitude(orbit.semiMajorAxis - orbit.referenceBody.Radius) + "\n";
            }

            // Display the targeted vessel (transport- and construction-missions):
            Vessel targetVessel = null;

            if (targetVesselId != null && (targetVessel = TargetVessel.GetVesselById((Guid)targetVesselId)) != null)
            {
                description += "<b>Target:</b> " + targetVessel.vesselName + " @ " + GUI.FormatAltitude(targetVessel.altitude) + "\n";
            }

            // Display the total weight of the payload we are hauling (transport-missions):
            if (resourcesToDeliver != null)
            {
                double totalMass = 0;
                foreach (var item in resourcesToDeliver)
                {
                    if (!KSTS.resourceDictionary.ContainsKey(item.Key))
                    {
                        continue;
                    }

                    totalMass += KSTS.resourceDictionary[item.Key].density * item.Value;
                }
                description += "<b>Cargo:</b> " + totalMass.ToString("#,##0.00t") + "\n";
            }

            // Display the crew-members we are transporting and collection:
            if (crewToDeliver != null && crewToDeliver.Count > 0)
            {
                description += "<b>Crew-Transfer (Outbound):</b> " + String.Join(", ", crewToDeliver.ToArray()).Replace(" Kerman", "") + "\n";
            }
            if (crewToCollect != null && crewToCollect.Count > 0)
            {
                description += "<b>Crew-Transfer (Inbound):</b> " + String.Join(", ", crewToCollect.ToArray()).Replace(" Kerman", "") + "\n";
            }

            // Display the remaining time:
            var remainingTime = eta - Planetarium.GetUniversalTime();

            if (remainingTime < 0)
            {
                remainingTime = 0;
            }

            var etaColorComponent = 0xFF;

            if (remainingTime <= 300)
            {
                etaColorComponent = (int)Math.Round((0xFF / 300.0) * remainingTime); // Starting at 5 minutes, start turning the ETA green.
            }

            var etaColor = "#" + etaColorComponent.ToString("X2") + "FF" + etaColorComponent.ToString("X2");

            description += "<color=" + etaColor + "><b>ETA:</b> " + GUI.FormatDuration(remainingTime) + "</color>";

            description += "</color>";
            return(description);
        }
Example #3
0
        // Tries to execute this mission and returns true if it was successfull:
        public bool TryExecute()
        {
            switch (missionType)
            {
            case MissionType.DEPLOY:
                // Ship-Creation is only possible while not in flight with the current implementation:
                if (HighLogic.LoadedScene != GameScenes.FLIGHT)
                {
                    CreateShip();
                    return(true);
                }
                return(false);

            case MissionType.CONSTRUCT:
                if (HighLogic.LoadedScene != GameScenes.FLIGHT)
                {
                    Vessel targetVessel = null;
                    if (targetVesselId == null || (targetVessel = TargetVessel.GetVesselById((Guid)targetVesselId)) == null || !TargetVessel.IsValidTarget(targetVessel, MissionController.missionProfiles[profileName]))
                    {
                        // Abort mission (maybe the vessel was removed or got moved out of range):
                        Debug.Log("[KSTS] aborting transport-construction: target-vessel missing or out of range");
                        ScreenMessages.PostScreenMessage("Aborting construction-mission: Target-vessel not found at expected rendezvous-coordinates!");
                    }
                    else
                    {
                        CreateShip();
                        return(true);
                    }
                }
                return(false);

            case MissionType.TRANSPORT:
                // Our functions for manipulating ships don't work on active vessels, beeing in flight however should be fine:
                if (FlightGlobals.ActiveVessel == null || FlightGlobals.ActiveVessel.id != targetVesselId)
                {
                    Vessel targetVessel = null;
                    if (!MissionController.missionProfiles.ContainsKey(profileName))
                    {
                        throw new Exception("unable to execute transport-mission, profile '" + profileName + "' missing");
                    }

                    if (targetVesselId == null || (targetVessel = TargetVessel.GetVesselById((Guid)targetVesselId)) == null || !TargetVessel.IsValidTarget(targetVessel, MissionController.missionProfiles[profileName]))
                    {
                        // Abort mission (maybe the vessel was removed or got moved out of range):
                        Debug.Log("[KSTS] aborting transport-mission: target-vessel missing or out of range");
                        ScreenMessages.PostScreenMessage("Aborting transport-mission: Target-vessel not found at expected rendezvous-coordinates!");
                    }
                    else
                    {
                        // Do the actual transport-mission:
                        if (resourcesToDeliver != null)
                        {
                            foreach (var item in resourcesToDeliver)
                            {
                                TargetVessel.AddResources(targetVessel, item.Key, item.Value);
                            }
                        }
                        if (crewToCollect != null)
                        {
                            foreach (var kerbonautName in crewToCollect)
                            {
                                TargetVessel.RecoverCrewMember(targetVessel, kerbonautName);
                            }
                        }
                        if (crewToDeliver != null)
                        {
                            foreach (var kerbonautName in crewToDeliver)
                            {
                                TargetVessel.AddCrewMember(targetVessel, kerbonautName);
                            }
                        }
                    }
                    return(true);
                }
                return(false);

            default:
                throw new Exception("unexpected mission-type '" + missionType.ToString() + "'");
            }
        }
Example #4
0
        // Creates a new ship with the given parameters for this mission. The code however seems unnecessarily convoluted and
        // error-prone, but there are no better examples available on the internet.
        private void CreateShip()
        {
            // TODO: Apply the staging which was saved in the editor.
            // TODO: Settings from other mods like Part-Switchers must also be applied here, maybe copy the config-nodes...
            try
            {
                if (!File.Exists(shipTemplateFilename))
                {
                    throw new Exception("file '" + shipTemplateFilename + "' not found");
                }
                if (missionType == MissionType.DEPLOY)
                {
                    // Make sure that there won't be any collisions, when the vessel is created at the given orbit:
                    orbit = GUIOrbitEditor.ApplySafetyDistance(orbit);
                }
                else if (missionType == MissionType.CONSTRUCT)
                {
                    // Deploy the new ship next to the space-dock:
                    Vessel spaceDock = TargetVessel.GetVesselById((Guid)targetVesselId);
                    orbit = GUIOrbitEditor.CreateFollowingOrbit(spaceDock.orbit, 100); // TODO: Calculate the distance using the ships's size
                    orbit = GUIOrbitEditor.ApplySafetyDistance(orbit);
                }
                else
                {
                    throw new Exception("invalid mission-type '" + missionType.ToString() + "'");
                }

                // The ShipConstruct-object can only savely exist while not in flight, otherwise it will spam Null-Pointer Exceptions every tick:
                if (HighLogic.LoadedScene == GameScenes.FLIGHT)
                {
                    throw new Exception("unable to run CreateShip while in flight");
                }

                // Load the parts form the saved vessel:
                ShipConstruct shipConstruct = ShipConstruction.LoadShip(shipTemplateFilename);
                ProtoVessel   dummyProto    = new ProtoVessel(new ConfigNode(), null);
                Vessel        dummyVessel   = new Vessel();
                dummyProto.vesselRef = dummyVessel;

                // In theory it should be enough to simply copy the parts from the ShipConstruct to the ProtoVessel, but
                // this only seems to work when the saved vessel starts with the root-part and is designed top down from there.
                // It seems that the root part has to be the first part in the ProtoVessel's parts-list and all other parts have
                // to be listed in sequence radiating from the root part (eg 1=>2=>R<=3<=4 should be R,2,1,3,4). If the parts
                // are not in the correct order, their rotation seems to get messed up or they are attached to the wrong
                // attachmet-nodes, which is why we have to re-sort the parts with our own logic here.
                // This part of the code is experimental however and only based on my own theories and observations about KSP's vessels.
                Part rootPart = null;
                foreach (Part p in shipConstruct.parts)
                {
                    if (p.parent == null)
                    {
                        rootPart = p; break;
                    }
                }
                List <Part> pList = null;
                dummyVessel.parts = FindAndAddAttachedParts(rootPart, ref pList); // Find all parts which are directly attached to the root-part and add them in order.

                // Handle Subassemblies which are attached by surface attachment-nodes:
                bool handleSurfaceAttachments = true;
                while (dummyVessel.parts.Count < shipConstruct.parts.Count)
                {
                    int processedParts = 0;
                    foreach (Part p in shipConstruct.parts)
                    {
                        if (dummyVessel.parts.Contains(p))
                        {
                            continue;
                        }
                        if (handleSurfaceAttachments)
                        {
                            // Check if the part is attached by a surface-node:
                            if (p.srfAttachNode != null && dummyVessel.parts.Contains(p.srfAttachNode.attachedPart))
                            {
                                // Add this surface attached part and all the sub-parts:
                                dummyVessel.parts = FindAndAddAttachedParts(p, ref dummyVessel.parts);
                                processedParts++;
                            }
                        }
                        else
                        {
                            // Simply copy this part:
                            dummyVessel.parts.Add(p);
                        }
                    }
                    if (processedParts == 0)
                    {
                        // If there are still unprocessed parts, just throw them in the list during the next iteration,
                        // this should not happen but we don't want to end up in an endless loop:
                        handleSurfaceAttachments = false;
                    }
                }

                // Initialize all parts:
                uint missionID = (uint)Guid.NewGuid().GetHashCode();
                uint launchID  = HighLogic.CurrentGame.launchID++;
                foreach (Part p in dummyVessel.parts)
                {
                    p.flagURL     = flagURL == null ? HighLogic.CurrentGame.flagURL : flagURL;
                    p.missionID   = missionID;
                    p.launchID    = launchID;
                    p.temperature = 1.0;

                    // If the KRnD-Mod is installed, make sure that all parts of this newly created ship are set to the lates version:
                    foreach (PartModule module in p.Modules)
                    {
                        if (module.moduleName != "KRnDModule")
                        {
                            continue;
                        }
                        Debug.Log("[KSTS] found KRnD on '" + p.name.ToString() + "', setting to latest stats");
                        foreach (BaseField field in module.Fields)
                        {
                            if (field.name.ToString() == "upgradeToLatest")
                            {
                                field.SetValue(1, module); // Newer versions of KRnD use this flag to upgrade all attributes of the given part to the latest levels, when the vessel is activated.
                                if (field.GetValue(module).ToString() != "1")
                                {
                                    Debug.LogError("[KSTS] unable to modify '" + field.name.ToString() + "'");
                                }
                            }
                        }
                    }

                    dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto));
                }

                // Store the parts in Config-Nodes:
                foreach (ProtoPartSnapshot p in dummyProto.protoPartSnapshots)
                {
                    p.storePartRefs();
                }
                List <ConfigNode> partNodesL = new List <ConfigNode>();
                foreach (var snapShot in dummyProto.protoPartSnapshots)
                {
                    ConfigNode node = new ConfigNode("PART");
                    snapShot.Save(node);
                    partNodesL.Add(node);
                }
                ConfigNode[] partNodes       = partNodesL.ToArray();
                ConfigNode[] additionalNodes = new ConfigNode[0];

                // This will actually create the ship and add it to the global list of flights:
                ConfigNode  protoVesselNode = ProtoVessel.CreateVesselNode(shipName, VesselType.Ship, orbit, 0, partNodes, additionalNodes);
                ProtoVessel pv = HighLogic.CurrentGame.AddVessel(protoVesselNode);
                Debug.Log("[KSTS] deployed new ship '" + shipName.ToString() + "' as '" + pv.vesselRef.id.ToString() + "'");
                ScreenMessages.PostScreenMessage("Vessel '" + shipName.ToString() + "' deployed"); // Popup message to notify the player
                Vessel newVessel = FlightGlobals.Vessels.Find(x => x.id == pv.vesselID);

                // Maybe add the initial crew to the vessel:
                if (crewToDeliver != null && crewToDeliver.Count > 0 && newVessel != null)
                {
                    foreach (string kerbonautName in crewToDeliver)
                    {
                        TargetVessel.AddCrewMember(newVessel, kerbonautName);
                    }
                }
            }
            catch (Exception e)
            {
                Debug.LogError("[KSTS] Mission.CreateShip(): " + e.ToString());
            }
        }