示例#1
0
        private static bool Prefix([CanBeNull] CommandDriver __instance, ITwitchMessage twitchMessage)
        {
            if (__instance == null)
            {
                return(true);
            }

            if (!TkSettings.StoreState)
            {
                return(false);
            }

            Viewer         viewer  = Viewers.GetViewer(twitchMessage.Username);
            ITwitchMessage message = twitchMessage;

            if (!__instance.command.defName.Equals("Buy"))
            {
                message = twitchMessage.WithMessage($"!{CommandDefOf.Buy.command} {twitchMessage.Message.Substring(1)}");
            }

            if (message !.Message.Split(' ').Length < 2)
            {
                return(false);
            }

            Purchase_Handler.ResolvePurchase(viewer, message);

            return(false);
        }
示例#2
0
        public override bool IsPossible(string message, Viewer viewer, bool separateChannel = false)
        {
            if (!Purchase_Handler.CheckIfViewerHasEnoughCoins(viewer, this.storeIncident.cost, separateChannel))
            {
                return(false);
            }
            if (Current.Game.GetComponent <GameComponentPawns>().HasUserBeenNamed(viewer.username))
            {
                Toolkit.client.SendMessage($"@{viewer.username} you are already in the colony.", separateChannel);
                return(false);
            }

            this.separateChannel = separateChannel;
            this.viewer          = viewer;
            IIncidentTarget target = Helper.AnyPlayerMap;

            parms = StorytellerUtility.DefaultParmsNow(IncidentCategoryDefOf.Misc, target);
            map   = (Map)parms.target;

            bool cell = CellFinder.TryFindRandomEdgeCellWith((IntVec3 c) => map.reachability.CanReachColony(c) && !c.Fogged(map), map, CellFinder.EdgeRoadChance_Neutral, out loc);

            if (!cell)
            {
                return(false);
            }
            return(true);
        }
示例#3
0
 public override void RunCommand(TwitchIRCMessage message)
 {
     if (message.Message.Split(' ').Count() < 2)
     {
         return;
     }
     Purchase_Handler.ResolvePurchase(message.Viewer, message, CommandsHandler.SendToChatroom(message));
 }
示例#4
0
        public override void RunCommand(IRCMessage message)
        {
            Viewer viewer = Viewers.GetViewer(message.User);

            if (message.Message.Split(' ').Count() < 2)
            {
                return;
            }
            Purchase_Handler.ResolvePurchase(viewer, message, CommandsHandler.SendToChatroom(message));
        }
示例#5
0
        public override void RunCommand(ITwitchMessage twitchMessage)
        {
            Viewer viewer = Viewers.GetViewer(twitchMessage.Username);

            if (twitchMessage.Message.Split(' ').Count() < 2)
            {
                return;
            }
            Purchase_Handler.ResolvePurchase(viewer, twitchMessage);
        }
示例#6
0
        private static bool ResolvePurchaseSimplePrefix(
            [NotNull] Viewer viewer,
            ITwitchMessage twitchMessage,
            [NotNull] StoreIncidentSimple incident,
            string formattedMessage
            )
        {
            if (!Purchase_Handler.CheckIfViewerHasEnoughCoins(viewer, incident.cost))
            {
                return(false);
            }

            if (Purchase_Handler.CheckIfKarmaTypeIsMaxed(incident, viewer.username))
            {
                return(false);
            }

            if (!TryMakeIncident(incident, viewer, formattedMessage, out IncidentHelper inc))
            {
                TkUtils.Logger.Warn(@$ "The incident " "{incident.defName}" " does not define an incident helper");

                return(false);
            }

            if (!inc.IsPossible())
            {
                MessageHelper.ReplyToUser(viewer.username, "TwitchToolkitEventNotPossible".Localize());

                return(false);
            }

            viewer.Charge(incident);

            Current.Game.GetComponent <Coordinator>()?.QueueIncident(new IncidentProxy {
                SimpleIncident = inc
            });
            Current.Game.GetComponent <Store_Component>()?.LogIncident(incident);

            Store_Logger.LogPurchase(viewer.username, twitchMessage.Message);

            if (!ToolkitSettings.PurchaseConfirmations)
            {
                return(false);
            }

            TwitchWrapper.SendChatMessage(
                Helper.ReplacePlaceholder("TwitchToolkitEventPurchaseConfirm".Localize(), viewer: viewer.username, first: incident.label.CapitalizeFirst())
                );

            return(false);
        }
