Ejemplo n.º 1
0
        /// <summary>A Harmony postfix patch that excludes a list of NPCs from <see cref="ItemDeliveryQuest"/>.</summary>
        /// <param name="__result">A list of NPCs this quest type could target.</param>
        public static void ItemDeliveryQuest_GetValidTargetList(ref List <NPC> __result)
        {
            try
            {
                List <string> excluded = new List <string>();                                    //a record of NPCs excluded during this process

                Dictionary <string, List <string> > exclusions = ModEntry.GetAllNPCExclusions(); //get all exclusion data

                for (int x = __result.Count - 1; x >= 0; x--)                                    //for each valid NPC returned by the original method (looping backward to allow removal)
                {
                    if (exclusions.ContainsKey(__result[x].Name))                                //if this NPC has exclusion data
                    {
                        if (exclusions[__result[x].Name].Exists(entry =>
                                                                entry.StartsWith("All", StringComparison.OrdinalIgnoreCase) || //if this NPC is excluded from everything
                                                                entry.StartsWith("TownQuest", StringComparison.OrdinalIgnoreCase) || //OR if this NPC is excluded from town quests
                                                                entry.StartsWith("ItemDelivery", StringComparison.OrdinalIgnoreCase) //OR if this NPC is excluded from item delivery quests
                                                                ))
                        {
                            excluded.Add(__result[x].Name); //add this NPC to the record
                            __result.RemoveAt(x);           //remove this NPC from the original results
                        }
                    }
                }

                if (excluded.Count > 0 && ModEntry.Instance.Monitor.IsVerbose) //if any NPCs were excluded
                {
                    ModEntry.Instance.Monitor.Log($"Excluded NPCs from item delivery quest: {String.Join(", ", excluded)}", LogLevel.Trace);
                }
            }
            catch (Exception ex)
            {
                ModEntry.Instance.Monitor.LogOnce($"Harmony patch \"{nameof(ItemDeliveryQuest_GetValidTargetList)}\" has encountered an error and may revert to default behavior. Full error message:\n{ex.ToString()}", LogLevel.Error);
            }
        }
        /// <summary>Gets a random NPC from <see cref="Utility.getRandomTownNPC(Random)"/> while removing any NPCs who are excluded from random town-related shop dialog.</summary>
        /// <returns>An random NPC from the Town who is NOT excluded from random town-related shop dialog.</returns>
        public static NPC GetRandomTownNPC_ShopDialogExclusions()
        {
            List <string> excluded = new List <string>();                                          //a list of NPC names to exclude from giving or receiving gifts

            foreach (KeyValuePair <string, List <string> > data in ModEntry.GetAllNPCExclusions()) //for each NPC's set of exclusion data
            {
                if (data.Value.Exists(entry =>
                                      entry.StartsWith("All", StringComparison.OrdinalIgnoreCase) || //if this NPC is excluded from everything
                                      entry.StartsWith("TownEvent", StringComparison.OrdinalIgnoreCase) || //OR if this NPC is excluded from town events
                                      entry.StartsWith("ShopDialog", StringComparison.OrdinalIgnoreCase) //OR this NPC is excluded from the Winter Star event
                                      ))
                {
                    excluded.Add(data.Key); //add this NPC's name to the excluded list
                }
            }

            HashSet <string> rerolledNames = new HashSet <string>();               //a record of NPCs excluded below

            NPC npc = Utility.getRandomTownNPC();                                  //get a random NPC

            while (excluded.Contains(npc?.Name, StringComparer.OrdinalIgnoreCase)) //while the selected NPC is NOT in the excluded list
            {
                rerolledNames.Add(npc?.Name);                                      //add NPC name to record
                npc = Utility.getRandomTownNPC();                                  //get another random NPC
            }

            if (rerolledNames.Count > 0) //if any NPCs were excluded
            {
                string logMessage = String.Join(", ", rerolledNames);
                ModEntry.Instance.Monitor.Log($"Excluded NPCs from random shop dialog: {logMessage}", LogLevel.Trace);
            }

            return(npc);
        }
        [EventPriority(EventPriority.Low)] //use low priority to run after most asset updates
        private static void DayStarted_SetupIslandSchedules(object sender, StardewModdingAPI.Events.DayStartedEventArgs e)
        {
            if (!Context.IsMainPlayer)                                                                                   //if this is NOT the main player
            {
                return;                                                                                                  //do nothing
            }
            ExcludedVisitors = new HashSet <string>(StringComparer.OrdinalIgnoreCase);                                   //create a new case-insensitive set and enable scheduling

            foreach (KeyValuePair <string, List <string> > data in ModEntry.GetAllNPCExclusions(forceCacheUpdate: true)) //for each NPC's set of exclusion data
            {
                if (data.Value.Exists(entry =>
                                      entry.StartsWith("All", StringComparison.OrdinalIgnoreCase) || //if this NPC is excluded from everything
                                      entry.StartsWith("IslandEvent", StringComparison.OrdinalIgnoreCase) || //OR if this NPC is excluded from island events
                                      entry.StartsWith("IslandVisit", StringComparison.OrdinalIgnoreCase) //OR if this NPC is excluded from visting the island resort
                                      ))
                {
                    ExcludedVisitors.Add(data.Key); //add this NPC's name to the excluded set
                }
            }

            if (ExcludedVisitors.Count > 0 && ModEntry.Instance.Monitor.IsVerbose) //if any NPCs were excluded
            {
                string logMessage = string.Join(", ", ExcludedVisitors);
                ModEntry.Instance.Monitor.Log($"Excluded NPCs from possible island visit: {logMessage}", LogLevel.Trace);
            }

            IslandSouth.SetupIslandSchedules(); //set up visitors' schedules

            ExcludedVisitors = null;            //clear the set and disable scheduling
        }
        /// <summary>Removes all entries from a dictionary where the key equals an excluded NPC's name.</summary>
        /// <param name="dispositions">A dictionary of data, generally loaded from Stardew's "Data/NPCDispositions" asset.</param>
        /// <returns>A copy of the dictionary with any excluded NPCs' entries removed.</returns>
        public static Dictionary <string, string> ExcludeFromNPCDispositions(Dictionary <string, string> dispositions)
        {
            if (dispositions == null) //if NPCDispositions is null for some reason
            {
                return(dispositions); //return the original asset
            }
            try
            {
                Dictionary <string, string> dispositionsWithExclusions = new Dictionary <string, string>(dispositions); //copy the dispositions to avoid editing the game's cached version

                List <string> excluded = new List <string>();                                                           //a list of NPC names to exclude from the dispositions

                foreach (KeyValuePair <string, List <string> > data in ModEntry.GetAllNPCExclusions())                  //for each NPC's set of exclusion data
                {
                    if (data.Value.Exists(entry =>
                                          entry.StartsWith("All", StringComparison.OrdinalIgnoreCase) || //if this NPC is excluded from everything
                                          entry.StartsWith("OtherEvent", StringComparison.OrdinalIgnoreCase) || //OR if this NPC is excluded from other events
                                          entry.StartsWith("PerfectFriend", StringComparison.OrdinalIgnoreCase) //OR if this NPC is excluded from the perfection system's friendship percentage
                                          ))
                    {
                        excluded.Add(data.Key); //add this NPC's name to the excluded list
                    }
                }

                for (int x = excluded.Count - 1; x >= 0; x--)                                                                                                            //for each excluded NPC (looping backward to allow removal)
                {
                    string matchingDispositionsKey = dispositionsWithExclusions.Keys.FirstOrDefault(key => key.Equals(excluded[x], StringComparison.OrdinalIgnoreCase)); //search for a dispositions key that matches the excluded NPC's name

                    if (matchingDispositionsKey != null)                                                                                                                 //if a key was found for this NPC
                    {
                        dispositionsWithExclusions.Remove(matchingDispositionsKey);                                                                                      //remove it from the dispositions
                    }
                    else //if a key was NOT found for this NPC
                    {
                        excluded.RemoveAt(x); //remove the excluded NPC from the list (for use in log messages)
                    }
                }

                if (excluded.Count > 0) //if any NPCs were excluded
                {
                    string logMessage = string.Join(", ", excluded);
                    ModEntry.Instance.Monitor.Log($"Excluded NPCs from perfect friendship tracking: {logMessage}", LogLevel.Trace);
                }

                return(dispositionsWithExclusions); //return the filtered dispositions
            }
            catch (Exception ex)
            {
                ModEntry.Instance.Monitor.LogOnce($"Harmony patch \"{nameof(HarmonyPatch_PerfectionFriendship)}\" has encountered an error. Method \"{nameof(ExcludeFromNPCDispositions)}\" might not remove excluded NPCs. Full error message:\n{ex.ToString()}", LogLevel.Error);
                return(dispositions); //return the original asset
            }
        }
