fix #234: port retail appraisal floaty and inscriptions
This commit is contained in:
parent
643cdfe66e
commit
f1a7912160
23 changed files with 1310 additions and 106 deletions
|
|
@ -23,18 +23,23 @@ public sealed class AppraisalUiControllerTests
|
|||
Type = ItemType.MeleeWeapon,
|
||||
Value = 1250,
|
||||
Burden = 350,
|
||||
ContainerId = 0x50000002u,
|
||||
PublicWeenieBitfield = (uint)PublicWeenieFlags.Inscribable,
|
||||
});
|
||||
var sent = new List<uint>();
|
||||
var inscriptions = new List<(uint ObjectId, string Text)>();
|
||||
var messages = new List<string>();
|
||||
using var interaction = NewInteraction(objects, sent);
|
||||
var combat = new CombatState();
|
||||
int shown = 0;
|
||||
int closed = 0;
|
||||
using AppraisalUiController controller = AppraisalUiController.Bind(
|
||||
using AppraisalUiController controller = Bind(
|
||||
layout,
|
||||
objects,
|
||||
interaction,
|
||||
combat,
|
||||
new Spellbook(),
|
||||
inscriptions,
|
||||
messages,
|
||||
() => shown++,
|
||||
() => closed++)!;
|
||||
|
||||
|
|
@ -64,10 +69,12 @@ public sealed class AppraisalUiControllerTests
|
|||
UiField inscription = Assert.IsType<UiField>(
|
||||
layout.FindElement(AppraisalUiController.InscriptionTextId));
|
||||
Assert.Contains("Remember the fallen", inscription.Text);
|
||||
Assert.False(inscription.Enabled);
|
||||
Assert.True(inscription.Editable);
|
||||
UiText signature = Assert.IsType<UiText>(
|
||||
layout.FindElement(AppraisalUiController.SignatureTextId));
|
||||
Assert.Equal("Inscribed by Tester", Assert.Single(signature.LinesProvider()).Text);
|
||||
Assert.Equal("--Tester", Assert.Single(signature.LinesProvider()).Text);
|
||||
Assert.Empty(inscriptions);
|
||||
Assert.Empty(messages);
|
||||
|
||||
((UiButton)layout.FindElement(AppraisalUiController.CloseId)!).OnClick!.Invoke();
|
||||
Assert.Equal(1, closed);
|
||||
|
|
@ -88,12 +95,13 @@ public sealed class AppraisalUiControllerTests
|
|||
using var interaction = NewInteraction(objects, sent);
|
||||
var combat = new CombatState();
|
||||
int shown = 0;
|
||||
using AppraisalUiController controller = AppraisalUiController.Bind(
|
||||
using AppraisalUiController controller = Bind(
|
||||
layout,
|
||||
objects,
|
||||
interaction,
|
||||
combat,
|
||||
new Spellbook(),
|
||||
[],
|
||||
[],
|
||||
() => shown++,
|
||||
() => { })!;
|
||||
|
||||
|
|
@ -145,12 +153,13 @@ public sealed class AppraisalUiControllerTests
|
|||
var objects = new ClientObjectTable();
|
||||
objects.AddOrUpdate(new ClientObject { ObjectId = ObjectId, Name = "Item" });
|
||||
using var interaction = NewInteraction(objects, []);
|
||||
using AppraisalUiController controller = AppraisalUiController.Bind(
|
||||
using AppraisalUiController controller = Bind(
|
||||
layout,
|
||||
objects,
|
||||
interaction,
|
||||
new CombatState(),
|
||||
new Spellbook(),
|
||||
[],
|
||||
[],
|
||||
() => throw new InvalidOperationException("must not show"),
|
||||
() => { })!;
|
||||
|
||||
|
|
@ -158,6 +167,281 @@ public sealed class AppraisalUiControllerTests
|
|||
Assert.Equal(0u, controller.CurrentObjectId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyOwnedInscription_FocusEditAndBlur_SendsRetailTransactionOnce()
|
||||
{
|
||||
ImportedLayout layout = FixtureLoader.LoadExamination();
|
||||
var objects = new ClientObjectTable();
|
||||
objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = ObjectId,
|
||||
Name = "Sword",
|
||||
Type = ItemType.MeleeWeapon,
|
||||
ContainerId = 0x50000002u,
|
||||
PublicWeenieBitfield = (uint)PublicWeenieFlags.Inscribable,
|
||||
});
|
||||
var inscriptions = new List<(uint ObjectId, string Text)>();
|
||||
using var interaction = NewInteraction(objects, []);
|
||||
using AppraisalUiController controller = Bind(
|
||||
layout,
|
||||
objects,
|
||||
interaction,
|
||||
new CombatState(),
|
||||
inscriptions,
|
||||
[],
|
||||
() => { },
|
||||
() => { })!;
|
||||
|
||||
interaction.ExamineSelectedOrEnterMode(ObjectId);
|
||||
Assert.True(controller.Apply(Parsed(new PropertyBundle())));
|
||||
|
||||
UiField field = Assert.IsType<UiField>(
|
||||
layout.FindElement(AppraisalUiController.InscriptionTextId));
|
||||
UiText signature = Assert.IsType<UiText>(
|
||||
layout.FindElement(AppraisalUiController.SignatureTextId));
|
||||
Assert.True(field.Editable);
|
||||
Assert.Equal("<Inscribe here>", field.Text);
|
||||
|
||||
field.OnEvent(new UiEvent(field.EventId, field, UiEventType.FocusGained));
|
||||
Assert.Equal(string.Empty, field.Text);
|
||||
Assert.Equal("--Tester", Assert.Single(signature.LinesProvider()).Text);
|
||||
foreach (char c in "For glory")
|
||||
field.InsertChar(c);
|
||||
field.OnEvent(new UiEvent(field.EventId, field, UiEventType.FocusLost));
|
||||
|
||||
Assert.Equal(
|
||||
new[] { (ObjectId, "For glory") },
|
||||
inscriptions);
|
||||
Assert.Equal("--Tester", Assert.Single(signature.LinesProvider()).Text);
|
||||
|
||||
field.OnEvent(new UiEvent(field.EventId, field, UiEventType.FocusGained));
|
||||
field.OnEvent(new UiEvent(field.EventId, field, UiEventType.FocusLost));
|
||||
Assert.Single(inscriptions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExistingInscription_ClearOnBlur_SendsEmptyAndRestoresPlaceholder()
|
||||
{
|
||||
ImportedLayout layout = FixtureLoader.LoadExamination();
|
||||
var objects = new ClientObjectTable();
|
||||
objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = ObjectId,
|
||||
Name = "Sword",
|
||||
Type = ItemType.MeleeWeapon,
|
||||
ContainerId = 0x50000002u,
|
||||
PublicWeenieBitfield = (uint)PublicWeenieFlags.Inscribable,
|
||||
});
|
||||
var inscriptions = new List<(uint ObjectId, string Text)>();
|
||||
using var interaction = NewInteraction(objects, []);
|
||||
using AppraisalUiController controller = Bind(
|
||||
layout,
|
||||
objects,
|
||||
interaction,
|
||||
new CombatState(),
|
||||
inscriptions,
|
||||
[],
|
||||
() => { },
|
||||
() => { })!;
|
||||
interaction.ExamineSelectedOrEnterMode(ObjectId);
|
||||
var properties = new PropertyBundle();
|
||||
properties.Strings[7u] = "Old words";
|
||||
properties.Strings[8u] = "Tester";
|
||||
Assert.True(controller.Apply(Parsed(properties)));
|
||||
|
||||
UiField field = Assert.IsType<UiField>(
|
||||
layout.FindElement(AppraisalUiController.InscriptionTextId));
|
||||
UiText signature = Assert.IsType<UiText>(
|
||||
layout.FindElement(AppraisalUiController.SignatureTextId));
|
||||
field.SetText(string.Empty);
|
||||
field.OnEvent(new UiEvent(field.EventId, field, UiEventType.FocusLost));
|
||||
|
||||
Assert.Equal(new[] { (ObjectId, string.Empty) }, inscriptions);
|
||||
Assert.Equal("<Inscribe here>", field.Text);
|
||||
Assert.Equal(string.Empty, Assert.Single(signature.LinesProvider()).Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InscriptionPermissionMessages_MatchRetail()
|
||||
{
|
||||
ImportedLayout otherScribeLayout = FixtureLoader.LoadExamination();
|
||||
var otherScribeObjects = new ClientObjectTable();
|
||||
otherScribeObjects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = ObjectId,
|
||||
Name = "Sword",
|
||||
ContainerId = 0x50000002u,
|
||||
PublicWeenieBitfield = (uint)PublicWeenieFlags.Inscribable,
|
||||
});
|
||||
var messages = new List<string>();
|
||||
using var otherInteraction = NewInteraction(otherScribeObjects, []);
|
||||
using AppraisalUiController otherController = Bind(
|
||||
otherScribeLayout,
|
||||
otherScribeObjects,
|
||||
otherInteraction,
|
||||
new CombatState(),
|
||||
[],
|
||||
messages,
|
||||
() => { },
|
||||
() => { })!;
|
||||
otherInteraction.ExamineSelectedOrEnterMode(ObjectId);
|
||||
var otherProperties = new PropertyBundle();
|
||||
otherProperties.Strings[7u] = "Hands off";
|
||||
otherProperties.Strings[8u] = "Other";
|
||||
Assert.True(otherController.Apply(Parsed(otherProperties)));
|
||||
UiField otherField = Assert.IsType<UiField>(
|
||||
otherScribeLayout.FindElement(AppraisalUiController.InscriptionTextId));
|
||||
Assert.False(otherField.Editable);
|
||||
otherField.OnEvent(new UiEvent(
|
||||
otherField.EventId,
|
||||
otherField,
|
||||
UiEventType.Click));
|
||||
Assert.Equal("Only Other can change the inscription", Assert.Single(messages));
|
||||
|
||||
ImportedLayout unownedLayout = FixtureLoader.LoadExamination();
|
||||
var unownedObjects = new ClientObjectTable();
|
||||
unownedObjects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = ObjectId,
|
||||
Name = "Sword",
|
||||
ContainerId = 0x60000000u,
|
||||
PublicWeenieBitfield = (uint)PublicWeenieFlags.Inscribable,
|
||||
});
|
||||
messages.Clear();
|
||||
using var unownedInteraction = NewInteraction(unownedObjects, []);
|
||||
using AppraisalUiController unownedController = Bind(
|
||||
unownedLayout,
|
||||
unownedObjects,
|
||||
unownedInteraction,
|
||||
new CombatState(),
|
||||
[],
|
||||
messages,
|
||||
() => { },
|
||||
() => { })!;
|
||||
unownedInteraction.ExamineSelectedOrEnterMode(ObjectId);
|
||||
Assert.True(unownedController.Apply(Parsed(new PropertyBundle())));
|
||||
UiField unownedField = Assert.IsType<UiField>(
|
||||
unownedLayout.FindElement(AppraisalUiController.InscriptionTextId));
|
||||
unownedField.OnEvent(new UiEvent(
|
||||
unownedField.EventId,
|
||||
unownedField,
|
||||
UiEventType.Click));
|
||||
Assert.Equal(
|
||||
"Item must be in your inventory to inscribe.",
|
||||
Assert.Single(messages));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NonInscribableItem_HidesEditorAndBackgroundReportsRetailMessage()
|
||||
{
|
||||
ImportedLayout layout = FixtureLoader.LoadExamination();
|
||||
var objects = new ClientObjectTable();
|
||||
objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = ObjectId,
|
||||
Name = "Component",
|
||||
ContainerId = 0x50000002u,
|
||||
});
|
||||
var messages = new List<string>();
|
||||
using var interaction = NewInteraction(objects, []);
|
||||
using AppraisalUiController controller = Bind(
|
||||
layout,
|
||||
objects,
|
||||
interaction,
|
||||
new CombatState(),
|
||||
[],
|
||||
messages,
|
||||
() => { },
|
||||
() => { })!;
|
||||
interaction.ExamineSelectedOrEnterMode(ObjectId);
|
||||
Assert.True(controller.Apply(Parsed(new PropertyBundle())));
|
||||
|
||||
UiField field = Assert.IsType<UiField>(
|
||||
layout.FindElement(AppraisalUiController.InscriptionTextId));
|
||||
UiText signature = Assert.IsType<UiText>(
|
||||
layout.FindElement(AppraisalUiController.SignatureTextId));
|
||||
Assert.False(field.Visible);
|
||||
Assert.False(signature.Visible);
|
||||
|
||||
UiDatElement background = Assert.IsType<UiDatElement>(
|
||||
layout.FindElement(AppraisalUiController.InscriptionBackgroundId));
|
||||
background.OnClick!.Invoke();
|
||||
Assert.Equal("This item is not inscribable.", Assert.Single(messages));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HookProfileControlsVisibilityButPublicFlagStillControlsEditing()
|
||||
{
|
||||
ImportedLayout layout = FixtureLoader.LoadExamination();
|
||||
var objects = new ClientObjectTable();
|
||||
objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = ObjectId,
|
||||
Name = "Hooked Decoration",
|
||||
ContainerId = 0x50000002u,
|
||||
});
|
||||
var messages = new List<string>();
|
||||
using var interaction = NewInteraction(objects, []);
|
||||
using AppraisalUiController controller = Bind(
|
||||
layout,
|
||||
objects,
|
||||
interaction,
|
||||
new CombatState(),
|
||||
[],
|
||||
messages,
|
||||
() => { },
|
||||
() => { })!;
|
||||
interaction.ExamineSelectedOrEnterMode(ObjectId);
|
||||
|
||||
AppraiseInfoParser.Parsed appraisal = Parsed(new PropertyBundle()) with
|
||||
{
|
||||
Flags = AppraiseInfoParser.IdentifyResponseFlags.HookProfile,
|
||||
HookProfile = new AppraiseInfoParser.HookProfile(
|
||||
Flags: 1u,
|
||||
ValidLocations: 0u,
|
||||
AmmoType: 0u),
|
||||
};
|
||||
Assert.True(controller.Apply(appraisal));
|
||||
|
||||
UiField field = Assert.IsType<UiField>(
|
||||
layout.FindElement(AppraisalUiController.InscriptionTextId));
|
||||
Assert.True(field.Visible);
|
||||
Assert.False(field.Editable);
|
||||
field.OnEvent(new UiEvent(field.EventId, field, UiEventType.Click));
|
||||
Assert.Equal("This item is not inscribable.", Assert.Single(messages));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Examination_IsAnIndependentFloatyWindow_NotSharedMainPanelContent()
|
||||
{
|
||||
Assert.False(
|
||||
RetailPanelCatalog.TryGetPanelId(WindowNames.Examination, out _));
|
||||
Assert.DoesNotContain(
|
||||
RetailPanelCatalog.MountedPanels,
|
||||
mounted => mounted.WindowName == WindowNames.Examination);
|
||||
}
|
||||
|
||||
private static AppraisalUiController? Bind(
|
||||
ImportedLayout layout,
|
||||
ClientObjectTable objects,
|
||||
ItemInteractionController interaction,
|
||||
CombatState combat,
|
||||
List<(uint ObjectId, string Text)> inscriptions,
|
||||
List<string> messages,
|
||||
Action show,
|
||||
Action close)
|
||||
=> AppraisalUiController.Bind(
|
||||
layout,
|
||||
objects,
|
||||
interaction,
|
||||
combat,
|
||||
new Spellbook(),
|
||||
() => "Tester",
|
||||
(objectId, text) => inscriptions.Add((objectId, text)),
|
||||
messages.Add,
|
||||
show,
|
||||
close);
|
||||
|
||||
private static ItemInteractionController NewInteraction(
|
||||
ClientObjectTable objects,
|
||||
List<uint> sent)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue