Beispiel #1
0
        /// <summary>
        /// Saves the character to application memory.
        /// </summary>
        public override SMItem ProduceCorpse()
        {
            // Create the corpse
            SMItem corpse = SMItemFactory.Get("Misc", "Corpse");

            corpse.ItemName = this.GetFullName() + " Corpse";

            // If it's an animal or some such, create the destroyed output elements.
            if (this.DestroyedOutput != null)
            {
                corpse.DestroyedOutput = this.DestroyedOutput;
            }

            // Previous item family type
            corpse.PreviousItemFamily = this.FamilyType;

            // Create the "held items" list ready for transferring items to the corpse.
            corpse.HeldItems = new List <SMItem>();

            if (this.Slots != null)
            {
                foreach (SMSlot sms in this.Slots)
                {
                    if (!sms.isEmpty())
                    {
                        corpse.HeldItems.Add(sms.EquippedItem);
                    }
                }
            }

            // TODO Add clothing / armour items to the held items list ready for looting.

            return(corpse);
        }
Beispiel #2
0
        /// <summary>
        /// Finds an item in a list by matching the items id, name or family to a given identifier.
        /// </summary>
        /// <returns>The item from the list.</returns>
        /// <param name="list">List od items to look search.</param>
        /// <param name="itemIdentifier">Item identifier.</param>
        private static SMItem FindItemInList(List <SMItem> list, string itemIdentifier)
        {
            string ciIdentifier = itemIdentifier.ToLower();

            SMItem foundItem = null;

            foundItem = list.FirstOrDefault((SMItem item) => item.ItemID == itemIdentifier);

            if (foundItem == null)
            {
                foundItem = list.FirstOrDefault((SMItem item) => item.ItemName.ToLower() == ciIdentifier);
            }

            if (foundItem == null)
            {
                foundItem = list.FirstOrDefault((SMItem item) => item.PluralName.ToLower() == ciIdentifier);
            }

            if (foundItem == null)
            {
                foundItem = list.FirstOrDefault((SMItem item) => item.ItemFamily.ToLower() == ciIdentifier);
            }

            if (foundItem == null)
            {
                foundItem = list.FirstOrDefault((SMItem item) => item.GetPluralFamilyName().ToLower() == ciIdentifier);
            }

            if (foundItem == null)
            {
                foundItem = list.FirstOrDefault((SMItem item) => item.ItemType.ToLower() == ciIdentifier);
            }

            return(foundItem);
        }
Beispiel #3
0
        /// <summary>
        /// Removes an item from a list recursivly looking through containers within containers.
        /// </summary>
        /// <returns><c>true</c>, if the item was removed, <c>false</c> otherwise.</returns>
        /// <param name="list">List to remove item from.</param>
        /// <param name="itemIdentifier">Item identifier.</param>
        private static bool RemoveItemFromListRecursive(List <SMItem> list, string itemIdentifier)
        {
            SMItem foundItem = FindItemInList(list, itemIdentifier);

            if (foundItem != null)
            {
                list.Remove(foundItem);
                return(true);
            }

            foreach (SMItem item in list)
            {
                // TODO account for locked containers

                if (item.CanHoldOtherItems() && item.HeldItems != null)
                {
                    foundItem = FindItemInListRecursive(item.HeldItems, itemIdentifier);
                    if (foundItem != null)
                    {
                        item.HeldItems.Remove(foundItem);
                        return(true);
                    }
                }
            }

            return(false);
        }
        /// <summary>
        /// Gets a new general item based on the spec provided.
        /// </summary>
        /// <param name="guid">A guid for the new item.</param>
        /// <param name="jsonSpec">The spec of the item as a json string.</param>
        /// <returns>An SMItem instance.</returns>
        private static SMItem GetItem(string guid, string jsonSpec)
        {
            SMItem item = JsonConvert.DeserializeObject <SMItem>(jsonSpec);

            item.ItemID = guid;

            return(item);
        }
