Esempio n. 1
0
        public List <Spell> Search(SpellSearchFilter filter)
        {
            //return filter.Apply(SpellList);
            if (filter.ClassMaxLevel == 0)
            {
                filter.ClassMinLevel = 1;
            }
            if (filter.ClassMaxLevel == 0)
            {
                filter.ClassMaxLevel = 255;
            }

            IEnumerable <Spell> query = SpellList;

            // if the spell text filter is an integer then just do a quick search by ID and ignore the other filters
            int id;

            if (Int32.TryParse(filter.Text, out id))
            {
                return(query.Where(x => x.ID == id || x.GroupID == id).ToList());
            }

            //  spell name and description are checked for literal text
            if (!String.IsNullOrEmpty(filter.Text))
            {
                query = query.Where(x => x.ID.ToString() == filter.Text ||
                                    x.Name.IndexOf(filter.Text, StringComparison.InvariantCultureIgnoreCase) >= 0 ||
                                    (x.Stacking != null && x.Stacking.Any(y => y.IndexOf(filter.Text, StringComparison.InvariantCultureIgnoreCase) >= 0)) ||
                                    (x.Desc != null && x.Desc.IndexOf(filter.Text, StringComparison.InvariantCultureIgnoreCase) >= 0));
            }

            // level filter is only used when a class is selected
            int levelArrayIndex = SpellParser.ParseClass(filter.Class) - 1;

            if (filter.Class == "Any PC")
            {
                query = query.Where(x => x.ClassesMask != 0);
            }
            else if (filter.Class == "Non PC")
            {
                //query = query.Where(x => x.ClassesMask == 0);
                query = query.Where(x => x.ExtLevels.All(y => y == 0));
            }
            else if (!String.IsNullOrEmpty(filter.Class) && filter.Category != "AA")
            {
                if (levelArrayIndex >= 0)
                {
                    query = query.Where(x => x.ClassesLevels != "ALL/254" && x.ExtLevels[levelArrayIndex] >= filter.ClassMinLevel && x.ExtLevels[levelArrayIndex] <= filter.ClassMaxLevel);
                }
            }

            if (!String.IsNullOrEmpty(filter.Category))
            {
                if (filter.Category == "AA" && levelArrayIndex >= 0)
                {
                    query = query.Where(x => x.ExtLevels[levelArrayIndex] == 254);
                }
                else if (filter.Category == "AA")
                {
                    query = query.Where(x => x.ExtLevels.Any(y => y == 254));
                }
                else
                {
                    query = query.Where(x => x.Categories.Any(y => y.StartsWith(filter.Category, StringComparison.InvariantCultureIgnoreCase)));
                }
            }

            // effect filter can be a literal string or a regex
            for (int i = 0; i < filter.Effect.Length; i++)
            {
                if (!String.IsNullOrEmpty(filter.Effect[i]))
                {
                    string effect = null;
                    if (SpellSearchFilter.CommonEffects.ContainsKey(filter.Effect[i]))
                    {
                        effect = SpellSearchFilter.CommonEffects[filter.Effect[i]];
                    }

                    if (!String.IsNullOrEmpty(effect))
                    {
                        var re   = new Regex(effect, RegexOptions.IgnoreCase);
                        int?slot = filter.EffectSlot[i];
                        query = query.Where(x => x.HasEffect(re, slot ?? 0));
                    }
                    else
                    {
                        string text = filter.Effect[i];
                        int?   slot = filter.EffectSlot[i];
                        query = query.Where(x => x.HasEffect(text, slot ?? 0));
                    }
                }
            }

            //if (filter.Ranks == "Unranked")
            //    query = query.Where(x => x.Rank == 0);
            //if (filter.Ranks == "Rank 1")
            //    query = query.Where(x => x.Rank == 1);
            //if (filter.Ranks == "Rank 2")
            //    query = query.Where(x => x.Rank == 2);
            //if (filter.Ranks == "Rank 3")
            //    query = query.Where(x => x.Rank == 3);
            //if (filter.Ranks == "Unranked + Rank 1")
            //    query = query.Where(x => x.Rank == 0 || x.Rank == 1);
            //if (filter.Ranks == "Unranked + Rank 2")
            //    query = query.Where(x => x.Rank == 0 || x.Rank == 2);
            //if (filter.Ranks == "Unranked + Rank 3")
            //    query = query.Where(x => x.Rank == 0 || x.Rank == 3);

            return(query.ToList());
        }
