/// <summary>
        /// All callout logic should be done here.
        /// </summary>
        public override void Process()
        {
            base.Process();

            GameFiber.StartNew(delegate
            {
                {
                    //A keys converter is used to convert a string to a key.
                    KeysConverter kc = new KeysConverter();

                    //We create two variables: one is a System.Windows.Keys, the other is a string.
                    Keys EndCalloutKey;


                    //Use a try/catch, because reading values from files is risky: we can never be sure what we're going to get and we don't want our plugin to crash.
                    try
                    {
                        //We assign myKeyBinding the value of the string read by the method getMyKeyBinding(). We then use the kc.ConvertFromString method to convert this to a key.
                        //If the string does not represent a valid key (see .ini file for a link) an exception is thrown. That's why we need a try/catch.
                        EndCalloutKey = (Keys)kc.ConvertFromString(getEndKey());
                    }
                    //If there was an error reading the values, we set them to their defaults. We also let the user know via a notification.
                    catch
                    {
                        EndCalloutKey = Keys.End;
                        Game.DisplayNotification("There was an error reading the .ini file. Setting defaults...");
                    }

                    if (Game.IsKeyDown(EndCalloutKey))
                    {
                        Game.DisplayNotification("The ~y~Public Disorder~w~ is ~g~Code 4~w~.");
                        Functions.PlayScannerAudio("WE_ARE_CODE_4 NO_FURTHER_UNITS_REQUIRED");
                        A1.Dismiss();

                        this.End();
                    }
                }
            }, "keyCheckerForPublicDisorder");

            if (A1.IsDead)
            {
                End();
            }

            //If the player is driving to the scene, and their distance to the scene is less than 15, start the callout's logic.
            if (state == EDisorderState.EnRoute && Game.LocalPlayer.Character.Position.DistanceTo(spawnPoint) <= 15)
            {
                //Set the player as on scene
                state = EDisorderState.OnScene;

                //Start the callout's logic. You can paste the logic from StartMuggingScenario straight into here, but I don't, since I like it to look clean, and place any long methods towards the bottom of the class.
                StartDisorderLogic();
            }

            //If the state is DecisionMade(The aggressor already decided what random outcome to execute), and the pursuit isn't running anymore, end the callout.
            if (state == EDisorderState.DecisionMade && !Functions.IsPursuitStillRunning(pursuit))
            {
                this.End();
            }
        }
        /// <summary>
        /// The method that contains the callout's logic
        /// </summary>
        public void StartDisorderLogic()
        {
            //ALWAYS START A NEW GAME FIBER IF YOU'RE GOING TO USE GameFiber.Sleep, DON'T SLEEP THE MAIN FIBER.
            GameFiber.StartNew(delegate
            {
                //Create the pursuit
                pursuit = Functions.CreatePursuit();

                //Set the state to decision made, since the outcome is chosen.
                state = EDisorderState.DecisionMade;

                int r = new Random().Next(1, 3);

                //Execute one of the random outcomes
                if (r == 1)
                {
                    if (new Random().Next(1, 3) == 2)
                    {
                        //The aggressor attacks the player.
                        NativeFunction.CallByName <uint>("TASK_COMBAT_PED", A1, Game.LocalPlayer.Character, 0, 1);

                        //We wait 4.5 seconds before adding the ped to a pursuit, since as soon as we add the aggressor to a pursuit, LSPDFR takes over the AI, and they won't attack the player anymore. They'll flee instead.
                        GameFiber.Sleep(4500);
                    }

                    //Dismiss the aggressor from our plugin
                    A1.Dismiss();

                    //Add the aggressor to a pursuit
                    Functions.AddPedToPursuit(pursuit, A1);

                    var persona = Functions.GetPersonaForPed(A1);
                    Functions.SetPersonaForPed(A1, new Persona(A1, persona.Gender, persona.BirthDay, persona.Citations, persona.Forename, persona.Surname, persona.LicenseState, persona.TimesStopped, true, false, false));

                    //Dispatch a backup unit.
                    Functions.RequestBackup(Game.LocalPlayer.Character.Position, LSPD_First_Response.EBackupResponseType.Pursuit, LSPD_First_Response.EBackupUnitType.LocalUnit);
                }
                else if (r == 2)
                {
                    GameFiber.StartNew(delegate
                    {
                        GameFiber.Wait(5000);

                        Game.DisplayHelp("You can End the callout by pressing your End Callout key.");
                    }, "displayNotificationPublicDisorder");
                }
            });
        }
        /// <summary>
        /// Called when the player accepts the callout
        /// </summary>
        /// <returns></returns>
        public override bool OnCalloutAccepted()
        {
            //Set the player as en route to the scene
            state = EDisorderState.EnRoute;

            //Attach a blip to the Aggressor, so the player knows where to go, and can find the aggressor if he flees
            B1 = A1.AttachBlip();

            A1.BlockPermanentEvents = true;

            //Display a message to let the user know that the callout was accepted.
            Game.DisplaySubtitle("Get to the ~y~scene~w~.", 6500);
            B1.EnableRoute(Color.Yellow);
            B1.Color = Color.Yellow;

            // Make the ped walk as drunk
            //AnimationSet animSet = new AnimationSet("move_m@drunk@verydrunk");
            //animSet.LoadAndWait();
            //A1.MovementAnimationSet = animSet;

            // Playing an animation
            // The list of hyper links on the Rage Anim list page is a list of Anim Dictionaries
            // Each one has a set of animation names underneath it
            // "amb@world_human_bum_standing@drunk@idle_a" is the dictionary name
            // And "idle_a" is the anim name
            // I'm not exactly sure how blend speed (not anim speed, but apparently its the speed that the anim blends in) affects anything, but I just set it to 1
            // Anim flags tells GTA to loop the anim, or ragdoll the ped when something hits it, etc.
            // The object browser or Rage docs can tell you all the AnimationFlags
            //A1.Tasks.PlayAnimation(new AnimationDictionary("amb@world_human_bum_standing@drunk@idle_a"), "idle_a", 1f, AnimationFlags.RagdollOnCollision);

            if (genderState == EGenderState.FemaleState && A1.IsFemale)
            {
                A1.Tasks.PlayAnimation(new AnimationDictionary("amb@world_human_partying@female@partying_beer@base"), "base", 1f, AnimationFlags.Loop);
            }
            else if (genderState == EGenderState.MaleState && A1.IsMale)
            {
                AnimationSet animSet = new AnimationSet("move_m@drunk@verydrunk");
                animSet.LoadAndWait();
                A1.MovementAnimationSet = animSet;
                A1.Tasks.PlayAnimation(new AnimationDictionary("amb@world_human_bum_standing@drunk@idle_a"), "idle_a", 1f, AnimationFlags.Loop);
            }

            return(base.OnCalloutAccepted());
        }