Reset cached mission attributes when changing characters; improve detection of who is part of the mission
This commit is contained in:
parent
821311e4cc
commit
75084ef5eb
@ -1,8 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
namespace Squadronista.Solver;
|
namespace Squadronista.Solver;
|
||||||
|
|
||||||
internal class Attributes
|
internal class Attributes : IEquatable<Attributes>
|
||||||
{
|
{
|
||||||
public required int PhysicalAbility { get; init; }
|
public required int PhysicalAbility { get; init; }
|
||||||
public required int MentalAbility { get; init; }
|
public required int MentalAbility { get; init; }
|
||||||
public required int TacticalAbility { get; init; }
|
public required int TacticalAbility { get; init; }
|
||||||
|
|
||||||
|
public bool Equals(Attributes? other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
return PhysicalAbility == other.PhysicalAbility && MentalAbility == other.MentalAbility && TacticalAbility == other.TacticalAbility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
|
if (ReferenceEquals(this, obj)) return true;
|
||||||
|
if (obj.GetType() != this.GetType()) return false;
|
||||||
|
return Equals((Attributes)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(PhysicalAbility, MentalAbility, TacticalAbility);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Attributes? left, Attributes? right)
|
||||||
|
{
|
||||||
|
return Equals(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Attributes? left, Attributes? right)
|
||||||
|
{
|
||||||
|
return !Equals(left, right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
11
Squadronista/Solver/SquadronMemberUiFlags.cs
Normal file
11
Squadronista/Solver/SquadronMemberUiFlags.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Squadronista.Solver;
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum SquadronMemberUiFlags : int
|
||||||
|
{
|
||||||
|
Unknown1 = 1,
|
||||||
|
IsPartOfMission = 2,
|
||||||
|
NewChemistryAvailable = 8192,
|
||||||
|
}
|
@ -40,9 +40,9 @@ internal sealed class SquadronSolver
|
|||||||
|
|
||||||
public IEnumerable<CalculationResult> SolveFor(SquadronMission mission, int requiredMatchingStats)
|
public IEnumerable<CalculationResult> SolveFor(SquadronMission mission, int requiredMatchingStats)
|
||||||
{
|
{
|
||||||
int minPhysical = mission.CurrentAttributes.PhysicalAbility;
|
int minPhysical = mission.CurrentAttributes!.PhysicalAbility;
|
||||||
int minMental = mission.CurrentAttributes.MentalAbility;
|
int minMental = mission.CurrentAttributes!.MentalAbility;
|
||||||
int minTactical = mission.CurrentAttributes.TacticalAbility;
|
int minTactical = mission.CurrentAttributes!.TacticalAbility;
|
||||||
|
|
||||||
bool foundWithoutTraining = false;
|
bool foundWithoutTraining = false;
|
||||||
List<CalculationResult> intermediates = CalculateForAllMemberCombinations(mission.Level, _state.Bonus);
|
List<CalculationResult> intermediates = CalculateForAllMemberCombinations(mission.Level, _state.Bonus);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Squadronista.Solver;
|
using System.Collections.Generic;
|
||||||
|
using Squadronista.Solver;
|
||||||
|
|
||||||
namespace Squadronista;
|
namespace Squadronista;
|
||||||
|
|
||||||
@ -9,5 +10,6 @@ internal sealed class SquadronMission
|
|||||||
public required byte Level { get; init; }
|
public required byte Level { get; init; }
|
||||||
public required bool IsFlaggedMission { get; init; }
|
public required bool IsFlaggedMission { get; init; }
|
||||||
|
|
||||||
|
public required IReadOnlyList<Attributes> PossibleAttributes { get; init; }
|
||||||
public Attributes? CurrentAttributes { get; set; }
|
public Attributes? CurrentAttributes { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
<Version>0.3</Version>
|
<Version>0.4</Version>
|
||||||
<LangVersion>11.0</LangVersion>
|
<LangVersion>11.0</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
@ -55,6 +55,15 @@ public class SquadronistaPlugin : IDalamudPlugin
|
|||||||
|
|
||||||
// 13 and 14 seems to be a duplicate
|
// 13 and 14 seems to be a duplicate
|
||||||
IsFlaggedMission = x.RowId is 7 or 14 or 15 or 34,
|
IsFlaggedMission = x.RowId is 7 or 14 or 15 or 34,
|
||||||
|
PossibleAttributes = Enumerable.Range(0, x.RequiredPhysical.Length)
|
||||||
|
.Select(i => new Attributes
|
||||||
|
{
|
||||||
|
PhysicalAbility = x.RequiredPhysical[i],
|
||||||
|
MentalAbility = x.RequiredMental[i],
|
||||||
|
TacticalAbility = x.RequiredTactical[i],
|
||||||
|
})
|
||||||
|
.ToList()
|
||||||
|
.AsReadOnly(),
|
||||||
})
|
})
|
||||||
.ToList()
|
.ToList()
|
||||||
.AsReadOnly();
|
.AsReadOnly();
|
||||||
@ -73,7 +82,7 @@ public class SquadronistaPlugin : IDalamudPlugin
|
|||||||
.AsReadOnly();
|
.AsReadOnly();
|
||||||
|
|
||||||
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
||||||
_clientState.Logout += Logout;
|
_clientState.Logout += ResetCharacterSpecificData;
|
||||||
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "GcArmyMemberList", UpdateSquadronState);
|
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "GcArmyMemberList", UpdateSquadronState);
|
||||||
_addonLifecycle.RegisterListener(AddonEvent.PostRefresh, "GcArmyExpedition", UpdateExpeditionState);
|
_addonLifecycle.RegisterListener(AddonEvent.PostRefresh, "GcArmyExpedition", UpdateExpeditionState);
|
||||||
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "GcArmyExpedition", UpdateExpeditionState);
|
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "GcArmyExpedition", UpdateExpeditionState);
|
||||||
@ -94,7 +103,7 @@ public class SquadronistaPlugin : IDalamudPlugin
|
|||||||
if (addon->AtkValuesCount != 133)
|
if (addon->AtkValuesCount != 133)
|
||||||
{
|
{
|
||||||
_pluginLog.Error("Unexpected AddonGcArmyMemberList atkvalues count");
|
_pluginLog.Error("Unexpected AddonGcArmyMemberList atkvalues count");
|
||||||
SquadronState = null;
|
ResetCharacterSpecificData();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +113,7 @@ public class SquadronistaPlugin : IDalamudPlugin
|
|||||||
// can't do any missions like this...
|
// can't do any missions like this...
|
||||||
if (memberCount < 4)
|
if (memberCount < 4)
|
||||||
{
|
{
|
||||||
SquadronState = null;
|
ResetCharacterSpecificData();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +166,7 @@ public class SquadronistaPlugin : IDalamudPlugin
|
|||||||
{
|
{
|
||||||
AvailableMissions.Clear();
|
AvailableMissions.Clear();
|
||||||
if (type == AddonEvent.PostSetup)
|
if (type == AddonEvent.PostSetup)
|
||||||
SquadronState = null;
|
ResetCharacterSpecificData();
|
||||||
|
|
||||||
AddonGcArmyExpedition* addonExpedition = (AddonGcArmyExpedition*)args.Addon;
|
AddonGcArmyExpedition* addonExpedition = (AddonGcArmyExpedition*)args.Addon;
|
||||||
if (addonExpedition->AtkUnitBase.AtkValuesCount != 216)
|
if (addonExpedition->AtkUnitBase.AtkValuesCount != 216)
|
||||||
@ -182,9 +191,11 @@ public class SquadronistaPlugin : IDalamudPlugin
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Logout()
|
private void ResetCharacterSpecificData()
|
||||||
{
|
{
|
||||||
SquadronState = null;
|
SquadronState = null;
|
||||||
|
foreach (var mission in _allMissions)
|
||||||
|
mission.CurrentAttributes = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@ -193,7 +204,7 @@ public class SquadronistaPlugin : IDalamudPlugin
|
|||||||
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "GcArmyExpedition", UpdateExpeditionState);
|
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "GcArmyExpedition", UpdateExpeditionState);
|
||||||
_addonLifecycle.UnregisterListener(AddonEvent.PostRefresh, "GcArmyExpedition", UpdateExpeditionState);
|
_addonLifecycle.UnregisterListener(AddonEvent.PostRefresh, "GcArmyExpedition", UpdateExpeditionState);
|
||||||
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "GcArmyMemberList", UpdateSquadronState);
|
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "GcArmyMemberList", UpdateSquadronState);
|
||||||
_clientState.Logout -= Logout;
|
_clientState.Logout -= ResetCharacterSpecificData;
|
||||||
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
|
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ internal sealed class MainWindow : Window, IDisposable
|
|||||||
{
|
{
|
||||||
var atkValues = addonMemberList->AtkValues;
|
var atkValues = addonMemberList->AtkValues;
|
||||||
activeMembers = Enumerable.Range(0, (int)atkValues[4].UInt)
|
activeMembers = Enumerable.Range(0, (int)atkValues[4].UInt)
|
||||||
.Where(i => atkValues[5 + i * 15].UInt == 3)
|
.Where(i => ((SquadronMemberUiFlags)atkValues[5 + i * 15].Int).HasFlag(SquadronMemberUiFlags.IsPartOfMission))
|
||||||
.Select(i => atkValues[6 + i * 15].ReadAtkString())
|
.Select(i => atkValues[6 + i * 15].ReadAtkString())
|
||||||
.Where(x => !string.IsNullOrEmpty(x))
|
.Where(x => !string.IsNullOrEmpty(x))
|
||||||
.Cast<string>()
|
.Cast<string>()
|
||||||
@ -170,21 +170,21 @@ internal sealed class MainWindow : Window, IDisposable
|
|||||||
ImGui.Text("Final Stats:");
|
ImGui.Text("Final Stats:");
|
||||||
ImGui.SameLine(0);
|
ImGui.SameLine(0);
|
||||||
ImGui.TextColored(
|
ImGui.TextColored(
|
||||||
result.PhysicalAbility >= selectedMission.CurrentAttributes.PhysicalAbility
|
result.PhysicalAbility >= selectedMission.CurrentAttributes!.PhysicalAbility
|
||||||
? ImGuiColors.HealerGreen
|
? ImGuiColors.HealerGreen
|
||||||
: ImGuiColors.DalamudYellow, $"{result.PhysicalAbility}");
|
: ImGuiColors.DalamudYellow, $"{result.PhysicalAbility}");
|
||||||
ImGui.SameLine(0);
|
ImGui.SameLine(0);
|
||||||
ImGui.Text("/");
|
ImGui.Text("/");
|
||||||
ImGui.SameLine(0);
|
ImGui.SameLine(0);
|
||||||
ImGui.TextColored(
|
ImGui.TextColored(
|
||||||
result.MentalAbility >= selectedMission.CurrentAttributes.MentalAbility
|
result.MentalAbility >= selectedMission.CurrentAttributes!.MentalAbility
|
||||||
? ImGuiColors.HealerGreen
|
? ImGuiColors.HealerGreen
|
||||||
: ImGuiColors.DalamudYellow, $"{result.MentalAbility}");
|
: ImGuiColors.DalamudYellow, $"{result.MentalAbility}");
|
||||||
ImGui.SameLine(0);
|
ImGui.SameLine(0);
|
||||||
ImGui.Text("/");
|
ImGui.Text("/");
|
||||||
ImGui.SameLine(0);
|
ImGui.SameLine(0);
|
||||||
ImGui.TextColored(
|
ImGui.TextColored(
|
||||||
result.TacticalAbility >= selectedMission.CurrentAttributes.TacticalAbility
|
result.TacticalAbility >= selectedMission.CurrentAttributes!.TacticalAbility
|
||||||
? ImGuiColors.HealerGreen
|
? ImGuiColors.HealerGreen
|
||||||
: ImGuiColors.DalamudYellow, $"{result.TacticalAbility}");
|
: ImGuiColors.DalamudYellow, $"{result.TacticalAbility}");
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ internal sealed class MainWindow : Window, IDisposable
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ImGui.TextColored(ImGuiColors.DalamudRed, $"No combination of members/trainings can achieve\n{(selectedMission.IsFlaggedMission ? "all" : "2 out of 3")} attributes for {selectedMission.CurrentAttributes.PhysicalAbility} / {selectedMission.CurrentAttributes.MentalAbility} / {selectedMission.CurrentAttributes.TacticalAbility}.");
|
ImGui.TextColored(ImGuiColors.DalamudRed, $"No combination of members/trainings can achieve\n{(selectedMission.IsFlaggedMission ? "all" : "2 out of 3")} attributes for {selectedMission.CurrentAttributes!.PhysicalAbility} / {selectedMission.CurrentAttributes!.MentalAbility} / {selectedMission.CurrentAttributes!.TacticalAbility}.");
|
||||||
ImGui.Text("Level the squadron further and check again.");
|
ImGui.Text("Level the squadron further and check again.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,12 +315,16 @@ internal sealed class MainWindow : Window, IDisposable
|
|||||||
int mental = int.Parse(mentalText->NodeText.ToString());
|
int mental = int.Parse(mentalText->NodeText.ToString());
|
||||||
int tactical = int.Parse(tacticalText->NodeText.ToString());
|
int tactical = int.Parse(tacticalText->NodeText.ToString());
|
||||||
|
|
||||||
selectedMission.CurrentAttributes = new Attributes
|
var newAttributes = new Attributes
|
||||||
{
|
{
|
||||||
PhysicalAbility = physical,
|
PhysicalAbility = physical,
|
||||||
MentalAbility = mental,
|
MentalAbility = mental,
|
||||||
TacticalAbility = tactical,
|
TacticalAbility = tactical,
|
||||||
};
|
};
|
||||||
|
if (selectedMission.PossibleAttributes.Contains(newAttributes))
|
||||||
|
selectedMission.CurrentAttributes = newAttributes;
|
||||||
|
else
|
||||||
|
_pluginLog.Warning($"Wrong attributes for {selectedMission.Name}: {physical} / {mental} / {tactical}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe T* GetNodeById<T>(AtkUldManager uldManager, uint nodeId, NodeType? type = null)
|
private static unsafe T* GetNodeById<T>(AtkUldManager uldManager, uint nodeId, NodeType? type = null)
|
||||||
|
Loading…
Reference in New Issue
Block a user