示例#1
0
        void CreateStateMachine()
        {
            state_fertile = new KFSMState("Fertile");

            state_pregnant = new KFSMState("Pregnant");

            state_resting = new KFSMState("Resting");

            state_dead = new KFSMState("Dead");

            event_conceive = new KFSMEvent("Conceive");
            event_conceive.GoToStateOnEvent = state_pregnant;
            event_conceive.OnCheckCondition = check_conceive;
            event_birthe = new KFSMEvent("Birthe");
            event_birthe.GoToStateOnEvent = state_resting;
            event_birthe.OnCheckCondition = check_birthe;
            event_rested = new KFSMEvent("Conceive");
            event_rested.GoToStateOnEvent = state_fertile;
            event_rested.OnCheckCondition = check_rested;

            AddState(state_fertile);
            AddState(state_pregnant);
            AddState(state_resting);
            AddState(state_dead);

            AddEvent(event_conceive, new KFSMState [] { state_fertile, });
            AddEvent(event_birthe, new KFSMState [] { state_pregnant, });
            AddEvent(event_rested, new KFSMState [] { state_resting, });
        }
示例#2
0
		public static void Freeze(KerbalEVA kerbal)
		{
			// set kerbal to the 'freezed' unescapable state
			// how it works:
			// - kerbal animations and ragdoll state are driven by a finite-state-machine (FSM)
			// - this function is called every frame for all active eva kerbals flagged as dead
			// - if the FSM current state is already 'freezed', we do nothing and this function is a no-op
			// - we create an 'inescapable' state called 'freezed'
			// - we switch the FSM to that state using an ad-hoc event from current state
			// - once the 'freezed' state is set, the FSM cannot switch to any other states
			// - the animator of the object is stopped to stop any left-over animations from previous state

			// do nothing if already freezed
			if (!string.IsNullOrEmpty(kerbal.fsm.currentStateName) && kerbal.fsm.currentStateName != "freezed")
			{
				// create freezed state
				KFSMState freezed = new KFSMState("freezed");

				// create freeze event
				KFSMEvent eva_freeze = new KFSMEvent("EVAfreeze")
				{
					GoToStateOnEvent = freezed,
					updateMode = KFSMUpdateMode.MANUAL_TRIGGER
				};
				kerbal.fsm.AddEvent(eva_freeze, kerbal.fsm.CurrentState);

				// trigger freeze event
				kerbal.fsm.RunEvent(eva_freeze);

				// stop animations
				kerbal.GetComponent<Animation>().Stop();
			}
		}
 public void FlightGeometryUpdate()
 {
     if (deployEvent == null)
     {
         Debug.Log("Update fairing event");
         FieldInfo[] fields = fairing.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
         deployEvent          = (KFSMEvent)fields[31].GetValue(fairing);
         deployEvent.OnEvent += delegate { FairingDeployGeometryUpdate(); };
     }
 }
 private void DisableRunStopCondition(KerbalEVA eva)
 {
     if (this.runStopCondition == null)
     {
         //Debug.Log("Disabling RunStop");
         KFSMEvent eRunStop = (KFSMEvent)eventFields[3].GetValue(eva); // End Run
         this.runStopCondition     = eRunStop.OnCheckCondition;
         eRunStop.OnCheckCondition = this.eventConditionDisabled;
     }
 }
 private void DisableLadderStopCondition(KerbalEVA eva)
 {
     if (this.ladderStopCondition == null)
     {
         //Debug.Log("Disabling LadderStop");
         KFSMEvent eLadderStop = (KFSMEvent)eventFields[26].GetValue(eva); // Ladder Stop
         this.ladderStopCondition     = eLadderStop.OnCheckCondition;
         eLadderStop.OnCheckCondition = this.eventConditionDisabled;
     }
 }
 private void DisableSwimStopCondition(KerbalEVA eva)
 {
     if (this.swimStopCondition == null)
     {
         //Debug.Log("Disabling SwimStop");
         KFSMEvent eSwimStop = (KFSMEvent)eventFields[21].GetValue(eva); // Swim Stop
         this.swimStopCondition     = eSwimStop.OnCheckCondition;
         eSwimStop.OnCheckCondition = this.eventConditionDisabled;
     }
 }
        public void ToggleJetpack()
        {
            if (!FlightGlobals.ActiveVessel.isEVA)
            {
                return;
            }

            KerbalEVA eva             = GetKerbalEVA();
            KFSMEvent togglePackEvent = (KFSMEvent)eventFields[17].GetValue(eva);

            togglePackEvent.GoToStateOnEvent = eva.fsm.CurrentState;
            eva.fsm.RunEvent(togglePackEvent);
        }
示例#8
0
        /// <summary>
        /// This is the eva callback that sends the events to the server
        /// </summary>
        public void LmpOnStateChange(KFSMState prevState, KFSMState newState, KFSMEvent eventToRun)
        {
            var module = GetKerbalEvaModule(FlightGlobals.ActiveVessel) as KerbalEVA;

            if (module != null)
            {
                MessageSender.SendEvaData(FlightGlobals.ActiveVessel, newState.name, eventToRun.name, module.lastBoundStep);
                UpdateFsmStateInProtoVessel(FlightGlobals.ActiveVessel.protoVessel, newState.name, module.lastBoundStep);
            }
            else
            {
                MessageSender.SendEvaData(FlightGlobals.ActiveVessel, newState.name, eventToRun.name);
                UpdateFsmStateInProtoVessel(FlightGlobals.ActiveVessel.protoVessel, newState.name);
            }
        }
示例#9
0
        private void SetupFlightEvents()
        {
            if (deployEvent == null)
            {
                Debug.Log("Update fairing event");
                FieldInfo[] fields = fairing.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
                bool        deployBool = false, breakBool = false;

                deployEvent          = (KFSMEvent)fields[32].GetValue(fairing);
                deployEvent.OnEvent += delegate { FairingDeployGeometryUpdate(); };
                deployBool           = true;

                breakEvent          = (KFSMEvent)fields[33].GetValue(fairing);
                breakEvent.OnEvent += delegate { FairingDeployGeometryUpdate(); };
                breakBool           = true;

                /*for (int i = 0; i < fields.Length; ++i)
                 * {
                 *  FieldInfo field = fields[i];
                 *  if (field.Name.ToLowerInvariant() == "on_deploy")
                 *  {
                 *      deployEvent = (KFSMEvent)field.GetValue(fairing);
                 *      deployEvent.OnEvent += delegate { FairingDeployGeometryUpdate(); };
                 *      deployBool = true;
                 *      Debug.Log("Deploy event field index " + i);
                 *  }
                 *  else if (field.Name.ToLowerInvariant() == "on_breakoff")
                 *  {
                 *      breakEvent = (KFSMEvent)field.GetValue(fairing);
                 *      breakEvent.OnEvent += delegate { FairingDeployGeometryUpdate(); };
                 *      breakBool = true;
                 *      Debug.Log("Break event field index " + i);
                 *  }
                 *  if (deployBool && breakBool)
                 *      break;
                 * }*/
                if (!deployBool)
                {
                    Debug.LogError("FAR could not find Stock Procedural Fairing deploy event");
                }
                if (!breakBool)
                {
                    Debug.LogError("FAR could not find Stock Procedural Fairing break event");
                }
            }
        }
示例#10
0
        EVABoundFix(KerbalEVA eva)
        {
            myeva = eva;

            ReflectedMembers.Initialize();

            //*********Increase bound timeout*********
            myeva.On_bound_fall.OnCheckCondition = Replacement_On_bound_fall_OnCheckCondition;

            //*********Fix for "cannot land" on steep surfaces*********
            myeva.On_bound_land.OnCheckCondition = Replacement_On_bound_land_OnCheckCondition;

            //See if we are hooked yet.
            bool found_packtoggle_bound = false;

            for (int i = 0; i < myeva.st_bound_fl.StateEvents.Count; ++i)
            {
                if (myeva.st_bound_fl.StateEvents [i].name == "Pack Toggle (Bound)")
                {
                    found_packtoggle_bound = true;
                    break;
                }
            }

            if (!found_packtoggle_bound)
            {
                //KSPLog.print ("Bound Pack Toggle not found, adding.");

                //*********Bound floating RCS toggle*********
                evt_packtoggle_bound                  = new KFSMEvent("Pack Toggle (Bound)");
                evt_packtoggle_bound.updateMode       = KFSMUpdateMode.UPDATE;
                evt_packtoggle_bound.GoToStateOnEvent = myeva.st_idle_fl;
                evt_packtoggle_bound.OnCheckCondition = Check_Bound_Jetpack;
                evt_packtoggle_bound.OnEvent          = Do_Toggle_Jetpack;
                myeva.fsm.AddEvent(evt_packtoggle_bound, myeva.st_bound_fl);

                //*********Ability to break out of long bound*********
                evt_long_bound_breakout                  = new KFSMEvent("Long Bound Breakout");
                evt_long_bound_breakout.updateMode       = KFSMUpdateMode.UPDATE;
                evt_long_bound_breakout.GoToStateOnEvent = myeva.st_idle_fl;
                evt_long_bound_breakout.OnCheckCondition = Check_Bound_Breakout;
                myeva.fsm.AddEvent(evt_long_bound_breakout, myeva.st_bound_fl);
            }
        }
示例#11
0
 /// <summary>
 /// Forcibly restores the ability to drop parts in the editor
 /// </summary>
 public void RestorePartDropping()
 {
     if (st_place_Backup != null)
     {
         EditorLogic.fetch.GetType().GetField("st_place", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy)?.SetValue(EditorLogic.fetch, st_place_Backup);
         st_place_Backup = null;
         Logging.DebugLog("Restored st_place");
     }
     if (on_partDropped_Backup != null)
     {
         KFSMEvent on_partDropped = EditorLogic.fetch.GetType().GetField("on_partDropped", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy)?.GetValue(EditorLogic.fetch) as KFSMEvent;
         if (on_partDropped != null)
         {
             on_partDropped.OnCheckCondition = on_partDropped_Backup;
             on_partDropped_Backup           = null;
             Logging.DebugLog("Restored on_partDropped");
         }
     }
 }