Beispiel #5
0
        /// <summary>
        /// Puts an item in a container, initialising the containers HeldItems property to an new list if required.
        /// </summary>
        /// <param name="item">The item to put.</param>
        /// <param name="container">The container to put in.</param>
        public static void PutItemInContainer(SMItem item, SMItem container)
        {
            if (container.HeldItems == null)
            {
                container.HeldItems = new List <SMItem>();
            }

            container.HeldItems.Add(item);
        }
Beispiel #6
0
        /// <summary>
        /// Removes an item from the room, recursively looks through containers for the item if required.
        /// </summary>
        /// <param name="item">SMItem to remove.</param>
        public void RemoveItem(SMItem item)
        {
            if (this.RoomItems != null)
            {
                SMItemHelper.RemoveItemFromList(this.RoomItems, item.ItemID);
            }

            this.SaveToApplication();
        }
Beispiel #7
0
        /// <summary>
        /// Adds an item to the room, so any user can collect it.
        /// </summary>
        /// <param name="item">Item.</param>
        public void AddItem(SMItem item)
        {
            if (this.RoomItems == null)
            {
                this.RoomItems = new List <SMItem>();
            }

            this.RoomItems.Add(item);
            this.SaveToApplication();
        }
Beispiel #8
0
        /// <summary>
        /// Gets the id of an item in the room by its name
        /// </summary>
        /// <param name="itemName"></param>
        /// <returns>The ItemID</returns>
        public string GetRoomItemID(string itemName)
        {
            SMItem item = this.GetItemByName(itemName);

            if (item != null)
            {
                return(item.ItemID);
            }

            return(null);
        }
Beispiel #9
0
        /// <summary>
        /// Gets a container item from the room matching a given identifier.
        /// </summary>
        /// <param name="identifier">The container identifier.</param>
        /// <returns>The container if found otherwise null.</returns>
        public SMItem GetRoomContainer(string identifier)
        {
            SMItem item = SMItemHelper.GetItemFromList(this.RoomItems, identifier);

            if (item == null || !item.CanHoldOtherItems())
            {
                return(null);
            }

            return(item);
        }
Beispiel #10
0
        /// <summary>
        /// Checks if this item contains a specified other item.
        /// </summary>
        /// <param name="item">The item to test for inside this.</param>
        /// <returns>Bool indicating of the item is inside this.</returns>
        public bool Contains(SMItem item)
        {
            if (this.HeldItems != null && this.HeldItems.Any())
            {
                SMItem foundItem = SMItemHelper.GetItemFromList(this.HeldItems, item.ItemID);

                return(foundItem == null ? false : true);
            }

            return(false);
        }
Beispiel #11
0
        /// <summary>
        /// Checks if a given item matches a given string identifier (id, name, family).
        /// </summary>
        /// <returns><c>true</c>, if the identifier matches the itemed, <c>false</c> otherwise.</returns>
        /// <param name="item">SMItem.</param>
        /// <param name="identifier">String identifier (id, name, family).</param>
        public static bool ItemMatches(SMItem item, string identifier)
        {
            if (item.ItemID == identifier ||
                item.ItemName.ToLower() == identifier.ToLower() ||
                item.ItemFamily.ToLower() == identifier.ToLower() ||
                item.ItemType.ToLower() == identifier.ToLower())
            {
                return(true);
            }

            return(false);
        }
Beispiel #12
0
        /// <summary>
        /// Determines if the item can hold a given other item by checking the properties of both items and the available
        /// capacity of this item.
        /// </summary>
        /// <param name="item">The item to be put inside this.</param>
        /// <returns>Bool indicating if the item can be put inside this.</returns>
        public bool CanHoldItem(SMItem item)
        {
            if (this.CanHoldOtherItems() && this.CanHoldItemByFamily(item))
            {
                if (SMItemHelper.GetItemAvailbleCapacity(this) >= item.ItemSize)
                {
                    return(true);
                }
            }

            return(false);
        }
