Live in 0.1.19 the plugin put three buttons on the plugin bar (MM, Mossy Tracker, Metas), the tracker carried the icon that belongs to the main window, and the metas downloads were in a window of their own. Now only the main window has a bar button: "MM" with the original window's icon (7735, 0x06001E37). Its tabs follow the original's notebook: Main, Settings, Statistics, Mossy Tracker, Metas, Tools. The Mossy Tracker tab is the original page, one "Open Mossy Tracker" button that opens the tracker window; that window is registered without a bar button and opened through the host's ShowPanel. The Metas tab holds everything the metas window had (list with search, refresh, check, download outdated, download one file, last check, status), plus the repository address and the two folders the files land in. The main window forwards those bindings to the meta sync's view model, since markup binds one object. Downloads already went to the host's VTank profile storage, the one MossTank reads, under mosstank/metas and mosstank/navs with each file's own name and extension; the tab now shows those full folder paths instead of the storage root. Backend frames are untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
240 lines
9.9 KiB
C#
240 lines
9.9 KiB
C#
using AcDream.Plugin.Abstractions;
|
|
using OpenAC.MosswartMassacre.FlagTracker;
|
|
using OpenAC.MosswartMassacre.Tests.Fakes;
|
|
|
|
namespace OpenAC.MosswartMassacre.Tests.FlagTracker;
|
|
|
|
public sealed class FlagTrackerTests
|
|
{
|
|
private const uint Player = 0x50000001;
|
|
|
|
private static PluginHarness WithUi(Action<FakeHost>? arrange = null) =>
|
|
new(arrange: host =>
|
|
{
|
|
host.HasUi = true;
|
|
arrange?.Invoke(host);
|
|
});
|
|
|
|
private static void SetPlayerInts(FakeHost host, Dictionary<uint, int> ints) =>
|
|
host.Automation.Objects.Properties[Player] = new PluginItemProperties(
|
|
ints,
|
|
new Dictionary<uint, long>(),
|
|
new Dictionary<uint, bool>(),
|
|
new Dictionary<uint, double>(),
|
|
new Dictionary<uint, string>(),
|
|
new Dictionary<uint, uint>(),
|
|
new Dictionary<uint, uint>());
|
|
|
|
private static FlagTrackerViewModel Panel(PluginHarness harness) =>
|
|
harness.Feature<FlagTrackerFeature>().Panel!;
|
|
|
|
private static int Row(IReadOnlyList<string> names, string name)
|
|
{
|
|
int index = names.ToList().IndexOf(name);
|
|
Assert.True(index >= 0, $"no row {name}");
|
|
return index;
|
|
}
|
|
|
|
[Fact]
|
|
public void A_headless_host_gets_no_window_and_login_does_nothing()
|
|
{
|
|
using var harness = new PluginHarness();
|
|
harness.Login();
|
|
harness.Run(6);
|
|
|
|
FlagTrackerFeature feature = harness.Feature<FlagTrackerFeature>();
|
|
Assert.Null(feature.Panel);
|
|
Assert.Empty(harness.Host.Ui.Panels);
|
|
}
|
|
|
|
[Fact]
|
|
public void A_graphical_host_gets_the_mossy_tracker_window_closed()
|
|
{
|
|
using var harness = WithUi();
|
|
|
|
RegisteredPanel panel = Assert.Single(harness.Host.Ui.Panels, registered => registered.Descriptor.WindowId == "flagtracker");
|
|
Assert.Equal("flagtracker", panel.Descriptor.WindowId);
|
|
Assert.Equal("Mossy Tracker", panel.Descriptor.Title);
|
|
Assert.False(panel.Descriptor.ShowInSidePanel);
|
|
Assert.Equal(0u, panel.Descriptor.IconSurfaceId);
|
|
Assert.EndsWith(FlagTrackerFeature.MarkupFile, panel.MarkupPath, StringComparison.Ordinal);
|
|
Assert.Same(Panel(harness), panel.Binding);
|
|
Assert.False(Panel(harness).IsVisible);
|
|
Assert.True(Panel(harness).AugsSelected);
|
|
|
|
Panel(harness).ShowQuests();
|
|
Assert.True(Panel(harness).QuestsSelected);
|
|
Assert.False(Panel(harness).AugsSelected);
|
|
}
|
|
|
|
[Fact]
|
|
public void Augmentations_come_from_the_players_own_properties()
|
|
{
|
|
using var harness = WithUi(host => SetPlayerInts(host, new() { [231] = 3, [230] = 2 }));
|
|
harness.Login();
|
|
FlagTrackerViewModel panel = Panel(harness);
|
|
|
|
Assert.Equal("--- Death Augs ---", panel.AugNames[0]);
|
|
int keepItems = Row(panel.AugNames, "Keep Items");
|
|
Assert.Equal("[MAX]", panel.AugProgress[keepItems]);
|
|
Assert.Equal(0x008000u, panel.AugProgressColors[keepItems]);
|
|
Assert.Equal("Rohula bint Ludun", panel.AugTrainers[keepItems]);
|
|
Assert.Equal("Ayan Baqur", panel.AugLocations[keepItems]);
|
|
|
|
int keepSpells = Row(panel.AugNames, "Keep Spells");
|
|
Assert.Equal("[0/1]", panel.AugProgress[keepSpells]);
|
|
Assert.Equal(0xFF0000u, panel.AugProgressColors[keepSpells]);
|
|
|
|
int carrying = Row(panel.AugNames, "Extra Carrying Capacity");
|
|
Assert.Equal("[2/5]", panel.AugProgress[carrying]);
|
|
Assert.Equal(0xFFFF00u, panel.AugProgressColors[carrying]);
|
|
|
|
// A bought augmentation shows after Refresh.
|
|
SetPlayerInts(harness.Host, new() { [232] = 1 });
|
|
panel.RefreshAugs();
|
|
Assert.Equal("[MAX]", panel.AugProgress[keepSpells]);
|
|
}
|
|
|
|
[Fact]
|
|
public void Luminance_auras_show_progress_and_the_seer_they_belong_to()
|
|
{
|
|
using var harness = WithUi(host => SetPlayerInts(host, new() { [333] = 5, [344] = 2 }));
|
|
harness.Login();
|
|
FlagTrackerViewModel panel = Panel(harness);
|
|
|
|
int damage = Row(panel.LumNames, "+1 Damage Rating");
|
|
Assert.Equal("5/5", panel.LumProgress[damage]);
|
|
Assert.Equal(0x008000u, panel.LumProgressColors[damage]);
|
|
Assert.Equal("Nalicana Auras", panel.LumCategories[damage]);
|
|
|
|
int kahiri = Row(panel.LumNames, "(Ka'hiri) +2 Specialized Skills");
|
|
Assert.Equal("2/5", panel.LumProgress[kahiri]);
|
|
Assert.Equal(0xFFFF00u, panel.LumProgressColors[kahiri]);
|
|
Assert.Equal("LoyalToKahiri", panel.LumCategories[kahiri]);
|
|
}
|
|
|
|
[Fact]
|
|
public void Recalls_show_known_and_unknown_with_their_spell_icons()
|
|
{
|
|
using var harness = WithUi(host => host.Automation.Spells.KnownSpellIds.Add(2023));
|
|
harness.Login();
|
|
FlagTrackerViewModel panel = Panel(harness);
|
|
|
|
Assert.Equal(17, panel.RecallNames.Count);
|
|
Assert.Equal("Recall the Sanctuary", panel.RecallNames[0]);
|
|
Assert.Equal(2023u, panel.RecallSpellIds[0]);
|
|
Assert.Equal("Known", panel.RecallStatus[0]);
|
|
Assert.Equal(0x008000u, panel.RecallStatusColors[0]);
|
|
Assert.Equal("Unknown", panel.RecallStatus[1]);
|
|
Assert.Equal(0xFF0000u, panel.RecallStatusColors[1]);
|
|
}
|
|
|
|
[Fact]
|
|
public void Cantrips_are_matched_to_trained_skills_attributes_and_wards()
|
|
{
|
|
using var harness = WithUi(host =>
|
|
{
|
|
host.Automation.Character.Skills.Add(new PluginSkillInfo(34, "War Magic", PluginSkillTraining.Specialized, 400));
|
|
host.Automation.Character.Skills.Add(new PluginSkillInfo(6, "Melee Defense", PluginSkillTraining.Trained, 300));
|
|
host.Automation.Character.Skills.Add(new PluginSkillInfo(21, "Healing", PluginSkillTraining.Untrained, 10));
|
|
host.Automation.Spells.All =
|
|
[
|
|
FakeSpellCatalog.Spell(4715, "Epic War Magic Aptitude"),
|
|
FakeSpellCatalog.Spell(2248, "Major Invulnerability"),
|
|
FakeSpellCatalog.Spell(1, "Minor Invulnerability"),
|
|
FakeSpellCatalog.Spell(6099, "Legendary Flame Ward"),
|
|
FakeSpellCatalog.Spell(2091, "Major Strength"),
|
|
FakeSpellCatalog.Spell(2, "Strength Self VIII"),
|
|
];
|
|
host.Automation.Character.ActiveEnchantments =
|
|
[
|
|
new PluginActiveEnchantment(4715, 0, 0, -1),
|
|
new PluginActiveEnchantment(2248, 0, 0, -1),
|
|
new PluginActiveEnchantment(1, 0, 0, -1),
|
|
new PluginActiveEnchantment(6099, 0, 0, -1),
|
|
new PluginActiveEnchantment(2091, 0, 0, -1),
|
|
new PluginActiveEnchantment(2, 0, 0, 3600),
|
|
];
|
|
});
|
|
harness.Login();
|
|
FlagTrackerViewModel panel = Panel(harness);
|
|
|
|
Assert.Equal(
|
|
[
|
|
"--- Specialized Skills ---", "War Magic",
|
|
"--- Trained Skills ---", "Invulnerability",
|
|
"--- Attributes ---", "Strength",
|
|
"--- Protection Auras ---", "Armor", "Bludgeoning Ward", "Piercing Ward",
|
|
"Slashing Ward", "Flame Ward", "Frost Ward", "Acid Ward", "Storm Ward",
|
|
],
|
|
panel.CantripNames);
|
|
|
|
Assert.Equal(FlagTrackerData.Icons.CategoryStar, panel.CantripIcons[0]);
|
|
Assert.Equal("Epic", panel.CantripLevels[1]);
|
|
Assert.Equal(0x800080u, panel.CantripLevelColors[1]);
|
|
Assert.Equal(FlagTrackerData.Icons.GreenCircle, panel.CantripIcons[1]);
|
|
// The higher of two cantrips on one skill wins.
|
|
Assert.Equal("Major", panel.CantripLevels[3]);
|
|
Assert.Equal(0x0000FFu, panel.CantripLevelColors[3]);
|
|
Assert.Equal("Major", panel.CantripLevels[5]);
|
|
Assert.Equal("N/A", panel.CantripLevels[7]);
|
|
Assert.Equal(FlagTrackerData.Icons.RedCircle, panel.CantripIcons[7]);
|
|
int flame = Row(panel.CantripNames, "Flame Ward");
|
|
Assert.Equal("Legendary", panel.CantripLevels[flame]);
|
|
Assert.Equal(0xFFA500u, panel.CantripLevelColors[flame]);
|
|
}
|
|
|
|
[Fact]
|
|
public void Tracked_weapons_are_found_in_the_inventory_by_name()
|
|
{
|
|
using var harness = WithUi(host => host.Automation.Items.Owned.Add(
|
|
FakeItems.Item(0x80000001, "Atlan Sword") with { IconId = 0x06001234 }));
|
|
harness.Login();
|
|
FlagTrackerViewModel panel = Panel(harness);
|
|
|
|
int atlan = Row(panel.WeaponNames, "Atlan Sword");
|
|
Assert.Equal("Acquired", panel.WeaponStatus[atlan]);
|
|
Assert.Equal(0x06001234u, panel.WeaponIcons[atlan]);
|
|
int axe = Row(panel.WeaponNames, "Atlan Axe");
|
|
Assert.Equal("Not Acquired", panel.WeaponStatus[axe]);
|
|
Assert.Equal(FlagTrackerData.Icons.Portal, panel.WeaponIcons[axe]);
|
|
}
|
|
|
|
[Fact]
|
|
public void The_quest_page_hides_maxed_quests_and_sorts_by_solves()
|
|
{
|
|
using var harness = WithUi();
|
|
harness.Login();
|
|
long now = new DateTimeOffset(harness.Clock.UtcNow).ToUnixTimeSeconds();
|
|
var chat = harness.Host.Automation.Chat;
|
|
chat.Deliver($"stipendtimer_0812 - 2 solves ({now - 10})\"x\" -1 3700");
|
|
chat.Deliver($"maxed - 5 solves ({now})\"x\" 5 60");
|
|
chat.Deliver($"aaa - 7 solves ({now - 100})\"x\" -1 50");
|
|
|
|
FlagTrackerViewModel panel = Panel(harness);
|
|
Assert.Equal(["aaa", "Stipend Collection Timer"], panel.QuestRowNames);
|
|
Assert.Equal(["READY", "1h 01m"], panel.QuestCountdowns);
|
|
Assert.Equal([0x008000u, 0xFFFF00u], panel.QuestCountdownColors);
|
|
Assert.Equal(["50s", "1h 1m 40s"], panel.QuestCooldowns);
|
|
Assert.Equal(["7", "2"], panel.QuestSolves);
|
|
|
|
// The countdowns move on every five seconds.
|
|
harness.Run(5.1);
|
|
Assert.Equal("1h 01m", panel.QuestCountdowns[1]);
|
|
harness.Run(120);
|
|
Assert.StartsWith("59m ", panel.QuestCountdowns[1], StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Logoff_empties_the_pages()
|
|
{
|
|
using var harness = WithUi();
|
|
harness.Login();
|
|
Assert.NotEmpty(Panel(harness).AugNames);
|
|
|
|
harness.Plugin.OnLogoff();
|
|
|
|
Assert.Empty(Panel(harness).AugNames);
|
|
Assert.Empty(Panel(harness).QuestRowNames);
|
|
}
|
|
}
|