示例#12
0
        //adds an FSM state to show that we are animating
        private void AddAnimationState()
        {
            if (States.Find(k => k.name == "KAS_Animation") == null)
            {
                KFSMState state = new KFSMState("KAS_Animation");
                state.updateMode = KFSMUpdateMode.MANUAL_TRIGGER;
                FSM.AddState(state);

                KFSMEvent enterEvent = new KFSMEvent("Enter KAS_Animation");
                enterEvent.GoToStateOnEvent = state;
                enterEvent.updateMode       = KFSMUpdateMode.MANUAL_TRIGGER;
                var idleGrounded = States.Find(k => k.name == "Idle (Grounded)");
                FSM.AddEvent(enterEvent, idleGrounded);

                KFSMEvent exitEvent = new KFSMEvent("Exit KAS_Animation");
                exitEvent.GoToStateOnEvent = idleGrounded;
                exitEvent.updateMode       = KFSMUpdateMode.MANUAL_TRIGGER;
                FSM.AddEvent(exitEvent, state);
            }
        }
示例#13
0
  // set kerbal to the 'freezed' unescapable state
  public static void SetFreezed(KerbalEVA kerbal)
  {
    // do nothing if already freezed
    if (kerbal.fsm.currentStateName != "freezed")
    {
      // create freezed state
      KFSMState freezed = new KFSMState("freezed");

      // create freeze event
      KFSMEvent eva_freeze = new KFSMEvent("EVAfreeze");
      eva_freeze.GoToStateOnEvent = freezed;
      eva_freeze.updateMode = KFSMUpdateMode.MANUAL_TRIGGER;
      kerbal.fsm.AddEvent(eva_freeze, kerbal.fsm.CurrentState);

      // trigger eva death event
      kerbal.fsm.RunEvent(eva_freeze);
    }

    // stop animations
    kerbal.GetComponent<Animation>().Stop();
  }
示例#14
0
        private void InjectEvent(KFSMState state, KFSMEvent injectedEvent)
        {
            state.AddEvent(injectedEvent);
            OnCleanup += () => {
//				((List<KFSMEvent>)Refl.GetValue(state, "stateEvents")).Remove(injectedEvent);
//				List<KFSMState> kfsmstatelist = (List<KFSMState>)Refl.GetValue(state, GET_STATEEVENTS);
#if false
                foreach (var kfsmstate in kfsmstatelist)
                {
                    if (kfsmstate == state)
                    {
                        state.
                        kfsmstatelist.Remove(injectedEvent);
                        Log.Info("Removed event " + injectedEvent.name + " from state " + state.name);
                        return;
                    }
                }
#endif
            };
            Log.Info("Injected event " + injectedEvent.name + " into state " + state.name);
        }
        private void SelectRootInjectEvent(KFSMState state, KFSMEvent injectedEvent)
        {
            state.AddEvent(injectedEvent);
            OnCleanup += () => {
//				((List<KFSMEvent>)Refl.GetValue(state, "stateEvents")).Remove(injectedEvent);
//				List<KFSMState> kfsmstatelist = (List<KFSMState>)Refl.GetValue(state, EditorExtensions.c.GET_STATEEVENTS);
                state.StateEvents.Remove(injectedEvent);
                Log.dbg("Removed event {0} from state {1}", injectedEvent.name, state.name);
#if false
                foreach (var kfsmstate in kfsmstatelist)
                {
                    if (kfsmstate == state)
                    {
                        kfsmstatelist.Remove(kfsmstate);
                        Log.Info("Removed event " + injectedEvent.name + " from state " + state.name);
                        return;
                    }
                }
#endif
            };
            Log.dbg("Injected event {0} into state {1}", injectedEvent.name, state.name);
        }
示例#16
0
 /// <summary>
 /// Forcibly disables the ability to drop parts in the editor
 /// </summary>
 public void DisablePartDropping()
 {
     if (on_partDropped_Backup == null)
     {
         KFSMEvent on_partDropped = EditorLogic.fetch.GetType().GetField("on_partDropped", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy)?.GetValue(EditorLogic.fetch) as KFSMEvent;
         if (on_partDropped != null)
         {
             on_partDropped_Backup           = on_partDropped.OnCheckCondition;
             on_partDropped.OnCheckCondition = (s) => false;
             Logging.DebugLog("Disabled on_partDropped");
         }
     }
     if (st_place_Backup == null)
     {
         KFSMState st_place = EditorLogic.fetch.GetType().GetField("st_place", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy)?.GetValue(EditorLogic.fetch) as KFSMState;
         if (st_place != null)
         {
             st_place_Backup = st_place;
             EditorLogic.fetch.GetType().GetField("st_place", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy)?.SetValue(EditorLogic.fetch, null);
             Logging.DebugLog("Disabled st_place");
         }
     }
 }
 private void ReEnableStopConditions(KerbalEVA eva)
 {
     if (this.ladderStopCondition != null)
     {
         //Debug.Log("Re-enable LadderStop");
         KFSMEvent eLadderStop = (KFSMEvent)eventFields[26].GetValue(eva);
         eLadderStop.OnCheckCondition = this.ladderStopCondition;
         this.ladderStopCondition     = null;
     }
     if (this.swimStopCondition != null)
     {
         //Debug.Log("Re-enable SwimStop");
         KFSMEvent eSwimStop = (KFSMEvent)eventFields[21].GetValue(eva);
         eSwimStop.OnCheckCondition = this.swimStopCondition;
         this.swimStopCondition     = null;
     }
     if (this.runStopCondition != null)
     {
         //Debug.Log("Re-enable RunStop");
         KFSMEvent eRunStop = (KFSMEvent)eventFields[3].GetValue(eva);
         eRunStop.OnCheckCondition = this.runStopCondition;
         this.runStopCondition     = null;
     }
 }
 /// <summary>
 /// Cause the machine to execute the transition specified by evt.
 /// </summary>
 /// <param name="evt">The event to execute.</param>
 public extern void RunEvent(KFSMEvent evt);
 /// <summary>
 /// Add a new event (possible transition) to the finite state machine.
 /// </summary>
 /// <param name="ev">The event to add.</param>
 /// <param name="excStates">A list of states *not* to add the event to. The event can only be triggered
 /// when the machine is *not* in one of these states.</param>
 public extern void AddEventExcluding(KFSMEvent ev, params KFSMState[] excStates);
		public RecyclerFSM (ExRecycler recycler)
		{
			this.recycler = recycler;

			state_off = new KFSMState ("Off");
			state_off.OnEnter = onenter_off;

			state_idle = new KFSMState ("Idle");
			state_idle.OnEnter = onenter_idle;
			state_idle.OnLeave = onleave_idle;

			state_captured_idle = new KFSMState ("Captured Idle");
			state_captured_idle.OnEnter = onenter_captured_idle;
			state_captured_idle.OnLeave = onleave_captured_idle;

			state_processing_part = new KFSMState ("Processing Part");
			state_processing_part.OnEnter = onenter_processing_part;
			state_processing_part.OnLeave = onleave_processing_part;

			state_transferring_resources = new KFSMState ("Transferring Resources");
			state_transferring_resources.OnEnter = onenter_transferring_resources;
			state_transferring_resources.OnLeave = onleave_transferring_resources;
			state_transferring_resources.OnFixedUpdate = onupdate_transferring_resources;

			event_enabled = new KFSMEvent ("Enabled");
			event_enabled.GoToStateOnEvent = state_idle;
			event_enabled.OnCheckCondition = check_enabled;
			event_enabled.updateMode = KFSMUpdateMode.FIXEDUPDATE;
			event_enabled.OnEvent = delegate { LogEvent ("Enabled"); };

			event_disabled = new KFSMEvent ("Disabled");
			event_disabled.GoToStateOnEvent = state_off;
			event_disabled.OnCheckCondition = check_disabled;
			event_disabled.updateMode = KFSMUpdateMode.FIXEDUPDATE;
			event_disabled.OnEvent = delegate { LogEvent ("Disabled"); };

			event_enter_field = new KFSMEvent ("Enter Field");
			event_enter_field.GoToStateOnEvent = state_captured_idle;
			event_enter_field.updateMode = KFSMUpdateMode.MANUAL_TRIGGER;
			event_enter_field.OnEvent = delegate { LogEvent ("Enter Field"); };

			event_part_selected = new KFSMEvent ("Part Selected");
			event_part_selected.GoToStateOnEvent = state_processing_part;
			event_part_selected.OnCheckCondition = check_part_selected;
			event_part_selected.updateMode = KFSMUpdateMode.FIXEDUPDATE;
			event_part_selected.OnEvent = delegate { LogEvent ("Part Selected"); };

			event_resources_collected = new KFSMEvent ("Resources Collected");
			event_resources_collected.GoToStateOnEvent = state_transferring_resources;
			event_resources_collected.OnCheckCondition = check_resources_collected;
			event_resources_collected.updateMode = KFSMUpdateMode.FIXEDUPDATE;
			event_resources_collected.OnEvent = delegate { LogEvent ("Resources Collected"); };

			event_resources_transferred = new KFSMEvent ("Resources Transferred");
			event_resources_transferred.GoToStateOnEvent = state_captured_idle;
			event_resources_transferred.OnCheckCondition = check_resources_transferred;
			event_resources_transferred.updateMode = KFSMUpdateMode.FIXEDUPDATE;
			event_resources_transferred.OnEvent = delegate { LogEvent ("Resources Transferred"); };

			event_parts_exhausted = new KFSMEvent ("Parts Exhausted");
			event_parts_exhausted.GoToStateOnEvent = state_idle;
			event_parts_exhausted.OnCheckCondition = check_parts_exhausted;
			event_parts_exhausted.updateMode = KFSMUpdateMode.FIXEDUPDATE;
			event_parts_exhausted.OnEvent = delegate { LogEvent ("Parts Exhausted"); };

			fsm = new RecFSM ();
			fsm.AddState (state_off);
			fsm.AddState (state_idle);
			fsm.AddState (state_captured_idle);
			fsm.AddState (state_processing_part);
			fsm.AddState (state_transferring_resources);

			fsm.AddEvent (event_enabled, new KFSMState [] {state_off});
			fsm.AddEvent (event_disabled, new KFSMState [] {state_idle});
			fsm.AddEvent (event_enter_field, new KFSMState [] {state_idle});
			fsm.AddEvent (event_part_selected, new KFSMState [] {state_captured_idle});
			fsm.AddEvent (event_resources_collected, new KFSMState [] {state_processing_part});
			fsm.AddEvent (event_resources_transferred, new KFSMState [] {state_transferring_resources});
			fsm.AddEvent (event_parts_exhausted, new KFSMState [] {state_captured_idle});

			start_state = state_off;


			recycle_parts = new HashSet<uint> ();
		}
        //adds an FSM state to show that we are animating
        private void AddAnimationState()
        {
            if (States.Find (k => k.name == "KAS_Animation") == null)
            {
                KFSMState state = new KFSMState ("KAS_Animation");
                state.updateMode = KFSMUpdateMode.MANUAL_TRIGGER;
                FSM.AddState (state);

                KFSMEvent enterEvent = new KFSMEvent ("Enter KAS_Animation");
                enterEvent.GoToStateOnEvent = state;
                enterEvent.updateMode = KFSMUpdateMode.MANUAL_TRIGGER;
                var idleGrounded = States.Find (k => k.name == "Idle (Grounded)");
                FSM.AddEvent (enterEvent, idleGrounded);

                KFSMEvent exitEvent = new KFSMEvent ("Exit KAS_Animation");
                exitEvent.GoToStateOnEvent = idleGrounded;
                exitEvent.updateMode = KFSMUpdateMode.MANUAL_TRIGGER;
                FSM.AddEvent (exitEvent, state);
            }
        }