Beispiel #13
0
 /// <summary>
 /// Attack an item
 /// </summary>
 /// <param name="attackingCharacter">The attacking character</param>
 /// <param name="targetItem">The target item</param>
 public static void Attack(SMCharacter attackingCharacter, SMItem targetItem)
 {
     // Check that the target has hitpoints
     if (targetItem.HitPoints > 0)
     {
         // Use the skill
         attackingCharacter.UseSkill(GetSkillToUse(attackingCharacter), targetItem.ItemName, true);
     }
     else             // Report that the target can not be found
     {
         attackingCharacter.sendMessageToPlayer(ResponseFormatterFactory.Get().General($"{targetItem.ItemName} can not be found"));
     }
 }
Beispiel #14
0
        /// <summary>
        /// Checks if a given item can be equipped, based on its type and the slots status
        /// </summary>
        /// <returns><c>true</c>, if the iten can be equipped, <c>false</c> otherwise.</returns>
        /// <param name="item">Item.</param>
        public bool canEquipItem(SMItem item)
        {
            if (this.isEmpty())
            {
                if (this.AllowedTypes.Contains("any"))
                {
                    return(true);
                }

                return(this.AllowedTypes.Contains(item.ItemType));
            }

            return(false);
        }
Beispiel #15
0
        /// <summary>
        /// Gets the item weight, including any items it contains.
        /// </summary>
        /// <returns>The item weight.</returns>
        /// <param name="item">Item to get the weight for.</param>
        public static int GetItemWeight(SMItem item)
        {
            int weight = item.ItemWeight;

            if (item.CanHoldOtherItems() && item.HeldItems != null)
            {
                foreach (SMItem smi in item.HeldItems)
                {
                    weight += GetItemWeight(smi);
                }
            }

            return(weight);
        }
Beispiel #16
0
        /// <summary>
        /// Checks if a given item matches a given string identifier (id, name, family).
        /// </summary>
        /// <returns><c>true</c>, if the identifier matches the itemed, <c>false</c> otherwise.</returns>
        /// <param name="item">SMItem.</param>
        /// <param name="identifier">String identifier (id, name, family).</param>
        public static bool ItemMatches(SMItem item, string identifier)
        {
            string ciIdentifier = identifier.ToLower();

            if (item.ItemID == identifier ||
                item.ItemName.ToLower() == ciIdentifier ||
                item.PluralName.ToLower() == ciIdentifier ||
                item.ItemFamily.ToLower() == ciIdentifier ||
                item.GetPluralFamilyName().ToLower() == ciIdentifier ||
                item.ItemType.ToLower() == ciIdentifier)
            {
                return(true);
            }

            return(false);
        }
Beispiel #17
0
        /// <summary>
        /// Counts the number of items in a given container that match a given id, name or family.
        /// </summary>
        /// <param name="container">The countainer to look in.</param>
        /// <param name="itemIdentiifier">The id, name or family to match.</param>
        /// <returns>The count of matching items.</returns>
        public static int CountItemsInContainer(SMItem container, string itemIdentiifier)
        {
            int count = 0;

            if (container.HeldItems != null && container.HeldItems.Any())
            {
                foreach (SMItem item in container.HeldItems)
                {
                    if (ItemMatches(item, itemIdentiifier))
                    {
                        count++;
                    }
                }
            }

            return(count);
        }
Beispiel #18
0
        /// <summary>
        /// Calculates the used capacity of a container.
        /// </summary>
        /// <param name="item">The container to look at.</param>
        /// <returns>The containers used capacity.</returns>
        public static int GetItemUsedCapacity(SMItem item)
        {
            if (!item.CanHoldOtherItems())
            {
                return(0);
            }

            int used = 0;

            if (item.HeldItems.Any())
            {
                foreach (SMItem smi in item.HeldItems)
                {
                    used += GetItemWeight(smi);
                }
            }

            return(used);
        }
Beispiel #19
0
        public SMItem GetProducedItem()
        {
            SMItem smi = null;

            // Get the right path, and work out if the file exists.
            string path = FilePathSystem.GetFilePath("Objects", this.GetProducedItemName());

            // Check if the character exists..
            if (File.Exists(path))
            {
                using (StreamReader r = new StreamReader(path))
                {
                    // Get the character from the json string
                    string json = r.ReadToEnd();
                    smi = JsonConvert.DeserializeObject <SMItem>(json);
                }
            }

            return(smi);
        }
