Here is my hybrid spell implementation in about 50 lines (supporting multiple baseline or specline attached from specs)
It's not really tested, but it's to give some example on how a whole "career" can be handled using some fine tuned query (Performance may be low with this kind of code, but it get cached pretty good by the runtime !)
If I were to drop the "auto"-merge capability of DOL Core Hybrid spell line handling it could get half of the code
- Code: Select all
public override IDictionary<SpellLine, List<Spell>> GetLinesSpellsForLiving(GameLiving living) { Dictionary<SpellLine, IEnumerable<Tuple<Spell, int, bool>>> buffer = new Dictionary<SpellLine, IEnumerable<Tuple<Spell, int, bool>>>(); IList<SpellLine> lines = GetSpellLinesForLiving(living); foreach (SpellLine ls in lines) { var lib = SkillBase.GetSpellList(ls.KeyName).Where(item => item.Level <= ls.Level); int take = 1; if (living is GamePlayer && AllowMultipleSpellVersions(ls, (GamePlayer)living)) { // Get 2-First Better Spell for each type take = 2; } var firstBetterSpellNoGroup = lib.Where(item => item.Group == 0) .GroupBy(item => new { item.SpellType, item.Target, item.IsAoE, item.IsInstantCast, item.HasSubSpell }) .Select(ins => ins.OrderByDescending(it => it.Level).ThenByDescending(it => it.ID).Take(take)); var firstBetterSpellGroup = lib.Where(item => item.Group != 0) .GroupBy(item => item.Group) .Select(ins => ins.OrderByDescending(it => it.Level).ThenByDescending(it => it.ID).Take(take); // no need for sorting we'll use the order collection for this... var firstBetterSpellFinal = firstBetterSpellGroup.SelectMany(el => el).Union(firstBetterSpellNoGroup.SelectMany(el => el)).Where(item => item != null); // Get Appearance Order // not group base var baseOrderNoGroup = lib.Where(item => item.Group == 0) .GroupBy(item => new { item.SpellType, item.Target, item.IsAoE, item.IsInstantCast, item.HasSubSpell }) .Select(ins => ins.OrderBy(it => it.Level).ThenBy(it => it.ID).FirstOrDefault()); // group based var baseOrderGroup = lib.Where(item => item.Group != 0) .GroupBy(item => item.Group) .Select(ins => ins.OrderBy(it => it.Level).ThenBy(it => it.ID).FirstOrDefault()); // Join and sort... var baseOrderFinal = baseOrderNoGroup.Union(baseOrderGroup).Where(item => item != null).OrderBy(item => item.Level).ThenBy(item => item.ID).ToList(); // Join all this in the Dictionary ! We have to save appearance index order here (as it will be merged later) // the previous "baseOrderFinal" query is used as an index range... var finalList = firstBetterSpellFinal.Select(item => new Tuple<Spell, int, bool>(item, baseOrderFinal.FindIndex(od => (od.Group == 0 && (od.SpellType == item.SpellType && od.Target == item.Target && od.IsAoE == item.IsAoE && od.HasSubSpell == item.HasSubSpell && od.IsInstantCast == item.IsInstantCast)) || (od.Group != 0 && od.Group == item.Group)) , ls.IsBaseLine)); if (!buffer.ContainsKey(ls)) { buffer.Add(ls, finalList); } } // bind them in ONE spellLine return buffer.GroupBy(entry => entry.Key.Spec) .ToDictionary(k => lines.First(), v => v.SelectMany(el => el.Value) .OrderBy(el => (el.Item3 ? 0 : 1)) .ThenBy(el => el.Item2) .ThenBy(el => el.Item1.Level) .Select(Level => Level.Item1).ToList()); }