示例#22
0
 /// <summary>
 /// Add a new event (possible transition) to the finite state machine.
 /// </summary>
 /// <param name="ev">The event to add.</param>
 /// <param name="toStates">The states to add the event to. The event can only be triggered when
 /// the machine is in one of these states.</param>
 public extern void AddEvent(KFSMEvent ev, params KFSMState[] toStates);
示例#23
0
        protected override void OnTutorialSetup()
        {
            try {

                happyEmotes.Add (instructor.anim_true_thumbsUp);
                happyEmotes.Add (instructor.anim_true_smileA);
                happyEmotes.Add (instructor.anim_true_nodA);
                happyEmotes.Add (instructor.anim_true_thumbUp);
                happyEmotes.Add (instructor.anim_true_smileB);
                happyEmotes.Add (instructor.anim_true_nodB);

                #region welcome
                welcome = new TutorialPage ("welcome");
                welcome.windowTitle = formatWindowTitle ("Intro");
                welcome.OnEnter = (KFSMState st) =>
                {
                    instructor.StopRepeatingEmote ();

                    // disable some stuff
                    InputLockManager.SetControlLock (
                        ControlTypes.STAGING |
                        ControlTypes.THROTTLE |
                        ControlTypes.LINEAR |
                        ControlTypes.VESSEL_SWITCHING,
                        "ORDA_Tutorial2_Lock");
                };
                welcome.OnDrawContent = () =>
                {
                    GUILayout.Label (
                        "Welcome back!\n\n" +
                        "In this tutorial we will look at how the ORDA autopilot can help you dock to another spacecraft.\n\n" +
                        "It can either perform a autonomous docking or just maintain the correct orientation of your spacecraft while you control the relative position and velocity using the translational RCS controls.");
                    if (GUILayout.Button ("Next")) {
                        Tutorial.GoToNextPage ();
                    }
                };
                Tutorial.AddPage (welcome);
                #endregion
                #region dock1
                dock1 = new TutorialPage ("dock1");
                dock1.windowTitle = formatWindowTitle ("Docking");
                dock1.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmoteRepeating (instructor.anim_idle_lookAround, 5f);

                    // find vessels, ports and computers
                    if(!findVesselsPartsAndComputers(true)) {
                        handleError();
                    }
                };
                dock1.OnDrawContent = () =>
                {
                    GUILayout.Label (
                        "Let's try the autonomous docking first.\n\n" +
                        "This vessel will serve as your docking target. When using the autonomous docking mode it is absolutely mandatory to use some kind of Attitude-Hold on the target vessel. You can either achieve this by using an Advanced Stability Augmentation System (ASAS) or by using the Att->Hold mode of your ORDA autopilot.\n\n" +
                        "Use the rotational controls to point your nose in the approximate direction of the other spacecraft (optional) and then activate the Att -> Hold mode.");
                };
                dock1.SetAdvanceCondition ((KFSMState st) => {
                    ORDA.GNCconfig gncConfig = otherComputer.getGNCConfig();
                    return (gncConfig.command == GNC.Command.ATT && gncConfig.attMode == GNC.AttMode.HOLD);
                });
                Tutorial.AddPage (dock1);
                #endregion
                #region dock2
                dock2 = new TutorialPage ("dock2");
                dock2.windowTitle = formatWindowTitle ("Docking");
                dock2.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());

                    // allow vessel switching
                    InputLockManager.SetControlLock (
                        ControlTypes.STAGING |
                        ControlTypes.THROTTLE |
                        ControlTypes.LINEAR,
                        "ORDA_Tutorial2_Lock");
                };
                dock2.OnDrawContent = () =>
                {
                    GUILayout.Label ("Good job! Now lets switch over to the other vessel using the [" + GameSettings.FOCUS_NEXT_VESSEL.primary.ToString() + "] key.");
                };
                dock2.SetAdvanceCondition ((KFSMState st) => {
                    return (FlightGlobals.ActiveVessel == thisVessel);
                });
                Tutorial.AddPage (dock2);
                #endregion
                #region dock3
                dock3 = new TutorialPage ("dock3");
                dock3.windowTitle = formatWindowTitle ("Docking");
                dock3.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());

                    // forbid vessel switching
                    InputLockManager.SetControlLock (
                        ControlTypes.STAGING |
                        ControlTypes.THROTTLE |
                        ControlTypes.LINEAR |
                        ControlTypes.VESSEL_SWITCHING,
                        "ORDA_Tutorial2_Lock");
                };
                dock3.OnDrawContent = () =>
                {
                    GUILayout.Label (
                        "Before you can activate the docking mode you need to select the target vessel, the target docking port and your local docking port.\n\n" +
                        "Let's select the local docking port first. Open the target page and select 'local port 1'. Note the matching docking port on your vessel being highlighted in green.");
                };
                dock3.SetAdvanceCondition ((KFSMState st) => {
                    return (thisComputer.getVesselDockingPort() == thisDockingPort);
                });
                Tutorial.AddPage (dock3);
                #endregion
                #region dock4
                dock4 = new TutorialPage ("dock4");
                dock4.windowTitle = formatWindowTitle ("Docking");
                dock4.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                dock4.OnDrawContent = () =>
                {
                    GUILayout.Label (
                        "Nicely done! There are two ways to select the target vessel and it's docking port. You can either select them in the target page like you did with your local docking port or you can select them in-game by right-clicking the docking port on the other vessel and selecting 'Set as target'.\n\n" +
                        "Go ahead and try both methods. Note that the target page will only show free docking ports. Lateral ports will only show up if they are open.");

                    if(thisComputer.getTargetVessel() == otherVessel &&
                       thisComputer.getTargetDockingPort() == otherDockingPort &&
                       thisComputer.getVesselDockingPort() == thisDockingPort) {
                        if(GUILayout.Button("Next")) {
                            Tutorial.GoToNextPage();
                        }
                    }
                };
                Tutorial.AddPage (dock4);
                #endregion
                #region dock5
                dock5 = new TutorialPage ("dock5");
                dock5.windowTitle = formatWindowTitle ("Docking");
                dock5.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                dock5.OnDrawContent = () =>
                {
                    GUILayout.Label (
                        "So far so good. Head over to the autopilot page and note the new 'Dock' master mode. It will only show up if you have both docking ports selected in the target page.\n\n" +
                        "Activate the 'Dock' master mode.");
                };
                dock5.SetAdvanceCondition ((KFSMState st) => {
                    GNCconfig gncConfig = thisComputer.getGNCConfig();
                    return (gncConfig.command == GNC.Command.DOCK);
                });
                Tutorial.AddPage (dock5);
                #endregion
                #region dock6
                dock6 = new TutorialPage ("dock6");
                dock6.windowTitle = formatWindowTitle ("Docking");
                dock6.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                dock6.OnDrawContent = () =>
                {
                    GUILayout.Label (
                        "As i have previously mentioned there are two docking modes:\n\n" +
                        "ATTITUDE will only maintain your correct orientation while you are in charge of the translational RCS controls.\n\n" +
                        "AUTO will (try to) perform a fully autonomous docking.\n\n" +
                        "Select 'AUTO' and click on 'Engage'.");
                };
                dock6.SetAdvanceCondition ((KFSMState st) => {
                    GNCconfig gncConfig = thisComputer.getGNCConfig();
                    return (gncConfig.command == GNC.Command.DOCK &&
                            gncConfig.dockMode == GNC.DockMode.AUTO &&
                            gncConfig.dockState == GNC.DockState.ORIENT);
                });
                Tutorial.AddPage (dock6);
                #endregion
                #region dock7
                dock7 = new TutorialPage ("dock7");
                dock7.windowTitle = formatWindowTitle ("Docking");
                dock7.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                dock7.OnDrawContent = () =>
                {
                    GUILayout.Label (
                        "Good job! The autopilot will now run through a sequence of states that might lead to a successful capture.\n\n" +
                        "If you want to abort the autonomous docking at any point you can click 'AUTO' again and take over manual control.\n\n" +
                        "Make sure your RCS is activated, lean back and enjoy the ride.");
                };
                dock7.SetAdvanceCondition ((KFSMState st) => {
                    return (thisVessel == null || otherVessel == null);
                });
                Tutorial.AddPage (dock7);
                #endregion
                #region dock8
                dock8 = new TutorialPage ("dock8");
                dock8.windowTitle = formatWindowTitle ("Docking");
                dock8.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());

                    // allow linear thrusters
                    InputLockManager.SetControlLock (
                        ControlTypes.STAGING |
                        ControlTypes.THROTTLE |
                        ControlTypes.VESSEL_SWITCHING,
                        "ORDA_Tutorial2_Lock");
                };
                dock8.OnDrawContent = () =>
                {
                    string s =
                        "Looks like a solid connection!\n\n" +
                        "The autopilot will automatically deactivate itself if you dock or undock. You can now use Rate->Zero or Att->Hold or ASAS to kill any residual spin.\n\n" +
                        "Now undock the two spacecraft and get them seperated by at least 25m using the translational RCS controls.";

                    // find vessels, ports and computers again, will succeed after undocking
                    if(findVesselsPartsAndComputers(false)) {
                        float dist = (thisVessel.transform.position - otherVessel.transform.position).magnitude;
                        s += "\n\nCurrent Distance: " + dist.ToString("F1") + "m";
                    }

                    GUILayout.Label(s);
                };
                dock8.SetAdvanceCondition ((KFSMState st) => {
                    if(thisVessel == null || otherVessel == null) {
                        return false;
                    }
                    float dist = (thisVessel.transform.position - otherVessel.transform.position).magnitude;
                    return (dist > 25);
                });
                Tutorial.AddPage (dock8);
                #endregion
                #region dock9
                dock9 = new TutorialPage ("dock9");
                dock9.windowTitle = formatWindowTitle ("Docking");
                dock9.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                dock9.OnDrawContent = () =>
                {
                    GUILayout.Label (
                        "Alright. Now select your target vessel, target docking port and local docking port as you did before and then activate the Dock->Attitude mode on the Autopilot page.");
                };
                dock9.SetAdvanceCondition ((KFSMState st) => {
                    GNCconfig gncConfig = thisComputer.getGNCConfig();

                    return (thisComputer.getTargetVessel() == otherVessel &&
                            thisComputer.getTargetDockingPort() == otherDockingPort &&
                            thisComputer.getVesselDockingPort() == thisDockingPort &&
                            gncConfig.command == GNC.Command.DOCK &&
                            gncConfig.dockMode == GNC.DockMode.ATTITUDE);
                });
                Tutorial.AddPage (dock9);
                #endregion
                #region dock10
                dock10 = new TutorialPage ("dock10");
                dock10.windowTitle = formatWindowTitle ("Docking");
                dock10.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());

                    otherComputer.activateAttitudeMode("Hold");
                };
                dock10.OnDrawContent = () =>
                {
                    GUILayout.Label (
                        "Looks good! I have activated the Attitude-Hold on the other spacecraft for you.\n\n" +
                        "Now try to re-dock using the translational RCS controls while the autopilot will keep you oriented properly.\n\n" +
                        "Try setting the camera mode to 'Chase' if you get confused.");
                };
                dock10.SetAdvanceCondition ((KFSMState st) => {
                    return (thisVessel == null || otherVessel == null);
                });
                Tutorial.AddPage (dock10);
                #endregion
                #region complete
                complete = new TutorialPage ("complete");
                complete.windowTitle = formatWindowTitle ("Complete");
                complete.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                complete.OnDrawContent = () =>
                {
                    GUILayout.Label ("Congratulations! You finished this tutorial.\n\n" +
                        "You can close the tutorial window now and play around with your ships if you want."
                    );
                    if (GUILayout.Button ("Close tutorial")) {
                        Destroy (this);
                    }
                };
                Tutorial.AddPage (complete);
                #endregion
                #region error
                error = new TutorialPage ("special page 1");
                error.OnEnter = (KFSMState lastSt) =>
                {
                    error.windowTitle = "Error (from " + lastSt.name + ")";
                    instructor.PlayEmote (instructor.anim_false_sadA);
                };
                error.OnDrawContent = () =>
                {
                    GUILayout.Label ("Ooops!\n\nSomething went wrong ...", GUILayout.ExpandHeight (true));
                };
                Tutorial.AddState (error);

                onError = new KFSMEvent ("Something Unplanned");
                onError.updateMode = KFSMUpdateMode.MANUAL_TRIGGER;
                onError.GoToStateOnEvent = error;
                Tutorial.AddEventExcluding (onError, error);
                #endregion

                Tutorial.StartTutorial (welcome);

            } catch (Exception e) {
                print("exception in OnTutorialSetup: " + e.ToString());
            }
        }
        /**
         * The stock root selection has two states:
         *  - st_root_unselected: Active after switching to root mode. Waits for mouse up, picks part and sets SelectedPart.
         *  - st_root_select: The state after the first click.
         *
         * Skip straight to st_root state by adding an event to st_root_unselected with
         * always true condition that sets up SelectedPart and transitions to st_root.
         *
         * Needs to run after EditorLogic#Start() so the states are initialized.
         */
        public void Start()
        {
            Instance = this;
            if (!EditorExtensions.validVersion)
            {
                return;
            }

            //if (!EditorExtensions.Instance.ReRootActive || !EditorExtensions.Instance.cfg.ReRootEnabled)
            //    return;

            //log = new Log(this.GetType().Name);
            Log.Info("SelectRoot2 Start");

            // Oh god, so much dirty reflection. Please don't sue me, Squad :(
            //KerbalFSM editorFSM = (KerbalFSM)Refl.GetValue(EditorLogic.fetch, "\u0001");


            // Skip first click in root selection mode:
            KFSMEvent skipFirstClickEvent = new KFSMEvent("SelectRoot2_skipFirstClickEvent");

            skipFirstClickEvent.OnCheckCondition = (state) => {
                // Um about that always true condition... There is a funny sound glitch
                // if the root part doesn't have any ROOTABLE children so check for that.
                // Thanks Kerbas_ad_astra, http://forum.kerbalspaceprogram.com/threads/43208?p=1948755#post1948755
                return(EditorReRootUtil.GetRootCandidates(EditorLogic.RootPart.GetComponentsInChildren <Part>()).Any());
            };


            skipFirstClickEvent.OnEvent = () => {
                //Refl.SetValue(EditorLogic.fetch, "selectedPart", EditorLogic.RootPart); // SelectedPart
                Refl.SetValue(EditorLogic.fetch, EditorExtensions.c.SELECTEDPART, EditorLogic.RootPart); // SelectedPart
            };
            //KFSMState st_root_select = (KFSMState)Refl.GetValue(EditorLogic.fetch, "st_root_select");
            KFSMState st_root_select = (KFSMState)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.ST_ROOT_SELECT);

            skipFirstClickEvent.GoToStateOnEvent = st_root_select;

            //KFSMState st_root_unselected = (KFSMState)Refl.GetValue(EditorLogic.fetch, "st_root_unselected");
            KFSMState st_root_unselected = (KFSMState)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.ST_ROOT_UNSELECTED);

            InjectEvent(st_root_unselected, skipFirstClickEvent);

            // Fix ability to select if already hovering:
            KFSMStateChange fixAlreadyHoveringPartFn = (from) => {
                Part partUnderCursor = GetPartUnderCursor();
                var  selectors       = EditorLogic.SortedShipList;

                //EditorLogic.fetch.Lock (true, true, true, "SelectRoot2");

                var selectorUnderCursor = selectors.Find(x => (Part)x == partUnderCursor);
                if (selectorUnderCursor)
                {
//						Refl.Invoke(selectorUnderCursor, "OnMouseIsOver");
                    Refl.Invoke(selectorUnderCursor, EditorExtensions.c.ONMOUSEISOVER);
                }
            };

            st_root_select.OnEnter += fixAlreadyHoveringPartFn;
            OnCleanup += () => {
                st_root_select.OnEnter -= fixAlreadyHoveringPartFn;
            };

            // Provide a more meaningful message after our changes:
            KFSMStateChange postNewMessageFn = (from) => {
                //var template = (ScreenMessage)Refl.GetValue(EditorLogic.fetch, "modeMsg");
                var template = (ScreenMessage)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.MODEMSG);
                ScreenMessages.PostScreenMessage("Select a new root part", template);
            };

            st_root_select.OnEnter += postNewMessageFn;
            OnCleanup += () => {
                st_root_select.OnEnter -= postNewMessageFn;
            };

            // Drop the new root part after selection:

            KFSMEvent dropNewRootPartEvent = new KFSMEvent("SelectRoot2_dropNewRootPartEvent");

            dropNewRootPartEvent.OnCheckCondition = (state) => {
                return(EditorLogic.fetch.lastEventName.Equals("on_rootSelect"));
            };

            dropNewRootPartEvent.OnEvent = () => {
                // Normally the backup is triggered in on_partDropped#OnCheckCondition()
                // But we skip that, so do backup here instead.

                EditorLogic.fetch.SetBackup();
                // Normally triggered in on_partDropped#OnEvent().
                GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartDropped, EditorLogic.SelectedPart);
                //var template = (ScreenMessage)Refl.GetValue(EditorLogic.fetch, "modeMsg");
                var template = (ScreenMessage)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.MODEMSG);
                //ScreenMessages.PostScreenMessage(String.Empty, template);
                if (template != null)
                {
                    ScreenMessages.PostScreenMessage("New Root selected and dropped", template);
                }
                else
                {
                    ScreenMessages.PostScreenMessage("New Root selected and dropped");
                }

                EditorLogic.SelectedPart.gameObject.SetLayerRecursive(0, 1 << 21);