Beispiel #20
0
        /// <summary>
        /// Searches a specified container recursively to find a container matching a given identifier.
        /// Will return the specified container itself if the identifier matches.
        /// </summary>
        /// <param name="identifier">The identifier for the container to search for.</param>
        /// <param name="container">The container to search in.</param>
        /// <returns>An SMItem object representing the container matching the idetifier.</returns>
        public static SMItem FindContainerInContainerRecursive(string identifier, SMItem container)
        {
            SMItem foundContainer = ItemMatches(container, identifier) ? container : null;

            if (foundContainer == null)
            {
                foreach (SMItem innerItem in container.HeldItems)
                {
                    if (innerItem.CanHoldOtherItems())
                    {
                        if (ItemMatches(innerItem, identifier))
                        {
                            return(innerItem);
                        }

                        return(FindContainerInContainerRecursive(identifier, innerItem));
                    }
                }
            }

            return(foundContainer);
        }
Beispiel #21
0
        /// <summary>
        /// Removes anSMItem from a list of items based on a given item identifier.
        /// </summary>
        /// <returns><c>true</c>, if the was removed, <c>false</c> otherwise.</returns>
        /// <param name="list">List of SMItems to remove from.</param>
        /// <param name="itemIdentifier">Item identifier (id, name, family).</param>
        /// <param name="recursive">If set to <c>true</c> recursive look through container items in the list until
        /// one item is removed.</param>
        public static bool RemoveItemFromList(List <SMItem> list, string itemIdentifier, bool recursive = true)
        {
            if (list == null)
            {
                return(false);
            }

            if (recursive == true)
            {
                return(RemoveItemFromListRecursive(list, itemIdentifier));
            }

            SMItem itemToRemove = GetItemFromList(list, itemIdentifier, false);

            if (itemToRemove != null)
            {
                list.Remove(itemToRemove);
                return(true);
            }

            return(false);
        }
Beispiel #22
0
        /// <summary>
        /// Searches a specified container recursively to find a suitable container to place a given item in.
        /// Will return the specified container itself if the item can go directly in to it.
        /// </summary>
        /// <param name="item">The item to find a container for.</param>
        /// <param name="container">The container to search in.</param>
        /// <returns>An SMItem object the item can go in or null.</returns>
        public static SMItem FindContainerForItemRecursive(SMItem item, SMItem container)
        {
            SMItem foundContainer = container.CanHoldItem(item) ? container : null;

            if (foundContainer == null)
            {
                foreach (SMItem innerItem in container.HeldItems)
                {
                    if (innerItem.CanHoldOtherItems() && innerItem.HeldItems != null)
                    {
                        foundContainer = FindContainerForItemRecursive(item, innerItem);

                        if (foundContainer != null)
                        {
                            return(foundContainer);
                        }
                    }
                }
            }

            return(foundContainer);
        }
Beispiel #23
0
        public static string GetSkillToUse(SMCharacter attackingCharacter)
        {
            string skillToUse = "Brawl";

            if (!attackingCharacter.AreHandsEmpty())
            {
                // Get the equipped item from the character if any
                SMItem smi = attackingCharacter.GetEquippedItem();
                skillToUse = "Basic Attack";

                if ((smi != null) && (smi.RequiredSkills != null))
                {
                    // Check the player has the required skills
                    bool hasAllRequiredSkills = true;
                    bool isFirst = true;

                    foreach (SMRequiredSkill smrs in smi.RequiredSkills)
                    {
                        if (hasAllRequiredSkills)
                        {
                            hasAllRequiredSkills = attackingCharacter.HasRequiredSkill(smrs.SkillName, smrs.SkillLevel);
                            if (isFirst)
                            {
                                skillToUse = smrs.SkillName;
                            }
                        }
                    }

                    // If the player has all the required skills
                    if (!hasAllRequiredSkills)
                    {
                        // Tell the player they can't really wield that item.
                        attackingCharacter.sendMessageToPlayer(ResponseFormatterFactory.Get().General($"You are not skilled with the {smi.ItemFamily}, practicing gives you a chance to increase your skill"));
                    }
                }
            }
            return(skillToUse);
        }