Ejemplo n.º 5
0
        /// <summary>A Harmony postfix patch that excludes a list of NPCs from <see cref="SocializeQuest"/>.</summary>
        /// <param name="__instance">This instance of <see cref="SocializeQuest"/>.</param>
        public static void SocializeQuest_loadQuestInfo(SocializeQuest __instance)
        {
            try
            {
                List <string> excluded = new List <string>();                                    //a record of NPCs excluded during this process

                Dictionary <string, List <string> > exclusions = ModEntry.GetAllNPCExclusions(); //get all exclusion data

                for (int x = __instance.whoToGreet.Count - 1; x >= 0; x--)                       //for each NPC name selected by the original method (looping backward to allow removal)
                {
                    if (exclusions.ContainsKey(__instance.whoToGreet[x]))                        //if this NPC has exclusion data
                    {
                        if (exclusions[__instance.whoToGreet[x]].Exists(entry =>
                                                                        entry.StartsWith("All", StringComparison.OrdinalIgnoreCase) || //if this NPC is excluded from everything
                                                                        entry.StartsWith("TownQuest", StringComparison.OrdinalIgnoreCase) || //OR if this NPC is excluded from town quests
                                                                        entry.StartsWith("Socialize", StringComparison.OrdinalIgnoreCase) //OR if this NPC is excluded from socialize quests
                                                                        ))
                        {
                            excluded.Add(__instance.whoToGreet[x]); //add this NPC to the record
                            __instance.whoToGreet.RemoveAt(x);      //remove this NPC from the greeting list
                        }
                    }
                }

                if (excluded.Count > 0)                                           //if any NPCs were excluded
                {
                    __instance.total.Value -= excluded.Count;                     //subtract the removed NPCs from the quest's total
                    __instance.objective.Value.param[1] = __instance.total.Value; //update the displayed total

                    if (ModEntry.Instance.Monitor.IsVerbose)
                    {
                        ModEntry.Instance.Monitor.Log($"Excluded NPCs from socialize quest: {String.Join(", ", excluded)}", LogLevel.Trace);
                    }
                }
            }
            catch (Exception ex)
            {
                ModEntry.Instance.Monitor.LogOnce($"Harmony patch \"{nameof(SocializeQuest_loadQuestInfo)}\" has encountered an error and may revert to default behavior. Full error message:\n{ex.ToString()}", LogLevel.Error);
            }
        }