#if false
                Part[] parts = EditorLogic.RootPart.GetComponentsInChildren <Part>();
                foreach (var p in parts)
                {
                    Log.Info(p.ToString() + "p.enabled: " + p.enabled.ToString());

                    //Log.Info(p.ToString() + "p.frozen: " + p.active .ToString());
                }
#endif
                //EditorLogic.fetch.Unlock("SelectRoot2");
            };

            // problem is with the following line
            //KFSMState st_idle = (KFSMState)Refl.GetValue(EditorLogic.fetch, "st_idle");
            KFSMState st_idle = (KFSMState)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.ST_IDLE);
            dropNewRootPartEvent.GoToStateOnEvent = st_idle;

            //KFSMState st_place = (KFSMState)Refl.GetValue(EditorLogic.fetch, "st_place");
            KFSMState st_place = (KFSMState)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.ST_PLACE);
            InjectEvent(st_place, dropNewRootPartEvent);


            Log.Info("Setup complete..");
        }
示例#25
0
 /// <summary>
 /// Cause the machine to execute the transition specified by evt.
 /// </summary>
 /// <param name="evt">The event to execute.</param>
 public extern void RunEvent(KFSMEvent evt);
示例#26
0
        private void InitMachine()
        {
            Log.Info("InitMachine");
            //  if (saveLoadWinPos == null)
            //     saveLoadWinPos = new SaveLoadWinPos();


            // Create the states

            initial  = new InitialState("Init", _machine);
            settings = new SettingState("Settings", _machine);
            sequence = new SequenceState("Sequence", _machine);
            launch   = new LaunchState("Launch", _machine);
            launched = new LaunchedState("Launched", _machine);
            finish   = new KFSMState("Finish");

            // Add events to the states

            var go2Finish = new KFSMEvent("Finish")
            {
                GoToStateOnEvent = finish,
                updateMode       = KFSMUpdateMode.MANUAL_TRIGGER
            };

            var go2Settings = new KFSMEvent("Settings")
            {
                GoToStateOnEvent = settings, updateMode = KFSMUpdateMode.MANUAL_TRIGGER
            };

            initial.AddEvent(go2Settings);

            var go2Init = new KFSMEvent("Init")
            {
                GoToStateOnEvent = initial, updateMode = KFSMUpdateMode.MANUAL_TRIGGER
            };

            settings.AddEvent(go2Init);
            sequence.AddEvent(go2Init);
            finish.AddEvent(go2Init);

            var go2Sequence = new KFSMEvent("Sequence")
            {
                GoToStateOnEvent = sequence, updateMode = KFSMUpdateMode.MANUAL_TRIGGER
            };

            initial.AddEvent(go2Sequence);

            var go2Launch = new KFSMEvent("Launch")
            {
                GoToStateOnEvent = launch, updateMode = KFSMUpdateMode.MANUAL_TRIGGER
            };

            initial.AddEvent(go2Launch);
            launch.AddEvent(go2Init);
            launch.AddEvent(go2Finish);

            var go2Launched = new KFSMEvent("Launched")
            {
                GoToStateOnEvent = launched, updateMode = KFSMUpdateMode.MANUAL_TRIGGER
            };

            launch.AddEvent(go2Launched);

            initial.AddEvent(go2Finish);
            launched.AddEvent(go2Finish);

            // Add states to the state  machine

            _machine.AddState(initial);
            _machine.AddState(settings);
            _machine.AddState(sequence);
            _machine.AddState(launch);
            _machine.AddState(finish);
        }
        /// <summary>
        /// Intiialize the maneuver pilot FSM.
        /// </summary>
        private void ManeuverPilotInitialize()
        {
            KFSMState idleState = new KFSMState("Idle");

            idleState.updateMode = KFSMUpdateMode.FIXEDUPDATE;

            KFSMState coastState = new KFSMState("Coasting");

            coastState.updateMode = KFSMUpdateMode.FIXEDUPDATE;

            MASFlyState flyState = new MASFlyState("Flying", this);

            flyState.updateMode    = KFSMUpdateMode.FIXEDUPDATE;
            flyState.OnEnter       = flyState.OnEnterImpl;
            flyState.OnFixedUpdate = flyState.OnFixedUpdateImpl;

            KFSMEvent stopPilot = new KFSMEvent("Stop Pilot");

            stopPilot.updateMode       = KFSMUpdateMode.FIXEDUPDATE;
            stopPilot.OnCheckCondition = (KFSMState currentState) =>
            {
                bool stopThisPilot = (maneuverPilotEngaged == false || attitudePilotEngaged == false || node == null);
                if (stopThisPilot)
                {
                    CancelAutopilots();
                    //Utility.LogMessage(this, "StopPilot  event: Transitioning");
                }
                return(stopThisPilot);
            };
            stopPilot.GoToStateOnEvent = idleState;

            KFSMEvent startPilot = new KFSMEvent("Start Pilot");

            startPilot.updateMode       = KFSMUpdateMode.FIXEDUPDATE;
            startPilot.OnCheckCondition = (KFSMState currentState) =>
            {
                return(maneuverPilotEngaged);
            };
            startPilot.GoToStateOnEvent = coastState;

            KFSMEvent flyPilot = new KFSMEvent("Fly Pilot");

            flyPilot.updateMode       = KFSMUpdateMode.FIXEDUPDATE;
            flyPilot.OnCheckCondition = (KFSMState currentState) =>
            {
                if (maneuverPilotEngaged)     // Should be redundant?
                {
                    double burnTime = NodeBurnTime();

                    if (burnTime > 0.0 && burnTime * 0.5 >= -maneuverNodeTime)
                    {
#if VERBOSE_AUTOPILOT_LOGGING
                        Utility.LogMessage(this, "FlyPilot   event: Transitioning");
#endif
                        return(true);
                    }
                }
                return(false);
            };
            flyPilot.GoToStateOnEvent = flyState;

            KFSMEvent doneFlying = new KFSMEvent("Done Event");
            doneFlying.updateMode       = KFSMUpdateMode.FIXEDUPDATE;
            doneFlying.OnCheckCondition = (KFSMState currentState) =>
            {
                if (maneuverNodeDeltaV < 0.15)
                {
                    CancelAutopilots();
                    if (vessel.patchedConicSolver != null)
                    {
                        vessel.patchedConicSolver.maneuverNodes.Clear();
                    }
                    try
                    {
                        FlightInputHandler.state.mainThrottle = 0.0f;
                    }
                    catch
                    {
                    }
#if VERBOSE_AUTOPILOT_LOGGING
                    Utility.LogMessage(this, "Done flying...");
#endif
                    return(true);
                }
                return(false);
            };
            doneFlying.GoToStateOnEvent = idleState;

            idleState.AddEvent(startPilot);
            coastState.AddEvent(stopPilot);
            coastState.AddEvent(flyPilot);
            flyState.AddEvent(stopPilot);
            flyState.AddEvent(doneFlying);

            maneuverPilot.AddState(idleState);
            maneuverPilot.AddState(coastState);
            maneuverPilot.AddState(flyState);

            maneuverPilot.StartFSM(idleState);
        }