Beispiel #24
0
        /// <summary>
        /// Gets the items listing of a given container in a string ready for outputting.
        /// </summary>
        /// <param name="container">Container SMItem to get the listings for.</param>
        /// <returns>Containers item listings.</returns>
        public static string GetContainerContents(SMItem container)
        {
            // Return null it not a container
            if (!container.CanHoldOtherItems())
            {
                return(null);
            }

            // If the container is empty
            if (container.HeldItems == null || !container.HeldItems.Any())
            {
                return(OutputFormatterFactory.Get().Italic("Empty"));
            }

            // Get list of item counts
            // TODO bring this functionality into this class
            List <ItemCountObject> lines = SMItemUtils.GetItemCountList(container.HeldItems);

            string output = "";

            foreach (ItemCountObject line in lines)
            {
                string itemDetails = $"{line.Count} x ";

                if (line.Count > 1)
                {
                    itemDetails += line.PluralName;
                }
                else
                {
                    itemDetails += line.SingularName;
                }

                output += OutputFormatterFactory.Get().General(itemDetails);
            }

            return(output);
        }
Beispiel #25
0
        /// <summary>
        /// Finds an item in a list recursivly looking through containers within containers.
        /// </summary>
        /// <returns>The item from the list.</returns>
        /// <param name="list">List.</param>
        /// <param name="itemIdentifier">Item identifier.</param>
        private static SMItem FindItemInListRecursive(List <SMItem> list, string itemIdentifier)
        {
            SMItem foundItem = FindItemInList(list, itemIdentifier);

            if (foundItem == null)
            {
                foreach (SMItem item in list)
                {
                    // TODO account for locked containers

                    if (item.CanHoldOtherItems() && item.HeldItems != null)
                    {
                        foundItem = FindItemInListRecursive(item.HeldItems, itemIdentifier);
                        if (foundItem != null)
                        {
                            return(foundItem);
                        }
                    }
                }
            }

            return(foundItem);
        }
Beispiel #26
0
        /// <summary>
        /// Determines if the item can hold a given itme based on the properties of both items.
        /// </summary>
        /// <param name="item">The item that is to be put in this item.</param>
        /// <returns>Bool indicating if the item can be put in this item.</returns>
        public bool CanHoldItemByFamily(SMItem item)
        {
            if (!this.CanHoldOtherItems())
            {
                return(false);
            }

            if (this.CanHoldFamilies != null && this.CanHoldFamilies.Any())
            {
                if (this.CanHoldFamilies.Contains("any"))
                {
                    return(true);
                }

                if (CanHoldFamilies.FirstOrDefault(s => s.ToLower() == item.ItemFamily.ToLower()) != null)
                {
                    return(true);
                }

                return(false);
            }

            return(true);
        }
Beispiel #27
0
        /// <summary>
        /// Calculates the available capacity of a container.
        /// </summary>
        /// <param name="item">The container to look at.</param>
        /// <returns>The containers available capacity.</returns>
        public static int GetItemAvailbleCapacity(SMItem item)
        {
            if (!item.CanHoldOtherItems())
            {
                return(0);
            }

            if (item.HeldItems == null || !item.HeldItems.Any())
            {
                return(item.ItemCapacity);
            }

            int used = 0;

            if (item.HeldItems.Any())
            {
                foreach (SMItem smi in item.HeldItems)
                {
                    used += GetItemWeight(smi);
                }
            }

            return(item.ItemCapacity - used);
        }
Beispiel #28
0
        public static void StartAnNPCReactionCheck(SMNPC npc, string actionType, SMCharacter invokingCharacter, SMItem itemIn = null)
        {
            HttpContext ctx = HttpContext.Current;

            Thread npcReactionThread = new Thread(new ThreadStart(() =>
            {
                HttpContext.Current = ctx;
                npc.RespondToAction("PlayerCharacter.GivesItemToThem", invokingCharacter, itemIn);
            }));

            npcReactionThread.Start();
        }