示例#7
0
        private static bool IsOnCooldown(StoreIncidentVariables incident, [NotNull] Viewer viewer)
        {
            if (incident == StoreIncidentDefOf.Item)
            {
                return(Purchase_Handler.CheckIfCarePackageIsOnCooldown(viewer.username));
            }

            if (incident != IncidentDefOf.Sanctuary && Purchase_Handler.CheckIfKarmaTypeIsMaxed(incident, viewer.username))
            {
                return(true);
            }

            return(Purchase_Handler.CheckIfIncidentIsOnCooldown(incident, viewer.username));
        }
示例#8
0
        private static bool ResolvePurchasePrefix([NotNull] Viewer viewer, [NotNull] ITwitchMessage twitchMessage)
        {
            if (Purchase_Handler.CheckIfViewerIsInVariableCommandList(viewer.username))
            {
                return(false);
            }

            List <string> segments = CommandFilter.Parse(twitchMessage.Message).ToList();
            var           worker   = ArgWorker.CreateInstance(segments);

            if (!worker.HasNext())
            {
                return(false);
            }

            string query = segments.Skip(1).FirstOrFallback("");

            if (TryProcessIncident(viewer, twitchMessage, query))
            {
                return(false);
            }

            Helper.Log($"abr: {query} ");

            segments.Insert(1, "item");

            if (segments.Count < 4)
            {
                segments.Add("1");
            }

            if (!int.TryParse(segments[3], out int _))
            {
                segments.Insert(3, "1");
            }

            try
            {
                Purchase_Handler.ResolvePurchaseVariables(viewer, twitchMessage, StoreIncidentDefOf.Item, string.Join(" ", segments.ToArray()));
            }
            catch (Exception e)
            {
                TkUtils.Logger.Error("Could not resolve purchase", e);
            }

            return(false);
        }
示例#9
0
        private void TryQueueNextMessage()
        {
            if (SimpleIncident is VotingHelper)
            {
                return;
            }

            if (SimpleIncident != null)
            {
                Purchase_Handler.QueuePlayerMessage(SimpleIncident.Viewer, SimpleIncident.message);
            }

            if (VariablesIncident != null)
            {
                Purchase_Handler.QueuePlayerMessage(VariablesIncident.Viewer, VariablesIncident.message, VariablesIncident.storeIncident.variables);
            }
        }
示例#10
0
        private static bool TryProcessVariablesIncident(Viewer viewer, ITwitchMessage twitchMessage, string query)
        {
            if (!TryFindVariableIncident(query, out StoreIncidentVariables incidentVariables))
            {
                return(false);
            }

            try
            {
                Purchase_Handler.ResolvePurchaseVariables(viewer, twitchMessage, incidentVariables, twitchMessage.Message);
            }
            catch (Exception e)
            {
                TkUtils.Logger.Error("Could not resolve purchase", e);
            }

            return(true);
        }
示例#11
0
        public static bool PointsWagerIsValid(string wager, Viewer viewer, ref int pointsWager, ref StoreIncidentVariables incident, bool separateChannel = false, int quantity = 1, int maxPrice = 25000)
        {
            try
            {
                if (!int.TryParse(wager, out checked (pointsWager)))
                {
                    ViewerDidWrongSyntax(viewer.username, incident.syntax);
                    return(false);
                }
                pointsWager = checked (pointsWager * quantity);
            }
            catch (OverflowException e)
            {
                Helper.Log(e.Message);
                TwitchWrapper.SendChatMessage($"@{viewer.username} points wager is invalid.");
                return(false);
            }

            if (incident.maxWager > 0 && incident.maxWager > incident.cost && pointsWager > incident.maxWager)
            {
                TwitchWrapper.SendChatMessage($"@{viewer.username} you cannot spend more than {incident.maxWager} coins on {incident.abbreviation.CapitalizeFirst()}");
                return(false);
            }

            //|| (incident.minPointsToFire > 0 && pointsWager < incident.minPointsToFire)
            if (pointsWager < incident.cost || pointsWager < incident.minPointsToFire)
            {
                TwitchWrapper.SendChatMessage(Helper.ReplacePlaceholder(
                                                  "TwitchToolkitMinPurchaseNotMet".Translate(),
                                                  viewer: viewer.username,
                                                  amount: pointsWager.ToString(),
                                                  first: incident.cost.ToString()
                                                  ));
                return(false);
            }

            if (!Purchase_Handler.CheckIfViewerHasEnoughCoins(viewer, pointsWager))
            {
                return(false);
            }

            return(true);
        }