示例#28
0
        private void GetFSM()
        {
            var evaType = EVA.GetType();
            var fields = evaType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);

            Type kfsmEventType = typeof(KFSMEvent);
            Type kfsmStateType = typeof(KFSMState);

            string fieldNames = "Field Names for " + evaType.ToString() + ":\n";
            foreach (var field in fields)
            {
                try
                {
                    if (field.FieldType == kfsmEventType)
                    {
                        KFSMEvent ke = (KFSMEvent)field.GetValue(EVA);
                        fieldNames += "KFSMEvent: " + field.Name + " (" + ke.name + ")\n";
                        if (ke.name == "Stumble")
                        {
                            _stumble = ke;
                        }
                        else if (ke.name == "Swim Forward")
                        {
                            _swimForward = ke;
                        }
                        else if (ke.name == "Ladder Climb")
                        {
                            _ladderClimb = ke;
                        }
                        else if (ke.name == "Start Run")
                        {
                            _startRun = ke;
                        }
                    }
                    else if (field.FieldType == kfsmStateType)
                    {
                        KFSMState ks = (KFSMState)field.GetValue(EVA);
                        fieldNames += "KFSMState: " + field.Name + " (" + ks.name + ")\n";
                        if (ks.name == "Idle (Floating)")
                        {
                            _floating = ks;
                        }
                    }
                }
                catch (Exception)
                {
                    fieldNames += "???\n";
                }
            }
            //Util.Log(fieldNames);
        }
