Beispiel #1
0
        public static string FindConflictingConditions(string conds, char seperator = ',', int limit = 5, bool strict = true)
        {
            string[] conditions = conds.Split(seperator);
            // Force the limit to be 4~16
            // Less then 4 would not allow enough freedom
            // While more then 16 would take a lot of time to process
            limit = Math.Max(4, Math.Min(16, limit));
            if (conditions.Length > limit)
            {
                return("The conditions list contains more then the maximum `" + limit + "` conditions allowed");
            }
            List <string> cache             = new List <string>();
            string        weekdayFound      = null;
            string        seasonFound       = null;
            string        marriageFound     = null;
            string        engagementFound   = null;
            int           negatedSeasons    = 0;
            int           negatedDays       = 0;
            string        positiveYearMod   = null;
            int           positiveYearStart = 0;
            int           negativeYearStart = 0;
            string        houseLevel        = null;
            string        weatherCondition  = null;

            foreach (string condition in conditions)
            {
                /*
                 *  There are times where a condition becomes deprecated due to a change in the condition system
                 *  Deprecated conditions are only reported as being deprecated if strict conflict detection is used
                 *  Otherwise, the deprecated conditions are treated as generic conditions
                 *
                 *  Note that deprecated conditions are internally replaced by their newer equivalent when resolving
                 *  This means that deprecated conditions not only do not have full conflict resultion, they also are one step slower to process
                 *
                 *  Further, as said earlier, deprecated conditions are treated as generic conditions rather then connected conditions
                 *  What this means, is that where `year>1,year>2` would be reported as having conflicts, the same is not true for `secondYear,thirdYear`
                 *  This is because of the difference between generic and connected conditions
                 *  Generic conditions are true/false flags that do not have a connection to any other condition
                 *  Connected conditions are true/false flags that do have this connected behaviour
                 *
                 *  Because of this, extra resolution logic exists in order to detect and report as many of the possible conflicts as it can
                 *  Deprecated conditions do not trigger this resolution logic, and have in fact been purposefully excluded from it
                 *
                 *
                 */
                if (strict)
                {
                    if (DeprecatedConditions.ContainsKey(condition))
                    {
                        return(Format(ConditionDeprecated, new string[] { condition, DeprecatedConditions[condition] }));
                    }
                    else if (DeprecatedConditions.ContainsKey('!' + condition))
                    {
                        return(Format(ConditionDeprecated, new string[] { '!' + condition, '!' + DeprecatedConditions[condition] }));
                    }
                }
                // Check for conditions where another condition would be faster to resolve the true/false state but the end-result is the same
                if (strict && ConditionRecommend.ContainsKey(condition))
                {
                    return("The `" + condition + "` condition should be replaced by the functionally equivalent `" + ConditionRecommend[condition] + "` condition as it is faster");
                }
                // Check for conditions that are at least double-negatives
                if (condition.StartsWith("!!"))
                {
                    return("The `" + condition + "` condition performs negation more then once");
                }
                // Check if a condition is in the list more then once
                if (strict && cache.Contains(condition))
                {
                    return("The `" + condition + "` condition has been specified more then once");
                }
                // Check if the positive to this condition is in the list, since that would result in a always-false situation
                else if (condition.StartsWith("!") && cache.Contains(condition.Substring(1)))
                {
                    return(Format(ConditionAndNegation, new string[] { condition.Substring(1), condition }));
                }
                // Check if the negative to this condition is in the list, since that would result in a always-false situation
                else if (cache.Contains('!' + condition))
                {
                    return(Format(ConditionAndNegation, new string[] { condition, '!' + condition }));
                }
                // Check for weather conditions
                if (condition.StartsWith("weather"))
                {
                    if (weatherCondition != null)
                    {
                        return(Format(ConditionExclusive, new string[] { condition, weatherCondition }));
                    }
                    else
                    {
                        weatherCondition = condition;
                    }
                    string t = CheckSnow(cache);
                    if (t != null)
                    {
                        return(t);
                    }
                }
                // Check for house upgrade based conditions where conflicts may occur
                if (condition.StartsWith("houseLevel="))
                {
                    if (houseLevel != null)
                    {
                        return(Format(ConditionExclusive, new string[] { condition, houseLevel }));
                    }
                    else
                    {
                        houseLevel = condition;
                    }
                    if (Convert.ToInt32(condition.Substring(11)) < 0)
                    {
                        return(Format(ConditionFormat, new string[] { condition }));
                    }
                }
                // Check for the positive year-based conditions where conflicts may occur
                if (condition.StartsWith("year"))
                {
                    if (positiveYearMod != null)
                    {
                        return(Format(ConditionExclusive, new string[] { condition, positiveYearMod }));
                    }
                    positiveYearMod = condition;
                    if (condition.StartsWith("year>"))
                    {
                        try
                        {
                            int posYear = Convert.ToInt32(condition.Substring(5));
                            if (posYear < 1)
                            {
                                return(Format(ConditionFormat, new string[] { condition }));
                            }
                            if (negativeYearStart < posYear)
                            {
                                return(Format(ConditionExclusive, new string[] { condition, "!year>" + negativeYearStart }));
                            }
                            positiveYearStart = posYear;
                        }
                        catch
                        {
                            return(Format(ConditionFormat, new string[] { condition }));
                        }
                    }
                }
                // Check for the negative year-based conditions where conflicts may occur
                else if (condition.StartsWith("!year>"))
                {
                    try
                    {
                        if (negativeYearStart > 0)
                        {
                            return(Format(ConditionExclusive, new string[] { condition, "!year>" + negativeYearStart }));
                        }
                        int negYear = Convert.ToInt32(condition.Substring(5));
                        if (negYear < 1)
                        {
                            return(Format(ConditionFormat, new string[] { condition }));
                        }
                        if (positiveYearStart >= negYear)
                        {
                            return(Format(ConditionExclusive, new string[] { condition, "year>" + positiveYearStart }));
                        }
                        negativeYearStart = negYear;
                    }
                    catch
                    {
                        return(Format(ConditionFormat, new string[] { condition }));
                    }
                }
                // Check for situations where marriage conditions may conflict
                else if (condition.StartsWith("married"))
                {
                    if (engagementFound != null)
                    {
                        return(Format(ConditionExclusive, new string[] { condition, marriageFound }));
                    }
                    else if (strict && condition == "married" && marriageFound != null)
                    {
                        return(Format(ConditionImplied, new string[] { condition, marriageFound }));
                    }
                    else if (strict && cache.Contains("married"))
                    {
                        return(Format(ConditionImplied, new string[] { "married", condition }));
                    }
                    else if (marriageFound != null)
                    {
                        return(Format(ConditionExclusive, new string[] { condition, marriageFound }));
                    }
                    else
                    {
                        marriageFound = condition;
                    }
                }
                // Check for situations where engagement conditions may conflict
                else if (condition.StartsWith("engaged"))
                {
                    if (engagementFound != null)
                    {
                        return(Format(ConditionExclusive, new string[] { condition, engagementFound }));
                    }
                    else if (strict && condition == "engaged" && engagementFound != null)
                    {
                        return(Format(ConditionImplied, new string[] { condition, engagementFound }));
                    }
                    else if (strict && cache.Contains("engaged"))
                    {
                        return(Format(ConditionImplied, new string[] { "engaged", condition }));
                    }
                    else if (marriageFound != null)
                    {
                        return(Format(ConditionExclusive, new string[] { condition, engagementFound }));
                    }
                    else
                    {
                        engagementFound = condition;
                    }
                }
                // Check for multiple weekday or season conditions where neither have been negated, since it cannot be multiple days or seasons at the same time
                // Also check if any negated weekday or season conditions apply, since having both a fixed day/season and a not day/season is pointless
                else
                {
                    switch (condition)
                    {
                    case "sunday":
                    case "monday":
                    case "tuesday":
                    case "wednesday":
                    case "thursday":
                    case "friday":
                    case "saturday":
                        if (weekdayFound != null)
                        {
                            return(Format(ConditionExclusive, new string[] { condition, weekdayFound }));
                        }
                        else
                        {
                            weekdayFound = condition;
                        }
                        if (!strict)
                        {
                            break;
                        }
                        string[] matchedDays = (string[])cache.Intersect(WeekdaysInverted);
                        if (matchedDays.Any())
                        {
                            return(Format(ConditionImplied, new string[] { condition, matchedDays[0] }));
                        }
                        break;

                    case "spring":
                    case "summer":
                    case "fall":
                    case "winter":
                        if (seasonFound != null)
                        {
                            return(Format(ConditionExclusive, new string[] { condition, seasonFound }));
                        }
                        else
                        {
                            seasonFound = condition;
                        }
                        string t = CheckSnow(cache);
                        if (t != null)
                        {
                            return(t);
                        }
                        if (!strict)
                        {
                            break;
                        }
                        string[] matchedSeasons = (string[])cache.Intersect(SeasonsInverted);
                        if (matchedSeasons.Any())
                        {
                            return(Format(ConditionImplied, new string[] { condition, matchedSeasons[0] }));
                        }
                        break;

                    case "!spring":
                    case "!summer":
                    case "!fall":
                    case "!winter":
                        negatedSeasons++;
                        if (strict && negatedSeasons > 2)
                        {
                            return("The condition list contains more then 2 negative season conditions, use a single positive season condition instead");
                        }
                        string ts = CheckSnow(cache);
                        if (ts != null)
                        {
                            return(ts);
                        }
                        break;

                    case "!sunday":
                    case "!monday":
                    case "!tuesday":
                    case "!wednesday":
                    case "!thursday":
                    case "!friday":
                    case "!saturday":
                        if (!strict)
                        {
                            break;
                        }
                        negatedDays++;
                        if (negatedDays > 5)
                        {
                            return("The condition list contains more then 5 negative weekday conditions, use a single positive weekday condition instead");
                        }
                        if (negatedDays > 4 && !cache.Contains("!sunday") && !cache.Contains("!saturday"))
                        {
                            return("The condition list contains negated weekday conditions for all days except saturday and sunday, use the positive `weekend` condition instead");
                        }
                        break;
                    }
                }
                // If this condition has passed all the checks, we cache the condition so other conditions in the list can refer to it
                cache.Add(condition);
            }
            return(null);
        }
