// Transforms body references in the savegames void TransformBodyReferencesOnSave(GameEvents.FromToAction <ProtoVessel, ConfigNode> data) { // Save the reference to the real body if (data.to == null) { return; } ConfigNode orbit = data.to.GetNode("ORBIT"); CelestialBody body = PSystemManager.Instance.localBodies.FirstOrDefault(b => b.flightGlobalsIndex == data.from.orbitSnapShot.ReferenceBodyIndex); if (body == null) { return; } orbit.AddValue("IDENT", body.Get <String>("identifier")); }
private void OnCrewBoardVessel(GameEvents.FromToAction <Part, Part> data) { try { Part evaKerbal = data.from; Part boardedPart = data.to; double kerbalSnacks = consumer.GetSnackResource(evaKerbal, SnacksProperties.SnacksPerMeal); boardedPart.RequestResource(SnacksProperties.SnackResourceID, -kerbalSnacks, ResourceFlowMode.ALL_VESSEL); SnackSnapshot.Instance().RebuildSnapshot(); SnacksScenario.Instance.RegisterCrew(boardedPart.vessel); } catch (Exception ex) { Debug.Log("Snacks - OnCrewBoardVessel: " + ex.Message + ex.StackTrace); } }
private void onEVA(GameEvents.FromToAction <Part, Part> data) { if (!FlightGlobals.ActiveVessel.packed && !FlightGlobals.ActiveVessel.HoldPhysics) { if (FlightGlobals.ActiveVessel.isEVA) { //AddToVesselList(FlightGlobals.ActiveVessel); } else { } } else { } }
/// <summary>GameEvents callback.</summary> /// <remarks> /// Detects vessel docking events. /// <para> /// Parts coupling is not a strightforward event. Depending on what has docked to what there may /// or may not be a vessel switch event sent. To be on a safe side just disable switch event /// handling in such case and fix camera in <c>LastUpdate</c>. /// </para> /// </remarks> void OnPartCouple(GameEvents.FromToAction <Part, Part> action) { // Only do camera fix if either the source or the destination is an active vessel. if (action.from.vessel.isActiveVessel) { state = SwitchEvent.VesselDocked; Debug.Log("Active vessel docked to a station. Waiting for LateUpdate..."); oldInfo = new VesselInfo(action.from.vessel, FlightCamera.fetch); } else if (action.to.vessel.isActiveVessel) { state = SwitchEvent.VesselDocked; Debug.Log("Something has docked to the active vessel. Waiting for LateUpdate..."); oldInfo = new VesselInfo(action.to.vessel, FlightCamera.fetch); } }
private void OnGameSceneSwitch(GameEvents.FromToAction <GameScenes, GameScenes> Data) { if (GameHelper.AllowWindow(Data.from)) { WindowSettings W = _window.BuildSettings( ); Config.SetWindowConfig(W, Data.from); } if (GameHelper.AllowWindow(Data.to)) { WindowSettings W = Config.GetWindowConfig("ScienceCheckList", Data.to); _window.ApplySettings(W); } _vExperimentsRefreshPending = true; }
// Called when a docking/coupling action is about to happen. Gives access to old and new vessel // Remove PAW buttons from the command parts and disable ourselves when the vessel // is about to be removed following a docking / coupling operation. private void OnPartCouple(GameEvents.FromToAction <Part, Part> data) { Lib.LogDebug($"OnPartCouple on {vessel.vesselName}, docked vessel : {data.from.vessel.vesselName}, dominant vessel : {data.to.vessel.vesselName}"); // in the case of KIS-adding parts, from / to vessel are the same : // we ignore the event and just pack the part. if (data.from.vessel == data.to.vessel && data.from.vessel == vessel && physicsHold) { OnPackPartTweaks(data.from, true, false, true); return; } // "from" is the part on the vessel that will be removed following coupling/docking // when docking to a packed vessel, depending on the stock choice for which one is the dominant vessel, we have two cases : // A. the dominant vessel is the on-hold vessel // - non-packed parts will be transferred to the resulting (already packed) vessel, we have to pack them // B. the dominant vessel is the not-on-hold vessel : // - the resulting vessel isn't packed, and physicsHold is false // - transferred parts will be packed, the others won't // from : docking vessel that will be removed if (data.from.vessel == vessel) { PhysicsHoldManager.RemoveInstance(this); // case B handling if (physicsHold) { DisablePhysicsHold(true); VesselPhysicsHold fromInstance = data.to.vessel.GetComponent <VesselPhysicsHold>(); fromInstance.delayedPhysicsHoldEnableRequest = true; } physicsHold = false; ClearEvents(); isEnabled = false; } // case A handling if (data.to.vessel == vessel && physicsHold) { foreach (Part part in data.from.vessel.Parts) { OnPackPartTweaks(part, true, false, true); } } }
/// <summary> /// Event triggered when a kerbal boards a vessel /// </summary> public void OnCrewBoard(GameEvents.FromToAction <Part, Part> partAction) { LunaLog.Log("Crew boarding detected!"); if (!VesselCommon.IsSpectating) { var kerbalVessel = partAction.from.vessel; var vessel = partAction.to.vessel; LunaLog.Log($"EVA Boarding. Kerbal: {kerbalVessel.id} ({kerbalVessel.vesselName}) boarding: {vessel.id} ({vessel.vesselName})"); VesselRemoveSystem.Singleton.MessageSender.SendVesselRemove(kerbalVessel.id); VesselRemoveSystem.Singleton.AddToKillList(kerbalVessel.id, "Killing kerbal as it boarded a vessel"); LockSystem.Singleton.ReleaseAllVesselLocks(new[] { kerbalVessel.vesselName }, kerbalVessel.id); VesselProtoSystem.Singleton.MessageSender.SendVesselMessage(vessel, true, false); } }
private void OnCrewBoardVessel(GameEvents.FromToAction <Part, Part> data) { try { //Debug.Log("EVA End"); double got = consumer.GetSnackResource(data.from, 1.0); //Debug.Log("EVA Got:" + got); List <PartResource> resources = new List <PartResource>(); data.to.GetConnectedResources(snackResourceId, ResourceFlowMode.ALL_VESSEL, resources); resources.First().amount += got; SnackSnapshot.Instance().SetRebuildSnapshot(); } catch (Exception ex) { Debug.Log("Snacks - OnCrewBoardVessel: " + ex.Message + ex.StackTrace); } }
/* This gets called when a crew going on EVA is detected. * No need to hook this in if the vessel is loaded or off rails since * save/load and time warp are not permitted when a kerbal is on a ladder. */ public void EjectionFixHook(GameEvents.FromToAction <Part, Part> EVAParts) { if (null == EVAParts.to) { return; } // tipping the kerbal back prevents collision induced ejection EVAParts.to.vessel.transform.Rotate(-30f, 0f, 0f); // nullify the ladder slide upon initially going EVA EVAParts.to.vessel.rigidbody.velocity = EVAParts.from.rigidbody.velocity; EVAParts.to.rigidbody.velocity = EVAParts.from.rigidbody.velocity; // hook in the module that reacquires the ladder EVAParts.to.AddModule("ModuleEVAEjectionFix"); }
void OnPartCoupleEvent(GameEvents.FromToAction <Part, Part> action) { AttachNode node = null; if (action.from == part) { node = action.from.FindPartThroughNodes(action.to); } else if (action.to == part) { node = action.to.FindPartThroughNodes(action.from); } if (node != null && node.id == attachNodeName) { AsyncCall.CallOnEndOfFrame(this, CheckCoupleNode); } }
void vesselDock(GameEvents.FromToAction <Part, Part> e) { // this need to happen when db is in a valid state if (DB.Ready()) { // merge computer data from vessel A to vessel B on docking Computer a = DB.VesselData(e.from.vessel.id).computer; Computer b = DB.VesselData(e.to.vessel.id).computer; b.merge(a); // forget vessel being docked DB.ForgetVessel(e.from.vessel.id); } // purge vessel from resource cache ResourceCache.Purge(e.from.vessel.id); }
// Transforms body references in the save games private static void TransformBodyReferencesOnLoad(GameEvents.FromToAction <ProtoVessel, ConfigNode> data) { // Check if the config node is null if (data.to == null) { return; } ConfigNode orbit = data.to.GetNode("ORBIT"); String bodyIdent = orbit.GetValue("IDENT"); CelestialBody body = UBI.GetBody(bodyIdent); if (body == null) { return; } orbit.SetValue("REF", body.flightGlobalsIndex); }
/// <summary> /// Change UI state to hidden to prevent app button weirdness (PopupDialog is automatically hidden on scene change) /// </summary> /// <param name="ev"></param> public void OnGameSceneSwitchRequested(GameEvents.FromToAction <GameScenes, GameScenes> ev) { if (appLauncherButton != null) { appLauncherButton.SetFalse(true); } else { mainViewVisible = false; } if (controlViewVisible) { ToggleControlWindow(); } InputLockManager.RemoveControlLock("BonVoyageInputLock"); }
private void OnInputLocksModified(GameEvents.FromToAction <ControlTypes, ControlTypes> data) { // Detect if a control lock is active bool controlIsLocked = InputLockManager.GetControlLock("RP0ControlLocker") != 0; // Keeps track if we've ever lost control controlHasLapsed |= controlIsLocked; // Differing logic depending on parameter properties parameterIsSatisified = continuousControlRequired ? !controlHasLapsed && !controlIsLocked : !controlIsLocked; // Refresh title in contracts screen in case we've had a lapse of control with continousControlRequired true GetTitle(); // Have CC re-evaluate the parameter state (will call VesselMeetsCondition() internally) CheckVessel(FlightGlobals.ActiveVessel); }
// Transforms body references in the savegames void TransformBodyReferencesOnLoad(GameEvents.FromToAction <ProtoVessel, ConfigNode> data) { // Check if the config node is null if (data.to == null) { return; } ConfigNode orbit = data.to.GetNode("ORBIT"); String bodyIdent = orbit.GetValue("IDENT"); CelestialBody body = PSystemManager.Instance.localBodies.FirstOrDefault(b => b.Get <String>("identifier") == bodyIdent); if (body == null) { return; } orbit.SetValue("REF", body.flightGlobalsIndex); }
private void OnEvaStart(GameEvents.FromToAction <Part, Part> evaData) { printDebug("entered; Parts: " + evaData.from + "; " + evaData.to); printDebug("active vessel: " + FlightGlobals.ActiveVessel); Vessel v = evaData.to.vessel; if (!v || !v.evaController) { return; } printDebug("vessel: " + v + "; evaCtl: " + v.evaController); ProtoCrewMember crew = v.GetVesselCrew() [0]; printDebug("crew: " + crew); if (this.tourists == null) { // Why we get here twice with the same data? printDebug("for some reasons tourists is null"); return; } foreach (KeyValuePair <String, Tourist> pair in this.tourists) { printDebug(pair.Key + "=" + pair.Value); } printDebug("roster: " + this.tourists); Tourist t; if (!tourists.TryGetValue(crew.name, out t)) { return; } printDebug("tourist: " + t); if (!Tourist.isTourist(crew) || t.hasAbility("Jetpack")) { return; } evaData.to.RequestResource(v.evaController.propellantResourceName, v.evaController.propellantResourceDefaultAmount); // Set propellantResourceDefaultAmount to 0 for EVAFuel to recognize it. v.evaController.propellantResourceDefaultAmount = 0.0; ScreenMessages.PostScreenMessage(String.Format( "<color=orange>Jetpack propellant drained as tourists of level {0} are not allowed to use it</color>", t.level)); }
private void HandleEvaEnd(GameEvents.FromToAction <Part, Part> data) { var module = (new[] { data.from, data.to }) .Where(p => p.Modules.Contains(Config.Instance.ModuleKerbalHook)) .Select(p => p.Modules[Config.Instance.ModuleKerbalHook] as ModuleKerbalHook) .FirstOrDefault(); //Debug.Log("[IRAS] on eva end module has been found!"); if (module != null) { var modulePart = module.part; module.Die(); if (modulePart != null) { modulePart.RemoveModule(module); } } }
public void onEvaEnd(GameEvents.FromToAction <Part, Part> data) { Log.Info("onEvaEnd"); if (ModEnabled) { double fuelLeft = data.from.RequestResource(resourceName, HighLogic.CurrentGame.Parameters.CustomParams <EVAFuelSettings>().EvaTankFuelMax); double fuelStored = data.to.RequestResource(HighLogic.CurrentGame.Parameters.CustomParams <EVAFuelSettings>().ShipPropellantName, -fuelLeft / HighLogic.CurrentGame.Parameters.CustomParams <EVAFuelSettings>().FuelConversionFactor); if (ShowInfoMessage) { ScreenMessages.PostScreenMessage("Returned " + Math.Round(fuelLeft / HighLogic.CurrentGame.Parameters.CustomParams <EVAFuelSettings>().FuelConversionFactor, 2).ToString() + " units of " + HighLogic.CurrentGame.Parameters.CustomParams <EVAFuelSettings>().ShipPropellantName + " to ship.", HighLogic.CurrentGame.Parameters.CustomParams <EVAFuelSettings>().ScreenMessageLife, ScreenMessageStyle.UPPER_CENTER); } Log.Info("fuelLeft: " + fuelLeft.ToString() + " fuelStored: " + fuelStored.ToString()); data.from.RequestResource(resourceName, fuelStored + fuelLeft); onBoardHandler(data, fuelLeft + fuelStored); } }
/* public void OnDestroy() * { * GameEvents.onCrewOnEva.Remove(this.OnEvaStart); * GameEvents.onCrewBoardVessel.Remove(this.OnEvaEnd); * } */ public void OnEvaStart(GameEvents.FromToAction <Part, Part> vessel) { KerbalEVA eva = null; vessel.to.GetComponentCached <KerbalEVA>(ref eva); var crew = eva.vessel.GetVesselCrew().FirstOrDefault(); // check for trait here if (crew.trait != "Robot") { Debug.LogWarning("KerbalBot: Kerbal is no Robot but: " + crew.trait); // return; } // EC removed from origin vessel and added to new kerbaleva }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Executes the game scene switch requested action to make sure that the Mod's button /// does not appear in scenes it should not appear in, such as the Main Menu.</summary> /// /// <param name="data"> Specification of the scene being switch from and to.</param> private void OnGameSceneSwitchRequested(GameEvents.FromToAction <GameScenes, GameScenes> data) { if (_toolbarButton == null) { return; } KRnDUI.showGui = false; KRnDUI.selectedPart = null; // If going to the main menu, then make sure the button has been removed. if (data.to == GameScenes.MAINMENU) { ApplicationLauncher.Instance.RemoveModApplication(_toolbarButton); _toolbarButton = null; } }
public void OnVesselDock(GameEvents.FromToAction <Part, Part> partAction) { Debug.Log("[LMP]: Vessel docking detected!"); if (!VesselCommon.IsSpectating) { if ((partAction.from.vessel != null) && (partAction.to.vessel != null)) { var fromVesselUpdateLockExists = LockSystem.Singleton.LockExists("update-" + partAction.from.vessel.id); var toVesselUpdateLockExists = LockSystem.Singleton.LockExists("update-" + partAction.to.vessel.id); var fromVesselUpdateLockIsOurs = LockSystem.Singleton.LockIsOurs("update-" + partAction.from.vessel.id); var toVesselUpdateLockIsOurs = LockSystem.Singleton.LockIsOurs("update-" + partAction.to.vessel.id); if (fromVesselUpdateLockIsOurs || toVesselUpdateLockIsOurs || !fromVesselUpdateLockExists || !toVesselUpdateLockExists) { if (FlightGlobals.ActiveVessel != null) { Debug.Log($"[LMP]: Vessel docking, our vessel: {VesselCommon.CurrentVesselId}"); } Debug.Log($"[LMP]: Vessel docking, from: {partAction.from.vessel.id}, Name: {partAction.from.vessel.vesselName}"); Debug.Log($"[LMP]: Vessel docking, to: {partAction.to.vessel.id}, Name: {partAction.to.vessel.vesselName}"); System.PrintDockingInProgress(); System.HandleDocking(partAction.from.vessel.id, partAction.to.vessel.id); } else { Debug.Log("[LMP]: Inconsistent docking state detected, killing both vessels if possible."); if (partAction.from.vessel != FlightGlobals.ActiveVessel) { VesselRemoveSystem.Singleton.KillVessel(partAction.from.vessel, true); } if (partAction.to.vessel != FlightGlobals.ActiveVessel) { VesselRemoveSystem.Singleton.KillVessel(partAction.to.vessel, true); } } } } else { Debug.Log("[LMP]: Spectator docking happened. This needs to be fixed later."); } }
private void onCouple(GameEvents.FromToAction <Part, Part> p) { if (p.from == null) { return; } if (p.to == null) { return; } if (p.from != part) { return; } StartCoroutine(waitOnVessel()); }
void VesselDock(GameEvents.FromToAction<Part, Part> e) { // note: // we do not forget vessel data here, it just became inactive // and ready to be implicitly activated again on undocking // we do however tweak the data of the vessel being docked a bit, // to avoid states getting out of sync, leading to unintuitive behaviours VesselData vd = DB.Vessel(e.from.vessel); vd.msg_belt = false; vd.msg_signal = false; vd.storm_age = 0.0; vd.storm_time = 0.0; vd.storm_state = 0; vd.supplies.Clear(); vd.scansat_id.Clear(); // merge drives data Drive.Transfer(e.from.vessel, e.to.vessel); }
public void onEvaStart(GameEvents.FromToAction <Part, Part> data) { string shipProp = this.settings.ShipPropellantName; string shipElec = this.settings.ShipElectricityName; string evaProp = this.settings.EvaPropellantName; double evaFuelMax = this.settings.EvaTankFuelMax; int messageLife = this.settings.ScreenMessageLife; int waringLife = this.settings.ScreenMessageWarningLife; double fuelRequest = data.from.RequestResource(shipProp, evaFuelMax); if (fuelRequest == evaFuelMax) { data.to.RequestResource(evaProp, evaFuelMax - fuelRequest); ScreenMessages.PostScreenMessage("Filled EVA tank with " + Math.Round(fuelRequest, 2).ToString() + " units of " + shipProp + ".", messageLife, ScreenMessageStyle.UPPER_CENTER); } if (fuelRequest < evaFuelMax) { if (fuelRequest == 0) //Check if it's likely a rescue contract ship. { double shipElectricity = data.from.RequestResource(shipElec, 1); if (shipElectricity == 0) { if (data.from.vessel.Parts.Count == 1) //only one part on ship { data.to.RequestResource(evaProp, evaFuelMax - 1); //give one unit of eva propellant ScreenMessages.PostScreenMessage("The Kerbal manages to scrounge together 1 unit of " + evaProp + ".", waringLife, ScreenMessageStyle.UPPER_CENTER); } } else //This has electricity, and thus isn't a rescue contract ship. { data.from.RequestResource(shipElec, -1); data.to.RequestResource(evaProp, evaFuelMax - fuelRequest); ScreenMessages.PostScreenMessage("Warning! No " + shipProp + " available for EVA!", waringLife, ScreenMessageStyle.UPPER_CENTER); } } else { data.to.RequestResource(evaProp, evaFuelMax - fuelRequest); ScreenMessages.PostScreenMessage("Warning! Only " + Math.Round(fuelRequest, 2).ToString() + " units of " + shipProp + " available for EVA!", waringLife, ScreenMessageStyle.UPPER_CENTER); } } }
private void onGameScenceSwitch(GameEvents.FromToAction <GameScenes, GameScenes> data) { Debug.Log($"[{DISPLAYNAME}] Destroy()"); parallelNegative.onClick.RemoveAllListeners(); parallelPlus.onClick.RemoveAllListeners(); foreach (UIStateToggleButton button in modebuttons) { button.onClick.RemoveListener(delegate { onSASbuttonPressed(button); }); } Destroy(parallelNegative.gameObject); Destroy(parallelPlus.gameObject); buttonInit = false; vesselDockingAid = null; autopilotState = false; }
/// <summary>Triggers coupled node check.</summary> void OnPartCoupleEvent(GameEvents.FromToAction <Part, Part> action) { AttachNode node = null; if (action.from == part) { node = action.from.FindPartThroughNodes(action.to); } else if (action.to == part) { node = action.to.FindPartThroughNodes(action.from); } if (node != null && node.id == attachNodeName) { HostedDebugLog.Fine(this, "Schedule coupling check on coupling event: from={0}, to={1}", action.from, action.to); AsyncCall.CallOnEndOfFrame(this, CheckCoupleNode); } }
void ToEVA(GameEvents.FromToAction <Part, Part> data) { // get total crew in the origin vessel double tot_crew = (double)Lib.CrewCount(data.from.vessel) + 1.0; // get vessel resources handler Vessel_resources resources = ResourceCache.Get(data.from.vessel); // setup supply resources capacity in the eva kerbal Profile.SetupEva(data.to); // for each resource in the kerbal for (int i = 0; i < data.to.Resources.Count; ++i) { // get the resource PartResource res = data.to.Resources[i]; // determine quantity to take double quantity = Math.Min(resources.Info(data.from.vessel, res.resourceName).amount / tot_crew, res.maxAmount); // remove resource from vessel quantity = data.from.RequestResource(res.resourceName, quantity); // add resource to eva kerbal data.to.RequestResource(res.resourceName, -quantity); } // show warning if there isn't monoprop in the eva suit string prop_name = Lib.EvaPropellantName(); if (Lib.Amount(data.to, prop_name) <= double.Epsilon && !Lib.Landed(data.from.vessel)) { Message.Post(Severity.danger, Lib.BuildString("There isn't any <b>", prop_name, "</b> in the EVA suit"), "Don't let the ladder go!"); } // turn off headlamp light, to avoid stock bug that show them for a split second when going on eva KerbalEVA kerbal = data.to.FindModuleImplementing <KerbalEVA>(); EVA.HeadLamps(kerbal, false); // execute script DB.Vessel(data.from.vessel).computer.Execute(data.from.vessel, ScriptType.eva_out); }
public void OnVesselDock(GameEvents.FromToAction <Part, Part> partAction) { LunaLog.Log("[LMP]: Vessel docking detected!"); if (!VesselCommon.IsSpectating) { if (partAction.from.vessel != null && partAction.to.vessel != null) { var fromVesselUpdateLockExists = SystemsContainer.Get <LockSystem>().LockExists($"update-{partAction.from.vessel.id}"); var toVesselUpdateLockExists = SystemsContainer.Get <LockSystem>().LockExists($"update-{partAction.to.vessel.id}"); var fromVesselUpdateLockIsOurs = SystemsContainer.Get <LockSystem>().LockIsOurs($"update-{partAction.from.vessel.id}"); var toVesselUpdateLockIsOurs = SystemsContainer.Get <LockSystem>().LockIsOurs($"update-{partAction.to.vessel.id}"); if (fromVesselUpdateLockIsOurs || toVesselUpdateLockIsOurs || !fromVesselUpdateLockExists || !toVesselUpdateLockExists) { if (FlightGlobals.ActiveVessel != null) { LunaLog.Log($"[LMP]: Vessel docking, our vessel: {VesselCommon.CurrentVesselId}"); } LunaLog.Log($"[LMP]: Vessel docking, from: {partAction.from.vessel.id}, Name: {partAction.from.vessel.vesselName}"); LunaLog.Log($"[LMP]: Vessel docking, to: {partAction.to.vessel.id}, Name: {partAction.to.vessel.vesselName}"); System.HandleDocking(partAction.from.vessel.id, partAction.to.vessel.id); } else { LunaLog.Log("[LMP]: Inconsistent docking state detected, killing both vessels if possible."); if (partAction.from.vessel != FlightGlobals.ActiveVessel) { SystemsContainer.Get <VesselRemoveSystem>().KillVessel(partAction.from.vessel, true); } if (partAction.to.vessel != FlightGlobals.ActiveVessel) { SystemsContainer.Get <VesselRemoveSystem>().KillVessel(partAction.to.vessel, true); } } } } else { LunaLog.Log("[LMP]: Spectator docking happened. This needs to be fixed later."); } }
internal void OnCrewOnEva(GameEvents.FromToAction <Part, Part> data) { if (VesselType.EVA != data.to.vessel.vesselType) { return; } LaunchCrewEvent crewLaunch = GetKerbalLaunch(data.to.vessel.vesselName); EvaCrewEvent evaCrewEvent = new EvaCrewEvent(); crewLaunch.AddEvent(evaCrewEvent); LaunchEvent launch = GetLaunch(data.from.vessel); if (launch != null) { EvaEvent evaEvent = new EvaEvent(); launch.AddEvent(evaEvent); } }
/// <summary> /// Called when 2 parts couple /// </summary> /// <param name="partAction"></param> public void OnPartCouple(GameEvents.FromToAction <Part, Part> partAction) { if (!VesselCommon.IsSpectating) { if (partAction.from.vessel != null && partAction.to.vessel != null) { var dock = new VesselDockStructure(partAction.from.vessel.id, partAction.to.vessel.id); if (dock.StructureIsOk()) { //We add it to the event so the event is handled AFTER all the docking event in ksp is over and we can //safely remove the weak vessel from the game and save the updated dominant vessel. VesselDockings.Add(dock.DominantVesselId, dock); } } } else { LunaLog.Log("[LMP]: Spectator docking happened. This needs to be fixed later."); } }
private void TransferCrewMember(ProtoCrewMember sourceMember, Part sourcePart, Part targetPart) { try { if (sourcePart.internalModel != null && targetPart.internalModel != null) { // Build source and target seat indexes. int curIdx = sourceMember.seatIdx; int newIdx = curIdx; InternalSeat sourceSeat = sourceMember.seat; InternalSeat targetSeat = null; if (sourcePart == targetPart) { // Must be a move... if (newIdx + 1 >= sourcePart.CrewCapacity) newIdx = 0; else newIdx += 1; // get target seat from part's inernal model targetSeat = sourcePart.internalModel.seats[newIdx]; } else { // Xfer to another part // get target seat from part's inernal model for (int x = 0; x < targetPart.internalModel.seats.Count; x += 1) { InternalSeat seat = targetPart.internalModel.seats[x]; if (!seat.taken) { targetSeat = seat; newIdx = x; break; } } // All seats full? if (targetSeat == null) { // try to match seat if possible (swap with counterpart) if (newIdx >= targetPart.internalModel.seats.Count) newIdx = 0; targetSeat = targetPart.internalModel.seats[newIdx]; } } // seats have been chosen. // Do we need to swap places with another Kerbal? if (targetSeat.taken) { // Swap places. // get Kerbal to swap with through his seat... ProtoCrewMember targetMember = targetSeat.kerbalRef.protoCrewMember; // Remove the crew members from the part(s)... RemoveCrew(sourceMember, sourcePart); RemoveCrew(targetMember, targetPart); // At this point, the kerbals are in the "ether". // this may be why there is an issue with refreshing the internal view.. // It may allow (or expect) a board call from an (invisible) eva object. // If I can manage to properly trigger that call... then all should properly refresh... // I'll look into that... // Update: Thanks to Extraplanetary LaunchPads for helping me solve this problem! // Send the kerbal(s) eva. This is the eva trigger I was looking for // We will fie the board event when we are ready, in the update code. evaAction = new GameEvents.FromToAction<Part, Part>(sourcePart, targetPart); if (SettingsManager.EnableTextureReplacer) GameEvents.onCrewOnEva.Fire(evaAction); // Add the crew members back into the part(s) at their new seats. sourcePart.AddCrewmemberAt(targetMember, curIdx); targetPart.AddCrewmemberAt(sourceMember, newIdx); } else { // Just move. RemoveCrew(sourceMember, sourcePart); evaAction = new GameEvents.FromToAction<Part, Part>(sourcePart, targetPart); if (SettingsManager.EnableTextureReplacer) GameEvents.onCrewOnEva.Fire(evaAction); targetPart.AddCrewmemberAt(sourceMember, newIdx); } // if moving within a part, set the seat2seat flag if (sourcePart == targetPart) ShipManifestBehaviour.isSeat2Seat = true; else ShipManifestBehaviour.isSeat2Seat = false; // set the crew transfer flag and wait forthe timeout before firing the board event. ShipManifestBehaviour.crewXfer = true; } else { // no portraits, so let's just move kerbals... RemoveCrew(sourceMember, sourcePart); AddCrew(sourceMember, targetPart); ShipManifestBehaviour.crewXfer = true; } } catch (Exception ex) { ManifestUtilities.LogMessage(string.Format("Error moving crewmember. Error: {0} \r\n\r\n{1}", ex.Message, ex.StackTrace), "Error", true); } }