示例#29
0
        protected override void OnTutorialSetup()
        {
            Log.post("AirshipsTutorial OnTutorialSetup", LogLevel.LOG_DEBUG);

            ProcAirships.Instance.pressureDestruction = false;



            TutorialPage page1 = new TutorialPage("page1");

            page1.windowTitle   = "Airships Tutorial";
            page1.OnDrawContent = () =>
            {
                GUILayout.Label("Welcome to the Procedural Airships tutorial. \n" +
                                "Today we will learn how to control a simple airship by using ballonets.", GUILayout.ExpandHeight(true));

                if (GUILayout.Button("Next"))
                {
                    Tutorial.GoToNextPage();
                }
            };
            this.Tutorial.AddPage(page1);

            TutorialPage page2 = new TutorialPage("page2");

            page2.windowTitle   = "Airships Tutorial";
            page2.OnDrawContent = () =>
            {
                GUILayout.Label("Lets have a look at our airship. Its envelope is composed of three parts. Two pointy 'envelope caps', and one cylindric envelope between those two caps.\n" +
                                "It is important to understand that stacked envelopes automatically form a connection between each other. Gas can flow freely between them. " +
                                "So everything you do on one envelope part will affect connected envelopes.\n", GUILayout.ExpandHeight(true));

                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Previous"))
                {
                    Tutorial.GoToLastPage();
                }
                if (GUILayout.Button("Next"))
                {
                    Tutorial.GoToNextPage();
                }
                GUILayout.EndHorizontal();
            };
            this.Tutorial.AddPage(page2);

            TutorialPage page3 = new TutorialPage("page3");

            page3.windowTitle   = "Airships Tutorial";
            page3.OnDrawContent = () =>
            {
                GUILayout.Label("Now please do a right-click on the cylindric envelope between the two pointy caps. " +
                                "Wow thats a lot of complicated stuff isn't it? Well, it's not that hard actually. First thing you have to learn about is " +
                                "'net. Buoyancy'. It is the airships static lift after substracting the gravitational force. It is negative at the moment, " +
                                "and thats the reason why our airship sits patiently on the runway instead of floating around. Gravity holds it on the ground.\n" +
                                "Lets see how we can change that.", GUILayout.ExpandHeight(true));

                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Previous"))
                {
                    Tutorial.GoToLastPage();
                }
                if (GUILayout.Button("Next"))
                {
                    Tutorial.GoToNextPage();
                }
                GUILayout.EndHorizontal();
            };
            this.Tutorial.AddPage(page3);

            TutorialPage page4 = new TutorialPage("page4");

            page4.windowTitle = "Airships Tutorial";

            page4.OnEnter = (KFSMState st) =>
            {
            };

            page4.OnUpdate = () =>
            {
                if (FlightGlobals.ActiveVessel.altitude >= 200.0)
                {
                    Tutorial.GoToNextPage();
                }
            };

            page4.OnDrawContent = () =>
            {
                GUILayout.Label("To change an envelopes buoyancy, you can use it's ballonet. A ballonet is an inflatable balloon that limits the space " +
                                "that the lifting gas can use to expand. Inflating the ballonet results in less buoyancy. Deflating the ballonet results in more " +
                                "buoyancy. But be careful! The ballonet direclty affects the pressure of the gas in the envelope. Please make sure you have selected the " +
                                "cylindrical envelope (not the caps) and carefully deflate the ballonet until the airship rises to an altitude of 200 meters.", GUILayout.ExpandHeight(true));
            };

            page4.OnLeave = (KFSMState st) =>
            {
            };

            this.Tutorial.AddPage(page4);

            TutorialPage page5 = new TutorialPage("page5");

            page5.windowTitle = "Airships Tutorial";

            page5.OnEnter = (KFSMState st) =>
            {
                instructor.PlayEmote(instructor.anim_true_thumbsUp);
            };

            page5.OnDrawContent = () =>
            {
                GUILayout.Label("Well done! But what will happen if we alter the ballonets of the envelope caps? More power to you! Try it. " +
                                "But be careful. Before going wild on the ballonets. Have a look at the 'press. Status' bar. It shows you how much the pressure in your envelope " +
                                "differs from the ideal pressure. A half filled bar is good. An empty or completely filled bar is bad. Feel free to experiment. But make sure to set the " +
                                "inflation of both caps back to 50% when you are ready to continue the tutorial.", GUILayout.ExpandHeight(true));


                if (fiftyfifty())
                {
                    if (GUILayout.Button("Next"))
                    {
                        Tutorial.GoToNextPage();
                    }
                }
            };
            this.Tutorial.AddPage(page5);

            TutorialPage page6 = new TutorialPage("page6");

            page6.windowTitle = "Airships Tutorial";

            page6.OnEnter = (KFSMState st) => { instructor.PlayEmote(instructor.anim_true_smileA); };

            page6.OnDrawContent = () =>
            {
                GUILayout.Label("Alright. You might have noticed that you can use the ballonets on the caps to pitch your airship up and down. " +
                                "Using the right click menus is a good way to do it. But professional airship instructors, like me, know a better way: " +
                                "Action Groups! I have already assigned some. Use the 1 Key to pitch the airship up and 2 to pitch it down. Try it, it works quite well, doesn't it?", GUILayout.ExpandHeight(true));

                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Previous"))
                {
                    Tutorial.GoToLastPage();
                }
                if (GUILayout.Button("Next"))
                {
                    Tutorial.GoToNextPage();
                }
                GUILayout.EndHorizontal();
            };
            this.Tutorial.AddPage(page6);


            TutorialPage page7 = new TutorialPage("page7");

            page7.windowTitle   = "Airships Tutorial";
            page7.OnDrawContent = () =>
            {
                GUILayout.Label("There is one more important thing before we can start flying around. The higher you get, the less pressure the air will exert on your envelopes. " +
                                "You must balance that out by deflating a ballonet or... well pressure will rise and bad things will happen. Fortunately there is a built-in automatic to assist " +
                                "us. 'Pressure Control'. The Pressure Control system can take over control of a ballonet to assure pressure is always near the perfect spot to prevent damage to the envelopes. " +
                                "Please activate Pressure Control now. Do it on the cylindric envelope but NOT on the caps, since we need to control the caps ourself to pitch the airship.", GUILayout.ExpandHeight(true));

                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Previous"))
                {
                    Tutorial.GoToLastPage();
                }
                if (GUILayout.Button("Next"))
                {
                    Tutorial.GoToNextPage();
                }
                GUILayout.EndHorizontal();
            };
            this.Tutorial.AddPage(page7);

            TutorialPage page8 = new TutorialPage("page8");

            page8.windowTitle   = "Airships Tutorial";
            page8.OnDrawContent = () =>
            {
                GUILayout.Label("Alright, you are ready to go. Start your engines and throttle up to 100% Trim your pitch with '1' and '2' and use WASD to steer around. " +
                                "Be careful though. It is a very maneuverable airship and turning too fast can cause it to spin out of control.", GUILayout.ExpandHeight(true));

                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Previous"))
                {
                    Tutorial.GoToLastPage();
                }
                if (GUILayout.Button("Next"))
                {
                    Tutorial.GoToNextPage();
                }
                GUILayout.EndHorizontal();
            };
            this.Tutorial.AddPage(page8);


            TutorialPage page9 = new TutorialPage("page9");

            page9.windowTitle   = "Airships Tutorial";
            page9.OnDrawContent = () =>
            {
                GUILayout.Label("Congartulations. You just learned the basic airship controls. My Job here is done. But here are some challenges if you want to hang around a bit:\n" +
                                "- Try to land on the VAB\n-See if you can land on the Island Runway\n-Find out how high you can get the airship without destroying the envelopes\n\n" +
                                "You may also load the tutorial airship in a sandbox game and see if you can improve it.", GUILayout.ExpandHeight(true));
            };

            this.Tutorial.AddPage(page9);

            TutorialPage pressureAlertPage = new TutorialPage("pressureAlertPage");

            pressureAlertPage.windowTitle = "OH NO!";

            pressureAlertPage.OnEnter = (KFSMState lastSt) =>
            {
                instructor.PlayEmote(instructor.anim_false_disagreeA);
                pressureAlertPage.onAdvanceConditionMet.GoToStateOnEvent = lastSt;
            };

            pressureAlertPage.SetAdvanceCondition((KFSMState currentState) =>
            {
                AirshipEnvelope envelope = FlightGlobals.ActiveVessel.rootPart.GetComponent <AirshipEnvelope>();

                float overpressure = Math.Abs((envelope.RelPressure - envelope.IdealRelPressure)) - envelope.PressureTolerance;

                if (overpressure > 0)
                {
                    return(false);
                }
                return(true);
            });

            pressureAlertPage.OnDrawContent = () =>
            {
                GUILayout.Label("Oh no! Envelope Pressure reaches critical range! Use the ballonets to bring it back to normal before everything explodes.\n" +
                                "Try to get the 'press. Status' bar in a position thats near to 0", GUILayout.ExpandHeight(true));
            };

            pressureAlertPage.OnLeave = (KFSMState st) =>
            {
                instructor.PlayEmote(instructor.anim_idle_sigh);
            };

            Tutorial.AddState(pressureAlertPage);

            onPressureAlert                  = new KFSMEvent("PressureAlert");
            onPressureAlert.updateMode       = KFSMUpdateMode.LATEUPDATE;
            onPressureAlert.OnCheckCondition = (KFSMState currentState) =>
            {
                AirshipEnvelope envelope = FlightGlobals.ActiveVessel.rootPart.GetComponent <AirshipEnvelope>();

                float overpressure = Math.Abs((envelope.RelPressure - envelope.IdealRelPressure)) - envelope.PressureTolerance;

                if (overpressure > 0)
                {
                    if (Tutorial.Started)
                    {
                        return(true);
                    }
                }
                return(false);
            };

            onPressureAlert.GoToStateOnEvent = pressureAlertPage;
            Tutorial.AddEventExcluding(onPressureAlert, pressureAlertPage);

            this.Tutorial.StartTutorial(page1);
        }
