private void UpdateUsedBy() { //print ("*RK* Updating UsedBy"); usedBy.Clear(); List <Part> enginesList = GetEnginesFedBy(part); engineCount = enginesList.Count; foreach (Part engine in enginesList) { foreach (PartModule engine_module in engine.Modules) { List <Propellant> propellants = GetEnginePropellants(engine_module); if ((object)propellants != null) { FuelInfo f = new FuelInfo(propellants, this, engine.partInfo.title); if (f.ratioFactor > 0.0) { FuelInfo found; if (!usedBy.TryGetValue(f.Label, out found)) { usedBy.Add(f.Label, f); } else if (!found.names.Contains(engine.partInfo.title)) { found.names += ", " + engine.partInfo.title; } } } } } // Need to update the tweakable menu too if (HighLogic.LoadedSceneIsEditor) { Events.RemoveAll(button => button.name.StartsWith("MFT")); bool activeEditor = (AvailableVolume >= 0.001); int idx = 0; foreach (FuelInfo info in usedBy.Values) { KSPEvent kspEvent = new KSPEvent { name = "MFT" + idx++, guiActive = false, guiActiveEditor = activeEditor, guiName = info.Label }; FuelInfo info1 = info; BaseEvent button = new BaseEvent(Events, kspEvent.name, () => ConfigureFor(info1), kspEvent) { guiActiveEditor = activeEditor }; Events.Add(button); } MarkWindowDirty(); } }
public void AddRepair(RepairData repairData) { repairDatas.Add(repairData); KSPEvent attribHolder = GenerateRepairOptionSelectionAttribs(repairData); repairData.customControllerData = new CustomPRCData(repairData.RequestedResources.Keys.AsEnumerable()); BaseEvent PAWButton = new BaseEvent(Events, $"SelectionToggle {repairData.RepairOptionDescription}", () => { ToggleRepairSelection(repairData); }, attribHolder); Events.Add(PAWButton); (repairData.customControllerData as CustomPRCData).PAWSelectionToggleButton = PAWButton; }
static KSPEvent GenerateRepairOptionSelectionAttribs(RepairData repairData) { KSPEvent attribHolder = new KSPEvent { guiActive = true, guiActiveUncommand = true, guiActiveUnfocused = true, requireFullControl = false, guiName = $"Select: {repairData.RepairOptionDescription}", groupName = "KRTRepeirsSelection", groupDisplayName = "KRT Repairs Selection", }; return(attribHolder); }
void SelectRepair(RepairData repairData) // Does not call repairData.Select, supposed to be used after/before calling it or Toggle somewhere else { string displayedResList = $"Chosen repair option is {repairData.RepairOptionDescription}.\nIt needs this set of rsources to be completed\n(Assuming repair efficiency is not lower than 1):"; foreach (KeyValuePair <string, double> i in repairData.RequestedResources) { displayedResList += $"\n{PartResourceLibrary.Instance.GetDefinition(i.Key).displayName}: {i.Value}"; } PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "KRTRepairRequests", "Repair Option Chosen", displayedResList, "Prepare Duct Tape!", false, HighLogic.UISkin); (repairData.customControllerData as CustomPRCData).PAWSelectionToggleButton.guiName = $"Deselect: {repairData.RepairOptionDescription}"; KSPEvent attribHolder = GenerateRepairAssignmentCatchingToggleAtribs(repairData); BaseEvent PAWButton = new BaseEvent(Events, $"AssigningToggle: {repairData.RepairOptionDescription}", () => { ToggleRepairAssigning(repairData); }, attribHolder); Events.Add(PAWButton); (repairData.customControllerData as CustomPRCData).PAWCatchingAssignmentButton = PAWButton; }
//[KSPField(guiActive = true, guiName = "Status", isPersistant = false)] //public string status; public void addDataButton(ScienceData sd, IScienceDataContainer cont) { var subject = ResearchAndDevelopment.GetSubjectByID(sd.subjectID); var parts = sd.subjectID.Split('@'); var experiment = ResearchAndDevelopment.GetExperiment(parts[0]); if (experiment != null && sd.baseTransmitValue < txValue) { KSPEvent kspevent = new KSPEvent(); kspevent.active = true; kspevent.name = sd.subjectID; kspevent.guiActive = true; kspevent.guiName = sd.title; IScienceDataContainer my_cont = cont; ScienceData my_sd = sd; BaseEvent ev = new BaseEvent(Events, sd.subjectID, delegate() { analyze(my_cont, my_sd); }, kspevent); sampleEvents.Add(ev); Events.Add(ev); } }
/// <summary> /// Given a BaseEvent, obtain a KSPEvent. /// Note : This is used in UIPartActionMenuPatcher.Wrap in case there no KSPEvent in the custom attributes of the BaseEventDelegate from the button event. /// </summary> /// <param name="baseEvent">BaseEvent from which to obtain a KSPEvent.</param> /// <returns>KSPEvent instance from the BaseEvent parameter.</returns> public static KSPEvent KspEventFromBaseEvent(BaseEvent baseEvent) { var kspEvent = new KSPEvent { active = baseEvent.active, guiActive = baseEvent.guiActive, requireFullControl = baseEvent.requireFullControl, guiActiveEditor = baseEvent.guiActiveEditor, guiActiveUncommand = baseEvent.guiActiveUncommand, guiIcon = baseEvent.guiIcon, guiName = baseEvent.guiName, category = baseEvent.category, advancedTweakable = baseEvent.advancedTweakable, guiActiveUnfocused = baseEvent.guiActiveUnfocused, unfocusedRange = baseEvent.unfocusedRange, externalToEVAOnly = baseEvent.externalToEVAOnly, isPersistent = baseEvent.isPersistent }; return(kspEvent); }
// Adding Selfie button private void addSelfie(KerbalEVA evaCtl) { Log.dbg("Adding Selfie to {0}", evaCtl.GUIName); BaseEventList pEvents = evaCtl.Events; BaseEventDelegate slf = new BaseEventDelegate(TakeSelfie); KSPEvent evt = new KSPEvent { active = true, externalToEVAOnly = true, guiActive = true, guiActiveEditor = false, guiActiveUnfocused = false, guiActiveUncommand = false, guiName = "Take Selfie", name = "TakeSelfie" }; BaseEvent selfie = new BaseEvent(pEvents, "Take Selfie", slf, evt); pEvents.Add(selfie); selfie.guiActive = true; selfie.active = true; }
public void UpdateUsedBy() { //print ("*RK* Updating UsedBy"); usedBy.Clear (); // Get part list List<Part> parts; if (HighLogic.LoadedSceneIsEditor && EditorLogic.fetch.ship != null) parts = EditorLogic.fetch.ship.parts; else if (HighLogic.LoadedSceneIsFlight && vessel != null) parts = vessel.parts; else parts = new List<Part>(); FuelInfo f; string title; PartModule m; for(int i = 0; i < parts.Count; ++i) { title = parts[i].partInfo.title; for(int j = 0; j < parts[i].Modules.Count; ++j) { m = parts[i].Modules[j]; if (m is ModuleEngines) { f = new FuelInfo((m as ModuleEngines).propellants, this, title); if(f.ratioFactor > 0d) UpdateFuelInfo(f, title); } else if (m is ModuleRCS) { f = new FuelInfo((m as ModuleRCS).propellants, this, title); if (f.ratioFactor > 0d) UpdateFuelInfo(f, title); } } } // Need to update the tweakable menu too if (HighLogic.LoadedSceneIsEditor) { Events.RemoveAll (button => button.name.StartsWith ("MFT")); bool activeEditor = (AvailableVolume >= 0.001); int idx = 0; foreach (FuelInfo info in usedBy.Values) { KSPEvent kspEvent = new KSPEvent { name = "MFT" + idx++, guiActive = false, guiActiveEditor = activeEditor, guiName = info.Label }; FuelInfo info1 = info; BaseEvent button = new BaseEvent (Events, kspEvent.name, () => ConfigureFor (info1), kspEvent) { guiActiveEditor = activeEditor }; Events.Add (button); } MarkWindowDirty (); } }
private void reinitEvents(Vessel v) { printDebug("entered"); if (v.evaController == null) { return; } KerbalEVA evaCtl = v.evaController; ProtoCrewMember crew = v.GetVesselCrew() [0]; String kerbalName = crew.name; printDebug("evCtl found; checking name: " + kerbalName); Tourist t; if (!tourists.TryGetValue(kerbalName, out t)) { return; } printDebug("among tourists: " + kerbalName); t.smile = false; t.taken = false; if (!Tourist.isTourist(v.GetVesselCrew()[0])) { printDebug("...but is a crew"); return; // not a real tourist } // Change crew type right away to avoid them being crew after recovery crew.type = ProtoCrewMember.KerbalType.Tourist; BaseEventList pEvents = evaCtl.Events; foreach (BaseEvent e in pEvents) { printDebug("disabling event " + e.guiName); e.guiActive = false; e.guiActiveUnfocused = false; e.guiActiveUncommand = false; } // Adding Selfie button BaseEventDelegate slf = new BaseEventDelegate(TakeSelfie); KSPEvent evt = new KSPEvent(); evt.active = true; evt.externalToEVAOnly = true; evt.guiActive = true; evt.guiActiveEditor = false; evt.guiActiveUnfocused = false; evt.guiActiveUncommand = false; evt.guiName = "Take Selfie"; evt.name = "TakeSelfie"; BaseEvent selfie = new BaseEvent(pEvents, "Take Selfie", slf, evt); pEvents.Add(selfie); selfie.guiActive = true; selfie.active = true; foreach (PartModule m in evaCtl.part.Modules) { if (!m.ClassName.Equals("ModuleScienceExperiment")) { continue; } printDebug("science module id: " + ((ModuleScienceExperiment)m).experimentID); // Disable all science foreach (BaseEvent e in m.Events) { e.guiActive = false; e.guiActiveUnfocused = false; e.guiActiveUncommand = false; } foreach (BaseAction a in m.Actions) { a.active = false; } } printDebug("Initializing sound"); // Should we always invalidate cache??? fx = null; getOrCreateAudio(evaCtl.part.gameObject); }
public WrappedEvent(BaseEvent originalEvent, BaseEventList baseParentList, string name, BaseEventDelegate baseActionDelegate, KSPEvent kspEvent) : base(baseParentList, name, baseActionDelegate, kspEvent) { _originalEvent = originalEvent; }
public static void WrapPartActionEventItem(Part part, Action <BaseEvent, bool> passthrough) { var controller = UIPartActionController.Instance; if (!controller) { return; } // get the part action window corresponding to the part var window = controller.GetItem(part); if (window == null) { return; } // get all the items that makes this window (toggle buttons, sliders, etc.) var partActionItems = window.ListItems; // loop through all of those UI components for (var i = 0; i < partActionItems.Count(); i++) { // check that the part action item is actually a UIPartActionFieldItem (it could be a UIPartActionEventItem) var uiPartActionEventItem = (partActionItems[i] as UIPartActionEventItem); if (uiPartActionEventItem == null) { continue; } // get event from button BaseEvent originalEvent = uiPartActionEventItem.Evt; // Search for the BaseEventDelegate (BaseEvent.onEvent) field defined for the current BaseEvent type. // Note that 'onEvent' is protected, so we have to go through reflection. FieldInfo partEventFieldInfo = typeof(BaseEvent).GetFields(BindingFlags.Instance | BindingFlags.NonPublic) .First(fi => fi.FieldType == typeof(BaseEventDelegate)); // Get the actual value of the 'onEvent' field BaseEventDelegate partEvent = (BaseEventDelegate)partEventFieldInfo.GetValue(originalEvent); // Gets the method represented by the delegate and from this method returns an array of custom attributes applied to this member. // Simply put, we want all [KSPEvent] attributes applied to the BaseEventDelegate.Method field. object[] customAttributes = partEvent.Method.GetCustomAttributes(typeof(KSPEvent), true); // Look for the custom attribute skip_control bool skipControl = customAttributes.Any(a => ((KSPEvent)a).category.Contains("skip_control")); if (skipControl) { continue; } /* * Override the old BaseEvent with our BaseEvent to the button */ // fix problems with other mods (behavior not seen with KSP) when the customAttributes list is empty. KSPEvent kspEvent = !customAttributes.Any() ? WrappedEvent.KspEventFromBaseEvent(originalEvent) : (KSPEvent)customAttributes[0]; // Look for the custom attribute skip_delay bool ignoreDelay = customAttributes.Any(a => ((KSPEvent)a).category.Contains("skip_delay")); // create the new BaseEvent BaseEvent hookedEvent = EventWrapper.CreateWrapper(originalEvent, passthrough, ignoreDelay, kspEvent); // get the original event index in the event list BaseEventList eventList = originalEvent.listParent; int listIndex = eventList.IndexOf(originalEvent); // remove the original event in the event list and add our hooked event eventList.RemoveAt(listIndex); eventList.Add(hookedEvent); // get the baseEvent field from UIPartActionEventItem (note: this is uiPartActionEventItem.Evt, but we can't set its value...) FieldInfo baseEventField = typeof(UIPartActionEventItem).GetFields(BindingFlags.Instance | BindingFlags.NonPublic) .First(fi => fi.FieldType == typeof(BaseEvent)); // replace the button baseEvent value with our hooked event baseEventField.SetValue(uiPartActionEventItem, hookedEvent); } }
void EngagePumpPair() { if (isEVASide) { if (awaitingPump.isEVASide) { Debug.LogError("[EVARefueling] Both pumps marked for engaging are EVA-Side. Normally this error message should NEVER arise as engaging is only called for EVA+nonEVA pump pairs"); } else { EVARefuelingPump tmp = awaitingPump; awaitingPump = this; tmp.EngagePumpPair(); // Actual engaging is to be done by non-EVA-Side pump } } else { awaitingPump.connectedPump = this; awaitingPump.connected = true; connectedPump = awaitingPump; connected = true; awaitingPump = null; foreach (string resourceName in resourcePumpingRatesDict.Keys) { if (part.Resources.Contains(resourceName) && connectedPump.part.Resources.Contains(resourceName)) { KSPEvent attributeHolder = new KSPEvent(); #region Setting Attribs attributeHolder.guiActive = true; attributeHolder.guiName = $"Pump {part.Resources[resourceName].info.displayName} here"; attributeHolder.groupName = "EVARefuelingPump"; attributeHolder.groupDisplayName = "EVA Refueling"; attributeHolder.guiActiveUnfocused = true; attributeHolder.requireFullControl = false; attributeHolder.guiActiveUncommand = true; #endregion Events.Add(new BaseEvent(Events, $"InPump_{resourceName}", () => { activeResourcePumpingRatedDict[resourceName] = resourcePumpingRatesDict[resourceName]; Events[$"InPump_{resourceName}"].guiActive = false; Events[$"InPump_{resourceName}"].guiActiveUnfocused = false; Events[$"StopPump_{resourceName}"].guiActive = true; Events[$"StopPump_{resourceName}"].guiActiveUnfocused = true; connectedPump.Events[$"InPump_{resourceName}"].guiActive = true; connectedPump.Events[$"InPump_{resourceName}"].guiActiveUnfocused = true; connectedPump.Events[$"StopPump_{resourceName}"].guiActive = true; connectedPump.Events[$"StopPump_{resourceName}"].guiActiveUnfocused = true; }, attributeHolder)); attributeHolder = new KSPEvent(); #region Setting Attribs attributeHolder.guiActive = true; attributeHolder.guiName = $"Pump {part.Resources[resourceName].info.displayName} here"; attributeHolder.groupName = "EVARefuelingPump"; attributeHolder.groupDisplayName = "EVA Refueling"; attributeHolder.guiActiveUnfocused = true; attributeHolder.requireFullControl = false; attributeHolder.guiActiveUncommand = true; #endregion connectedPump.Events.Add(new BaseEvent(connectedPump.Events, $"InPump_{resourceName}", () => { activeResourcePumpingRatedDict[resourceName] = -resourcePumpingRatesDict[resourceName]; Events[$"InPump_{resourceName}"].guiActive = true; Events[$"InPump_{resourceName}"].guiActiveUnfocused = true; Events[$"StopPump_{resourceName}"].guiActive = true; Events[$"StopPump_{resourceName}"].guiActiveUnfocused = true; connectedPump.Events[$"InPump_{resourceName}"].guiActive = false; connectedPump.Events[$"InPump_{resourceName}"].guiActiveUnfocused = false; connectedPump.Events[$"StopPump_{resourceName}"].guiActive = true; connectedPump.Events[$"StopPump_{resourceName}"].guiActiveUnfocused = true; }, attributeHolder)); attributeHolder = new KSPEvent(); #region Setting Attribs attributeHolder.guiActive = false; attributeHolder.guiName = $"Stop Pumping {part.Resources[resourceName].info.displayName}"; attributeHolder.groupName = "EVARefuelingPump"; attributeHolder.groupDisplayName = "EVA Refueling"; attributeHolder.guiActiveUnfocused = false; attributeHolder.requireFullControl = false; attributeHolder.guiActiveUncommand = false; #endregion Events.Add(new BaseEvent(Events, $"StopPump_{resourceName}", () => { activeResourcePumpingRatedDict[resourceName] = 0; Events[$"InPump_{resourceName}"].guiActive = true; Events[$"InPump_{resourceName}"].guiActiveUnfocused = true; Events[$"StopPump_{resourceName}"].guiActive = false; Events[$"StopPump_{resourceName}"].guiActiveUnfocused = false; connectedPump.Events[$"InPump_{resourceName}"].guiActive = true; connectedPump.Events[$"InPump_{resourceName}"].guiActiveUnfocused = true; connectedPump.Events[$"StopPump_{resourceName}"].guiActive = false; connectedPump.Events[$"StopPump_{resourceName}"].guiActiveUnfocused = false; }, attributeHolder)); attributeHolder = new KSPEvent(); #region Setting Attribs attributeHolder.guiActive = false; attributeHolder.guiName = $"Stop Pumping {part.Resources[resourceName].info.displayName}"; attributeHolder.groupName = "EVARefuelingPump"; attributeHolder.groupDisplayName = "EVA Refueling"; attributeHolder.guiActiveUnfocused = false; attributeHolder.requireFullControl = false; attributeHolder.guiActiveUncommand = false; #endregion connectedPump.Events.Add(new BaseEvent(connectedPump.Events, $"StopPump_{resourceName}", () => { activeResourcePumpingRatedDict[resourceName] = 0; Events[$"InPump_{resourceName}"].guiActive = true; Events[$"InPump_{resourceName}"].guiActiveUnfocused = true; Events[$"StopPump_{resourceName}"].guiActive = false; Events[$"StopPump_{resourceName}"].guiActiveUnfocused = false; connectedPump.Events[$"InPump_{resourceName}"].guiActive = true; connectedPump.Events[$"InPump_{resourceName}"].guiActiveUnfocused = true; connectedPump.Events[$"StopPump_{resourceName}"].guiActive = false; connectedPump.Events[$"StopPump_{resourceName}"].guiActiveUnfocused = false; }, attributeHolder)); } } } }
/// <summary> /// Given a BaseEvent, obtain a KSPEvent. /// Note : This is used in UIPartActionMenuPatcher.Wrap in case there no KSPEvent in the custom attributes of the BaseEventDelegate from the button event. /// </summary> /// <param name="baseEvent">BaseEvent from which to obtain a KSPEvent.</param> /// <returns>KSPEvent instance from the BaseEvent parameter.</returns> public static KSPEvent KspEventFromBaseEvent(BaseEvent baseEvent) { var kspEvent = new KSPEvent { active = baseEvent.active, guiActive = baseEvent.guiActive, requireFullControl = baseEvent.requireFullControl, guiActiveEditor = baseEvent.guiActiveEditor, guiActiveUncommand = baseEvent.guiActiveUncommand, guiIcon = baseEvent.guiIcon, guiName = baseEvent.guiName, category = baseEvent.category, advancedTweakable = baseEvent.advancedTweakable, guiActiveUnfocused = baseEvent.guiActiveUnfocused, unfocusedRange = baseEvent.unfocusedRange, externalToEVAOnly = baseEvent.externalToEVAOnly, isPersistent = baseEvent.isPersistent }; return kspEvent; }
public void UpdateUsedBy() { //print ("*RK* Updating UsedBy"); usedBy.Clear(); // Get part list List <Part> parts; if (HighLogic.LoadedSceneIsEditor && EditorLogic.fetch.ship != null) { parts = EditorLogic.fetch.ship.parts; } else if (HighLogic.LoadedSceneIsFlight && vessel != null) { parts = vessel.parts; } else { parts = new List <Part>(); } FuelInfo f; string title; PartModule m; for (int i = 0; i < parts.Count; ++i) { title = parts[i].partInfo.title; for (int j = 0; j < parts[i].Modules.Count; ++j) { m = parts[i].Modules[j]; if (m is ModuleEngines) { f = new FuelInfo((m as ModuleEngines).propellants, this, title); if (f.ratioFactor > 0d) { UpdateFuelInfo(f, title); } } else if (m is ModuleRCS) { f = new FuelInfo((m as ModuleRCS).propellants, this, title); if (f.ratioFactor > 0d) { UpdateFuelInfo(f, title); } } } } // Need to update the tweakable menu too if (HighLogic.LoadedSceneIsEditor) { Events.RemoveAll(button => button.name.StartsWith("MFT")); bool activeEditor = (AvailableVolume >= 0.001); int idx = 0; foreach (FuelInfo info in usedBy.Values) { KSPEvent kspEvent = new KSPEvent { name = "MFT" + idx++, guiActive = false, guiActiveEditor = activeEditor, guiName = info.Label }; FuelInfo info1 = info; BaseEvent button = new BaseEvent(Events, kspEvent.name, () => ConfigureFor(info1), kspEvent) { guiActiveEditor = activeEditor }; Events.Add(button); } //MarkWindowDirty (); } }
public static BaseEvent CreateWrapper(BaseEvent original, Action <BaseEvent, bool> passthrough, bool ignoreDelay, KSPEvent kspEvent) { // Create a new configuration node and fill this node with the original base event with the values ConfigNode cn = new ConfigNode(); original.OnSave(cn); // create the wrapper (used solely for its Invoke() method) // this class keeps the: // * pass through event (leading to the ModuleSPU.InvokeEvent() method) // * the original event (button click event) // * the ignore delay boolean value (true if the event ignore delay, false otherwise) EventWrapper wrapper = new EventWrapper(original, passthrough, ignoreDelay); // Create a new event, its main features are: // 1. It retains its original base event invokable method: invokable directly through its InvokeOriginalEvent() method [useful for other mods, e.g. kOS] // 2. Its new invoke() method which is in this wrapper class and decorated with and new KSPEvent category, namely "skip_control" (meaning we have already seen this event). BaseEvent newEvent = new WrappedEvent(original, original.listParent, original.name, wrapper.Invoke, kspEvent); // load the original base event values into the new base event newEvent.OnLoad(cn); return(newEvent); }
public static BaseEvent CreateWrapper(BaseEvent original, Action<BaseEvent, bool> passthrough, bool ignoreDelay, KSPEvent kspEvent) { // Create a new configuration node and fill this node with the original base event with the values ConfigNode cn = new ConfigNode(); original.OnSave(cn); // create the wrapper (used solely for its Invoke() method) // this class keeps the: // * pass through event (leading to the ModuleSPU.InvokeEvent() method) // * the original event (button click event) // * the ignore delay boolean value (true if the event ignore delay, false otherwise) EventWrapper wrapper = new EventWrapper(original, passthrough, ignoreDelay); // Create a new event, its main features are: // 1. It retains its original base event invokable method: invokable directly through its InvokeOriginalEvent() method [useful for other mods, e.g. kOS] // 2. Its new invoke() method which is in this wrapper class and decorated with and new KSPEvent category, namely "skip_control" (meaning we have already seen this event). BaseEvent newEvent = new WrappedEvent(original, original.listParent, original.name, wrapper.Invoke, kspEvent); // load the original base event values into the new base event newEvent.OnLoad(cn); return newEvent; }