/// <summary> /// Given a list of skill to add, we return a list of all entries to add, also including all dependencies. No entry is added by this method. /// </summary> /// <param name="skillsToAdd">The enumerations of skills to add.</param> /// <param name="note">The note for new entries.</param> /// <param name="lowestPrereqPriority">The lowest priority (highest number) among all the prerequisites.</param> /// <returns>A list of all the entries to add.</returns> public List <PlanEntry> GetAllEntriesToAdd <T>(IEnumerable <T> skillsToAdd, string note, out int lowestPrereqPriority) where T : ISkillLevel { SkillLevelSet <PlanEntry> entriesSet = new SkillLevelSet <PlanEntry>(); List <PlanEntry> planEntries = new List <PlanEntry>(); lowestPrereqPriority = 1; // For every items to add foreach (var itemToAdd in skillsToAdd) { // Already trained ? We skip it. if (m_character.GetSkillLevel(itemToAdd.Skill) >= itemToAdd.Level) { continue; } // Already planned ? We update the lowestPrereqPriority and skip it. if (IsPlanned(itemToAdd.Skill, itemToAdd.Level)) { lowestPrereqPriority = Math.Max(GetEntry(itemToAdd.Skill, itemToAdd.Level).Priority, lowestPrereqPriority); continue; } // Let's first add dependencies var item = new StaticSkillLevel(itemToAdd); foreach (var dependency in item.AllDependencies) { // Already in the "entries to add" list ? We skip it. if (entriesSet.Contains(dependency)) { continue; } // Already trained ? We skip it. if (m_character.GetSkillLevel(dependency.Skill) >= dependency.Level) { continue; } // Create an entry (even for existing ones, we will update them later from those new entries) var dependencyEntry = CreateEntryToAdd(dependency.Skill, dependency.Level, PlanEntryType.Prerequisite, note, ref lowestPrereqPriority); planEntries.Add(dependencyEntry); entriesSet.Set(dependencyEntry); } // Already in the "entries to add" list ? We skip it (done at this point only because of recursive prereqs) if (entriesSet.Contains(itemToAdd)) { continue; } // Then add the item itself var entry = CreateEntryToAdd(itemToAdd.Skill, itemToAdd.Level, PlanEntryType.Planned, note, ref lowestPrereqPriority); planEntries.Add(entry); entriesSet.Set(entry); } return(planEntries); }
/// <summary> /// Ensures the prerequsiites order is correct /// </summary> /// <param name="list"></param> private void FixPrerequisitesOrder(List <PlanEntry> list) { // Gather prerequisites/postrequisites relationships and use them to connect nodes - O(n²) operation var dependencies = new Dictionary <PlanEntry, List <PlanEntry> >(); foreach (var entry in list) { dependencies[entry] = new List <PlanEntry>(list.Where(x => entry.IsDependentOf(x))); } // Insert entries var entriesToAdd = new LinkedList <PlanEntry>(list); var set = new SkillLevelSet <PlanEntry>(); list.Clear(); while (entriesToAdd.Count != 0) { // Gets the first entry which has all its prerequisites satisfied. var item = entriesToAdd.First(x => dependencies[x].All(y => set[y.Skill, y.Level] != null)); // Add it to the set and list, and remove it from the entries to add set[item.Skill, item.Level] = item; entriesToAdd.Remove(item); list.Add(item); } }
/// <summary> /// Given a list of skill to remove, we return a list of entries also including all dependencies. No entry is removed by this method. /// </summary> /// <returns>A list of all the entries to remove.</returns> public List <PlanEntry> GetAllEntriesToRemove <T>(IEnumerable <T> skillsToRemove) where T : ISkillLevel { SkillLevelSet <PlanEntry> entriesSet = new SkillLevelSet <PlanEntry>(); List <PlanEntry> planEntries = new List <PlanEntry>(); // For every items to add foreach (var itemToRemove in skillsToRemove) { // Not planned ? We skip it. if (!IsPlanned(itemToRemove.Skill, itemToRemove.Level)) { continue; } // Already in the "entries to remove" list ? We skip it (done at this point only because of recursive prereqs) if (entriesSet.Contains(itemToRemove)) { continue; } // Let's first gather dependencies var item = new StaticSkillLevel(itemToRemove); foreach (var dependencyEntry in m_items) { // Already in the "entries to remove" list ? We skip it. if (entriesSet.Contains(dependencyEntry)) { continue; } // Not dependent ? We skip it. if (!dependencyEntry.IsDependentOf(itemToRemove)) { continue; } // Gather this entry planEntries.Add(dependencyEntry); entriesSet.Set(dependencyEntry); } // Then add the item itself var entryToRemove = GetEntry(itemToRemove.Skill, itemToRemove.Level); planEntries.Add(entryToRemove); entriesSet.Set(entryToRemove); } return(planEntries); }
/// <summary> /// Rebuild the plan from the given entries enumeration. /// </summary> /// <remarks>Entries from another plan will be cloned.</remarks> /// <param name="preserveOldEntries">When true, old entries will be reused as often as possible, preserving their statistics.</param> /// <param name="entries"></param> public void RebuildPlanFrom(IEnumerable <PlanEntry> entries, bool preserveOldEntries) { if (!preserveOldEntries) { RebuildPlanFrom(entries); return; } using (SuspendingEvents()) { // Save the old entries var set = new SkillLevelSet <PlanEntry>(); foreach (var entry in m_items) { set[entry.Skill, entry.Level] = entry; } // Clear items m_items.Clear(); for (int i = 0; i < m_lookup.Length; i++) { m_lookup[i] = null; } // Add the new entries foreach (var entry in entries) { var oldEntry = set[entry.Skill, entry.Level]; PlanEntry entryToAdd; if (entry.Plan != this) { entryToAdd = entry.Clone(this); } else if (oldEntry != null) { entryToAdd = oldEntry; } else { entryToAdd = entry; } AddCore(entryToAdd); } } }