Beispiel #2
0
        public static bool CheckCondition(string condition, Func <string, bool?> customResolver = null)
        {
            // Check if this is a negated condition
            if (condition.StartsWith("!"))
            {
                // Check if it is negated multiple times, as this risks a infinite loop situation
                if (condition.StartsWith("!!"))
                {
                    // If we find multiple negations, we forcibly return false
                    return(false);
                }
                else
                {
                    // If we dont find multiple negations, we negate the result of a positive condition lookup
                    return(!CheckCondition(condition.Substring(1)));
                }
            }
            // If it is not a negated condition, we perform a positive condition lookup
            else
            {
                // First, we check for the mostly-static conditions
                switch (condition)
                {
                // Conditions for the possible weather states
                case "weatherSun":
                case "weatherRain":
                case "weatherSnow":
                case "weatherStorm":
                case "weatherFestival":
                case "weatherWedding":
                case "weatherFallDebris":
                case "weatherSummerDebris":
                    return(condition == WeatherTypes[Game1.weatherIcon]);

                // Special condition for "Any debris weather"
                case "weatherDebris":
                    return(Game1.weatherIcon == 3 || Game1.weatherIcon == 6);

                // Special condition for "Weather only possible in the current season"
                case "weatherSeasonal":
                    switch (Game1.currentSeason)
                    {
                    case "summer":
                        return(Game1.weatherIcon == 3);

                    case "fall":
                        return(Game1.weatherIcon == 6);

                    case "winter":
                        return(Game1.weatherIcon == 7);

                    default:
                        return(false);
                    }

                // Condition for if one of the two special weather states is the current state
                case "weatherSpecial":
                    return(Game1.weatherIcon < 2);

                // Conditions for each of the 7 days
                case "sunday":
                case "monday":
                case "tuesday":
                case "wednesday":
                case "thursday":
                case "friday":
                case "saturday":
                    return(condition == Weekdays[Game1.dayOfMonth % 7]);

                // Special condition for either saturday or sunday
                case "weekend":
                    int day = Game1.dayOfMonth % 7;
                    return(day == 0 || day == 6);

                // Conditions for each of the 4 seasons
                case "spring":
                case "summer":
                case "fall":
                case "winter":
                    return(condition == Game1.currentSeason);

                // Generic condition that is true whenever the player is married, irrelevant of the person they are married to
                case "married":
                    return(Game1.player.spouse != null && !Game1.player.spouse.Contains("engaged"));

                // Generic condition that is true whenever the player is engaged to be married, irrelevant of the person they are engaged to
                case "engaged":
                    return(Game1.player.spouse != null && Game1.player.spouse.Contains("engaged"));

                // Condition that is only true after the earthquake event has happened
                case "earthquake":
                    return(Game1.stats.daysPlayed > 31);

                // Condition that is only true after the player has received the rusty key
                case "rustyKey":
                    return(Game1.player.hasRustyKey);

                // Condition that is only true after the player has received the skull key
                case "skullKey":
                    return(Game1.player.hasSkullKey);

                // Condition that is only true after the player has received the club card
                case "clubMember":
                    return(Game1.player.hasClubCard);

                // Condition that is only true after the player has learned to speak the dwarven language
                case "dwarfSpeak":
                    return(Game1.player.canUnderstandDwarves);

                // New and updated condition handling for more complex conditions
                default:
                    // Handle marriage for any NPC instead of just the default bachelors (Backwards compatible)
                    if (condition.StartsWith("married"))
                    {
                        return(Game1.player.spouse != null && Game1.player.spouse.Equals(condition.Substring(7)));
                    }
                    // Handle engagement for any NPC instead of just the default bachelors *new*
                    if (condition.StartsWith("engaged"))
                    {
                        return(Game1.player.spouse != null && Game1.player.spouse.Contains(condition.Substring(7)) && Game1.player.spouse.Contains("engaged"));
                    }
                    // Allow year-based conditions for during any specific year
                    if (condition.StartsWith("year="))
                    {
                        return(Game1.year == Convert.ToInt32(condition.Substring(5)));
                    }
                    // Allow year-based conditions for after any specific year
                    if (condition.StartsWith("year>"))
                    {
                        return(Game1.year > Convert.ToInt32(condition.Substring(5)));
                    }
                    // House upgrade level conditions
                    if (condition.StartsWith("houseLevel="))
                    {
                        return(Game1.player.houseUpgradeLevel == Convert.ToInt32(condition.Substring(11)));
                    }
                    // Farm type conditions
                    if (condition.StartsWith("farmType="))
                    {
                        return(Game1.whichFarm == Convert.ToInt32(condition.Substring(9)));
                    }
                    // Time conditions *new*
                    if (condition.StartsWith("time>"))
                    {
                        return(Game1.timeOfDay > Convert.ToInt32(condition.Substring(5)));
                    }
                    // Check if the condition is a deprecated one, and if so, evaluate its replacement instead
                    if (DeprecatedConditions.ContainsKey(condition))
                    {
                        return(CheckCondition(DeprecatedConditions[condition]));
                    }
                    if (customResolver != null)
                    {
                        bool?x = customResolver(condition);
                        if (x != null)
                        {
                            return((bool)x);
                        }
                    }
                    // Check for mail flags
                    return(Game1.player.mailReceived.Contains(condition));
                }
            }
        }