314 lines
12 KiB
C#
314 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Server;
|
|
using Server.Items;
|
|
using Server.Mobiles;
|
|
using Server.Text;
|
|
using Xunit;
|
|
|
|
namespace UOContent.Tests;
|
|
|
|
[Collection("Sequential UOContent Tests")]
|
|
public class UnwieldyPropertyTests
|
|
{
|
|
private const int SingleWeightCliloc = 1072788;
|
|
private const int MultipleWeightCliloc = 1072789;
|
|
private const double OriginalWeight = 7.25;
|
|
private const double UnwieldyWeight = 50;
|
|
|
|
[Fact]
|
|
public void NegativeAttribute_ReservesTheNextNonCollidingBitForUnwieldy()
|
|
{
|
|
Assert.True(Enum.TryParse<NegativeAttribute>("Unwieldy", out var unwieldy));
|
|
Assert.Equal(0x00000010, (int)unwieldy);
|
|
}
|
|
|
|
[Fact]
|
|
public void NegativeAttributes_StoresDupesAndSerializesUnwieldyOnSupportedFamilies()
|
|
{
|
|
var previousExpansion = Core.Expansion;
|
|
|
|
try
|
|
{
|
|
Core.Expansion = Expansion.HS;
|
|
|
|
AssertStoresDupesAndSerializesUnwieldy(new TestKatana(), new TestKatana(), new TestKatana());
|
|
AssertStoresDupesAndSerializesUnwieldy(new LeatherChest(), new LeatherChest(), new LeatherChest());
|
|
AssertStoresDupesAndSerializesUnwieldy(new Buckler(), new Buckler(), new Buckler());
|
|
}
|
|
finally
|
|
{
|
|
Core.Expansion = previousExpansion;
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void NegativeAttributes_DoesNotStoreUnwieldyOnUnsupportedJewelry()
|
|
{
|
|
var previousExpansion = Core.Expansion;
|
|
var ring = new GoldRing { Weight = OriginalWeight };
|
|
|
|
try
|
|
{
|
|
Core.Expansion = Expansion.HS;
|
|
ring.NegativeAttributes.Unwieldy = 1;
|
|
|
|
Assert.Equal(0, ring.NegativeAttributes.Unwieldy);
|
|
Assert.Equal(OriginalWeight, ring.Weight);
|
|
}
|
|
finally
|
|
{
|
|
Core.Expansion = previousExpansion;
|
|
ring.Delete();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Unwieldy_UsesStandardWeightTotalsAndWeightPresentationInHighSeas()
|
|
{
|
|
var previousExpansion = Core.Expansion;
|
|
|
|
try
|
|
{
|
|
Core.Expansion = Expansion.HS;
|
|
|
|
AssertUsesStandardWeightTotalsAndPresentation(new TestKatana());
|
|
AssertUsesStandardWeightTotalsAndPresentation(new LeatherChest());
|
|
AssertUsesStandardWeightTotalsAndPresentation(new Buckler());
|
|
}
|
|
finally
|
|
{
|
|
Core.Expansion = previousExpansion;
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Unwieldy_IsNoOpBeforeHighSeasIncludingAfterDeserialization()
|
|
{
|
|
var previousExpansion = Core.Expansion;
|
|
var source = new TestKatana { Weight = OriginalWeight };
|
|
var direct = new TestKatana { Weight = OriginalWeight };
|
|
var deserialized = new TestKatana();
|
|
|
|
try
|
|
{
|
|
Core.Expansion = Expansion.HS;
|
|
source.NegativeAttributes.Unwieldy = 1;
|
|
|
|
var writer = new BufferWriter(true);
|
|
source.Serialize(writer);
|
|
var buffer = new byte[writer.Position];
|
|
writer.Buffer.AsSpan(0, (int)writer.Position).CopyTo(buffer);
|
|
|
|
Core.Expansion = Expansion.SA;
|
|
direct.NegativeAttributes.Unwieldy = 1;
|
|
|
|
Assert.Equal(1, direct.NegativeAttributes.Unwieldy);
|
|
Assert.Equal(OriginalWeight, direct.Weight);
|
|
AssertShowsWeightWithoutUnwieldyRow(direct, (int)Math.Ceiling(OriginalWeight));
|
|
|
|
var reader = new BufferReader(buffer);
|
|
deserialized.Deserialize(reader);
|
|
|
|
Assert.Equal(buffer.Length, reader.Position);
|
|
Assert.Equal(1, deserialized.NegativeAttributes.Unwieldy);
|
|
Assert.Equal(OriginalWeight, deserialized.Weight);
|
|
AssertShowsWeightWithoutUnwieldyRow(deserialized, (int)Math.Ceiling(OriginalWeight));
|
|
}
|
|
finally
|
|
{
|
|
Core.Expansion = previousExpansion;
|
|
source.Delete();
|
|
direct.Delete();
|
|
deserialized.Delete();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void RunicAttributeGeneration_DoesNotRollUnwieldy()
|
|
{
|
|
var previousExpansion = Core.Expansion;
|
|
var weapon = new TestKatana();
|
|
var armor = new LeatherChest();
|
|
var shield = new Buckler();
|
|
|
|
try
|
|
{
|
|
Core.Expansion = Expansion.HS;
|
|
|
|
BaseRunicTool.ApplyAttributesTo(weapon, false, 0, 25, 100, 100);
|
|
BaseRunicTool.ApplyAttributesTo(armor, false, 0, 25, 100, 100);
|
|
BaseRunicTool.ApplyAttributesTo(shield, false, 0, 25, 100, 100);
|
|
|
|
Assert.Equal(0, weapon.NegativeAttributes.Unwieldy);
|
|
Assert.Equal(0, armor.NegativeAttributes.Unwieldy);
|
|
Assert.Equal(0, shield.NegativeAttributes.Unwieldy);
|
|
}
|
|
finally
|
|
{
|
|
Core.Expansion = previousExpansion;
|
|
weapon.Delete();
|
|
armor.Delete();
|
|
shield.Delete();
|
|
}
|
|
}
|
|
|
|
private static void AssertStoresDupesAndSerializesUnwieldy<TItem>(TItem source, TItem dupe, TItem deserialized)
|
|
where TItem : Item
|
|
{
|
|
try
|
|
{
|
|
source.Weight = OriginalWeight;
|
|
GetNegativeAttributes(source).Unwieldy = 1;
|
|
|
|
source.Dupe(dupe);
|
|
|
|
Assert.Equal(1, GetNegativeAttributes(dupe).Unwieldy);
|
|
Assert.Equal(UnwieldyWeight, dupe.Weight);
|
|
GetNegativeAttributes(dupe).Unwieldy = 0;
|
|
Assert.Equal(OriginalWeight, dupe.Weight);
|
|
|
|
var writer = new BufferWriter(true);
|
|
source.Serialize(writer);
|
|
var buffer = new byte[writer.Position];
|
|
writer.Buffer.AsSpan(0, (int)writer.Position).CopyTo(buffer);
|
|
|
|
var reader = new BufferReader(buffer);
|
|
deserialized.Deserialize(reader);
|
|
|
|
Assert.Equal(buffer.Length, reader.Position);
|
|
Assert.Equal(1, GetNegativeAttributes(deserialized).Unwieldy);
|
|
Assert.Equal(UnwieldyWeight, deserialized.Weight);
|
|
GetNegativeAttributes(deserialized).Unwieldy = 0;
|
|
Assert.Equal(OriginalWeight, deserialized.Weight);
|
|
}
|
|
finally
|
|
{
|
|
source.Delete();
|
|
dupe.Delete();
|
|
deserialized.Delete();
|
|
}
|
|
}
|
|
|
|
private static void AssertUsesStandardWeightTotalsAndPresentation(Item item)
|
|
{
|
|
var player = CreatePlayerMobile();
|
|
|
|
try
|
|
{
|
|
item.Weight = OriginalWeight;
|
|
player.Backpack.AddItem(item);
|
|
|
|
var originalPileWeight = item.PileWeight;
|
|
var originalContainerWeight = player.Backpack.TotalWeight;
|
|
var originalMobileWeight = player.TotalWeight;
|
|
|
|
GetNegativeAttributes(item).Unwieldy = 1;
|
|
|
|
Assert.Equal(UnwieldyWeight, item.Weight);
|
|
Assert.Equal((int)UnwieldyWeight, item.PileWeight);
|
|
Assert.Equal(originalContainerWeight - originalPileWeight + (int)UnwieldyWeight, player.Backpack.TotalWeight);
|
|
Assert.Equal(originalMobileWeight - originalPileWeight + (int)UnwieldyWeight, player.TotalWeight);
|
|
AssertShowsWeightWithoutUnwieldyRow(item, (int)UnwieldyWeight);
|
|
|
|
GetNegativeAttributes(item).Unwieldy = 2;
|
|
Assert.Equal(1, GetNegativeAttributes(item).Unwieldy);
|
|
Assert.Equal((int)UnwieldyWeight, item.PileWeight);
|
|
Assert.Equal(originalContainerWeight - originalPileWeight + (int)UnwieldyWeight, player.Backpack.TotalWeight);
|
|
Assert.Equal(originalMobileWeight - originalPileWeight + (int)UnwieldyWeight, player.TotalWeight);
|
|
|
|
GetNegativeAttributes(item).Unwieldy = 0;
|
|
|
|
Assert.Equal(OriginalWeight, item.Weight);
|
|
Assert.Equal(originalPileWeight, item.PileWeight);
|
|
Assert.Equal(originalContainerWeight, player.Backpack.TotalWeight);
|
|
Assert.Equal(originalMobileWeight, player.TotalWeight);
|
|
AssertShowsWeightWithoutUnwieldyRow(item, originalPileWeight);
|
|
|
|
GetNegativeAttributes(item).Unwieldy = 0;
|
|
Assert.Equal(0, GetNegativeAttributes(item).Unwieldy);
|
|
Assert.Equal(OriginalWeight, item.Weight);
|
|
Assert.Equal(originalContainerWeight, player.Backpack.TotalWeight);
|
|
Assert.Equal(originalMobileWeight, player.TotalWeight);
|
|
}
|
|
finally
|
|
{
|
|
item.Delete();
|
|
player.Delete();
|
|
}
|
|
}
|
|
|
|
private static void AssertShowsWeightWithoutUnwieldyRow(Item item, int weight)
|
|
{
|
|
var properties = new RecordingPropertyList();
|
|
item.GetProperties(properties);
|
|
|
|
Assert.Contains(properties.Entries, entry =>
|
|
entry.Number == (weight == 1 ? SingleWeightCliloc : MultipleWeightCliloc) && entry.Argument == weight.ToString());
|
|
Assert.DoesNotContain(properties.Entries, entry =>
|
|
entry.Argument.Contains("Unwieldy", StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
private static NegativeAttributes GetNegativeAttributes(Item item) => item switch
|
|
{
|
|
BaseWeapon weapon => weapon.NegativeAttributes,
|
|
BaseArmor armor => armor.NegativeAttributes,
|
|
_ => throw new ArgumentException($"Unsupported Unwieldy host: {item.GetType().FullName}", nameof(item))
|
|
};
|
|
|
|
private static PlayerMobile CreatePlayerMobile()
|
|
{
|
|
var player = new PlayerMobile(World.NewMobile);
|
|
player.DefaultMobileInit();
|
|
player.AddItem(new Backpack());
|
|
return player;
|
|
}
|
|
|
|
private class TestKatana : Katana
|
|
{
|
|
}
|
|
|
|
private sealed record PropertyEntry(int Number, string Argument);
|
|
|
|
private sealed class RecordingPropertyList : IPropertyList
|
|
{
|
|
private string _interpolated = string.Empty;
|
|
|
|
public List<PropertyEntry> Entries { get; } = [];
|
|
|
|
public void Reset()
|
|
{
|
|
}
|
|
|
|
public void Terminate()
|
|
{
|
|
}
|
|
|
|
public void Add(int number) => Entries.Add(new PropertyEntry(number, string.Empty));
|
|
public void Add(int number, string argument) => Entries.Add(new PropertyEntry(number, argument));
|
|
public void Add(ReadOnlySpan<char> argument) => Entries.Add(new PropertyEntry(0, argument.ToString()));
|
|
public void Add(int number, ReadOnlySpan<char> argument) => Entries.Add(new PropertyEntry(number, argument.ToString()));
|
|
public void AddChunked(ReadOnlySpan<char> text) => Entries.Add(new PropertyEntry(0, text.ToString()));
|
|
public OplTextBlock TextBlock() => new(this);
|
|
public void Add(int number, int value) => Entries.Add(new PropertyEntry(number, value.ToString()));
|
|
public void AddLocalized(int value) => Entries.Add(new PropertyEntry(0, value.ToString()));
|
|
public void AddLocalized(int number, int value) => Entries.Add(new PropertyEntry(number, value.ToString()));
|
|
public void Add(ref IPropertyList.InterpolatedStringHandler handler) => Entries.Add(new PropertyEntry(0, _interpolated));
|
|
public void Add(int number, ref IPropertyList.InterpolatedStringHandler handler) =>
|
|
Entries.Add(new PropertyEntry(number, _interpolated));
|
|
public void InitializeInterpolation(int literalLength, int formattedCount) => _interpolated = string.Empty;
|
|
public void AppendLiteral(string value) => _interpolated += value;
|
|
public void AppendFormatted<T>(T value) => _interpolated += value;
|
|
public void AppendFormatted<T>(T value, string format) =>
|
|
_interpolated += value is IFormattable formattable ? formattable.ToString(format, null) : value;
|
|
public void AppendFormatted<T>(T value, int alignment) => _interpolated += value;
|
|
public void AppendFormatted<T>(T value, int alignment, string format) =>
|
|
_interpolated += value is IFormattable formattable ? formattable.ToString(format, null) : value;
|
|
public void AppendFormatted(ReadOnlySpan<char> value) => _interpolated += value.ToString();
|
|
public void AppendFormatted(ReadOnlySpan<char> value, int alignment, string format = null) =>
|
|
_interpolated += value.ToString();
|
|
public void AppendFormatted(object value, int alignment = 0, string format = null) => _interpolated += value;
|
|
public void AppendFormatted(string value) => _interpolated += value;
|
|
public void AppendFormatted(string value, int alignment, string format = null) => _interpolated += value;
|
|
}
|
|
}
|