示例#12
0
        private static bool ResolvePurchaseVariablesPrefix(
            [NotNull] Viewer viewer,
            ITwitchMessage twitchMessage,
            [NotNull] StoreIncidentVariables incident,
            string formattedMessage
            )
        {
            if (!Purchase_Handler.CheckIfViewerHasEnoughCoins(viewer, incident.cost) || IsOnCooldown(incident, viewer))
            {
                return(false);
            }

            if (!TryMakeIncident(incident, viewer, formattedMessage, out IncidentHelperVariables inc))
            {
                TkUtils.Logger.Warn(@$ "The incident " "{incident.defName}" " does not define an incident helper");

                return(false);
            }

            Purchase_Handler.viewerNamesDoingVariableCommands.Add(viewer.username.ToLowerInvariant());

            if (!inc.IsPossible(formattedMessage, viewer))
            {
                Purchase_Handler.viewerNamesDoingVariableCommands.Remove(viewer.username.ToLowerInvariant());

                return(false);
            }

            Store_Logger.LogPurchase(viewer.username, twitchMessage.Message);
            Current.Game.GetComponent <Coordinator>()?.QueueIncident(new IncidentProxy {
                VariablesIncident = inc
            });
            Current.Game.GetComponent <Store_Component>()?.LogIncident(incident);

            return(false);
        }
示例#13
0
        public override void Tick()
        {
            try
            {
                if (_game == null || _mod == null)
                {
                    return;
                }

                _mod.Tick();
                var    minutes = (int)(_game.Info.RealPlayTimeInteracting / 60f);
                double getTime = (double)Time.time / 60f;
                int    time    = Convert.ToInt32(Math.Truncate(getTime));

                if (IncidentHelpers.Count > 0)
                {
                    for (int i = 0; i < IncidentHelpers.Count; i++)
                    {
                        var incidentHelper = IncidentHelpers.Dequeue();
                        if (!(incidentHelper is VotingHelper))
                        {
                            Purchase_Handler.QueuePlayerMessage(incidentHelper.Viewer, incidentHelper.message);
                        }
                        incidentHelper.TryExecute();
                    }

                    Helper.playerMessages = new List <string>();
                }

                if (IncidentHelperVariables.Count > 0)
                {
                    for (int i = 0; i < IncidentHelperVariables.Count; i++)
                    {
                        var incidentHelper = IncidentHelperVariables.Dequeue();
                        Purchase_Handler.QueuePlayerMessage(incidentHelper.Viewer, incidentHelper.message, incidentHelper.storeIncident.variables);
                        incidentHelper.TryExecute();
                        if (Purchase_Handler.viewerNamesDoingVariableCommands.Contains(incidentHelper.Viewer.username))
                        {
                            Purchase_Handler.viewerNamesDoingVariableCommands.Remove(incidentHelper.Viewer.username);
                        }
                    }

                    Helper.playerMessages = new List <string>();
                }

                if (Incidents.Count > 0)
                {
                    var           incident      = Incidents.Dequeue();
                    IncidentParms incidentParms = new IncidentParms();
                    incidentParms.target = Helper.AnyPlayerMap;
                    incident.TryExecute(incidentParms);
                }

                if (FiringIncidents.Count > 0)
                {
                    Helper.Log("Firing " + FiringIncidents.First().def.defName);
                    var incident = FiringIncidents.Dequeue();
                    incident.def.Worker.TryExecute(incident.parms);
                }

                VoteHandler.CheckForQueuedVotes();

                if (_lastCoinReward < 0)
                {
                    _lastCoinReward = time;
                }
                else if (ToolkitSettings.EarningCoins && ((time - _lastCoinReward) >= ToolkitSettings.CoinInterval) && Viewers.jsonallviewers != null)
                {
                    _lastCoinReward = time;
                    Viewers.AwardViewersCoins();
                }
                if (_lastMinute < 0)
                {
                    _lastMinute = time;
                }
                else if (_lastMinute < time)
                {
                    _lastMinute = time;
                    Toolkit.JobManager.CheckAllJobs();
                    Viewers.RefreshViewers();
                }
            }
            catch (Exception ex)
            {
                Helper.Log("Exception: " + ex.Message + ex.StackTrace);
            }
        }
