public DialogueTreeResponse(DialogueTree _lastTopic, DialogueTree _nextTopic, NPC n, string responseID)
 {
     lastTopic = _lastTopic;
     nextTopic = _nextTopic;
     topicResponses[lastTopic.topicID] = responseID;
     npc = n;
 }
Beispiel #2
0
        private void GameLoop_UpdateTicked(object sender, StardewModdingAPI.Events.UpdateTickedEventArgs e)
        {
            // check for followup dialogue

            if (Game1.activeClickableMenu == null && responseData != null)
            {
                DialogueTree p = responseData.nextTopic;

                Monitor.Log($"Asking about followup topic {loadedTopicNames[p.topicID]}");

                Dictionary <string, string> npcDic = Helper.Content.Load <Dictionary <string, string> >($"Characters/Dialogue/{responseData.npc.name}", ContentSource.GameContent);
                List <string> npcKeys = npcDic.Keys.ToList();

                List <Response> responses = new List <Response>();
                foreach (var r in p.responseIDs)
                {
                    Monitor.Log(r);
                    responses.Add(new Response($"DialogueTrees_Response#{responseData.npc.Name}#{p.topicID}#{r}", string.Format(loadedResponseStrings[r], loadedTopicNames[p.topicID])));
                }
                string        qid = p.questionIDs[myRand.Next(p.questionIDs.Count)];
                List <string> possibleQuestionStrings = npcDic.Keys.ToList().FindAll(k => k.StartsWith("DialogueTrees_question_" + qid + "_"));
                string        questionString          = possibleQuestionStrings.Any() ? npcDic[possibleQuestionStrings[myRand.Next(possibleQuestionStrings.Count)]] : loadedQuestionStrings[qid];

                Game1.player.currentLocation.createQuestionDialogue(string.Format(questionString, loadedTopicNames[p.topicID]), responses.ToArray(), "DialogueTrees_NPC_Question");
                Game1.objectDialoguePortraitPerson = responseData.npc;
            }
        }