示例#30
0
        protected override void OnTutorialSetup()
        {
            try {

                happyEmotes.Add (instructor.anim_true_thumbsUp);
                happyEmotes.Add (instructor.anim_true_smileA);
                happyEmotes.Add (instructor.anim_true_nodA);
                happyEmotes.Add (instructor.anim_true_thumbUp);
                happyEmotes.Add (instructor.anim_true_smileB);
                happyEmotes.Add (instructor.anim_true_nodB);

                #region welcome
                welcome = new TutorialPage ("welcome");
                welcome.windowTitle = formatWindowTitle ("Intro");
                welcome.OnEnter = (KFSMState st) =>
                {
                    instructor.StopRepeatingEmote ();

                    // disable some stuff
                    InputLockManager.SetControlLock ((ControlTypes.STAGING |
                        ControlTypes.THROTTLE |
                        ControlTypes.LINEAR), "ORDA_Tutorial1_Lock");
                };
                welcome.OnDrawContent = () =>
                {
                    GUILayout.Label ("Welcome!\n\nIn this tutorial you will familiarize yourself with the Orbital Rendezvous and Docking Assistant (ORDA) - a basic autopilot system that can make your life in space a lot easier.\n\nLet's get started.");
                    if (GUILayout.Button ("Next")) {
                        Tutorial.GoToNextPage ();
                    }
                };
                Tutorial.AddPage (welcome);
                #endregion
                #region intro1
                intro1 = new TutorialPage ("intro1");
                intro1.windowTitle = formatWindowTitle ("Intro");
                intro1.OnEnter = (KFSMState st) =>
                {
                    //instructor.PlayEmoteRepeating(instructor.anim_idle_sigh, 5f);
                    //instructor.PlayEmoteRepeating(instructor.anim_idle_wonder, 5f);
                    instructor.PlayEmoteRepeating (instructor.anim_idle_lookAround, 5f);

                    // make ship spin
                    flyTime = 1;
                    flyYPR = new Vector3 (0, 0, 0.1f);
                    FlightGlobals.ActiveVessel.OnFlyByWire += new FlightInputCallback (fly);

                    // find active computer
                    computer = Util.getActiveComputerFromVessel(FlightGlobals.ActiveVessel);
                    if(computer == null) {
                        handleError ();
                    }
                };
                intro1.OnDrawContent = () =>
                {
                    GUILayout.Label ("We are currently orbiting Kerbin at 500km. As you can see there is a second vessel nearby. Both vessels are equipped with the ORDA computer system. Always make sure you install at least one of them on your vessel if you want to use it's functionality.\n\nThe ORDA control panel will always appear in the upper right corner of your screen. This one is currently minimized to declutter your sight. Click on 'ORDA' to restore it.");
                };
                intro1.SetAdvanceCondition ((KFSMState st) => {
                    return !computer.isMinimized (); });
                intro1.OnLeave = (KFSMState st) =>
                {
                    FlightGlobals.ActiveVessel.OnFlyByWire -= new FlightInputCallback (fly);
                };
                Tutorial.AddPage (intro1);
                #endregion
                #region intro2
                intro2 = new TutorialPage ("intro2");
                intro2.windowTitle = formatWindowTitle ("Intro");
                intro2.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                intro2.OnDrawContent = () =>
                {
                    GUILayout.Label ("Good job! Now don't get scared by all the weird buttons... they are on our side!\n\n" +
                        "The ORDA user interface consists of several pages. Because our capsules are so small we can only show one page at a time. The first row of buttons lets you choose between pages.\n\n" +
                        "Go ahead and select 'Autopilot' so we can stabilize your vehicle."
                    );
                };
                intro2.SetAdvanceCondition ((KFSMState st) => {
                    return computer.getCurrentPage () == ORDA_computer.PageType.PAGE_AUTOPILOT; });
                Tutorial.AddPage (intro2);
                #endregion
                #region intro3
                intro3 = new TutorialPage ("intro3");
                intro3.windowTitle = formatWindowTitle ("Intro");
                intro3.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                intro3.OnDrawContent = () =>
                {
                    GUILayout.Label ("Great! The Autopilot provides several modes of operation:\n\n" +
                        "Rate: Maintain angular velocity\n" +
                        "Att: Maintain attitude\n" +
                        "EAC: Enhanced attitude control\n" +
                        "Dock: Assisted / autonomous docking\n\n" +
                        "We want to kill your angular velocity so go ahead and click on 'Rate'"
                    );
                };
                intro3.SetAdvanceCondition ((KFSMState st) => {
                    GNCconfig config = computer.getGNCConfig ();
                    return (config.command == GNC.Command.RATE);
                }
                );
                Tutorial.AddPage (intro3);
                #endregion
                #region rate1
                rate1 = new TutorialPage ("rate1");
                rate1.windowTitle = formatWindowTitle ("Rate");
                rate1.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                rate1.OnDrawContent = () =>
                {
                    GUILayout.Label ("Now we have to tell the autopilot what angular velocity we want it to maintain.\n\n" +
                        "Select 'Zero' to stop the rotation."
                    );
                };
                rate1.SetAdvanceCondition ((KFSMState st) => {
                    GNCconfig config = computer.getGNCConfig ();

                    if (config.command == GNC.Command.RATE &&
                        config.rateMode == GNC.RateMode.ZERO &&
                        computer.vessel.angularVelocity.magnitude < 0.1f) {
                        return true;
                    }
                    return false;
                }
                );
                Tutorial.AddPage (rate1);
                #endregion
                #region att1
                att1 = new TutorialPage ("att1");
                att1.windowTitle = formatWindowTitle ("Attitude");
                att1.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                att1.OnDrawContent = () =>
                {
                    GUILayout.Label ("Great job! Looks like you're getting quite good at pushing buttons.\n\n" +
                        "Now that we have stabilized your vessel, we can take a look at the Attitude mode."
                    );
                };
                att1.SetAdvanceCondition ((KFSMState st) => {
                    GNCconfig config = computer.getGNCConfig ();

                    if (config.command == GNC.Command.ATT) {
                        return true;
                    }
                    return false;
                }
                );
                Tutorial.AddPage (att1);
                #endregion
                #region att2
                att2 = new TutorialPage ("att2");
                att2.windowTitle = formatWindowTitle ("Attitude");
                att2.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                att2.OnDrawContent = () =>
                {
                    GUILayout.Label ("Now we need to tell the autopilot what attitude we want it to maintain.\n\n" +
                        "Go ahead and try out all the different orientations.\n\n" +
                        "REF will orient you to the inertial reference frame. " +
                        "HOLD will maintain the orientation you are in when you activate it. " +
                        "V/N/R will orient you along your orbital velocity/normal/position vectors.\n\n" +
                        "To continue select Prograde (V+)"
                    );

                    GNCconfig config = computer.getGNCConfig ();
                    if (config.command == GNC.Command.ATT && config.attMode == GNC.AttMode.VP) {
                        if (GUILayout.Button ("Next")) {
                            Tutorial.GoToNextPage ();
                        }
                    }
                };
                Tutorial.AddPage (att2);
                #endregion
                #region att3
                att3 = new TutorialPage ("att3");
                att3.windowTitle = formatWindowTitle ("Attitude");
                att3.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                att3.OnDrawContent = () =>
                {
                    GUILayout.Label ("Great! The ship will now point it's nose in the direction of travel. If the engines were working you could now increase the height of your orbit.\n\n" +
                        "I'm sure you noticed that the RP (relative Position) and RV (relative Velocity) buttons are not doing anything.\n\n" +
                        "We need to select a target first before we can use them.\n\n" +
                        "Go to the Target page."
                    );
                };
                att3.SetAdvanceCondition ((KFSMState st) => {
                    return computer.getCurrentPage () == ORDA_computer.PageType.PAGE_TARGET;
                }
                );
                Tutorial.AddPage (att3);
                #endregion
                #region target1
                target1 = new TutorialPage ("target1");
                target1.windowTitle = formatWindowTitle ("Target");
                target1.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                target1.OnDrawContent = () =>
                {
                    string otherVesselName = "???";
                    foreach (Vessel v in FlightGlobals.Vessels) {
                        if (v != FlightGlobals.ActiveVessel) {
                            otherVesselName = v.vesselName;
                        }
                    }

                    GUILayout.Label ("Since our universe currently only contains two Spacecraft this list is pretty clear. The filter on the bottom might help you in the future.\n\n" +
                        "Select the other vessel by clicking on '" + otherVesselName + "' and return the the Autopilot page."
                    );
                };
                target1.SetAdvanceCondition ((KFSMState st) => {

                    if (computer.getCurrentPage () == ORDA_computer.PageType.PAGE_AUTOPILOT &&
                        computer.getTargetVessel () != null) {
                        return true;
                    }
                    return false;
                }
                );
                Tutorial.AddPage (target1);
                #endregion
                #region att4
                att4 = new TutorialPage ("att4");
                att4.windowTitle = formatWindowTitle ("Attitude");
                att4.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                att4.OnDrawContent = () =>
                {
                    GUILayout.Label ("Now that we have a target selected we can use the autopilot to point your nose towards the other vessel.\n\n" +
                        "Go ahead and activate RP+"
                    );
                };
                att4.SetAdvanceCondition ((KFSMState st) => {
                    GNCconfig config = computer.getGNCConfig ();
                    if (config.command == GNC.Command.ATT && config.attMode == GNC.AttMode.RPP) {
                        return true;
                    }
                    return false;
                }
                );
                Tutorial.AddPage (att4);
                #endregion
                #region att5
                att5 = new TutorialPage ("att5");
                att5.windowTitle = formatWindowTitle ("Attitude");
                att5.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                att5.OnDrawContent = () =>
                {
                    GUILayout.Label ("Good job! RP/RV orientations are very useful during Rendezvous, don't forget about them.\n\n" +
                        "The last thing we will try today is the Enhanced Attitude Control (EAC) mode.\n\n" +
                        "Lets activate the EAC Rate mode."
                    );
                };
                att5.SetAdvanceCondition ((KFSMState st) => {
                    GNCconfig config = computer.getGNCConfig ();
                    if (config.command == GNC.Command.EAC && config.eacMode == GNC.EACMode.RATE) {
                        return true;
                    }
                    return false;
                }
                );
                Tutorial.AddPage (att5);
                #endregion
                #region att6
                eac1 = new TutorialPage ("eac1");
                eac1.windowTitle = formatWindowTitle ("Enhanced Attitude Control");
                eac1.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                eac1.OnDrawContent = () =>
                {
                    GUILayout.Label ("In this mode the autopilot will maintain constant angular velocites while you make control inputs and stop any rotation otherwise. That angular velocity can be adjusted in the settings.\n\n" +
                        "Hold q/w/e/a/s/d and see what happens. Use this mode to orient your spacecraft towards the direction of travel to continue.\n\n" +
                        "The Rate+Att mode is very similar, except it will remember and maintain your current orientation when you release all control inputs."
                    );

                    Vector3 vbar = Util.reorder (FlightGlobals.ActiveVessel.orbit.vel, 132).normalized;
                    Vector3 fwd = FlightGlobals.ActiveVessel.ReferenceTransform.TransformDirection (new Vector3 (0, 1, 0));
                    float angle = Vector3.Angle (vbar, fwd);
                    GUILayout.Label ("Error: " + angle.ToString ("F1") + "°");

                    GNCconfig config = computer.getGNCConfig ();
                    if (config.command == GNC.Command.EAC && config.eacMode == GNC.EACMode.RATE && angle < 10) {
                        if (GUILayout.Button ("Next")) {
                            Tutorial.GoToNextPage ();
                        }
                    }
                };
                Tutorial.AddPage (eac1);
                #endregion
                #region off
                off = new TutorialPage ("off");
                off.windowTitle = formatWindowTitle ("Turn it off");
                off.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                off.OnDrawContent = () =>
                {
                    GUILayout.Label ("Nice flying!\n\nNow deactivate the autopilot and minimize the ORDA window (Off & Hide).");
                };
                off.SetAdvanceCondition ((KFSMState st) => {
                    GNCconfig config = computer.getGNCConfig ();
                    if (config.command == GNC.Command.OFF && computer.isMinimized ()) {
                        return true;
                    }
                    return false;
                }
                );
                Tutorial.AddPage (off);
                #endregion

                #region complete
                complete = new TutorialPage ("complete");
                complete.windowTitle = formatWindowTitle ("Complete");
                complete.OnEnter = (KFSMState st) =>
                {
                    instructor.PlayEmote (getHappyEmote ());
                };
                complete.OnDrawContent = () =>
                {
                    GUILayout.Label ("Congratulations! You finished this tutorial.\n\n" +
                        "Keep in mind that the autopilot consumes a lot of power when active and a little amount when in standby. If you run out of power the autopilot will stop working. The maximum power consumption will be " + computer.maxPowerConsumption.ToString("F0") + "/s when you are performing a fully autonomous docking, other modes will require less power. Four RTG's or two medium sized solar panels will deliver enough power for all your autopiloting needs.\n\n" +
                        "Next time we will learn how to dock. You can close the tutorial window now and play around with your ship if you want."
                    );
                    if (GUILayout.Button ("Close tutorial")) {
                        Destroy (this);
                    }
                };
                Tutorial.AddPage (complete);
                #endregion
                #region error
                error = new TutorialPage ("special page 1");
                error.OnEnter = (KFSMState lastSt) =>
                {
                    error.windowTitle = "Error (from " + lastSt.name + ")";
                    instructor.PlayEmote (instructor.anim_false_sadA);
                };
                error.OnDrawContent = () =>
                {
                    GUILayout.Label ("Ooops!\n\nSomething went wrong ...", GUILayout.ExpandHeight (true));
                };
                Tutorial.AddState (error);

                onError = new KFSMEvent ("Something Unplanned");
                onError.updateMode = KFSMUpdateMode.MANUAL_TRIGGER;
                onError.GoToStateOnEvent = error;
                Tutorial.AddEventExcluding (onError, error);
                #endregion

                Tutorial.StartTutorial (welcome);

            } catch (Exception e) {
                print("exception in OnTutorialSetup: " + e.ToString());
            }
        }
 /// <summary>
 /// Add a new event (possible transition) to the finite state machine.
 /// </summary>
 /// <param name="ev">The event to add.</param>
 /// <param name="toStates">The states to add the event to. The event can only be triggered when
 /// the machine is in one of these states.</param>
 public extern void AddEvent(KFSMEvent ev, params KFSMState[] toStates);
 /// <summary>
 /// Add an event (possible transition) to this state.
 /// </summary>
 /// <param name="ev">The event to add.</param>
 public extern void AddEvent(KFSMEvent ev);
        public void SetupFSM()
        {
            fsm = new KerbalFSM();

            st_stowed = new KFSMState("stowed");
            fsm.AddState(st_stowed);
            st_stowed_locked = new KFSMState("stowed_locked");
            fsm.AddState(st_stowed_locked);
            st_deploying = new KFSMState("deploying");
            fsm.AddState(st_deploying);
            st_deployed = new KFSMState("deployed");
            fsm.AddState(st_deployed);
            st_deployed_locked = new KFSMState("deployed_locked");
            fsm.AddState(st_deployed_locked);
            st_stowing = new KFSMState("stowing");
            fsm.AddState(st_stowing);

            on_deploy = new KFSMEvent("on_deploy")
            {
                GoToStateOnEvent = st_deploying
            };
            fsm.AddEvent(on_deploy, st_stowed, st_stowing);
            on_stow = new KFSMEvent("on_stow")
            {
                GoToStateOnEvent = st_stowing
            };
            fsm.AddEvent(on_stow, st_deployed, st_deploying);
            on_deployed = new KFSMEvent("on_deployed")
            {
                GoToStateOnEvent = st_deployed, updateMode = KFSMUpdateMode.UPDATE, OnCheckCondition = (st) => (deployAnimator?.animTime ?? 1) == 1
            };
            fsm.AddEvent(on_deployed, st_deploying);
            on_stowed = new KFSMEvent("on_stowed")
            {
                GoToStateOnEvent = st_stowed, updateMode = KFSMUpdateMode.UPDATE, OnCheckCondition = (st) => (deployAnimator?.animTime ?? 0) == 0
            };
            fsm.AddEvent(on_stowed, st_stowing);
            on_lock_deployed = new KFSMEvent("on_lock_deployed")
            {
                GoToStateOnEvent = st_deployed_locked, OnEvent = DisableAnimation
            };
            fsm.AddEvent(on_lock_deployed, st_deployed);
            on_unlock_deployed = new KFSMEvent("on_unlock_deployed")
            {
                GoToStateOnEvent = st_deployed, OnEvent = EnableAnimation
            };
            fsm.AddEvent(on_unlock_deployed, st_deployed_locked);
            on_lock_stowed = new KFSMEvent("on_lock_stowed")
            {
                GoToStateOnEvent = st_stowed_locked, OnEvent = DisableAnimation
            };
            fsm.AddEvent(on_lock_stowed, st_stowed);
            on_unlock_stowed = new KFSMEvent("on_unlock_stowed")
            {
                GoToStateOnEvent = st_stowed, OnEvent = EnableAnimation
            };
            fsm.AddEvent(on_unlock_stowed, st_stowed_locked);

            //fsm.OnStateChange = (fromSt, toSt, e) => UnityEngine.Debug.LogFormat("Moved from {0} to {1} by {2}", fromSt.name, toSt.name, e.name);

            CustomizeFSM();
        }
 /// <summary>
 /// Whether the given event can be triggered from this state. An event must be added to a state before
 /// it can be triggered from that state.
 /// </summary>
 /// <param name="ev">The event to check.</param>
 /// <returns>Whether the event can be triggered from this state.</returns>
 public extern bool IsValid(KFSMEvent ev);