示例#14
0
        public override void ParseCommand(IRCMessage msg)
        {
            Viewer viewer = Viewers.GetViewer(msg.User);

            GameComponentPawns component = Current.Game.GetComponent <GameComponentPawns>();

            if (msg.Message.StartsWith("!mypawnskills") && Commands.AllowCommand(msg.Channel))
            {
                if (!component.HasUserBeenNamed(viewer.username))
                {
                    Toolkit.client.SendMessage($"@{viewer.username} you are not in the colony.", true);
                    return;
                }

                Pawn   pawn   = component.PawnAssignedToUser(viewer.username);
                string output = $"@{viewer.username} {pawn.Name.ToStringShort.CapitalizeFirst()}'s skill levels are ";

                List <SkillRecord> skills = pawn.skills.skills;

                for (int i = 0; i < skills.Count; i++)
                {
                    output += $"{skills[i].def.LabelCap}: {skills[i].levelInt}";
                    if (i != skills.Count - 1)
                    {
                        output += ", ";
                    }
                }

                Toolkit.client.SendMessage(output, true);
            }

            if (msg.Message.StartsWith("!mypawnstory") && Commands.AllowCommand(msg.Channel))
            {
                if (!component.HasUserBeenNamed(viewer.username))
                {
                    Toolkit.client.SendMessage($"@{viewer.username} you are not in the colony.", true);
                    return;
                }

                Pawn pawn = component.PawnAssignedToUser(viewer.username);

                string output = $"@{viewer.username} About {pawn.Name.ToStringShort.CapitalizeFirst()}: ";

                List <Backstory> backstories = pawn.story.AllBackstories.ToList();

                for (int i = 0; i < backstories.Count; i++)
                {
                    output += backstories[i].titleShort;
                    if (i != backstories.Count - 1)
                    {
                        output += ", ";
                    }
                }

                output += " | Traits: ";

                List <Trait> traits = pawn.story.traits.allTraits;
                for (int i = 0; i < traits.Count; i++)
                {
                    output += traits[i].LabelCap;
                    if (i != traits.Count - 1)
                    {
                        output += ", ";
                    }
                }

                Toolkit.client.SendMessage(output, true);
            }

            if (msg.Message.StartsWith("!changepawnname") && Commands.AllowCommand(msg.Channel))
            {
                string[] command = msg.Message.Split(' ');

                if (command.Length < 2)
                {
                    return;
                }

                string newName = command[1];

                if (newName == null || newName == "" || newName.Length > 16)
                {
                    Toolkit.client.SendMessage($"@{viewer.username} your name can be up to 16 characters.", true);
                    return;
                }

                if (!component.HasUserBeenNamed(viewer.username))
                {
                    Toolkit.client.SendMessage($"@{viewer.username} you are not in the colony.", Commands.SendToChatroom(msg.Channel));
                    return;
                }

                if (!Purchase_Handler.CheckIfViewerHasEnoughCoins(viewer, 500, true))
                {
                    return;
                }

                viewer.TakeViewerCoins(500);
                nameRequests.Add(viewer.username, newName);
                Toolkit.client.SendMessage($"@{ToolkitSettings.Channel} {viewer.username} has requested to be named {newName}, use !approvename @{viewer.username} or !declinename @{viewer.username}", false);
            }

            if (Viewer.IsModerator(viewer.username) || viewer.username == ToolkitSettings.Channel)
            {
                if (msg.Message.StartsWith("!unstickpeople"))
                {
                    Purchase_Handler.viewerNamesDoingVariableCommands = new List <string>();
                }

                if (msg.Message.StartsWith("!approvename"))
                {
                    string[] command = msg.Message.Split(' ');

                    if (command.Length < 2)
                    {
                        return;
                    }

                    string username = command[1].Replace("@", "");

                    if (username == null || username == "" || !nameRequests.ContainsKey(username))
                    {
                        Toolkit.client.SendMessage($"@{viewer.username} invalid username", false);
                        return;
                    }

                    if (!component.HasUserBeenNamed(username))
                    {
                        return;
                    }

                    Pawn       pawn = component.PawnAssignedToUser(username);
                    NameTriple old  = pawn.Name as NameTriple;
                    pawn.Name = new NameTriple(old.First, nameRequests[username], old.Last);
                    Toolkit.client.SendMessage($"@{viewer.username} approved request for name change from {old} to {pawn.Name}");
                }

                if (msg.Message.StartsWith("!declinename"))
                {
                    string[] command = msg.Message.Split(' ');

                    if (command.Length < 2)
                    {
                        return;
                    }

                    string username = command[1].Replace("@", "");

                    if (username == null || username == "" || !nameRequests.ContainsKey(username))
                    {
                        Toolkit.client.SendMessage($"@{viewer.username} invalid username", false);
                        return;
                    }

                    if (!component.HasUserBeenNamed(username))
                    {
                        return;
                    }

                    nameRequests.Remove(username);
                    Toolkit.client.SendMessage($"@{viewer.username} declined name change request from {username}");
                }
            }
        }
