Skip to content

Commit

Permalink
Fix skill queue list time and sp/hr text.
Browse files Browse the repository at this point in the history
- Refactor booster duration to be calculated on a per skill basis instead of for the entire queue.
  • Loading branch information
mgoeppner committed Dec 23, 2022
1 parent e52e7fd commit 175c21b
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 36 deletions.
2 changes: 1 addition & 1 deletion src/EVEMon.Common/Models/BaseCharacter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ public TimeSpan GetTrainingTimeWithoutBoosters(StaticSkill skill, long level, Tr
/// <param name="sp"></param>
/// <param name="spPerHour"></param>
/// <returns></returns>
private static TimeSpan GetTrainingTime(long sp, float spPerHour)
internal static TimeSpan GetTrainingTime(long sp, float spPerHour)
=> Math.Abs(spPerHour) < float.Epsilon ? TimeSpan.FromDays(999.0) : TimeSpan.FromHours(sp / spPerHour);

/// <summary>
Expand Down
83 changes: 83 additions & 0 deletions src/EVEMon.Common/Models/QueuedSkill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,31 @@ public double SkillPointsPerHour
}
}

/// <summary>
/// Gets the training speed without boosters.
/// </summary>
/// <returns></returns>
public double SkillPointsPerHourWithoutBoosters
{
get
{
double rate;
if (Skill == Skill.UnknownSkill)
{
// Based on estimated end time - start time
double time = EndTime.Subtract(StartTime).TotalHours;
if (time <= 0.0)
// Do not divide by zero
rate = 0.0;
else
rate = Math.Ceiling((EndSP - StartSP) / time);
}
else
rate = Skill.SkillPointsPerHourWithoutBoosters;
return rate;
}
}

/// <summary>
/// Computes the remaining time.
/// </summary>
Expand Down Expand Up @@ -212,11 +237,69 @@ public bool IsTraining
}
}

public TimeSpan BoosterDuration
{
get
{
var remainingTime = RemainingTime;
var queueTime = EndTime - StartTime;

var expectedTime = Owner.GetTimeSpanForPointsWithoutBoosters(Skill.StaticData, Level);

var actualSPRate = Owner.GetBaseSPPerHour(Skill.StaticData);
var expectedSPRate = Owner.GetBaseSPPerHourWithoutBoosters(Skill.StaticData);

if (expectedTime > remainingTime || !IsTraining && (expectedTime > queueTime))
{
// Booster detected!
var remainingSP = EndSP - CurrentSP;
var expectedSPInActualTime = IsTraining ?
Math.Round(remainingTime.TotalHours * expectedSPRate) : Math.Round(queueTime.TotalHours * expectedSPRate);

var spRateDiff = actualSPRate - expectedSPRate;

if (spRateDiff <= 0)
{
return TimeSpan.Zero;
}

var boosterHours = (remainingSP - expectedSPInActualTime) / spRateDiff;

return TimeSpan.FromHours(boosterHours);
}
return TimeSpan.Zero;
}
}

/// <summary>
/// Gets true if the training has been completed, false otherwise.
/// </summary>
public bool IsCompleted => EndTime <= DateTime.UtcNow;

/// <summary>
/// Calculate the time it will take to train a certain amount of skill points.
/// </summary>
/// <param name="points">The amount of skill points.</param>
/// <returns>Time it will take.</returns>
public TimeSpan GetTimeSpanForPoints(long points)
{
if (BoosterDuration > TimeSpan.Zero)
{
var c = Owner as CCPCharacter;
if (c == null)
{
return TimeSpan.Zero;
}

var actualSPRate = c.GetBaseSPPerHour(Skill.StaticData);
var expectedSPRate = c.GetBaseSPPerHourWithoutBoosters(Skill.StaticData);

return Skill.GetTimeSpanForPoints(points, expectedSPRate, actualSPRate, BoosterDuration);
}

return Skill.GetTimeSpanForPoints(points);
}

