fix(ui): select and examine favorite spells like retail
This commit is contained in:
parent
043ab10b3c
commit
3e31b0ac70
23 changed files with 974 additions and 34 deletions
|
|
@ -1,4 +1,5 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Spells;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.Core.Combat;
|
||||
|
|
@ -688,6 +689,103 @@ public sealed class AppraisalUiControllerTests
|
|||
mounted => mounted.WindowName == WindowNames.Examination);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpellExamination_UsesAuthoredLocalSubviewWithoutSelectingOrAppraisingSpellId()
|
||||
{
|
||||
ImportedLayout layout = FixtureLoader.LoadExamination();
|
||||
var objects = new ClientObjectTable();
|
||||
objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = ObjectId,
|
||||
Name = "Selected Drudge",
|
||||
Type = ItemType.Creature,
|
||||
});
|
||||
var sent = new List<uint>();
|
||||
using var interaction = NewInteraction(objects, sent);
|
||||
var selection = new SelectionState();
|
||||
selection.Select(ObjectId, SelectionChangeSource.World);
|
||||
SpellMetadata metadata = ExaminedSpell();
|
||||
var spellbook = new Spellbook(SpellTable.Create([metadata]));
|
||||
var components = new[]
|
||||
{
|
||||
new SpellExamineComponent(
|
||||
10u,
|
||||
new SpellComponentDescriptor(100u, "Lead Scarab", 0u, 0x06000010u),
|
||||
Owned: true),
|
||||
new SpellExamineComponent(
|
||||
11u,
|
||||
new SpellComponentDescriptor(101u, "Malar Herb", 1u, 0x06000011u),
|
||||
Owned: false),
|
||||
};
|
||||
int shown = 0;
|
||||
using AppraisalUiController controller = Bind(
|
||||
layout,
|
||||
objects,
|
||||
interaction,
|
||||
new CombatState(),
|
||||
[],
|
||||
[],
|
||||
() => shown++,
|
||||
() => { },
|
||||
selection: selection,
|
||||
spellbook: spellbook,
|
||||
resolveSpellIcon: id => id + 1_000u,
|
||||
spellComponents: _ => components,
|
||||
magicSkill: _ => 200u)!;
|
||||
|
||||
Assert.True(interaction.ExamineSelectedOrEnterMode(ObjectId));
|
||||
Assert.Equal(1, interaction.BusyCount);
|
||||
|
||||
Assert.True(controller.ExamineSpell(metadata.SpellId));
|
||||
|
||||
Assert.Equal(AppraisalView.Spell, controller.ActiveView);
|
||||
Assert.Equal(1, shown);
|
||||
Assert.Equal(ObjectId, selection.SelectedObjectId);
|
||||
Assert.Equal(new uint[] { ObjectId, 0u }, sent);
|
||||
Assert.Equal(0, interaction.BusyCount);
|
||||
Assert.Equal(0u, controller.CurrentObjectId);
|
||||
Assert.True(layout.FindElement(AppraisalUiController.SpellPanelId)!.Visible);
|
||||
Assert.False(layout.FindElement(AppraisalUiController.ItemPanelId)!.Visible);
|
||||
Assert.False(layout.FindElement(AppraisalUiController.CreaturePanelId)!.Visible);
|
||||
|
||||
AssertSpellText(
|
||||
layout,
|
||||
AppraisalUiController.TitleId,
|
||||
"Incantation of Test");
|
||||
AssertSpellText(
|
||||
layout,
|
||||
AppraisalUiController.SpellSchoolTextId,
|
||||
"School: War Magic");
|
||||
AssertSpellText(
|
||||
layout,
|
||||
AppraisalUiController.SpellManaTextId,
|
||||
"Mana: 50 + 14 per target");
|
||||
AssertSpellText(
|
||||
layout,
|
||||
AppraisalUiController.SpellDurationTextId,
|
||||
"Duration: 1 min.");
|
||||
AssertSpellText(
|
||||
layout,
|
||||
AppraisalUiController.SpellRangeTextId,
|
||||
"Range: 82.0 yds.");
|
||||
string display = string.Join(
|
||||
'\n',
|
||||
((UiText)layout.FindElement(
|
||||
AppraisalUiController.SpellDisplayTextId)!)
|
||||
.LinesProvider()
|
||||
.Select(line => line.Text));
|
||||
Assert.Contains("A projected retail spell.", display);
|
||||
Assert.Contains("COMPONENTS:", display);
|
||||
Assert.Contains("Lead Scarab", display);
|
||||
Assert.Contains("Malar Herb", display);
|
||||
|
||||
UiElement iconHost = layout.FindElement(
|
||||
AppraisalUiController.SpellIconId)!;
|
||||
UiTextureElement icon = Assert.Single(
|
||||
iconHost.Children.OfType<UiTextureElement>());
|
||||
Assert.Equal(metadata.SpellId + 1_000u, icon.Texture);
|
||||
}
|
||||
|
||||
private static AppraisalUiController? Bind(
|
||||
ImportedLayout layout,
|
||||
ClientObjectTable objects,
|
||||
|
|
@ -700,14 +798,20 @@ public sealed class AppraisalUiControllerTests
|
|||
CreatureAppraisalRowTemplateFactory? creatureRows = null,
|
||||
CreatureDisplayNameResolver? creatureNames = null,
|
||||
SelectionState? selection = null,
|
||||
RetailAppraisalNameResolver? itemNames = null)
|
||||
RetailAppraisalNameResolver? itemNames = null,
|
||||
Spellbook? spellbook = null,
|
||||
Func<uint, uint>? resolveSpellIcon = null,
|
||||
Func<uint, uint>? resolveComponentIcon = null,
|
||||
Func<uint, IReadOnlyList<SpellExamineComponent>>? spellComponents = null,
|
||||
Func<MagicSchool, uint>? magicSkill = null,
|
||||
SpellExamineComponentTemplateFactory? spellComponentTemplates = null)
|
||||
=> AppraisalUiController.Bind(
|
||||
layout,
|
||||
objects,
|
||||
interaction,
|
||||
selection ?? new SelectionState(),
|
||||
combat,
|
||||
new Spellbook(),
|
||||
spellbook ?? new Spellbook(),
|
||||
() => "Tester",
|
||||
(objectId, text) => inscriptions.Add((objectId, text)),
|
||||
messages.Add,
|
||||
|
|
@ -715,7 +819,12 @@ public sealed class AppraisalUiControllerTests
|
|||
close,
|
||||
creatureRows,
|
||||
creatureNames,
|
||||
itemNames);
|
||||
itemNames,
|
||||
resolveSpellIcon,
|
||||
resolveComponentIcon,
|
||||
spellComponents,
|
||||
magicSkill,
|
||||
spellComponentTemplates);
|
||||
|
||||
private static ItemInteractionController NewInteraction(
|
||||
ClientObjectTable objects,
|
||||
|
|
@ -749,4 +858,48 @@ public sealed class AppraisalUiControllerTests
|
|||
ArmorEnchantments: null,
|
||||
WeaponEnchantments: null,
|
||||
ResistEnchantments: null);
|
||||
|
||||
private static void AssertSpellText(
|
||||
ImportedLayout layout,
|
||||
uint elementId,
|
||||
string expected)
|
||||
{
|
||||
UiText text = Assert.IsType<UiText>(layout.FindElement(elementId));
|
||||
Assert.Equal(
|
||||
expected,
|
||||
string.Join('\n', text.LinesProvider().Select(line => line.Text)));
|
||||
}
|
||||
|
||||
private static SpellMetadata ExaminedSpell()
|
||||
=> new(
|
||||
SpellId: 42u,
|
||||
Name: "Incantation of Test",
|
||||
School: "War Magic",
|
||||
Family: 1u,
|
||||
IconId: 0x06001234u,
|
||||
SpellWords: "Malar Aether",
|
||||
Duration: 90f,
|
||||
ManaCost: 50,
|
||||
IsDebuff: false,
|
||||
IsFellowship: false,
|
||||
Description: "A projected retail spell.",
|
||||
SortKey: 0,
|
||||
Difficulty: 0,
|
||||
Flags: 0u,
|
||||
Generation: 6,
|
||||
IsFastWindup: false,
|
||||
IsOffensive: true,
|
||||
IsUntargeted: false,
|
||||
Speed: 0f,
|
||||
CasterEffect: 0u,
|
||||
TargetEffect: 0u,
|
||||
TargetMask: 0u,
|
||||
SpellType: 0)
|
||||
{
|
||||
SchoolId = MagicSchool.WarMagic,
|
||||
BaseRangeConstant = 40f,
|
||||
BaseRangeModifier = 0.25f,
|
||||
ManaModifier = 14u,
|
||||
FormulaComponents = [10u, 11u],
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue