public override void OnUpdate() { if (isActive) { var startState = hasNearBeacon; nearBeacon = ScanForNearBeacons(); if (nearBeacon == null) { if (startState != hasNearBeacon) { HailerGUIClose(); } Events["HailerGUIClose"].active = false; Events["HailerGUIOpen"].active = false; } else { Events["HailerGUIClose"].active = false; Events["HailerGUIOpen"].active = true; if (guiopen) { listFarBeacons(); } } } }
public void Update() { UpdateNearBeacons(); if (nearBeacon == null || nearBeacon.Vessel != vessel) { bool present = nearBeacon != null; for (int i = hailers.Count - 1; i >= 0; i--) { bool hailerActive = hailers[i].hailerActive; hailers[i].Fields["nearBeaconDistance"].guiActive = present && hailerActive; hailers[i].Fields["nearBeaconRelVel"].guiActive = present && hailerActive; hailers[i].Fields["hasNearBeacon"].guiActive = hailerActive; hailers[i].hasNearBeacon = present ? "Present" : "Not Present"; } } else { for (int i = hailers.Count - 1; i >= 0; i--) { hailers[i].Fields["nearBeaconDistance"].guiActive = false; hailers[i].Fields["nearBeaconRelVel"].guiActive = false; hailers[i].Fields["hasNearBeacon"].guiActive = hailers[i].hailerActive; hailers[i].hasNearBeacon = "Onboard"; } } if (nearBeacon == null) { return; } float nearBeaconDistance = Vector3.Distance(vessel.GetWorldPos3D(), nearBeacon.Vessel.GetWorldPos3D()); float nearBeaconRelVel = Vector3.Magnitude(vessel.obt_velocity - nearBeacon.Vessel.obt_velocity); driftpenalty = ESLDBeacon.GetDriftPenalty(nearBeaconDistance, nearBeaconRelVel, nearBeacon.GetCrewBonuses("Pilot", 0.5f, 5)); HCUParts = GetHCUParts(vessel); //[Part name] - [Resource name] HCUPartFailures.Clear(); HCUPartFailures.AddRange(HCUParts.Select(kvp => kvp.Key.name + " - " + kvp.Value)); HCUPartsList = HCUParts.Keys.ToList(); tonnage = vessel.GetTotalMass(); sciBonus = nearBeacon.GetCrewBonuses("Scientist", 0.5f, 5); for (int i = targetDetails.Count - 1; i >= 0; i--) { targetDetails[i].Update(); } for (int i = hailers.Count - 1; i >= 0; i--) { hailers[i].nearBeaconDistance = nearBeaconDistance; hailers[i].nearBeaconRelVel = nearBeaconRelVel; } }
public void Update() { UpdateNearBeacons(); if (nearBeacon == null || (UnityEngine.Object)nearBeacon.Vessel != (UnityEngine.Object)vessel) { bool flag = nearBeacon != null; for (int i = hailers.Count - 1; i >= 0; i--) { bool hailerActive = hailers[i].hailerActive; ((BaseFieldList <BaseField, KSPField>)hailers[i].Fields)["nearBeaconDistance"].guiActive = (flag & hailerActive); ((BaseFieldList <BaseField, KSPField>)hailers[i].Fields)["nearBeaconRelVel"].guiActive = (flag & hailerActive); ((BaseFieldList <BaseField, KSPField>)hailers[i].Fields)["hasNearBeacon"].guiActive = hailerActive; hailers[i].hasNearBeacon = (flag ? "Present" : "Not Present"); } } else { for (int i = hailers.Count - 1; i >= 0; i--) { ((BaseFieldList <BaseField, KSPField>)hailers[i].Fields)["nearBeaconDistance"].guiActive = false; ((BaseFieldList <BaseField, KSPField>)hailers[i].Fields)["nearBeaconRelVel"].guiActive = false; ((BaseFieldList <BaseField, KSPField>)hailers[i].Fields)["hasNearBeacon"].guiActive = hailers[i].hailerActive; hailers[i].hasNearBeacon = "Onboard"; } } if (nearBeacon != null) { float nearBeaconDistance = Vector3.Distance(vessel.GetWorldPos3D(), nearBeacon.Vessel.GetWorldPos3D()); float nearBeaconRelVel = Vector3.Magnitude(vessel.obt_velocity - nearBeacon.Vessel.obt_velocity); driftpenalty = ESLDBeacon.GetDriftPenalty(nearBeaconDistance, nearBeaconRelVel, nearBeacon.GetCrewBonuses("Pilot", 0.5f, 5)); HCUParts = GetHCUParts(vessel); //[Part name] - [Resource name] HCUPartFailures.Clear(); HCUPartFailures.AddRange(from kvp in HCUParts select kvp.Key.name + " - " + kvp.Value); HCUPartsList = HCUParts.Keys.ToList(); tonnage = vessel.GetTotalMass(); sciBonus = nearBeacon.GetCrewBonuses("Scientist", 0.5f, 5); for (int i = targetDetails.Count - 1; i >= 0; i--) { targetDetails[i].Update(); } for (int i = hailers.Count - 1; i >= 0; i--) { hailers[i].nearBeaconDistance = (double)nearBeaconDistance; hailers[i].nearBeaconRelVel = (double)nearBeaconRelVel; } } }
// Update said predictions private void UpdateExitOrbit(Vessel nearObject, Vessel farObject) { if (!predictionsDrawn) { return; } if (!IsPatchedConicsAvailable) { HideExitOrbit(); return; } Vector3 mapCamPos = ScaledSpace.ScaledToLocalSpace(MapView.MapCamera.transform.position); MapObject farTarget = MapView.MapCamera.target; Vector3 farTarPos = ScaledSpace.ScaledToLocalSpace(farTarget.transform.position); float dirScalar = Vector3.Distance(mapCamPos, farTarPos); Vector3d exitTraj = ESLDBeacon.GetJumpVelOffset(nearObject, farObject); predictionOrbitRenderer.driver.referenceBody = farObject.mainBody; predictionOrbitRenderer.driver.orbit.referenceBody = farObject.mainBody; predictionOrbitRenderer.driver.pos = farObject.orbit.pos; predictionOrbitRenderer.celestialBody = farObject.mainBody; predictionOrbitRenderer.SetColor(Color.red); predictionOrbitDriver.orbit.UpdateFromStateVectors(farObject.orbit.pos, exitTraj, farObject.mainBody, Planetarium.GetUniversalTime()); /* Direction indicator is broken/not required * float baseWidth = 20.0f; * double baseStart = 10; * double baseEnd = 50; * oDirection.transform.position = ScaledSpace.LocalToScaledSpace(far.transform.position); * if (dirScalar / 325000 > baseWidth) baseWidth = dirScalar / 325000f; * oDirection.SetWidth(baseWidth, 0.01f); * if (dirScalar / 650000 > baseStart) baseStart = dirScalar / 650000; * if (dirScalar / 130000 > baseEnd) baseEnd = dirScalar / 130000; * // log.debug("Camera distance is " + dirScalar + " results: " + baseWidth + " " + baseStart + " " + baseEnd); * oDirection.SetPosition(0, Vector3d.zero + exitTraj.xzy.normalized * baseStart); * oDirection.SetPosition(1, exitTraj.xzy.normalized * baseEnd); * oDirection.transform.eulerAngles = Vector3d.zero;*/ }
// Show exit orbital predictions private void ShowExitOrbit(Vessel nearObject, Vessel farObject) { // Recenter map, save previous state. wasInMapView = MapView.MapIsEnabled; if (!MapView.MapIsEnabled) { MapView.EnterMapView(); } MapObject mapObject = FindVesselBody(farObject); if ((UnityEngine.Object)mapObject != (UnityEngine.Object)null) { MapView.MapCamera.SetTarget(mapObject); } Vector3 mapCamPos = ScaledSpace.ScaledToLocalSpace(MapView.MapCamera.transform.position); Vector3 farTarPos = ScaledSpace.ScaledToLocalSpace(mapObject.transform.position); float dirScalar = Vector3.Distance(mapCamPos, farTarPos); //log.Debug("Initializing, camera distance is " + dirScalar); if (!IsPatchedConicsAvailable) { HideExitOrbit(); } else { predictionsDrawn = true; Vector3d vel = ESLDBeacon.GetJumpVelOffset(nearObject, farObject); if (predictionGameObject != null) { Destroy(predictionGameObject); } predictionGameObject = new GameObject("OrbitRendererGameObject"); predictionOrbitDriver = predictionGameObject.AddComponent <OrbitDriver>(); predictionOrbitDriver.orbit.referenceBody = farObject.mainBody; predictionOrbitDriver.orbit = new Orbit(); predictionOrbitDriver.referenceBody = farObject.mainBody; predictionOrbitDriver.upperCamVsSmaRatio = 999999f; // Took forever to figure this out - this sets at what zoom level the orbit appears. Was causing it not to appear at small bodies. predictionOrbitDriver.lowerCamVsSmaRatio = 0.0001f; predictionOrbitDriver.orbit.UpdateFromStateVectors(farObject.orbit.pos, vel, farObject.mainBody, Planetarium.GetUniversalTime()); predictionOrbitDriver.orbit.Init(); Vector3d relativePositionAtUT = predictionOrbitDriver.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); Vector3d orbitalVelocityAtUT = predictionOrbitDriver.orbit.getOrbitalVelocityAtUT(Planetarium.GetUniversalTime()); predictionOrbitDriver.orbit.h = Vector3d.Cross(relativePositionAtUT, orbitalVelocityAtUT); predictionOrbitDriver.updateMode = OrbitDriver.UpdateMode.TRACK_Phys; predictionOrbitDriver.orbitColor = Color.red; predictionOrbitRenderer = predictionGameObject.AddComponent <OrbitRenderer>(); predictionOrbitRenderer.SetColor(Color.red); predictionOrbitRenderer.vessel = vessel; predictionOrbitDriver.vessel = vessel; predictionOrbitRenderer.upperCamVsSmaRatio = 999999f; predictionOrbitRenderer.lowerCamVsSmaRatio = 0.0001f; predictionOrbitRenderer.celestialBody = farObject.mainBody; predictionOrbitRenderer.driver = predictionOrbitDriver; predictionOrbitDriver.Renderer = predictionOrbitRenderer; if (true) { // This draws the full Patched Conics prediction. predictionPatchedConicSolver = predictionGameObject.AddComponent <PatchedConicSolver>(); predictionPatchedConicRenderer = predictionGameObject.AddComponent <PatchedConicRenderer>(); predictionOrbitRenderer.drawIcons = OrbitRendererBase.DrawIcons.NONE; predictionOrbitRenderer.drawMode = OrbitRendererBase.DrawMode.OFF; } #if false else { // This draws just the first patch, similar to a Level 1 tracking station. predictionOrbitRenderer.driver.drawOrbit = true; predictionOrbitRenderer.drawIcons = OrbitRenderer.DrawIcons.OBJ_PE_AP; predictionOrbitRenderer.drawMode = OrbitRenderer.DrawMode.REDRAW_AND_RECALCULATE; predictionOrbitRenderer.enabled = true; } #endif base.StartCoroutine(NullOrbitDriverVessels()); // Splash some color on it. // Directional indicator. /* * float baseWidth = 20.0f; * double baseStart = 10; * double baseEnd = 50; * oDirObj = new GameObject("Indicator"); * oDirObj.layer = 10; // Map layer! * oDirection = oDirObj.AddComponent<LineRenderer>(); * oDirection.useWorldSpace = false; * oOrigin = null; * foreach (Transform sstr in ScaledSpace.Instance.scaledSpaceTransforms) * { * if (sstr.name == far.mainBody.name) * { * oOrigin = sstr; * log.debug("Found origin: " + sstr.name); * break; * } * } * oDirection.transform.parent = oOrigin; * oDirection.transform.position = ScaledSpace.LocalToScaledSpace(far.transform.position); * oDirection.material = new Material(Shader.Find("Particles/Additive")); * oDirection.SetColors(Color.clear, Color.red); * if (dirScalar / 325000 > baseWidth) baseWidth = dirScalar / 325000f; * oDirection.SetWidth(baseWidth, 0.01f); * log.debug("Base Width set to " + baseWidth); * oDirection.SetVertexCount(2); * if (dirScalar / 650000 > baseStart) baseStart = dirScalar / 650000; * if (dirScalar / 130000 > baseEnd) baseEnd = dirScalar / 130000; * log.debug("Base Start set to " + baseStart); * log.debug("Base End set to " + baseEnd); * oDirection.SetPosition(0, Vector3d.zero + exitTraj.xzy.normalized * baseStart); * oDirection.SetPosition(1, exitTraj.xzy.normalized * baseEnd); * oDirection.enabled = true; */ } }
public void WindowInterface(int GuiId) { GUILayout.BeginVertical(); switch (displayMode) { case DisplayMode.Selection: if (farBeacons.Count <= 0 || nearBeacons.Count <= 0 || nearBeacon == null) { GUILayout.Label("No active beacons found."); } else { if (driftpenalty > 0f) { GUILayout.Label($"+{driftpenalty:F2}% due to Drift."); } if (nearBeacon.UnsafeTransfer) { if (vessel.GetCrewCount() > 0 || HCUPartFailures.Count > 0) { GUILayout.Label("WARNING: This beacon has no active Heisenkerb Compensator."); } if (vessel.GetCrewCount() > 0) { GUILayout.Label("Transfer will kill crew."); } if (HCUPartFailures.Count > 0) { GUILayout.Label("Some resources will destabilize."); } } int i; for (i = targetDetails.Count - 1; i >= 0; i--) { GUIStyle style = targetDetails[i].affordable ? (targetDetails[i].pathCheck.clear ? buttonHasFuel : buttonNoPath) : buttonNoFuel; if (GUILayout.Button($"{targetDetails[i].vesselName} ({targetDetails[i].targetSOI}, {targetDetails[i].targetAlt:F1}km) | {targetDetails[i].tripCost:F2}", style)) { if (targetDetails[i].affordable && targetDetails[i].pathCheck.clear) { selectedTarget = targetDetails[i]; if (nearBeacon.CarriesVelocity) { ShowExitOrbit(vessel, selectedTarget.targetVessel); } displayMode = DisplayMode.Confirmation; } else { string message = ""; if (!targetDetails[i].affordable) { int index = nearBeacon.JumpResources.FindIndex((ESLDJumpResource res) => (double)(res.ratio * targetDetails[i].tripCost) > res.fuelOnBoard); message = ((index >= 0) ? $"Cannot Warp: Origin beacon has {nearBeacon.JumpResources[index].fuelOnBoard:F2} of {nearBeacon.JumpResources[index].ratio * targetDetails[i].tripCost:F2} {nearBeacon.JumpResources[index].name} required to warp." : "Index error."); } else if (!targetDetails[i].pathCheck.clear) { string arg = (targetDetails[i].pathCheck.blockingBody.name == "Mun" || targetDetails[i].pathCheck.blockingBody.name == "Sun") ? "the " : ""; switch (targetDetails[i].pathCheck.blockReason) { case "Gravity": message = string.Format("Cannot Warp: Path of transfer intersects a high-gravity area around {1}{0}.", targetDetails[i].pathCheck.blockingBody.name, arg); break; case "Proximity": message = string.Format("Cannot Warp: Path of transfer passes too close to {1}{0}.", targetDetails[i].pathCheck.blockingBody.name, arg); break; case "Null": message = "Cannot Warp: No near beacon assigned. This is an error."; break; default: message = "Cannot Warp: Path is blocked."; break; } } ScreenMessages.PostScreenMessage(message, 5f, ScreenMessageStyle.UPPER_CENTER); } } } GUILayout.FlexibleSpace(); if (nearBeacons.Count > 1) { GUILayout.Label($"Current Beacon: {nearBeacon.Description} ({nearBeacon.Vessel.vesselName})"); if (GUILayout.Button($"Next Beacon ({currentBeaconIndex + 1} of {nearBeacons.Count})", buttonNeutral)) { if (currentBeaconIndex + 1 < nearBeacons.Count) { nearBeacon = nearBeacons[currentBeaconIndex + 1]; } else { nearBeacon = nearBeacons[0]; } } } if (GUILayout.Button("Close Beacon Interface", buttonNeutral)) { UnityEngine.Object.Destroy(this); } } break; case DisplayMode.Confirmation: { if (driftpenalty > 0f) { GUILayout.Label($"+{driftpenalty:F2}% due to Drift."); } if (nearBeacon.UnsafeTransfer) { if (vessel.GetCrewCount() > 0 || HCUPartFailures.Count > 0) { GUILayout.Label("WARNING: This beacon has no active Heisenkerb Compensator.", labelNoFuel); } if (vessel.GetCrewCount() > 0) { GUILayout.Label("Transfer will kill crew.", labelNoFuel); } if (HCUPartFailures.Count > 0) { GUILayout.Label("These resources will destabilize in transit:", labelNoFuel); for (int j = 0; j < HCUPartFailures.Count; j++) { GUILayout.Label(HCUPartFailures[j], labelNoFuel); } } } GUILayout.Label("Confirm Warp:"); string str = "Base cost: "; for (int k = 0; k < nearBeacon.JumpResources.Count; k++) { str += string.Format("{0:F2} {1}{2}", selectedTarget.tripCost * nearBeacon.JumpResources[k].ratio, nearBeacon.JumpResources[k].name, (k + 1 < nearBeacon.JumpResources.Count) ? ", " : ""); } GUILayout.Label(str + "."); List <string> costModifiers = nearBeacon.GetCostModifiers(vessel, selectedTarget.targetVessel, tonnage, HCUParts.Keys.ToList()); for (int l = 0; l < costModifiers.Count; l++) { GUILayout.Label(costModifiers[l]); } GUILayout.Label($"Destination: {selectedTarget.targetVessel.mainBody.name} at {selectedTarget.targetAlt:F1}km."); GUILayout.Label($"Transfer will emerge within {selectedTarget.precision:N0}m of destination beacon."); if (selectedTarget.targetVessel.altitude - (double)selectedTarget.precision <= selectedTarget.targetVessel.mainBody.Radius * 0.10000000149011612 || selectedTarget.targetVessel.altitude - (double)selectedTarget.precision <= selectedTarget.targetVessel.mainBody.atmosphereDepth) { GUILayout.Label($"Arrival area is very close to {selectedTarget.targetVessel.mainBody.name}.", labelNoFuel); } if (nearBeacon.CarriesVelocity) { GUILayout.Label($"Velocity relative to exit beacon will be {(ESLDBeacon.GetJumpVelOffset(vessel, selectedTarget.targetVessel) - selectedTarget.targetVessel.orbit.vel).magnitude:F0}m/s."); } if (selectedTarget.returnFuelCheck && selectedTarget.returnBeacon != null) { string str2 = (!selectedTarget.returnAffordable) ? "Destination beacon would need " : "Destination beacon can make return trip using "; string str3 = "Destination beacon has "; for (int m = 0; m < selectedTarget.returnBeacon.JumpResources.Count; m++) { str3 += string.Format("{0:F0} {1}{2}", selectedTarget.returnBeacon.JumpResources[m].fuelOnBoard, selectedTarget.returnBeacon.JumpResources[m].name, (m + 1 < selectedTarget.returnBeacon.JumpResources.Count) ? ", " : ""); } for (int n = 0; n < selectedTarget.returnBeacon.JumpResources.Count; n++) { str2 += string.Format("{0:F2} {1}{2}", selectedTarget.returnCost * selectedTarget.returnBeacon.JumpResources[n].ratio, selectedTarget.returnBeacon.JumpResources[n].name, (n + 1 < selectedTarget.returnBeacon.JumpResources.Count) ? ", " : ""); } GUILayout.Label(str3 + "."); GUILayout.Label(str2 + (selectedTarget.returnAffordable ? "." : " for return trip using active beacons."), selectedTarget.returnAffordable ? labelHasFuel : labelNoFuel); } else { GUILayout.Label("Destination beacon's fuel could not be checked."); } if (GUILayout.Button("Confirm and Warp", buttonNeutral)) { if (selectedTarget.pathCheck.clear) { HideExitOrbit(); nearBeacon.Warp(vessel, selectedTarget.targetVessel, selectedTarget.precision, HCUPartsList); UnityEngine.Object.Destroy(this); } else { ScreenMessages.PostScreenMessage("Jump Failed! Transfer path has become obstructed.", 5f, ScreenMessageStyle.UPPER_CENTER); } } if (GUILayout.Button("Back", buttonNeutral)) { displayMode = DisplayMode.Selection; window.height = 0f; } break; } } GUILayout.EndVertical(); GUI.DragWindow(/* new Rect(0f, 0f, 10000f, 20f) */); }
// Find loaded beacons. Only in physics distance, since otherwise they're too far out. private ESLDBeacon ScanForNearBeacons() { nearBeacons.Clear(); Fields["hasNearBeacon"].guiActive = true; ESLDBeacon nearBeaconCandidate = null; int candidateIndex = 0; string candidateDesc = ""; foreach (ESLDBeacon selfBeacon in vessel.FindPartModulesImplementing<ESLDBeacon>()) { if (selfBeacon.beaconModel == "IB1" && selfBeacon.activated) { nearBeaconDistance = 0; nearBeaconRelVel = 0; Fields["nearBeaconDistance"].guiActive = false; Fields["nearBeaconRelVel"].guiActive = false; hasNearBeacon = "Onboard"; return selfBeacon; } } double closest = 3000; foreach (Vessel craft in FlightGlobals.Vessels) { if (!craft.loaded) continue; // Eliminate far away craft. if (craft == vessel) continue; // Eliminate current craft. if (craft == FlightGlobals.ActiveVessel) continue; if (craft.FindPartModulesImplementing<ESLDBeacon>().Count == 0) continue; // Has beacon? foreach (ESLDBeacon craftbeacon in craft.FindPartModulesImplementing<ESLDBeacon>()) { if (!craftbeacon.activated) { continue; } // Beacon active? if (craftbeacon.beaconModel == "IB1") { continue; } // Jumpdrives can't do remote transfers. string bIdentifier = craftbeacon.beaconModel + " (" + craft.vesselName + ")"; nearBeacons.Add(craftbeacon, bIdentifier); int nbIndex = nearBeacons.Count - 1; nearBeaconDistance = Math.Round(Vector3d.Distance(vessel.GetWorldPos3D(), craft.GetWorldPos3D())); if (closest > nearBeaconDistance) { nearBeaconCandidate = craftbeacon; candidateIndex = nbIndex; candidateDesc = bIdentifier; closest = nearBeaconDistance; } } } if (nearBeacon != null && nearBeacon.vessel.loaded && nbWasUserSelected && nearBeacon.activated) // If we've already got one, just update the display. { nearBeaconDistance = Math.Round(Vector3d.Distance(vessel.GetWorldPos3D(), nearBeacon.vessel.GetWorldPos3D())); nearBeaconRelVel = Math.Round(Vector3d.Magnitude(vessel.obt_velocity - nearBeacon.vessel.obt_velocity) * 10) / 10; return nearBeacon; } if (nearBeacons.Count > 0) // If we hadn't selected one previously return the closest one. { nbWasUserSelected = false; Vessel craft = nearBeaconCandidate.vessel; Fields["nearBeaconDistance"].guiActive = true; nearBeaconDistance = Math.Round(Vector3d.Distance(vessel.GetWorldPos3D(), craft.GetWorldPos3D())); Fields["nearBeaconRelVel"].guiActive = true; nearBeaconRelVel = Math.Round(Vector3d.Magnitude(vessel.obt_velocity - craft.obt_velocity) * 10) / 10; hasNearBeacon = "Present"; currentBeaconIndex = candidateIndex; currentBeaconDesc = candidateDesc; return nearBeaconCandidate; } hasNearBeacon = "Not Present"; Fields["nearBeaconDistance"].guiActive = false; Fields["nearBeaconRelVel"].guiActive = false; nearBeacon = null; return null; }
// Screen 1 of beacon interface, displays beacons and where they go along with some fuel calculations. private void BeaconInterface(int GuiId) { if (!vessel.isActiveVessel) HailerGUIClose(); GUIStyle buttonHasFuel = new GUIStyle(GUI.skin.button); buttonHasFuel.padding = new RectOffset(8, 8, 8, 8); buttonHasFuel.normal.textColor = buttonHasFuel.focused.textColor = Color.green; buttonHasFuel.hover.textColor = buttonHasFuel.active.textColor = Color.white; GUIStyle buttonNoFuel = new GUIStyle(GUI.skin.button); buttonNoFuel.padding = new RectOffset(8, 8, 8, 8); buttonNoFuel.normal.textColor = buttonNoFuel.focused.textColor = Color.red; buttonNoFuel.hover.textColor = buttonNoFuel.active.textColor = Color.yellow; GUIStyle buttonNoPath = new GUIStyle(GUI.skin.button); buttonNoPath.padding = new RectOffset(8, 8, 8, 8); buttonNoPath.normal.textColor = buttonNoFuel.focused.textColor = Color.gray; buttonNoPath.hover.textColor = buttonNoFuel.active.textColor = Color.gray; GUIStyle buttonNeutral = new GUIStyle(GUI.skin.button); buttonNeutral.padding = new RectOffset(8, 8, 8, 8); buttonNeutral.normal.textColor = buttonNoFuel.focused.textColor = Color.white; buttonNeutral.hover.textColor = buttonNoFuel.active.textColor = Color.white; GUILayout.BeginVertical(HighLogic.Skin.scrollView); if (farTargets.Count() < 1 || nearBeacon == null) { GUILayout.Label("No active beacons found."); } else { double tonnage = vessel.GetTotalMass(); Vessel nbparent = nearBeacon.vessel; string nbModel = nearBeacon.beaconModel; nearBeacon.checkOwnTechBoxes(); double nbfuel = nearBeacon.fuelOnBoard; double driftpenalty = Math.Round(Math.Pow(Math.Floor(nearBeaconDistance / 200), 2) + Math.Floor(Math.Pow(nearBeaconRelVel, 1.5)) * nearBeacon.getCrewBonuses(nbparent,"Pilot",0.5,5)); if (driftpenalty > 0) GUILayout.Label("+" + driftpenalty + "% due to Drift."); Dictionary<Part, string> HCUParts = getHCUParts(vessel); if (!nearBeacon.hasHCU) { if (vessel.GetCrewCount() > 0 || HCUParts.Count > 0) GUILayout.Label("WARNING: This beacon has no active Heisenkerb Compensator."); if (vessel.GetCrewCount() > 0) GUILayout.Label("Transfer will kill crew."); if (HCUParts.Count > 0) GUILayout.Label("Some resources will destabilize."); } foreach (KeyValuePair<Vessel, string> ftarg in farTargets) { double tripdist = Vector3d.Distance(nbparent.GetWorldPos3D(), ftarg.Key.GetWorldPos3D()); double tripcost = getTripBaseCost(tripdist, tonnage, nbModel); double sciBonus = nearBeacon.getCrewBonuses(nbparent, "Scientist", 0.5, 5); if (nearBeacon.hasSCU) { if (driftpenalty == 0 && sciBonus >= 0.9) { tripcost *= 0.9; } if (sciBonus < 0.9 || (sciBonus < 1 && driftpenalty > 0)) { tripcost *= sciBonus; } } if (tripcost == 0) continue; tripcost += tripcost * (driftpenalty * .01); if (nearBeacon.hasAMU) tripcost += getAMUCost(vessel, ftarg.Key, tonnage, nearBeacon.beaconModel); double adjHCUCost = HCUCost; if (nearBeacon.beaconModel == "IB1") adjHCUCost = Math.Round((HCUCost - (tripcost * 0.02)) * 100) / 100; if (nearBeacon.hasHCU) tripcost += adjHCUCost; tripcost = Math.Round(tripcost * 100) / 100; string targetSOI = ftarg.Key.mainBody.name; double targetAlt = Math.Round(ftarg.Key.altitude / 1000); GUIStyle fuelstate = buttonNoFuel; string blockReason = ""; string blockRock = ""; if (tripcost <= nbfuel) // Show blocked status only for otherwise doable transfers. { fuelstate = buttonHasFuel; KeyValuePair<string, CelestialBody> checkpath = masterClass.HasTransferPath(nbparent, ftarg.Key, nearBeacon.gLimit); if (checkpath.Key != "OK") { fuelstate = buttonNoPath; blockReason = checkpath.Key; blockRock = checkpath.Value.name; } } if (GUILayout.Button(ftarg.Value + " " + ftarg.Key.vesselName + "(" + targetSOI + ", " + targetAlt + "km) | " + tripcost, fuelstate)) { if (fuelstate == buttonHasFuel) { farBeacon = ftarg.Key; farBeaconModel = ftarg.Value; drawConfirm(); if (!nearBeacon.hasAMU) showExitOrbit(vessel, farBeacon, nearBeacon.beaconModel); RenderingManager.AddToPostDrawQueue(4, new Callback(drawConfirm)); RenderingManager.RemoveFromPostDrawQueue(3, new Callback(drawGUI)); Events["HailerGUIClose"].active = false; Events["HailerGUIOpen"].active = true; } else { print("Current beacon has a g limit of " + nearBeacon.gLimit); string messageToPost = "Cannot Warp: Origin beacon has " + nbfuel + " of " + tripcost + " Karborundum required to warp."; string thevar = (blockRock == "Mun" || blockRock == "Sun") ? "the " : string.Empty; if (fuelstate == buttonNoPath && blockReason == "Gravity") messageToPost = "Cannot Warp: Path of transfer intersects a high-gravity area around " + thevar + blockRock + "."; if (fuelstate == buttonNoPath && blockReason == "Proximity") messageToPost = "Cannot Warp: Path of transfer passes too close to " + thevar + blockRock + "."; ScreenMessages.PostScreenMessage(messageToPost, 5.0f, ScreenMessageStyle.UPPER_CENTER); } } } } if(nearBeacons.Count > 1) { GUILayout.Label("Current Beacon: " + currentBeaconDesc); if (currentBeaconIndex >= nearBeacons.Count) currentBeaconIndex = nearBeacons.Count - 1; int nextIndex = currentBeaconIndex + 1; if (nextIndex >= nearBeacons.Count) nextIndex = 0; if (GUILayout.Button("Next Beacon (" + (currentBeaconIndex + 1) + " of " + nearBeacons.Count + ")", buttonNeutral)) { nbWasUserSelected = true; nearBeacon = nearBeacons.ElementAt(nextIndex).Key; currentBeaconDesc = nearBeacons.ElementAt(nextIndex).Value; currentBeaconIndex = nextIndex; } } if (GUILayout.Button("Close Beacon Interface", buttonNeutral)) { HailerGUIClose(); } GUILayout.EndVertical(); GUI.DragWindow(new Rect(0, 0, 10000, 20)); }
public override void OnFixedUpdate() { var startState = hasNearBeacon; nearBeacon = ScanForNearBeacons(); if (nearBeacon == null) { if (startState != hasNearBeacon) { HailerGUIClose(); } Events["HailerGUIClose"].active = false; Events["HailerGUIOpen"].active = false; } else { Events["HailerGUIClose"].active = false; Events["HailerGUIOpen"].active = true; if (guiopen) listFarBeacons(); } }
public void WindowInterface(int GuiId) { GUILayout.BeginVertical(); switch (displayMode) { case DisplayMode.Selection: if (farBeacons.Count <= 0 || nearBeacons.Count <= 0 || nearBeacon == null) { GUILayout.Label("No active beacons found."); } else { if (driftpenalty > 0) { GUILayout.Label(String.Format("+{0:F2}% due to Drift.", driftpenalty)); } if (nearBeacon.UnsafeTransfer) { if (vessel.GetCrewCount() > 0 || HCUPartFailures.Count > 0) { GUILayout.Label("WARNING: This beacon has no active Heisenkerb Compensator."); } if (vessel.GetCrewCount() > 0) { GUILayout.Label("Transfer will kill crew."); } if (HCUPartFailures.Count > 0) { GUILayout.Label("Some resources will destabilize."); } } for (int i = targetDetails.Count - 1; i >= 0; i--) { GUIStyle fuelstate = targetDetails[i].affordable ? (targetDetails[i].pathCheck.clear ? buttonHasFuel : buttonNoPath) : buttonNoFuel; if (GUILayout.Button(String.Format("{0} ({1}, {2:F1}km) | {3:F2}", targetDetails[i].vesselName, targetDetails[i].targetSOI, targetDetails[i].targetAlt, targetDetails[i].tripCost), fuelstate)) { if (targetDetails[i].affordable && targetDetails[i].pathCheck.clear) { selectedTarget = targetDetails[i]; if (nearBeacon.CarriesVelocity) { ShowExitOrbit(vessel, selectedTarget.targetVessel); } displayMode = DisplayMode.Confirmation; } else { string messageToPost = ""; if (!targetDetails[i].affordable) { int index = nearBeacon.JumpResources.FindIndex(res => res.ratio * targetDetails[i].tripCost > res.fuelOnBoard); if (index < 0) { messageToPost = "Index error."; } else { messageToPost = String.Format("Cannot Warp: Origin beacon has {0:F2} of {1:F2} {2} required to warp.", nearBeacon.JumpResources[index].fuelOnBoard, nearBeacon.JumpResources[index].ratio * targetDetails[i].tripCost, nearBeacon.JumpResources[index].name); } } else if (!targetDetails[i].pathCheck.clear) { string thevar = (targetDetails[i].pathCheck.blockingBody.name == "Mun" || targetDetails[i].pathCheck.blockingBody.name == "Sun") ? "the " : ""; switch (targetDetails[i].pathCheck.blockReason) { case "Gravity": messageToPost = String.Format("Cannot Warp: Path of transfer intersects a high-gravity area around {1}{0}.", targetDetails[i].pathCheck.blockingBody.name, thevar); break; case "Proximity": messageToPost = String.Format("Cannot Warp: Path of transfer passes too close to {1}{0}.", targetDetails[i].pathCheck.blockingBody.name, thevar); break; case "Null": messageToPost = "Cannot Warp: No near beacon assigned. This is an error."; break; default: messageToPost = "Cannot Warp: Path is blocked."; break; } } ScreenMessages.PostScreenMessage(messageToPost, 5.0f, ScreenMessageStyle.UPPER_CENTER); } } } GUILayout.FlexibleSpace(); if (nearBeacons.Count > 1) { GUILayout.Label(String.Format("Current Beacon: {0} ({1})", nearBeacon.Description, nearBeacon.Vessel.vesselName)); if (GUILayout.Button(String.Format("Next Beacon ({0} of {1})", (currentBeaconIndex + 1), nearBeacons.Count), buttonNeutral)) { if (currentBeaconIndex + 1 < nearBeacons.Count) { nearBeacon = nearBeacons[currentBeaconIndex + 1]; } else { nearBeacon = nearBeacons[0]; } } } if (GUILayout.Button("Close Beacon Interface", buttonNeutral)) { Destroy(this); } } break; case DisplayMode.Confirmation: if (driftpenalty > 0) { GUILayout.Label(String.Format("+{0:F2}% due to Drift.", driftpenalty)); } if (nearBeacon.UnsafeTransfer) { if (vessel.GetCrewCount() > 0 || HCUPartFailures.Count > 0) { GUILayout.Label("WARNING: This beacon has no active Heisenkerb Compensator.", labelNoFuel); } if (vessel.GetCrewCount() > 0) { GUILayout.Label("Transfer will kill crew.", labelNoFuel); } if (HCUPartFailures.Count > 0) { GUILayout.Label("These resources will destabilize in transit:", labelNoFuel); for (int i = 0; i < HCUPartFailures.Count; i++) { GUILayout.Label(HCUPartFailures[i], labelNoFuel); } } } GUILayout.Label("Confirm Warp:"); string costLabel = "Base cost: "; for (int i = 0; i < nearBeacon.JumpResources.Count; i++) { costLabel += String.Format("{0:F2} {1}{2}", selectedTarget.tripCost * nearBeacon.JumpResources[i].ratio, nearBeacon.JumpResources[i].name, i + 1 < nearBeacon.JumpResources.Count ? ", " : ""); } GUILayout.Label(costLabel + "."); List <string> modifiers = nearBeacon.GetCostModifiers(vessel, selectedTarget.targetVessel, tonnage, HCUParts.Keys.ToList()); for (int i = 0; i < modifiers.Count; i++) { GUILayout.Label(modifiers[i]); } GUILayout.Label(String.Format("Destination: {0} at {1:F1}km.", selectedTarget.targetVessel.mainBody.name, selectedTarget.targetAlt)); GUILayout.Label(String.Format("Transfer will emerge within {0:N0}m of destination beacon.", selectedTarget.precision)); if (selectedTarget.targetVessel.altitude - selectedTarget.precision <= selectedTarget.targetVessel.mainBody.Radius * 0.1f || selectedTarget.targetVessel.altitude - selectedTarget.precision <= selectedTarget.targetVessel.mainBody.atmosphereDepth) { GUILayout.Label(String.Format("Arrival area is very close to {0}.", selectedTarget.targetVessel.mainBody.name), labelNoFuel); } if (nearBeacon.CarriesVelocity) { Vector3d transferVelOffset = ESLDBeacon.GetJumpVelOffset(vessel, selectedTarget.targetVessel) - selectedTarget.targetVessel.orbit.vel; GUILayout.Label(String.Format("Velocity relative to exit beacon will be {0:F0}m/s.", transferVelOffset.magnitude)); } if (selectedTarget.returnFuelCheck && selectedTarget.returnBeacon != null) { string fuelMessage; if (selectedTarget.returnAffordable) { fuelMessage = "Destination beacon can make return trip using "; } else { fuelMessage = "Destination beacon would need "; } string fuelCount = "Destination beacon has "; for (int i = 0; i < selectedTarget.returnBeacon.JumpResources.Count; i++) { fuelCount += String.Format("{0:F0} {1}{2}", selectedTarget.returnBeacon.JumpResources[i].fuelOnBoard, selectedTarget.returnBeacon.JumpResources[i].name, i + 1 < selectedTarget.returnBeacon.JumpResources.Count ? ", " : ""); } for (int i = 0; i < selectedTarget.returnBeacon.JumpResources.Count; i++) { fuelMessage += String.Format("{0:F2} {1}{2}", selectedTarget.returnCost * selectedTarget.returnBeacon.JumpResources[i].ratio, selectedTarget.returnBeacon.JumpResources[i].name, i + 1 < selectedTarget.returnBeacon.JumpResources.Count ? ", " : ""); } GUILayout.Label(fuelCount + "."); GUILayout.Label(fuelMessage + (selectedTarget.returnAffordable ? "." : " for return trip using active beacons."), selectedTarget.returnAffordable ? labelHasFuel : labelNoFuel); } else { GUILayout.Label("Destination beacon's fuel could not be checked."); } if (GUILayout.Button("Confirm and Warp", buttonNeutral)) { if (selectedTarget.pathCheck.clear) { HideExitOrbit(); nearBeacon.Warp(vessel, selectedTarget.targetVessel, selectedTarget.precision, HCUPartsList); Destroy(this); } else { ScreenMessages.PostScreenMessage("Jump Failed! Transfer path has become obstructed.", 5.0f, ScreenMessageStyle.UPPER_CENTER); } } if (GUILayout.Button("Back", buttonNeutral)) { displayMode = DisplayMode.Selection; window.height = 0; } break; } GUILayout.EndVertical(); GUI.DragWindow(new Rect(0, 0, 10000, 20)); }
// Screen 1 of beacon interface, displays beacons and where they go along with some fuel calculations. private void BeaconInterface(int GuiId) { if (!vessel.isActiveVessel) { HailerGUIClose(); } GUIStyle buttonHasFuel = new GUIStyle(GUI.skin.button); buttonHasFuel.padding = new RectOffset(8, 8, 8, 8); buttonHasFuel.normal.textColor = buttonHasFuel.focused.textColor = Color.green; buttonHasFuel.hover.textColor = buttonHasFuel.active.textColor = Color.white; GUIStyle buttonNoFuel = new GUIStyle(GUI.skin.button); buttonNoFuel.padding = new RectOffset(8, 8, 8, 8); buttonNoFuel.normal.textColor = buttonNoFuel.focused.textColor = Color.red; buttonNoFuel.hover.textColor = buttonNoFuel.active.textColor = Color.yellow; GUIStyle buttonNoPath = new GUIStyle(GUI.skin.button); buttonNoPath.padding = new RectOffset(8, 8, 8, 8); buttonNoPath.normal.textColor = buttonNoFuel.focused.textColor = Color.gray; buttonNoPath.hover.textColor = buttonNoFuel.active.textColor = Color.gray; GUIStyle buttonNeutral = new GUIStyle(GUI.skin.button); buttonNeutral.padding = new RectOffset(8, 8, 8, 8); buttonNeutral.normal.textColor = buttonNoFuel.focused.textColor = Color.white; buttonNeutral.hover.textColor = buttonNoFuel.active.textColor = Color.white; GUILayout.BeginVertical(HighLogic.Skin.scrollView); if (farTargets.Count() < 1 || nearBeacon == null) { GUILayout.Label("No active beacons found."); } else { double tonnage = vessel.GetTotalMass(); Vessel nbparent = nearBeacon.vessel; string nbModel = nearBeacon.beaconModel; nearBeacon.checkOwnTechBoxes(); double nbfuel = nearBeacon.fuelOnBoard; double driftpenalty = Math.Round(Math.Pow(Math.Floor(nearBeaconDistance / 200), 2) + Math.Floor(Math.Pow(nearBeaconRelVel, 1.5)) * nearBeacon.getCrewBonuses(nbparent, "Pilot", 0.5, 5)); if (driftpenalty > 0) { GUILayout.Label("+" + driftpenalty + "% due to Drift."); } Dictionary <Part, string> HCUParts = getHCUParts(vessel); if (!nearBeacon.hasHCU) { if (vessel.GetCrewCount() > 0 || HCUParts.Count > 0) { GUILayout.Label("WARNING: This beacon has no active Heisenkerb Compensator."); } if (vessel.GetCrewCount() > 0) { GUILayout.Label("Transfer will kill crew."); } if (HCUParts.Count > 0) { GUILayout.Label("Some resources will destabilize."); } } foreach (KeyValuePair <Vessel, string> ftarg in farTargets) { double tripdist = Vector3d.Distance(nbparent.GetWorldPos3D(), ftarg.Key.GetWorldPos3D()); double tripcost = getTripBaseCost(tripdist, tonnage, nbModel); double sciBonus = nearBeacon.getCrewBonuses(nbparent, "Scientist", 0.5, 5); if (nearBeacon.hasSCU) { if (driftpenalty == 0 && sciBonus >= 0.9) { tripcost *= 0.9; } if (sciBonus < 0.9 || (sciBonus < 1 && driftpenalty > 0)) { tripcost *= sciBonus; } } if (tripcost == 0) { continue; } tripcost += tripcost * (driftpenalty * .01); if (nearBeacon.hasAMU) { tripcost += getAMUCost(vessel, ftarg.Key, tonnage, nearBeacon.beaconModel); } double adjHCUCost = HCUCost; if (nearBeacon.beaconModel == "IB1") { adjHCUCost = Math.Round((HCUCost - (tripcost * 0.02)) * 100) / 100; } if (nearBeacon.hasHCU) { tripcost += adjHCUCost; } tripcost = Math.Round(tripcost * 100) / 100; string targetSOI = ftarg.Key.mainBody.name; double targetAlt = Math.Round(ftarg.Key.altitude / 1000); GUIStyle fuelstate = buttonNoFuel; string blockReason = ""; string blockRock = ""; if (tripcost <= nbfuel) // Show blocked status only for otherwise doable transfers. { fuelstate = buttonHasFuel; KeyValuePair <string, CelestialBody> checkpath = masterClass.HasTransferPath(nbparent, ftarg.Key, nearBeacon.gLimit); if (checkpath.Key != "OK") { fuelstate = buttonNoPath; blockReason = checkpath.Key; blockRock = checkpath.Value.name; } } if (GUILayout.Button(ftarg.Value + " " + ftarg.Key.vesselName + "(" + targetSOI + ", " + targetAlt + "km) | " + tripcost, fuelstate)) { if (fuelstate == buttonHasFuel) { farBeacon = ftarg.Key; farBeaconModel = ftarg.Value; drawConfirm(); if (!nearBeacon.hasAMU) { showExitOrbit(vessel, farBeacon, nearBeacon.beaconModel); } RenderingManager.AddToPostDrawQueue(4, new Callback(drawConfirm)); RenderingManager.RemoveFromPostDrawQueue(3, new Callback(drawGUI)); Events["HailerGUIClose"].active = false; Events["HailerGUIOpen"].active = true; } else { print("Current beacon has a g limit of " + nearBeacon.gLimit); string messageToPost = "Cannot Warp: Origin beacon has " + nbfuel + " of " + tripcost + " Karborundum required to warp."; string thevar = (blockRock == "Mun" || blockRock == "Sun") ? "the " : string.Empty; if (fuelstate == buttonNoPath && blockReason == "Gravity") { messageToPost = "Cannot Warp: Path of transfer intersects a high-gravity area around " + thevar + blockRock + "."; } if (fuelstate == buttonNoPath && blockReason == "Proximity") { messageToPost = "Cannot Warp: Path of transfer passes too close to " + thevar + blockRock + "."; } ScreenMessages.PostScreenMessage(messageToPost, 5.0f, ScreenMessageStyle.UPPER_CENTER); } } } } if (nearBeacons.Count > 1) { GUILayout.Label("Current Beacon: " + currentBeaconDesc); if (currentBeaconIndex >= nearBeacons.Count) { currentBeaconIndex = nearBeacons.Count - 1; } int nextIndex = currentBeaconIndex + 1; if (nextIndex >= nearBeacons.Count) { nextIndex = 0; } if (GUILayout.Button("Next Beacon (" + (currentBeaconIndex + 1) + " of " + nearBeacons.Count + ")", buttonNeutral)) { nbWasUserSelected = true; nearBeacon = nearBeacons.ElementAt(nextIndex).Key; currentBeaconDesc = nearBeacons.ElementAt(nextIndex).Value; currentBeaconIndex = nextIndex; } } if (GUILayout.Button("Close Beacon Interface", buttonNeutral)) { HailerGUIClose(); } GUILayout.EndVertical(); GUI.DragWindow(new Rect(0, 0, 10000, 20)); }
// Find loaded beacons. Only in physics distance, since otherwise they're too far out. private ESLDBeacon ScanForNearBeacons() { nearBeacons.Clear(); Fields["hasNearBeacon"].guiActive = true; ESLDBeacon nearBeaconCandidate = null; int candidateIndex = 0; string candidateDesc = ""; foreach (ESLDBeacon selfBeacon in vessel.FindPartModulesImplementing <ESLDBeacon>()) { if (selfBeacon.beaconModel == "IB1" && selfBeacon.activated) { nearBeaconDistance = 0; nearBeaconRelVel = 0; Fields["nearBeaconDistance"].guiActive = false; Fields["nearBeaconRelVel"].guiActive = false; hasNearBeacon = "Onboard"; return(selfBeacon); } } double closest = 3000; foreach (Vessel craft in FlightGlobals.Vessels) { if (!craft.loaded) { continue; // Eliminate far away craft. } if (craft == vessel) { continue; // Eliminate current craft. } if (craft == FlightGlobals.ActiveVessel) { continue; } if (craft.FindPartModulesImplementing <ESLDBeacon>().Count == 0) { continue; // Has beacon? } foreach (ESLDBeacon craftbeacon in craft.FindPartModulesImplementing <ESLDBeacon>()) { if (!craftbeacon.activated) { continue; } // Beacon active? if (craftbeacon.beaconModel == "IB1") { continue; } // Jumpdrives can't do remote transfers. string bIdentifier = craftbeacon.beaconModel + " (" + craft.vesselName + ")"; nearBeacons.Add(craftbeacon, bIdentifier); int nbIndex = nearBeacons.Count - 1; nearBeaconDistance = Math.Round(Vector3d.Distance(vessel.GetWorldPos3D(), craft.GetWorldPos3D())); if (closest > nearBeaconDistance) { nearBeaconCandidate = craftbeacon; candidateIndex = nbIndex; candidateDesc = bIdentifier; closest = nearBeaconDistance; } } } if (nearBeacon != null && nearBeacon.vessel.loaded && nbWasUserSelected && nearBeacon.activated) // If we've already got one, just update the display. { nearBeaconDistance = Math.Round(Vector3d.Distance(vessel.GetWorldPos3D(), nearBeacon.vessel.GetWorldPos3D())); nearBeaconRelVel = Math.Round(Vector3d.Magnitude(vessel.obt_velocity - nearBeacon.vessel.obt_velocity) * 10) / 10; return(nearBeacon); } if (nearBeacons.Count > 0) // If we hadn't selected one previously return the closest one. { nbWasUserSelected = false; Vessel craft = nearBeaconCandidate.vessel; Fields["nearBeaconDistance"].guiActive = true; nearBeaconDistance = Math.Round(Vector3d.Distance(vessel.GetWorldPos3D(), craft.GetWorldPos3D())); Fields["nearBeaconRelVel"].guiActive = true; nearBeaconRelVel = Math.Round(Vector3d.Magnitude(vessel.obt_velocity - craft.obt_velocity) * 10) / 10; hasNearBeacon = "Present"; currentBeaconIndex = candidateIndex; currentBeaconDesc = candidateDesc; return(nearBeaconCandidate); } hasNearBeacon = "Not Present"; Fields["nearBeaconDistance"].guiActive = false; Fields["nearBeaconRelVel"].guiActive = false; nearBeacon = null; return(null); }