Beispiel #3
0
        private void Input_ButtonPressed(object sender, StardewModdingAPI.Events.ButtonPressedEventArgs e)
        {
            if (!Config.Enabled || !Context.IsWorldReady)
            {
                return;
            }

            Dictionary <string, string> npcDic;
            List <string> npcKeys;

            // check for click on dialogue

            if (Game1.activeClickableMenu != null && Game1.player?.currentLocation?.lastQuestionKey?.StartsWith("DialogueTrees_") == true)
            {
                IClickableMenu menu = Game1.activeClickableMenu;
                if (menu == null || menu.GetType() != typeof(DialogueBox))
                {
                    return;
                }

                DialogueBox     db    = menu as DialogueBox;
                int             resp  = db.selectedResponse;
                List <Response> resps = db.responses;

                if (resp < 0 || resps == null || resp >= resps.Count || resps[resp] == null)
                {
                    return;
                }

                string[] parts      = resps[resp].responseKey.Split('#');
                string   npcName    = parts[1];
                string   topicID    = parts[2];
                string   responseID = parts[3];
                npcDic  = Helper.Content.Load <Dictionary <string, string> >($"Characters/Dialogue/{npcName}", ContentSource.GameContent);
                npcKeys = npcDic.Keys.ToList();

                if (Game1.player.currentLocation.lastQuestionKey == "DialogueTrees_Player_Question")
                {
                    Monitor.Log($"asking {npcName} about {loadedTopicNames[topicID]}");
                    var possibleResponses = npcKeys.FindAll(k => k.StartsWith("DialogueTrees_response_" + topicID + "_"));
                    NPC n = Game1.getCharacterFromName(npcName);
                    Game1.drawDialogue(n, npcDic[possibleResponses[myRand.Next(possibleResponses.Count)]]);

                    string nextTopicID = GetNextTopicID(topicID, "any");

                    if (nextTopicID != null && loadedDialogues.ContainsKey(nextTopicID) && npcKeys.Exists(k => k.StartsWith("DialogueTrees_response_" + nextTopicID + "_")))
                    {
                        if (responseData != null)
                        {
                            responseData.lastTopic = loadedDialogues[topicID];
                            responseData.nextTopic = loadedDialogues[nextTopicID];
                            responseData.npc       = n;
                            responseData.topicResponses[topicID] = responseID;
                        }
                        else
                        {
                            responseData = new DialogueTreeResponse(loadedDialogues[topicID], loadedDialogues[nextTopicID], n, responseID);
                        }
                    }
                }
                else if (Game1.player.currentLocation.lastQuestionKey == "DialogueTrees_NPC_Question")
                {
                    Monitor.Log($"{npcName} is asking player about {loadedTopicNames[topicID]}, player response: {loadedResponseStrings[responseID]}");

                    var possibleReactions = npcKeys.FindAll(k => k.StartsWith("DialogueTrees_reaction_" + topicID + "_" + responseID + "_"));

                    if (!possibleReactions.Any())
                    {
                        Monitor.Log($"{npcName} has no reaction to {loadedTopicNames[topicID]} response {loadedResponseStrings[responseID]}! Check the [DT] content pack.", LogLevel.Warn);
                    }
                    else
                    {
                        NPC n = Game1.getCharacterFromName(npcName);
                        Game1.drawDialogue(n, npcDic[possibleReactions[myRand.Next(possibleReactions.Count)]]);
                        if (npcDic.ContainsKey("DialogueTrees_friendship_" + topicID + "_" + responseID) && int.TryParse(npcDic["DialogueTrees_friendship_" + topicID + "_" + responseID], out int amount))
                        {
                            Monitor.Log($"changing friendship with {n.Name} by {amount}");
                            Game1.player.changeFriendship(amount, n);
                        }

                        string nextTopicID = GetNextTopicID(topicID, responseID);

                        if (nextTopicID != null && loadedDialogues.ContainsKey(nextTopicID))
                        {
                            Monitor.Log($"Preparing followup dialogue {nextTopicID}");
                            if (responseData != null)
                            {
                                Monitor.Log($"Adding to existing responseData");

                                responseData.lastTopic = loadedDialogues[topicID];
                                responseData.nextTopic = loadedDialogues[nextTopicID];
                                responseData.npc       = n;
                                responseData.topicResponses[topicID] = responseID;
                            }
                            else
                            {
                                responseData = new DialogueTreeResponse(loadedDialogues[topicID], loadedDialogues[nextTopicID], n, responseID);
                            }
                        }
                        else
                        {
                            if (responseData != null)
                            {
                                Monitor.Log("No next topic, erasing response data");
                            }
                            responseData = null;
                        }
                    }
                }

                Game1.player.currentLocation.lastQuestionKey = "";
                return;
            }

            // check for click on NPC

            if (Game1.activeClickableMenu != null || !Context.CanPlayerMove || (Config.ModButton != SButton.None && !Helper.Input.IsDown(Config.ModButton)) || (e.Button != Config.AskButton && e.Button != Config.AnswerButton))
            {
                return;
            }

            Monitor.Log($"Pressed modkey + {e.Button}");

            Rectangle tileRect = new Rectangle((int)Game1.currentCursorTile.X * 64, (int)Game1.currentCursorTile.Y * 64, 64, 64);

            NPC npc = null;

            foreach (NPC i in Game1.currentLocation.characters)
            {
                if (i != null && !i.IsMonster && (!Game1.player.isRidingHorse() || !(i is Horse)) && i.GetBoundingBox().Intersects(tileRect) && !i.IsInvisible && !i.checkAction(Game1.player, Game1.currentLocation))
                {
                    npc = i;
                    break;
                }
            }

            if (npc == null)
            {
                return;
            }
            try
            {
                npcDic = Helper.Content.Load <Dictionary <string, string> >($"Characters/Dialogue/{npc.Name}", ContentSource.GameContent);
            }
            catch
            {
                Monitor.Log($"No dialogue file for {npc.Name}", LogLevel.Warn);

                return;
            }
            npcKeys = npcDic.Keys.ToList();

            if (e.Button == Config.AskButton)
            {
                Monitor.Log($"Asking question of {npc.Name}");

                var shuffled = loadedDialogues.Values.ToList().FindAll(d => d.isStarter && d.playerCanAsk && npcKeys.Exists(k => k.StartsWith("DialogueTrees_response_" + d.topicID + "_")));

                if (!shuffled.Any())
                {
                    Monitor.Log($"No questions that {npc.Name} has a response to! Check the [DT] content pack.", LogLevel.Warn);
                    return;
                }
                Monitor.Log($"{shuffled.Count} questions that {npc.Name} has a response to.");

                ShuffleList(shuffled);
                var             questions = shuffled.Take(Config.MaxPlayerQuestions);
                List <Response> responses = new List <Response>();
                foreach (var q in questions)
                {
                    Monitor.Log(q.topicID);
                    responses.Add(new Response($"DialogueTrees_Response#{npc.Name}#{q.topicID}", string.Format(loadedQuestionStrings[q.questionIDs[myRand.Next(q.questionIDs.Count)]], loadedTopicNames[q.topicID])));
                }

                Game1.player.currentLocation.createQuestionDialogue(string.Format(Helper.Translation.Get("ask-npc"), npc.Name), responses.ToArray(), "DialogueTrees_Player_Question");
            }
            else if (e.Button == Config.AnswerButton)
            {
                Monitor.Log($"Answering {npc.Name}'s question");

                var possibleQuestions = loadedDialogues.Values.ToList().FindAll(d => d.isStarter && npcKeys.Exists(k => k.StartsWith("DialogueTrees_reaction_" + d.topicID + "_")));

                if (!possibleQuestions.Any())
                {
                    Monitor.Log($"No questions that {npc.Name} can ask (no reactions)! Check the [DT] content pack.", LogLevel.Warn);
                    return;
                }

                DialogueTree p = possibleQuestions[myRand.Next(possibleQuestions.Count)];

                Monitor.Log($"Asking about {loadedTopicNames[p.topicID]}");

                List <Response> responses = new List <Response>();
                foreach (var r in p.responseIDs)
                {
                    Monitor.Log(r);

                    responses.Add(new Response($"DialogueTrees_Response#{npc.Name}#{p.topicID}#{r}", string.Format(loadedResponseStrings[r], loadedTopicNames[p.topicID])));
                }
                string qid = p.questionIDs[myRand.Next(p.questionIDs.Count)];

                List <string> possibleQuestionStrings = npcDic.Keys.ToList().FindAll(k => k.StartsWith("DialogueTrees_question_" + qid + "_"));
                string        questionString          = possibleQuestionStrings.Any() ? npcDic[possibleQuestionStrings[myRand.Next(possibleQuestionStrings.Count)]] : loadedQuestionStrings[qid];

                Game1.player.currentLocation.createQuestionDialogue(string.Format(questionString, loadedTopicNames[p.topicID]), responses.ToArray(), "DialogueTrees_NPC_Question");
                Game1.objectDialoguePortraitPerson = npc;
            }
        }