示例#35
0
 /// <summary>
 /// Add a new event (possible transition) to the finite state machine.
 /// </summary>
 /// <param name="ev">The event to add.</param>
 /// <param name="excStates">A list of states *not* to add the event to. The event can only be triggered
 /// when the machine is *not* in one of these states.</param>
 public extern void AddEventExcluding(KFSMEvent ev, params KFSMState[] excStates);
 public void FlightGeometryUpdate()
 {
     if (deployEvent == null)
     {
         Debug.Log("Update fairing event");
         FieldInfo[] fields = fairing.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
         deployEvent = (KFSMEvent)fields[31].GetValue(fairing);
         deployEvent.OnEvent += delegate { FairingDeployGeometryUpdate(); };
     }
 }
示例#37
0
        public void Hook(KerbalEVA peva)
        {
            if (ishooked)
            {
                throw new Exception("HookedKerbalFSMState already hooked.");
            }
            ishooked = true;
            eva      = peva;

            ReflectedMembers.Initialize();

            //******************************************
            //Add the original events back to our state.
            for (int i = 0; i < originalstate.StateEvents.Count; ++i)
            {
                AddEvent(originalstate.StateEvents [i]);
            }

            //*******************************************
            //Replace references to our state in the FSM.
            List <KFSMState> States;
            KFSMState        currentState;
            KFSMState        lastState;

            States       = (List <KFSMState>)ReflectedMembers.fsm_states.GetValue(eva.fsm);
            currentState = (KFSMState)ReflectedMembers.fsm_currentstate.GetValue(eva.fsm);
            lastState    = (KFSMState)ReflectedMembers.fsm_laststate.GetValue(eva.fsm);

            for (int i = 0; i < States.Count; ++i)
            {
                if (States [i] == originalstate)
                {
                    States [i] = this;
                    break;
                }
            }
            if (currentState == originalstate)
            {
                ReflectedMembers.fsm_currentstate.SetValue(eva.fsm, this);
            }
            if (lastState == originalstate)
            {
                ReflectedMembers.fsm_laststate.SetValue(eva.fsm, this);
            }

            //*******************************************
            //Replace references to our state in the EVA.
            for (int i = 0; i < ReflectedMembers.eva_type_kfsmstate.Count; ++i)
            {
                System.Reflection.FieldInfo f = ReflectedMembers.eva_type_kfsmstate [i];
                KFSMState refval = f.GetValue(eva) as KFSMState;
                if (refval == null)
                {
                    continue;
                }
                if (refval == originalstate)
                {
                    f.SetValue(eva, this);
                }
            }

            //******************************************
            //Replace references to our state in events.
            for (int i = 0; i < States.Count; ++i)
            {
                List <KFSMEvent> thisstateevents = States [i].StateEvents;
                for (int j = 0; j < thisstateevents.Count; ++j)
                {
                    KFSMEvent thisevent = thisstateevents [j];

                    if (thisevent.GoToStateOnEvent == originalstate)
                    {
                        thisevent.GoToStateOnEvent = this;
                    }
                }
            }
        }
示例#38
0
        public RecyclerFSM(ExRecycler recycler)
        {
            this.recycler = recycler;

            state_off         = new KFSMState("Off");
            state_off.OnEnter = onenter_off;

            state_idle         = new KFSMState("Idle");
            state_idle.OnEnter = onenter_idle;
            state_idle.OnLeave = onleave_idle;

            state_captured_idle         = new KFSMState("Captured Idle");
            state_captured_idle.OnEnter = onenter_captured_idle;
            state_captured_idle.OnLeave = onleave_captured_idle;

            state_processing_part         = new KFSMState("Processing Part");
            state_processing_part.OnEnter = onenter_processing_part;
            state_processing_part.OnLeave = onleave_processing_part;

            state_transferring_resources               = new KFSMState("Transferring Resources");
            state_transferring_resources.OnEnter       = onenter_transferring_resources;
            state_transferring_resources.OnLeave       = onleave_transferring_resources;
            state_transferring_resources.OnFixedUpdate = onupdate_transferring_resources;

            event_enabled = new KFSMEvent("Enabled");
            event_enabled.GoToStateOnEvent = state_idle;
            event_enabled.OnCheckCondition = check_enabled;
            event_enabled.updateMode       = KFSMUpdateMode.FIXEDUPDATE;
            event_enabled.OnEvent          = delegate { LogEvent("Enabled"); };

            event_disabled = new KFSMEvent("Disabled");
            event_disabled.GoToStateOnEvent = state_off;
            event_disabled.OnCheckCondition = check_disabled;
            event_disabled.updateMode       = KFSMUpdateMode.FIXEDUPDATE;
            event_disabled.OnEvent          = delegate { LogEvent("Disabled"); };

            event_enter_field = new KFSMEvent("Enter Field");
            event_enter_field.GoToStateOnEvent = state_captured_idle;
            event_enter_field.updateMode       = KFSMUpdateMode.MANUAL_TRIGGER;
            event_enter_field.OnEvent          = delegate { LogEvent("Enter Field"); };

            event_part_selected = new KFSMEvent("Part Selected");
            event_part_selected.GoToStateOnEvent = state_processing_part;
            event_part_selected.OnCheckCondition = check_part_selected;
            event_part_selected.updateMode       = KFSMUpdateMode.FIXEDUPDATE;
            event_part_selected.OnEvent          = delegate { LogEvent("Part Selected"); };

            event_resources_collected = new KFSMEvent("Resources Collected");
            event_resources_collected.GoToStateOnEvent = state_transferring_resources;
            event_resources_collected.OnCheckCondition = check_resources_collected;
            event_resources_collected.updateMode       = KFSMUpdateMode.FIXEDUPDATE;
            event_resources_collected.OnEvent          = delegate { LogEvent("Resources Collected"); };

            event_resources_transferred = new KFSMEvent("Resources Transferred");
            event_resources_transferred.GoToStateOnEvent = state_captured_idle;
            event_resources_transferred.OnCheckCondition = check_resources_transferred;
            event_resources_transferred.updateMode       = KFSMUpdateMode.FIXEDUPDATE;
            event_resources_transferred.OnEvent          = delegate { LogEvent("Resources Transferred"); };

            event_parts_exhausted = new KFSMEvent("Parts Exhausted");
            event_parts_exhausted.GoToStateOnEvent = state_idle;
            event_parts_exhausted.OnCheckCondition = check_parts_exhausted;
            event_parts_exhausted.updateMode       = KFSMUpdateMode.FIXEDUPDATE;
            event_parts_exhausted.OnEvent          = delegate { LogEvent("Parts Exhausted"); };

            fsm = new RecFSM();
            fsm.AddState(state_off);
            fsm.AddState(state_idle);
            fsm.AddState(state_captured_idle);
            fsm.AddState(state_processing_part);
            fsm.AddState(state_transferring_resources);

            fsm.AddEvent(event_enabled, new KFSMState [] { state_off });
            fsm.AddEvent(event_disabled, new KFSMState [] { state_idle });
            fsm.AddEvent(event_enter_field, new KFSMState [] { state_idle });
            fsm.AddEvent(event_part_selected, new KFSMState [] { state_captured_idle });
            fsm.AddEvent(event_resources_collected, new KFSMState [] { state_processing_part });
            fsm.AddEvent(event_resources_transferred, new KFSMState [] { state_transferring_resources });
            fsm.AddEvent(event_parts_exhausted, new KFSMState [] { state_captured_idle });

            start_state = state_off;


            recycle_parts = new HashSet <uint> ();
        }