示例#15
0
        public override bool IsPossible(string message, Viewer viewer, bool separateChannel = false)
        {
            this.separateChannel = separateChannel;
            this.viewer          = viewer;
            string[] command = message.Split(' ');
            if (command.Length < 4)
            {
                VariablesHelpers.ViewerDidWrongSyntax(viewer.username, storeIncident.syntax, separateChannel);
                return(false);
            }

            string itemKey = command[2].ToLower();

            if (itemKey == null || itemKey == "")
            {
                VariablesHelpers.ViewerDidWrongSyntax(viewer.username, storeIncident.syntax, separateChannel);
                return(false);
            }

            IEnumerable <Store.Item> itemSearch = StoreInventory.items.Where(s =>
                                                                             s.price > 0 &&
                                                                             (s.abr == itemKey ||
                                                                              s.defname.ToLower() == itemKey)
                                                                             );

            if (itemSearch.Count() > 0)
            {
                item = itemSearch.ElementAt(0);
            }

            if (item == null || item.price < 1)
            {
                Toolkit.client.SendMessage($"@{viewer.username} item not found.", separateChannel);
                return(false);
            }

            string quantityKey = command[3];

            if (quantityKey == null || quantityKey == "")
            {
                VariablesHelpers.ViewerDidWrongSyntax(viewer.username, storeIncident.syntax, separateChannel);
                return(false);
            }

            try
            {
                if (!int.TryParse(quantityKey, out checked (quantity)))
                {
                    return(false);
                }

                price = checked (item.price * quantity);
            }
            catch (OverflowException e)
            {
                Log.Warning(e.Message);
                return(false);
            }

            if (quantity < 1 || price < 1)
            {
                VariablesHelpers.ViewerDidWrongSyntax(viewer.username, storeIncident.syntax, separateChannel);
                return(false);
            }

            if (!Purchase_Handler.CheckIfViewerHasEnoughCoins(viewer, price, separateChannel))
            {
                return(false);
            }

            if (price < ToolkitSettings.MinimumPurchasePrice)
            {
                Toolkit.client.SendMessage(Helper.ReplacePlaceholder(
                                               "TwitchToolkitMinPurchaseNotMet".Translate(),
                                               viewer: viewer.username,
                                               amount: price.ToString(),
                                               first: ToolkitSettings.MinimumPurchasePrice.ToString()
                                               ), separateChannel);
                return(false);
            }

            return(true);
        }
        public override bool IsPossible(string message, Viewer viewer, bool separateChannel = false)
        {
            this.separateChannel = separateChannel;
            this.Viewer          = viewer;
            string[] command = message.Split(' ');
            if (command.Length < 4)
            {
                VariablesHelpers.ViewerDidWrongSyntax(viewer.username, storeIncident.syntax);
                return(false);
            }

            string itemKey = command[2].ToLower();

            if (itemKey == null || itemKey == "")
            {
                VariablesHelpers.ViewerDidWrongSyntax(viewer.username, storeIncident.syntax);
                return(false);
            }

            IEnumerable <Store.Item> itemSearch = StoreInventory.items.Where(s =>
                                                                             s.price > 0 &&
                                                                             (s.abr == itemKey ||
                                                                              s.defname.ToLower() == itemKey)
                                                                             );

            if (itemSearch.Count() > 0)
            {
                item = itemSearch.ElementAt(0);
            }

            if (item == null || item.price < 1)
            {
                TwitchWrapper.SendChatMessage($"@{viewer.username} item not found.");
                return(false);
            }

            ThingDef itemThingDef = ThingDef.Named(item.defname);

            bool isResearched = true;
            ResearchProjectDef researchProject = null;

            Helper.Log("Checking researched");
            if (itemThingDef.recipeMaker != null &&
                itemThingDef.recipeMaker.researchPrerequisite != null &&
                !itemThingDef.recipeMaker.researchPrerequisite.IsFinished)
            {
                Helper.Log("Recipe not researched");
                isResearched    = false;
                researchProject = itemThingDef.recipeMaker.researchPrerequisite;
            }
            else if (!itemThingDef.IsResearchFinished)
            {
                Helper.Log("Building not researched");
                isResearched    = false;
                researchProject = itemThingDef.researchPrerequisites.ElementAt(0);
            }

            if (BuyItemSettings.mustResearchFirst && !isResearched)
            {
                string output = $"@{viewer.username} {itemThingDef.LabelCap} has not been researched yet, must finish research project {researchProject.LabelCap} first.";

                TwitchWrapper.SendChatMessage(output);

                return(false);
            }

            string quantityKey = command[3];

            if (quantityKey == null || quantityKey == "")
            {
                VariablesHelpers.ViewerDidWrongSyntax(viewer.username, storeIncident.syntax);
                return(false);
            }

            try
            {
                if (!int.TryParse(quantityKey, out checked (quantity)))
                {
                    return(false);
                }

                price = checked (item.price * quantity);
            }
            catch (OverflowException e)
            {
                Helper.Log(e.Message);
                return(false);
            }

            if (quantity < 1 || price < 1)
            {
                VariablesHelpers.ViewerDidWrongSyntax(viewer.username, storeIncident.syntax);
                return(false);
            }

            if (!Purchase_Handler.CheckIfViewerHasEnoughCoins(viewer, price))
            {
                return(false);
            }

            if (price < ToolkitSettings.MinimumPurchasePrice)
            {
                TwitchWrapper.SendChatMessage(Helper.ReplacePlaceholder(
                                                  "TwitchToolkitMinPurchaseNotMet".Translate(),
                                                  viewer: viewer.username,
                                                  amount: price.ToString(),
                                                  first: ToolkitSettings.MinimumPurchasePrice.ToString()
                                                  ));
                return(false);
            }

            return(true);
        }