Beispiel #4
0
        private string GetNextTopicID(string topicID, string responseID)
        {
            Monitor.Log($"Looking for next topic after {topicID} for response {responseID}");

            DialogueTree  ldt = loadedDialogues[topicID];
            List <string> nextTopicIDs;

            if (ldt.nextTopics.ContainsKey("any"))
            {
                nextTopicIDs = ldt.nextTopics["any"];
            }
            else if (ldt.nextTopics.ContainsKey(responseID))
            {
                nextTopicIDs = ldt.nextTopics[responseID];
            }
            else
            {
                return(null);
            }

            Monitor.Log($"Got {nextTopicIDs.Count} topics for next topic");

            List <DialogueTree> possibleTopics = new List <DialogueTree>();
            float totalChance = 0;

            foreach (string id in nextTopicIDs)
            {
                if (!loadedDialogues.ContainsKey(id))
                {
                    Monitor.Log($"Invalid topic {id}");
                    continue;
                }

                bool possible = true;
                var  ndt      = loadedDialogues[id];
                foreach (var kvp in ndt.requiredResponses)
                {
                    if (!kvp.Value.Any())
                    {
                        continue;
                    }
                    if (kvp.Value[0] == "")
                    {
                        if (responseData != null && responseData.topicResponses.ContainsKey(kvp.Key))
                        {
                            Monitor.Log($"Disallowed topic {id}");
                            possible = false;
                        }
                        break;
                    }
                    if (responseData == null || !responseData.topicResponses.ContainsKey(kvp.Key) || !kvp.Value.Contains(responseData.topicResponses[kvp.Key]))
                    {
                        Monitor.Log($"missing required topic response to {id}. responseData: {responseData != null}, has response to {kvp.Key}: {responseData?.topicResponses.ContainsKey(kvp.Key)}");
                        possible = false;
                        break;
                    }
                }
                if (possible)
                {
                    Monitor.Log($"Adding {ndt.topicID} as possible next topic, chance {ndt.followupChance}");
                    possibleTopics.Add(ndt);
                    totalChance += ndt.followupChance;
                }
            }
            if (!possibleTopics.Any())
            {
                Monitor.Log($"No possible topics");
                return(null);
            }
            float  addChance = 0;
            double rand      = Game1.random.NextDouble();

            foreach (DialogueTree dt in possibleTopics)
            {
                addChance += dt.followupChance;
                if (rand < addChance / totalChance)
                {
                    Monitor.Log($"Choosing {dt.topicID} as next topic");
                    return(dt.topicID);
                }
            }
            return(null);
        }