Beispiel #29
0
        public void RespondToAction(string actionType, SMCharacter invokingCharacter, SMItem itemIn = null)
        {
            // Get a list of characters that respond to this action type in the room
            List <NPCResponses> listToChooseFrom = NPCResponses.FindAll(npcr => npcr.ResponseType == actionType);

            // If there are some responses for this character for the actionType
            if (listToChooseFrom != null)
            {
                // If there is more than one of the item randomise the list
                if (listToChooseFrom.Count > 1)
                {
                    listToChooseFrom = listToChooseFrom.OrderBy(item => new Random().Next()).ToList();
                }

                // Loop around until a response is selected
                bool responseSelected = false;
                foreach (NPCResponses npr in listToChooseFrom)
                {
                    // If we're still looking for a response try the next one (if there is one)
                    if (!responseSelected)
                    {
                        // randomly select whether this happens or not
                        int rndChance = new Random().Next(1, 100);
                        if (rndChance <= npr.Frequency)
                        {
                            // If the invoking character is null
                            if ((invokingCharacter == null) && (this.RoomID != "IsSpawned"))
                            {
                                // Get a random player (in line with the scope of the additional data)
                                invokingCharacter = this.GetRoom().GetRandomCharacter(this, npr.AdditionalData);
                            }

                            // If the invoking character is not null
                            if (invokingCharacter != null)
                            {
                                // Process the response
                                ProcessResponse(npr, invokingCharacter, itemIn);
                            }

                            // Set that a response has been selected so we can drop out of the loop
                            responseSelected = true;
                        }
                    }
                }
            }
        }
