/// <summary> /// Generate a trainings array from the skills already know by a character. /// </summary> /// <param name="character">The character.</param> /// <param name="plan">The plan.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException">character or plan</exception> public static RemappingResult OptimizeFromCharacter(Character character, BasePlan plan) { character.ThrowIfNull(nameof(character)); plan.ThrowIfNull(nameof(plan)); // Create a character without any skill CharacterScratchpad scratchpad = new CharacterScratchpad(character.After(plan.ChosenImplantSet)); scratchpad.ClearSkills(); // Create a new plan Plan newPlan = new Plan(scratchpad); // Add all trained skill levels that the character has trained so far foreach (Skill skill in character.Skills) { newPlan.PlanTo(skill, skill.Level); } // Create a new remapping RemappingResult remapping = new RemappingResult(scratchpad); // Add those skills to the remapping foreach (PlanEntry entry in newPlan) { remapping.Skills.Add(entry); } // Optimize remapping.Optimize(TimeSpan.MaxValue); return(remapping); }
/// <summary> /// Adds the tab page for the given remapping /// </summary> /// <param name="remapping">The remapping.</param> /// <param name="tabName">Name of the tab.</param> private void AddTabPage(RemappingResult remapping, string tabName) { AttributesOptimizerControl ctl = CreateAttributesOptimizationControl(remapping); if (ctl == null) { return; } m_remappingDictionary[ctl] = remapping; TabPage tempPage = null; try { tempPage = new TabPage(tabName); tempPage.Controls.Add(ctl); TabPage page = tempPage; tempPage = null; tabControl.TabPages.Add(page); } finally { tempPage?.Dispose(); } }
/// <summary> /// Adds summary information for given remapping. /// </summary> /// <param name="remap">Remapping object</param> /// <param name="lastRemap">Time of previous remapping</param> private void AddSummaryForRemapping(RemappingResult remap, ref TimeSpan lastRemap) { // Create the group string text = $"{remap} at {remap.StartTime.ToDescriptiveText(DescriptiveTextOptions.IncludeCommas)}"; ListViewGroup group = new ListViewGroup(text); lvPoints.Groups.Add(group); // Check there are at least one year between each remap TimeSpan timeSinceLastRemap = remap.StartTime.Subtract(lastRemap); if (timeSinceLastRemap < TimeSpan.FromDays(365) && remap.StartTime != TimeSpan.Zero) { ListViewItem item = lvPoints.Items.Add( new ListViewItem( $"The previous remap point was only {timeSinceLastRemap.ToDescriptiveText(DescriptiveTextOptions.IncludeCommas)} ago.", group)); item.ForeColor = Color.DarkRed; } lastRemap = remap.StartTime; // Add five items, one for each attribute AddItemForAttribute(remap, group, EveAttribute.Intelligence); AddItemForAttribute(remap, group, EveAttribute.Perception); AddItemForAttribute(remap, group, EveAttribute.Charisma); AddItemForAttribute(remap, group, EveAttribute.Willpower); AddItemForAttribute(remap, group, EveAttribute.Memory); }
/// <summary> /// Creates a <see cref="AttributesOptimizerControl"/> for a given remapping. /// </summary> /// <param name="remapping">The remapping object to represents.</param> /// <returns>The created control.</returns> private AttributesOptimizerControl CreateAttributesOptimizationControl(RemappingResult remapping) { AttributesOptimizerControl control; AttributesOptimizerControl ctl = null; try { ctl = new AttributesOptimizerControl(m_character, m_plan, remapping, m_description); ctl.AttributeChanged += AttributesOptimizationControl_AttributeChanged; // For a manually edited point, we initialize the control with the attributes from the current remapping point if (m_strategy == AttributeOptimizationStrategy.ManualRemappingPointEdition && m_manuallyEditedRemappingPoint.Status == RemappingPointStatus.UpToDate) { ctl.UpdateValuesFrom(m_manuallyEditedRemappingPoint); } control = ctl; ctl = null; } finally { ctl?.Dispose(); } return(control); }
/// <summary> /// Gets the list of remapping results from a plan. /// </summary> /// <param name="plan"></param> /// <returns></returns> /// <exception cref="System.ArgumentNullException">plan</exception> public static Collection <RemappingResult> GetResultsFromRemappingPoints(BasePlan plan) { plan.ThrowIfNull(nameof(plan)); CharacterScratchpad scratchpad = new CharacterScratchpad(plan.Character.After(plan.ChosenImplantSet)); Collection <RemappingResult> remappingList = new Collection <RemappingResult>(); Collection <ISkillLevel> list = new Collection <ISkillLevel>(); // Scroll through the entries and split it into remappings foreach (PlanEntry entry in plan) { // Ends the current remapping and start a new one if (entry.Remapping != null) { // Creates a new remapping RemappingResult remapping = new RemappingResult(entry.Remapping, scratchpad.Clone()); remappingList.Add(remapping); list = remapping.Skills; } // Add this skill to the training list scratchpad.Train(entry); list.Add(entry); } // Return return(remappingList); }
/// <summary> /// Gets the list of remapping results from a plan. /// </summary> /// <param name="plan"></param> /// <returns></returns> public static List <RemappingResult> GetResultsFromRemappingPoints(BasePlan plan) { var scratchpad = new CharacterScratchpad(plan.Character); var remappingList = new List <RemappingResult>(); var list = new List <ISkillLevel>(); RemappingResult remapping = null; // Scroll through the entries and split it into remappings foreach (var entry in plan) { // Ends the current remapping and start a new one if (entry.Remapping != null) { // Creates a new remapping remapping = new RemappingResult(entry.Remapping, scratchpad.Clone()); remappingList.Add(remapping); list = remapping.Skills; } // Add this skill to the training list scratchpad.Train(entry); list.Add(entry); } // Return return(remappingList); }
/// <summary> /// Adds the list item for the given attribute. /// </summary> /// <param name="remap"></param> /// <param name="group"></param> /// <param name="attrib"></param> private void AddItemForAttribute(RemappingResult remap, ListViewGroup group, EveAttribute attrib) { // Add the list view item for this attribute string itemText = RemappingPoint.GetStringForAttribute(attrib, remap.BaseScratchpad, remap.BestScratchpad); lvPoints.Items.Add(new ListViewItem(itemText, group)); }
/// <summary> /// Reset to remapping with current attributes. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonCurrent_Click(object sender, EventArgs e) { // Make unoptimized remap RemappingResult zeroRemapping = new RemappingResult(m_remapping, m_remapping.BaseScratchpad.Clone()); zeroRemapping.Update(); // Update the controls UpdateControls(m_character, m_plan, zeroRemapping, m_description); // Fires the event AttributeChanged?.ThreadSafeInvoke(this, new AttributeChangedEventArgs(zeroRemapping)); }
/// <summary> /// Updates bars and labels with given attributes from remapping. /// </summary> /// <param name="character">Character information</param> /// <param name="plan">Skill plan</param> /// <param name="remapping">Remapping with attributes and training time</param> /// <param name="description"></param> private void UpdateControls(Character character, BasePlan plan, RemappingResult remapping, string description) { UpdateAttributeControls(remapping, EveAttribute.Perception, lbPER, pbPERRemappable, pbPERImplants); UpdateAttributeControls(remapping, EveAttribute.Willpower, lbWIL, pbWILRemappable, pbWILImplants); UpdateAttributeControls(remapping, EveAttribute.Memory, lbMEM, pbMEMRemappable, pbMEMImplants); UpdateAttributeControls(remapping, EveAttribute.Intelligence, lbINT, pbINTRemappable, pbINTImplants); UpdateAttributeControls(remapping, EveAttribute.Charisma, lbCHA, pbCHARemappable, pbCHAImplants); // Update the description label labelDescription.Text = description; // Update the current time control lbCurrentTime.Text = remapping.BaseDuration.ToDescriptiveText(DescriptiveTextOptions.IncludeCommas); // Update the optimized time control lbOptimizedTime.Text = remapping.BestDuration.ToDescriptiveText(DescriptiveTextOptions.IncludeCommas); // Update the time benefit control string bestDurationTimeText = remapping.BaseDuration.Subtract(remapping.BestDuration) .ToDescriptiveText(DescriptiveTextOptions.IncludeCommas); string worseDurationTimeText = remapping.BestDuration.Subtract(remapping.BaseDuration) .ToDescriptiveText(DescriptiveTextOptions.IncludeCommas); lbGain.ForeColor = remapping.BestDuration < remapping.BaseDuration ? Color.DarkGreen : remapping.BaseDuration < remapping.BestDuration ? Color.DarkRed : Color.Black; lbGain.Text = remapping.BestDuration < remapping.BaseDuration ? $"{bestDurationTimeText} better than current" : remapping.BaseDuration < remapping.BestDuration ? $"{worseDurationTimeText} slower than current" : "Same as current"; // A plan may not have a years worth of skills in it, // only fair to warn the user lbWarning.Visible = remapping.BestDuration < TimeSpan.FromDays(365); // Spare points Int64 sparePoints = EveConstants.SpareAttributePointsOnRemap; for (int i = 0; i < 5; i++) { sparePoints -= remapping.BestScratchpad[(EveAttribute)i].Base - EveConstants.CharacterBaseAttributePoints; } pbUnassigned.Value = sparePoints; // If the implant set isn't the active one we notify the user lblNotice.Visible = plan.ChosenImplantSet != character.ImplantSets.Current; }
/// <summary> /// Compute the best remapping for the first year of this plan. /// </summary> /// <param name="plan"></param> /// <returns></returns> public static RemappingResult OptimizeFromFirstYearOfPlan(BasePlan plan) { var remapping = new RemappingResult(new CharacterScratchpad(plan.Character.After(plan.ChosenImplantSet))); // Scroll through the entries and split it into remappings foreach (var entry in plan) { remapping.Skills.Add(entry); } // Compute remapping.Optimize(TimeSpan.FromDays(365.0)); return(remapping); }
/// <summary> /// Recalculating plan and summary page after change of a <see cref="AttributesOptimizerControl"/>. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="AttributeChangedEventArgs"/> instance containing the event data.</param> private void AttributesOptimizationControl_AttributeChanged(object sender, AttributeChangedEventArgs e) { AttributesOptimizerControl control = (AttributesOptimizerControl)sender; if (m_strategy == AttributeOptimizationStrategy.RemappingPoints) { m_remappingDictionary[control] = e.Remapping; UpdateSummaryInformation(m_remappingDictionary.Values); } m_statisticsScratchpad = e.Remapping.BestScratchpad.Clone(); m_remapping = e.Remapping; // Update the plan order's column m_planEditor.ShowWithPluggable(this); }
/// <summary> /// Updates the UI once the computation has been done (for whole plan or character from birth) /// </summary> /// <param name="remapping"></param> private void UpdateForRemapping(RemappingResult remapping) { // Create control AttributesOptimizerControl ctrl = CreateAttributesOptimizationControl(remapping); Controls.Add(ctrl); IList <AttributesOptimizerControl> optControls = Controls.OfType <AttributesOptimizerControl>().ToList(); if (optControls.Count == 1) { return; } Controls.RemoveAt(Controls.IndexOf(optControls.First())); }
/// <summary> /// Starts optimization. /// </summary> /// <param name="update">if set to <c>true</c> [update].</param> /// <exception cref="System.NotImplementedException"></exception> private void Run(bool update = false) { // Compute best scratchpad RemappingResult remapping = null; ICollection <RemappingResult> remappingList = null; switch (m_strategy) { case AttributeOptimizationStrategy.ManualRemappingPointEdition: m_areRemappingPointsActive = true; if (update) { remapping = m_remapping; m_manuallyEditedRemappingPoint = remapping.Point.Clone(); } else { remapping = AttributesOptimizer.GetResultsFromRemappingPoints(m_plan).Single( x => x.Point == m_manuallyEditedRemappingPoint); m_manuallyEditedRemappingPoint = m_manuallyEditedRemappingPoint.Clone(); m_remapping = remapping; } remapping.Optimize(TimeSpan.MaxValue); break; case AttributeOptimizationStrategy.Character: m_areRemappingPointsActive = false; remapping = AttributesOptimizer.OptimizeFromCharacter(m_character, m_plan); break; case AttributeOptimizationStrategy.OneYearPlan: m_areRemappingPointsActive = false; remapping = AttributesOptimizer.OptimizeFromFirstYearOfPlan(m_plan); break; case AttributeOptimizationStrategy.RemappingPoints: m_areRemappingPointsActive = true; remappingList = AttributesOptimizer.OptimizeFromPlanAndRemappingPoints(m_plan); break; default: throw new NotImplementedException(); } // Update the controls for every attribute Dispatcher.Invoke(() => UpdateForm(remapping, remappingList)); }
/// <summary> /// Initializes a new instance of <see cref="AttributesOptimizerControl"/>. /// </summary> /// <param name="character">Character information</param> /// <param name="plan">Skill plan</param> /// <param name="remapping">Optimized remapping</param> /// <param name="description"></param> public AttributesOptimizerControl(Character character, BasePlan plan, RemappingResult remapping, string description) { InitializeComponent(); lbMEM.Font = FontFactory.GetFont("Tahoma"); lbWIL.Font = FontFactory.GetFont("Tahoma"); lbCHA.Font = FontFactory.GetFont("Tahoma"); lbPER.Font = FontFactory.GetFont("Tahoma"); lbINT.Font = FontFactory.GetFont("Tahoma"); m_character = character; m_plan = plan; m_remapping = remapping; m_description = description; UpdateControls(m_character, m_plan, m_remapping, m_description); }
/// <summary> /// Updates bars and labels for specified attribute. /// </summary> /// <param name="remapping">Attribute remapping</param> /// <param name="attrib">Attribute that will be used to update controls</param> /// <param name="label">Label control</param> /// <param name="pbRemappable">Attribute bar for remappable value</param> /// <param name="pbImplants">Attribute bar for implants</param> private static void UpdateAttributeControls(RemappingResult remapping, EveAttribute attrib, Control label, AttributeBarControl pbRemappable, AttributeBarControl pbImplants) { // Compute base and effective attributes Int64 effectiveAttribute = remapping.BestScratchpad[attrib].EffectiveValue; Int64 oldBaseAttribute = remapping.BaseScratchpad[attrib].Base; Int64 remappableAttribute = remapping.BestScratchpad[attrib].Base; Int64 implantsBonus = remapping.BestScratchpad[attrib].ImplantBonus; // Update the label label.Text = $"{effectiveAttribute} (new : {remappableAttribute} ; old : {oldBaseAttribute})"; // Update the bars pbRemappable.Value = remappableAttribute - EveConstants.CharacterBaseAttributePoints; pbImplants.Value = implantsBonus; }
/// <summary> /// Calculates new remapping from values of controls. /// </summary> private void Recalculate() { CharacterScratchpad scratchpad = m_remapping.BaseScratchpad.Clone(); scratchpad.Memory.Base = pbMEMRemappable.Value + EveConstants.CharacterBaseAttributePoints; scratchpad.Charisma.Base = pbCHARemappable.Value + EveConstants.CharacterBaseAttributePoints; scratchpad.Willpower.Base = pbWILRemappable.Value + EveConstants.CharacterBaseAttributePoints; scratchpad.Perception.Base = pbPERRemappable.Value + EveConstants.CharacterBaseAttributePoints; scratchpad.Intelligence.Base = pbINTRemappable.Value + EveConstants.CharacterBaseAttributePoints; // Get remapping for provided attributes RemappingResult manualRemapping = new RemappingResult(m_remapping, scratchpad); manualRemapping.Update(); UpdateControls(m_character, m_plan, manualRemapping, m_description); // Notify the changes AttributeChanged?.ThreadSafeInvoke(this, new AttributeChangedEventArgs(manualRemapping)); }
/// <summary> /// Updates the controls with the values from the current remapping point. /// </summary> /// <param name="point"></param> /// <exception cref="System.ArgumentNullException">point</exception> public void UpdateValuesFrom(RemappingPoint point) { point.ThrowIfNull(nameof(point)); // Creates a scratchpad with the base values from the provided point. CharacterScratchpad scratchpad = new CharacterScratchpad(m_character.After(m_plan.ChosenImplantSet)); for (int i = 0; i < 5; i++) { scratchpad[(EveAttribute)i].Base = point[(EveAttribute)i]; } RemappingResult remapping = new RemappingResult(m_remapping, scratchpad); remapping.Update(); // Update the controls UpdateControls(m_character, m_plan, remapping, m_description); // Fires the event AttributeChanged?.ThreadSafeInvoke(this, new AttributeChangedEventArgs(remapping)); }
/// <summary> /// Updates controls on the form. /// </summary> /// <param name="remapping">An <see cref="RemappingResult"/> object</param> /// <param name="remappingList">List of remappings</param> private void UpdateForm(RemappingResult remapping, ICollection <RemappingResult> remappingList) { // Update the attributes if (remapping != null) { m_statisticsScratchpad = remapping.BestScratchpad.Clone(); UpdateForRemapping(remapping); } else { UpdateForRemappingList(remappingList); } // Update the plan order's column if ((remapping != null) || (remappingList.Count != 0)) { m_planEditor.ShowWithPluggable(this); } // Hide the throbber and the waiting message panelWait.Hide(); }
/// <summary> /// Generate a trainings array from the skills already know by a character /// </summary> /// <param name="character"></param> /// <returns></returns> public static RemappingResult OptimizeFromCharacter(Character character) { // Create a character without any skill var scratchpad = new CharacterScratchpad(character); scratchpad.ClearSkills(); // Create a sorted plan for the learning skills var plan = new Plan(scratchpad); foreach (var learning in character.SkillGroups["Learning"]) { plan.PlanTo(learning, learning.Level); } plan.SortLearningSkills(false); // Add the non-training skills after that foreach (var skill in character.Skills) { if (skill.Group.Name != "Learning") { plan.PlanTo(skill, skill.Level); } } // Add those learning skills to a list var remapping = new RemappingResult(scratchpad); foreach (var entry in plan) { remapping.Skills.Add(entry); } // Optimize remapping.Optimize(TimeSpan.FromDays(365.0)); return(remapping); }
/// <summary> /// Constructor for a manually edited result from a base result. /// </summary> /// <param name="point">Associated remapping point, may be null.</param> /// <param name="baseScratchpad"></param> /// <param name="bestScratchpad"></param> public RemappingResult(RemappingResult result, CharacterScratchpad bestScratchpad) : this(result.Point, result.BaseScratchpad) { m_skills.AddRange(result.m_skills); m_bestScratchpad = bestScratchpad; }
/// <summary> /// Constructor. /// </summary> /// <param name="remapping">The remapping.</param> public AttributeChangedEventArgs(RemappingResult remapping) { Remapping = remapping; }