示例#17
0
        public override void ParseCommand(IRCMessage msg)
        {
            Viewer viewer = Viewers.GetViewer(msg.User);

            GameComponentPawns component = Current.Game.GetComponent <GameComponentPawns>();

            if (msg.Message.StartsWith("!mypawnskills") && Commands.AllowCommand(msg))
            {
                if (!component.HasUserBeenNamed(viewer.username))
                {
                    Toolkit.client.SendMessage($"@{viewer.username} you are not in the colony.", Commands.SendToChatroom(msg));
                    return;
                }

                Pawn   pawn   = component.PawnAssignedToUser(viewer.username);
                string output = $"@{viewer.username} {pawn.Name.ToStringShort.CapitalizeFirst()}'s skill levels are ";

                List <SkillRecord> skills = pawn.skills.skills;

                for (int i = 0; i < skills.Count; i++)
                {
                    if (skills[i].TotallyDisabled)
                    {
                        output += $"{skills[i].def.LabelCap}: -";
                    }
                    else
                    {
                        output += $"{skills[i].def.LabelCap}: {skills[i].levelInt}";
                    }

                    if (skills[i].passion == Passion.Minor)
                    {
                        output += "+";
                    }
                    if (skills[i].passion == Passion.Major)
                    {
                        output += "++";
                    }

                    if (i != skills.Count - 1)
                    {
                        output += ", ";
                    }
                }

                Toolkit.client.SendMessage(output, Commands.SendToChatroom(msg));
            }

            if (msg.Message.StartsWith("!mypawnstory") && Commands.AllowCommand(msg))
            {
                if (!component.HasUserBeenNamed(viewer.username))
                {
                    Toolkit.client.SendMessage($"@{viewer.username} you are not in the colony.", Commands.SendToChatroom(msg));
                    return;
                }

                Pawn pawn = component.PawnAssignedToUser(viewer.username);

                string output = $"@{viewer.username} About {pawn.Name.ToStringShort.CapitalizeFirst()}: ";

                List <Backstory> backstories = pawn.story.AllBackstories.ToList();

                for (int i = 0; i < backstories.Count; i++)
                {
                    output += backstories[i].title;
                    if (i != backstories.Count - 1)
                    {
                        output += ", ";
                    }
                }

                output += " | " + pawn.gender;

                StringBuilder stringBuilder            = new StringBuilder();
                WorkTags      combinedDisabledWorkTags = pawn.story.CombinedDisabledWorkTags;
                if (combinedDisabledWorkTags == WorkTags.None)
                {
                    stringBuilder.Append("(" + "NoneLower".Translate() + "), ");
                }
                else
                {
                    List <WorkTags> list  = WorkTagsFrom(combinedDisabledWorkTags).ToList <WorkTags>();
                    bool            flag2 = true;
                    foreach (WorkTags tags in list)
                    {
                        if (flag2)
                        {
                            stringBuilder.Append(tags.LabelTranslated().CapitalizeFirst());
                        }
                        else
                        {
                            stringBuilder.Append(tags.LabelTranslated());
                        }
                        stringBuilder.Append(", ");
                        flag2 = false;
                    }
                }
                string text = stringBuilder.ToString();
                text = text.Substring(0, text.Length - 2);

                output += " | Incapable of: " + text;

                output += " | Traits: ";

                List <Trait> traits = pawn.story.traits.allTraits;
                for (int i = 0; i < traits.Count; i++)
                {
                    output += traits[i].LabelCap;

                    if (i != traits.Count - 1)
                    {
                        output += ", ";
                    }
                }

                Toolkit.client.SendMessage(output, Commands.SendToChatroom(msg));
            }

            if (msg.Message.StartsWith("!changepawnname") && Commands.AllowCommand(msg))
            {
                string[] command = msg.Message.Split(' ');

                if (command.Length < 2)
                {
                    return;
                }

                string newName = command[1];

                if (newName == null || newName == "" || newName.Length > 16)
                {
                    Toolkit.client.SendMessage($"@{viewer.username} your name can be up to 16 characters.", Commands.SendToChatroom(msg));
                    return;
                }

                if (!component.HasUserBeenNamed(viewer.username))
                {
                    Toolkit.client.SendMessage($"@{viewer.username} you are not in the colony.", Commands.SendToChatroom(msg));
                    return;
                }

                if (!Purchase_Handler.CheckIfViewerHasEnoughCoins(viewer, 500, true))
                {
                    return;
                }

                viewer.TakeViewerCoins(500);
                nameRequests.Add(viewer.username, newName);
                Toolkit.client.SendMessage($"@{ToolkitSettings.Channel} {viewer.username} has requested to be named {newName}, use !approvename @{viewer.username} or !declinename @{viewer.username}", false);
            }

            if (Viewer.IsModerator(viewer.username) || viewer.username == ToolkitSettings.Channel)
            {
                if (msg.Message.StartsWith("!unstickpeople"))
                {
                    Purchase_Handler.viewerNamesDoingVariableCommands = new List <string>();
                }

                if (msg.Message.StartsWith("!approvename"))
                {
                    string[] command = msg.Message.Split(' ');

                    if (command.Length < 2)
                    {
                        return;
                    }

                    string username = command[1].Replace("@", "");

                    if (username == null || username == "" || !nameRequests.ContainsKey(username))
                    {
                        Toolkit.client.SendMessage($"@{viewer.username} invalid username", Commands.SendToChatroom(msg));
                        return;
                    }

                    if (!component.HasUserBeenNamed(username))
                    {
                        return;
                    }

                    Pawn       pawn = component.PawnAssignedToUser(username);
                    NameTriple old  = pawn.Name as NameTriple;
                    pawn.Name = new NameTriple(old.First, nameRequests[username], old.Last);
                    Toolkit.client.SendMessage($"@{viewer.username} approved request for name change from {old} to {pawn.Name}");
                }

                if (msg.Message.StartsWith("!declinename"))
                {
                    string[] command = msg.Message.Split(' ');

                    if (command.Length < 2)
                    {
                        return;
                    }

                    string username = command[1].Replace("@", "");

                    if (username == null || username == "" || !nameRequests.ContainsKey(username))
                    {
                        Toolkit.client.SendMessage($"@{viewer.username} invalid username", Commands.SendToChatroom(msg));
                        return;
                    }

                    if (!component.HasUserBeenNamed(username))
                    {
                        return;
                    }

                    nameRequests.Remove(username);
                    Toolkit.client.SendMessage($"@{viewer.username} declined name change request from {username}");
                }
            }

            Store_Logger.LogString("Parsed pawn command");
        }