Beispiel #30
0
        private void ProcessConversationStep(NPCConversations npcc, string stepID, SMCharacter invokingCharacter)
        {
            NPCConversationStep npccs = npcc.ConversationSteps.FirstOrDefault(cs => cs.StepID == stepID);
            bool continueToNextStep   = true;

            if (npccs != null)
            {
                switch (npccs.Scope.ToLower())
                {
                case "choice":
                    string[] choices       = npccs.AdditionalData.Split(',');
                    int      choicesNumber = choices.Count();
                    int      randomChoice  = (new Random().Next(1, choicesNumber + 1)) - 1;
                    if (randomChoice > choicesNumber)
                    {
                        randomChoice = 0;
                    }
                    ProcessConversationStep(npcc, choices[randomChoice], invokingCharacter);
                    break;

                case "say":
                    this.Say(ProcessResponseString(npccs.AdditionalData, invokingCharacter));
                    break;

                case "shout":
                    this.Shout(ProcessResponseString(npccs.AdditionalData, invokingCharacter));
                    break;

                case "whisper":
                    this.Whisper(ProcessResponseString(npccs.AdditionalData, invokingCharacter), invokingCharacter.GetFullName());
                    break;

                case "emote":
                    this.GetRoom().ChatEmote(ProcessResponseString(npccs.AdditionalData, invokingCharacter), this, this);
                    break;

                case "saytoplayer":
                    // Construct the message
                    string sayToPlayerMessage = OutputFormatterFactory.Get().Italic(this.GetFullName() + " says:", 0) + " \"" + ProcessResponseString(npccs.AdditionalData, invokingCharacter) + "\"";

                    // Send the message
                    invokingCharacter.sendMessageToPlayer(sayToPlayerMessage);
                    break;

                case "emotetoplayer":
                    // Construct the message
                    string emoteToPlayerMessage = OutputFormatterFactory.Get().Italic(this.GetFullName() + " " + ProcessResponseString(npccs.AdditionalData, invokingCharacter));

                    // Send the message
                    invokingCharacter.sendMessageToPlayer(emoteToPlayerMessage);
                    break;

                case "attack":
                    // Simply attack a target player
                    this.Attack(invokingCharacter.GetFullName());
                    break;

                case "giveitem":
                    // give an item to the player
                    string[] additionalDataSplit = npccs.AdditionalData.Split(',');
                    string[] itemParts           = additionalDataSplit[0].Split('.');

                    // Create the item..
                    if (itemParts.Count() == 2)
                    {
                        int numberToCreate = int.Parse(additionalDataSplit[1]);

                        // Create the right number of the items.
                        while (numberToCreate > 0)
                        {
                            // Get the item (with a new GUID)
                            SMItem itemBeingGiven = SMItemFactory.Get(itemParts[0], itemParts[1]);

                            // Pass it to the player
                            invokingCharacter.PickUpItem("", itemBeingGiven, true);

                            // Reduce the number to create
                            numberToCreate--;
                        }
                    }
                    break;

                case "addquest":
                    // Load the quest
                    SMQuest smq = SMQuestFactory.Get(npccs.AdditionalData);
                    if (smq != null)
                    {
                        invokingCharacter.AddQuest(smq);
                    }
                    break;

                case "updatequest":
                    // Load the quest
                    SMQuest qtu = SMQuestFactory.Get(npccs.AdditionalData);
                    if (qtu != null)
                    {
                        invokingCharacter.UpdateQuest(qtu);
                    }
                    break;

                case "checkquestinprogress":
                    // Check the quest log isn't null
                    if (invokingCharacter.QuestLog != null)
                    {
                        if (invokingCharacter.QuestLog.Count(questcheck => (questcheck.QuestName.ToLower() == npccs.AdditionalData.ToLower()) && (questcheck.Completed)) > 0)
                        {
                            continueToNextStep = false;
                        }
                    }
                    break;

                case "setplayerattribute":
                    // Add a response option
                    switch (npccs.AdditionalData.ToLower())
                    {
                    case "firstname":
                        invokingCharacter.FirstName = invokingCharacter.VariableResponse;
                        break;

                    case "lastname":
                        invokingCharacter.LastName = invokingCharacter.VariableResponse;
                        break;

                    case "sex":
                        invokingCharacter.Sex = char.Parse(invokingCharacter.VariableResponse);
                        break;
                    }
                    invokingCharacter.SaveToApplication();
                    invokingCharacter.SaveToFile();
                    break;

                case "setvariableresponse":
                    invokingCharacter.VariableResponse = npccs.AdditionalData.ToLower();
                    break;

                case "teachskill":
                    // Check if the player already has the skill
                    if (invokingCharacter.Skills == null)
                    {
                        invokingCharacter.Skills = new List <SMSkillHeld>();
                    }

                    // Get the skill and level to teach to
                    string[] skillToTeach = npccs.AdditionalData.Split('.');

                    // Check if the character already has the skill
                    if (invokingCharacter.Skills.Count(skill => skill.SkillName == skillToTeach[0]) == 0)
                    {
                        // Create a new skill help object
                        SMSkillHeld smsh = new SMSkillHeld();
                        smsh.SkillName  = skillToTeach[0];
                        smsh.SkillLevel = int.Parse(skillToTeach[1]);

                        // Finally add it to the player
                        invokingCharacter.Skills.Add(smsh);

                        // Save the player
                        invokingCharacter.SaveToApplication();
                        invokingCharacter.SaveToFile();

                        // Inform the player they have learnt a new skill
                        invokingCharacter.sendMessageToPlayer(OutputFormatterFactory.Get().Italic($"You learn a new skill: {smsh.SkillName}({smsh.SkillLevel})."));
                    }

                    break;

                case "wait":
                    System.Threading.Thread.Sleep(int.Parse(npccs.AdditionalData) * 1000);
                    break;
                }

                if (continueToNextStep)
                {
                    if (npccs.ResponseOptions != null)
                    {
                        if (npccs.ResponseOptions.Count > 0)
                        {
                            ProcessResponseOptions(npcc, npccs, invokingCharacter);
                        }
                    }

                    if (npccs.NextStep != null)
                    {
                        string[] splitNextStep = npccs.NextStep.Split('.');
                        if (splitNextStep[1] != "0")
                        {
                            System.Threading.Thread.Sleep(int.Parse(splitNextStep[1]) * 1000);
                        }
                        ProcessConversationStep(npcc, splitNextStep[0], invokingCharacter);
                    }
                }
            }
        }