Esempio n. 2
0
        /// <summary>
        /// Sort a spell list based on what kind of filters were used.
        /// </summary>
        public void Sort(List <Spell> list, SpellSearchFilter filter)
        {
            int cls = SpellParser.ParseClass(filter.Class) - 1;
            int id;

            Int32.TryParse(filter.Text, out id);

            // 1. if an effect is selected then sort by the effect strength
            // this is problematic since many spells have conditional effects
            //if (effect.Contains(@"(\d+)"))
            //{
            //    Sorting = "Results have been sorted by descending " + SearchEffect.Text + " strength.";
            //    var re = new Regex(effect, RegexOptions.IgnoreCase);
            //    Results.Sort((a, b) =>
            //    {
            //        int comp = b.ScoreEffect(re) - a.ScoreEffect(re);
            //        if (comp == 0)
            //            comp = a.ID - b.ID;
            //        return comp;
            //    });
            //}
            // 2. if a class is selected then sort by the casting levels for that class first
            // place castable spells before non castable effects (level == 0)
            if (cls >= 0)
            {
                list.Sort((a, b) =>
                {
                    if (a.Levels[cls] > 0 && b.Levels[cls] == 0)
                    {
                        return(-1);
                    }
                    if (b.Levels[cls] > 0 && a.Levels[cls] == 0)
                    {
                        return(1);
                    }
                    // move AA to bottom of list
                    if (a.Levels[cls] >= 250 && b.Levels[cls] < 250)
                    {
                        return(1);
                    }
                    if (b.Levels[cls] >= 250 && a.Levels[cls] < 250)
                    {
                        return(-1);
                    }
                    // b-a = descending
                    // a-b = ascending
                    int comp = b.Levels[cls] - a.Levels[cls];
                    if (comp == 0)
                    {
                        comp = String.Compare(StripRank(a.Name), StripRank(b.Name));
                    }
                    if (comp == 0)
                    {
                        comp = a.ID - b.ID;
                    }
                    return(comp);
                });
            }
            // 3. finally sort by name if no better method is found
            else
            {
                list.Sort((a, b) =>
                {
                    int comp = String.Compare(StripRank(a.Name), StripRank(b.Name));
                    if (comp == 0)
                    {
                        comp = a.ID - b.ID;
                    }
                    return(comp);
                });
            }

            // if searching by id, move the spell to the top of the results because it may be sorted below it's side effect spells
            if (id > 0)
            {
                var i = list.FindIndex(x => x.ID == id);
                if (i > 0)
                {
                    var move = list[i];
                    list.RemoveAt(i);
                    list.Insert(0, move);
                }
            }
            // move entries that begin with the search text to the front of the results
            else if (!String.IsNullOrEmpty(filter.Text))
            {
                var move = list.FindAll(x => x.Name.StartsWith(filter.Text, StringComparison.InvariantCultureIgnoreCase));
                if (move.Count > 0)
                {
                    list.RemoveAll(x => x.Name.StartsWith(filter.Text, StringComparison.InvariantCultureIgnoreCase));
                    list.InsertRange(0, move);
                }
            }
        }
Esempio n. 3
0
        public void LoadSpells(string spellPath)
        {
            SpellPath     = spellPath;
            SpellList     = SpellParser.LoadFromFile(spellPath);
            SpellsById    = SpellList.ToDictionary(x => x.ID);
            SpellsByGroup = SpellList.Where(x => x.GroupID != 0).ToLookup(x => x.GroupID);

            // fill LinksTo array for each spells - this will be used to include associated spells in search results
            // excluded spell IDs will be negated
            foreach (var spell in SpellList)
            {
                var linked = new List <int>(10);

                // add link for recourse spell
                if (spell.RecourseID != 0)
                {
                    linked.Add(spell.RecourseID);
                }

                // add links for spells reference in any slots
                foreach (var s in spell.Slots)
                {
                    if (s != null)
                    {
                        bool exclude = s.Desc.Contains("Exclude");

                        // match spell refs (works for a single ref)
                        //var match = Spell.SpellRefExpr.Match(s.Desc);
                        //if (match.Success)
                        //{
                        //    int id = Int32.Parse(match.Groups[1].Value);
                        //    linked.Add(exclude ? -id : id);
                        //}

                        // match spell refs (works for multiple refs on a single slot e.g. auras)
                        var matches = Spell.SpellRefExpr.Matches(s.Desc);
                        foreach (Match match in matches)
                        {
                            int id = Int32.Parse(match.Groups[1].Value);
                            linked.Add(exclude ? -id : id);
                        }

                        // match spell group refs
                        var gmatch = Spell.GroupRefExpr.Match(s.Desc);
                        if (gmatch.Success)
                        {
                            int id = Int32.Parse(gmatch.Groups[1].Value);
                            linked.AddRange(SpellsByGroup[id].Select(x => exclude ? -x.ID : x.ID));
                        }
                    }
                }

                // for each spell that is referenced, update ExtLevels if the spells isn't already flagged as usable by the class
                foreach (int id in linked)
                {
                    Spell target = null;
                    if (SpellsById.TryGetValue(id, out target))
                    {
                        target.RefCount++;

                        // only do this for spells that aren't already assigned to a class
                        if (target.ClassesMask != 0)
                        {
                            continue;
                        }

                        // a lot of side effect spells do not have a level on them. this will copy the level of the referring spell
                        // onto the side effect spell so that the spell will be searchable when filtering by class.
                        // e.g. Jolting Swings Strike has no level so it won't show up in a ranger search even though Jolting Swings will show up
                        // we create this separate array and never display it because modifying the levels array would imply different functionality
                        // e.g. some spells purposely don't have levels assigned so that they are not affected by focus spells
                        for (int i = 0; i < spell.Levels.Length; i++)
                        {
                            if (target.ExtLevels[i] == 0 && spell.Levels[i] != 0)
                            {
                                target.ExtLevels[i] = spell.Levels[i];
                            }

                            // apply in the reverse direction too. this will probably only be useful for including type3 augs
                            // todo: check if this includes too many focus spells
                            //if (spell.ExtLevels[i] == 0 && target.Levels[i] != 0)
                            //    spell.ExtLevels[i] = target.Levels[i];
                        }
                    }
                }

                spell.LinksTo = linked.ToArray();
            }
        }