Reset cached mission attributes when changing characters; improve detection of who is part of the mission

master v0.4
Liza 2023-10-15 08:56:49 +02:00
parent 821311e4cc
commit c859e2553c
Signed by: liza
GPG Key ID: 7199F8D727D55F67
7 changed files with 78 additions and 18 deletions

View File

@ -1,8 +1,40 @@
using System;
namespace Squadronista.Solver;
internal class Attributes
internal class Attributes : IEquatable<Attributes>
{
public required int PhysicalAbility { get; init; }
public required int MentalAbility { 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);
}
}

View File

@ -0,0 +1,11 @@
using System;
namespace Squadronista.Solver;
[Flags]
public enum SquadronMemberUiFlags : int
{
Unknown1 = 1,
IsPartOfMission = 2,
NewChemistryAvailable = 8192,
}

View File

@ -40,9 +40,9 @@ internal sealed class SquadronSolver
public IEnumerable<CalculationResult> SolveFor(SquadronMission mission, int requiredMatchingStats)
{
int minPhysical = mission.CurrentAttributes.PhysicalAbility;
int minMental = mission.CurrentAttributes.MentalAbility;
int minTactical = mission.CurrentAttributes.TacticalAbility;
int minPhysical = mission.CurrentAttributes!.PhysicalAbility;
int minMental = mission.CurrentAttributes!.MentalAbility;
int minTactical = mission.CurrentAttributes!.TacticalAbility;
bool foundWithoutTraining = false;
List<CalculationResult> intermediates = CalculateForAllMemberCombinations(mission.Level, _state.Bonus);

View File

@ -1,4 +1,5 @@
using Squadronista.Solver;
using System.Collections.Generic;
using Squadronista.Solver;
namespace Squadronista;
@ -9,5 +10,6 @@ internal sealed class SquadronMission
public required byte Level { get; init; }
public required bool IsFlaggedMission { get; init; }
public required IReadOnlyList<Attributes> PossibleAttributes { get; init; }
public Attributes? CurrentAttributes { get; set; }
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
<Version>0.3</Version>
<Version>0.4</Version>
<LangVersion>11.0</LangVersion>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

View File

@ -55,6 +55,15 @@ public class SquadronistaPlugin : IDalamudPlugin
// 13 and 14 seems to be a duplicate
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()
.AsReadOnly();
@ -73,7 +82,7 @@ public class SquadronistaPlugin : IDalamudPlugin
.AsReadOnly();
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
_clientState.Logout += Logout;
_clientState.Logout += ResetCharacterSpecificData;
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "GcArmyMemberList", UpdateSquadronState);
_addonLifecycle.RegisterListener(AddonEvent.PostRefresh, "GcArmyExpedition", UpdateExpeditionState);
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "GcArmyExpedition", UpdateExpeditionState);
@ -94,7 +103,7 @@ public class SquadronistaPlugin : IDalamudPlugin
if (addon->AtkValuesCount != 133)
{
_pluginLog.Error("Unexpected AddonGcArmyMemberList atkvalues count");
SquadronState = null;
ResetCharacterSpecificData();
return;
}
@ -104,7 +113,7 @@ public class SquadronistaPlugin : IDalamudPlugin
// can't do any missions like this...
if (memberCount < 4)
{
SquadronState = null;
ResetCharacterSpecificData();
return;
}
@ -157,7 +166,7 @@ public class SquadronistaPlugin : IDalamudPlugin
{
AvailableMissions.Clear();
if (type == AddonEvent.PostSetup)
SquadronState = null;
ResetCharacterSpecificData();
AddonGcArmyExpedition* addonExpedition = (AddonGcArmyExpedition*)args.Addon;
if (addonExpedition->AtkUnitBase.AtkValuesCount != 216)
@ -182,9 +191,11 @@ public class SquadronistaPlugin : IDalamudPlugin
return null;
}
private void Logout()
private void ResetCharacterSpecificData()
{
SquadronState = null;
foreach (var mission in _allMissions)
mission.CurrentAttributes = null;
}
public void Dispose()
@ -193,7 +204,7 @@ public class SquadronistaPlugin : IDalamudPlugin
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "GcArmyExpedition", UpdateExpeditionState);
_addonLifecycle.UnregisterListener(AddonEvent.PostRefresh, "GcArmyExpedition", UpdateExpeditionState);
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "GcArmyMemberList", UpdateSquadronState);
_clientState.Logout -= Logout;
_clientState.Logout -= ResetCharacterSpecificData;
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
}
}

View File

@ -126,7 +126,7 @@ internal sealed class MainWindow : Window, IDisposable
{
var atkValues = addonMemberList->AtkValues;
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())
.Where(x => !string.IsNullOrEmpty(x))
.Cast<string>()
@ -170,21 +170,21 @@ internal sealed class MainWindow : Window, IDisposable
ImGui.Text("Final Stats:");
ImGui.SameLine(0);
ImGui.TextColored(
result.PhysicalAbility >= selectedMission.CurrentAttributes.PhysicalAbility
result.PhysicalAbility >= selectedMission.CurrentAttributes!.PhysicalAbility
? ImGuiColors.HealerGreen
: ImGuiColors.DalamudYellow, $"{result.PhysicalAbility}");
ImGui.SameLine(0);
ImGui.Text("/");
ImGui.SameLine(0);
ImGui.TextColored(
result.MentalAbility >= selectedMission.CurrentAttributes.MentalAbility
result.MentalAbility >= selectedMission.CurrentAttributes!.MentalAbility
? ImGuiColors.HealerGreen
: ImGuiColors.DalamudYellow, $"{result.MentalAbility}");
ImGui.SameLine(0);
ImGui.Text("/");
ImGui.SameLine(0);
ImGui.TextColored(
result.TacticalAbility >= selectedMission.CurrentAttributes.TacticalAbility
result.TacticalAbility >= selectedMission.CurrentAttributes!.TacticalAbility
? ImGuiColors.HealerGreen
: ImGuiColors.DalamudYellow, $"{result.TacticalAbility}");
@ -193,7 +193,7 @@ internal sealed class MainWindow : Window, IDisposable
}
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.");
}
}
@ -315,12 +315,16 @@ internal sealed class MainWindow : Window, IDisposable
int mental = int.Parse(mentalText->NodeText.ToString());
int tactical = int.Parse(tacticalText->NodeText.ToString());
selectedMission.CurrentAttributes = new Attributes
var newAttributes = new Attributes
{
PhysicalAbility = physical,
MentalAbility = mental,
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)