Ejemplo n.º 6
0
        /// <summary>A Harmony postfix patch that excludes a list of NPCs from greeting and/or being greeted by other NPCs.</summary>
        /// <param name="__instance">The NPC saying the greeting.</param>
        /// <param name="c">The character being greeted.</param>
        public static bool NPC_sayHiTo(NPC __instance, Character c)
        {
            try
            {
                Dictionary <string, List <string> > exclusions = ModEntry.GetAllNPCExclusions();                     //get all exclusion data

                string greeterName   = __instance.Name;                                                              //get the greeter's name (NPC performing the greeting)
                string recipientName = c?.Name;                                                                      //get the recipient's name (character being greeted)

                bool SkipReply = false;                                                                              //true if the recipient should NOT respond to the greeting

                if (greeterName != null && exclusions.TryGetValue(greeterName, out List <string> greeterExclusions)) //if the greeter has exclusion data
                {
                    if (greeterExclusions.Exists(entry =>
                                                 entry.StartsWith("All", StringComparison.OrdinalIgnoreCase) || //if the greeter is excluded from everything
                                                 entry.StartsWith("OtherEvent", StringComparison.OrdinalIgnoreCase) || //OR if the greeter is excluded from other events
                                                 entry.StartsWith("Greet", StringComparison.OrdinalIgnoreCase) //OR if the greeter is excluded from greeting others
                                                 ))
                    {
                        if (ModEntry.Instance.Monitor.IsVerbose)
                        {
                            ModEntry.Instance.Monitor.Log($"Excluded NPC from greeting someone: {greeterName}", LogLevel.Trace);
                        }
                        return(false);                                                                                             //skip the original method
                    }
                    else if (greeterExclusions.Exists(entry => entry.StartsWith("BeGreeted", StringComparison.OrdinalIgnoreCase))) //if the greeter CAN greet others, but is excluded from being greeted
                    {
                        SkipReply = true;                                                                                          //skip the recipient's reply, if necessary
                    }
                }

                if (recipientName != null && exclusions.TryGetValue(recipientName, out List <string> recipientExclusions)) //if the recipient has exclusion data
                {
                    if (recipientExclusions.Exists(entry =>
                                                   entry.StartsWith("All", StringComparison.OrdinalIgnoreCase) || //if the recipient is excluded from everything
                                                   entry.StartsWith("OtherEvent", StringComparison.OrdinalIgnoreCase) || //OR if the recipient is excluded from other events
                                                   entry.StartsWith("BeGreeted", StringComparison.OrdinalIgnoreCase) //OR if the recipient is excluded from being greeted
                                                   ))
                    {
                        if (ModEntry.Instance.Monitor.IsVerbose)
                        {
                            ModEntry.Instance.Monitor.Log($"Excluded NPC from being greeted: {recipientName}", LogLevel.Trace);
                        }
                        return(false);                                                                                           //skip the original method
                    }
                    else if (recipientExclusions.Exists(entry => entry.StartsWith("Greet", StringComparison.OrdinalIgnoreCase))) //if the recipient CAN be greeted, but is excluded from greeting others
                    {
                        SkipReply = true;                                                                                        //skip the recipient's reply, if necessary
                    }
                }

                if (SkipReply)                                                  //if the greeting should still happen, but the recipient's reply should be skipped
                {
                    if (__instance.getHi(recipientName) is string greetingText) //if possible,
                    {
                        __instance.showTextAboveHead(greetingText);             //display the greeting (imitating the original code in "NPC.sayHiTo", as of SDV 1.5.4)
                    }
                    if (ModEntry.Instance.Monitor.IsVerbose)
                    {
                        ModEntry.Instance.Monitor.Log($"Excluded NPC from replying to greeting: {recipientName} replying to {greeterName}", LogLevel.Trace);
                    }
                    return(false); //skip the original method
                }

                return(true); //run the original method
            }
            catch (Exception ex)
            {
                ModEntry.Instance.Monitor.LogOnce($"Harmony patch \"{nameof(NPC_sayHiTo)}\" has encountered an error and may revert to default behavior. Full error message:\n{ex.ToString()}", LogLevel.Error);
                return(true); //run the original method
            }
        }