public override bool Equals(object obj)
{
var other = obj as QueuedSkill;
Expand Down
19 changes: 18 additions & 1 deletion src/EVEMon.Common/Models/Skill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -501,9 +501,26 @@ public Skill ToCharacter(Character character)
/// </summary>
/// <param name="points">The amount of skill points.</param>
/// <returns>Time it will take.</returns>
public TimeSpan GetTimeSpanForPoints(long points)
public TimeSpan GetTimeSpanForPoints(long points)
=> Character?.GetTimeSpanForPoints(this, points) ?? TimeSpan.Zero;

public TimeSpan GetTimeSpanForPoints(long points, float normalRate, float boostedRate, TimeSpan boostedDuration)
{
var boostedPoints = (long)Math.Round(boostedRate * boostedDuration.TotalHours);
var normalPoints = points - boostedPoints;

var boostedTime = BaseCharacter.GetTrainingTime(boostedPoints, boostedRate);
var normalTime = BaseCharacter.GetTrainingTime(normalPoints, normalRate);

if (normalPoints <= 0)
{
// Skill will complete training while booster is active!
return boostedTime;
}

return normalTime + boostedTime;
}

/// <summary>
/// Calculates the cumulative points required to reach the given level of this skill, starting from the current SP.
/// </summary>
Expand Down
30 changes: 1 addition & 29 deletions src/EVEMon.Common/Models/SkillQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,35 +64,7 @@ internal void Dispose()
/// <summary>
/// Gets the expected booster duration
/// </summary>
public TimeSpan BoosterDuration => !Items.Any() ? TimeSpan.Zero : TimeSpan.FromHours(Items.Select(i => {
var remainingTime = i.RemainingTime;
var queueTime = i.EndTime - i.StartTime;

var expectedTime = m_character.GetTimeSpanForPointsWithoutBoosters(i.Skill.StaticData, i.Level);

var actualSPRate = m_character.GetBaseSPPerHour(i.Skill.StaticData);
var expectedSPRate = m_character.GetBaseSPPerHourWithoutBoosters(i.Skill.StaticData);

if (expectedTime > remainingTime || !i.IsTraining && (expectedTime > queueTime))
{
// Booster detected!
var remainingSP = i.EndSP - i.CurrentSP;
var expectedSPInActualTime = i.IsTraining ?
Math.Round(remainingTime.TotalHours * expectedSPRate) : Math.Round(queueTime.TotalHours * expectedSPRate);

var spRateDiff = actualSPRate - expectedSPRate;

if (spRateDiff <= 0)
{
return TimeSpan.Zero.TotalHours;
}

var boosterHours = (remainingSP - expectedSPInActualTime) / spRateDiff;

return boosterHours;
}
return TimeSpan.Zero.TotalHours;
}).Sum());
public TimeSpan BoosterDuration => !Items.Any() ? TimeSpan.Zero : TimeSpan.FromHours(Items.Select(i => i.BoosterDuration.TotalHours).Sum());

/// <summary>
/// Gets the skill currently in training.
Expand Down
10 changes: 5 additions & 5 deletions src/EVEMon/CharacterMonitoring/CharacterSkillsQueueList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,15 @@ private void DrawItem(QueuedSkill skill, DrawItemEventArgs e)
skill.Skill.StaticData.GetPointsRequiredForLevel(Math.Min(skill.Level, 5));
long pointsLeft = skillPointsToNextLevel - skillPoints;
TimeSpan timeSpanFromPoints = !hasSkill ? skill.EndTime.Subtract(DateTime.UtcNow) :
skill.Skill.GetTimeSpanForPoints(pointsLeft);
skill.GetTimeSpanForPoints(pointsLeft);
string remainingTimeText = timeSpanFromPoints.ToDescriptiveText(
DescriptiveTextOptions.SpaceBetween);

double fractionCompleted = e.Index == 0 ? skill.FractionCompleted : 0.0;

string indexText = $"{e.Index + 1}. ";
string indexText = $"{e.Index + 1}. {(skill.BoosterDuration > TimeSpan.Zero ? "\u26a1" : "")}";
string rankText = $" (Rank {(skill.Skill == null ? 0 : skill.Rank)})";
string spPerHourText = $" SP/Hour: {skill.SkillPointsPerHour}";
string spPerHourText = $" SP/Hour: {(skill.BoosterDuration > TimeSpan.Zero ? skill.SkillPointsPerHour : skill.SkillPointsPerHourWithoutBoosters)}";
string spText = $"SP: {skillPoints:N0}/{skillPointsToNextLevel:N0}";
string trainingTimeText = $" Training Time: {remainingTimeText}";
string levelText = $"Level {skill.Level}";
Expand Down Expand Up @@ -646,7 +646,7 @@ private static string GetTooltip(QueuedSkill skill)
long pointsLeft = nextLevelSP - sp;
TimeSpan timeSpanFromPoints = skill.Skill == Skill.UnknownSkill
? skill.EndTime.Subtract(DateTime.UtcNow)
: skill.Skill.GetTimeSpanForPoints(pointsLeft);
: skill.GetTimeSpanForPoints(pointsLeft);
string remainingTimeText = timeSpanFromPoints.ToDescriptiveText(
DescriptiveTextOptions.IncludeCommas | DescriptiveTextOptions.UppercaseText);

Expand Down Expand Up @@ -769,7 +769,7 @@ private static void AddSkillBoilerPlate(StringBuilder toolTip, QueuedSkill skill
toolTip.AppendLine().AppendLine(skill.Skill.Description.WordWrap(100));
toolTip.Append("Primary: ").Append(skill.Skill.PrimaryAttribute).Append(", ");
toolTip.Append("Secondary: ").Append(skill.Skill.SecondaryAttribute).Append(" (");
toolTip.AppendFormat("{0:F0}", skill.SkillPointsPerHour).Append(" SP/Hour)");
toolTip.AppendFormat("{0:F0}", skill.BoosterDuration > TimeSpan.Zero ? skill.SkillPointsPerHour : skill.SkillPointsPerHourWithoutBoosters).Append(" SP/Hour)");
}

/// <summary>
Expand Down

0 comments on commit 175c21b

Please sign in to comment.