Merge pull request #13 from RebirthUO/feat/issue-8-prized
feat(items): add Prized negative property
This commit is contained in:
commit
b4e57ee9e5
11 changed files with 983 additions and 4 deletions
220
Projects/UOContent.Tests/Tests/Items/PrizedPropertyTests.cs
Normal file
220
Projects/UOContent.Tests/Tests/Items/PrizedPropertyTests.cs
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
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 PrizedPropertyTests
|
||||
{
|
||||
private const int PrizedCliloc = 1154910;
|
||||
|
||||
[Fact]
|
||||
public void NegativeAttributes_StoresAndDupesPrizedOnSupportedFamilies()
|
||||
{
|
||||
AssertStoresAndDupesPrized(new TestKatana(), new TestKatana());
|
||||
AssertStoresAndDupesPrized(new LeatherChest(), new LeatherChest());
|
||||
AssertStoresAndDupesPrized(new Buckler(), new Buckler());
|
||||
AssertStoresAndDupesPrized(new GoldRing(), new GoldRing());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProperties_GatesPrizedTooltipToHighSeasOnSupportedFamilies()
|
||||
{
|
||||
var previousExpansion = Core.Expansion;
|
||||
var items = CreateSupportedItems();
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
GetNegativeAttributes(item).Prized = 1;
|
||||
|
||||
Core.Expansion = Expansion.ML;
|
||||
var preHighSeas = new RecordingPropertyList();
|
||||
item.GetProperties(preHighSeas);
|
||||
Assert.DoesNotContain(preHighSeas.Numbers, number => number == PrizedCliloc);
|
||||
|
||||
Core.Expansion = Expansion.HS;
|
||||
var highSeas = new RecordingPropertyList();
|
||||
item.GetProperties(highSeas);
|
||||
Assert.Contains(highSeas.Numbers, number => number == PrizedCliloc);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Core.Expansion = previousExpansion;
|
||||
DeleteItems(items);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInsuranceCost_DoublesPrizedItemsOnlyInHighSeas()
|
||||
{
|
||||
var previousExpansion = Core.Expansion;
|
||||
var normal = new TestKatana();
|
||||
var prized = new TestKatana();
|
||||
|
||||
try
|
||||
{
|
||||
prized.NegativeAttributes.Prized = 1;
|
||||
|
||||
Core.Expansion = Expansion.ML;
|
||||
Assert.Equal(600, PlayerMobile.GetInsuranceCost(prized));
|
||||
Assert.False(NegativeAttributes.IsPrized(prized));
|
||||
|
||||
Core.Expansion = Expansion.HS;
|
||||
Assert.Equal(600, PlayerMobile.GetInsuranceCost(normal));
|
||||
Assert.Equal(1200, PlayerMobile.GetInsuranceCost(prized));
|
||||
Assert.True(NegativeAttributes.IsPrized(prized));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Core.Expansion = previousExpansion;
|
||||
normal.Delete();
|
||||
prized.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Prized_DoesNotChangeBlessedCursedOrInsuranceState()
|
||||
{
|
||||
var previousExpansion = Core.Expansion;
|
||||
var weapon = new TestKatana();
|
||||
|
||||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.NegativeAttributes.Prized = 1;
|
||||
|
||||
Assert.Equal(LootType.Regular, weapon.LootType);
|
||||
Assert.False(weapon.Insured);
|
||||
Assert.False(weapon.PaidInsurance);
|
||||
Assert.Null(weapon.BlessedFor);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Core.Expansion = previousExpansion;
|
||||
weapon.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RunicAttributeGeneration_DoesNotRollPrized()
|
||||
{
|
||||
var previousExpansion = Core.Expansion;
|
||||
var weapon = new TestKatana();
|
||||
var armor = new LeatherChest();
|
||||
var jewel = new GoldRing();
|
||||
|
||||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
|
||||
BaseRunicTool.ApplyAttributesTo(weapon, false, 0, 25, 100, 100);
|
||||
BaseRunicTool.ApplyAttributesTo(armor, false, 0, 25, 100, 100);
|
||||
BaseRunicTool.ApplyAttributesTo(jewel, false, 0, 25, 100, 100);
|
||||
|
||||
Assert.Equal(0, weapon.NegativeAttributes.Prized);
|
||||
Assert.Equal(0, armor.NegativeAttributes.Prized);
|
||||
Assert.Equal(0, jewel.NegativeAttributes.Prized);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Core.Expansion = previousExpansion;
|
||||
weapon.Delete();
|
||||
armor.Delete();
|
||||
jewel.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertStoresAndDupesPrized<TItem>(TItem source, TItem dupe) where TItem : Item
|
||||
{
|
||||
try
|
||||
{
|
||||
GetNegativeAttributes(source).Prized = 1;
|
||||
|
||||
source.Dupe(dupe);
|
||||
|
||||
Assert.Equal(1, GetNegativeAttributes(source).Prized);
|
||||
Assert.Equal(1, GetNegativeAttributes(dupe).Prized);
|
||||
}
|
||||
finally
|
||||
{
|
||||
source.Delete();
|
||||
dupe.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static Item[] CreateSupportedItems() =>
|
||||
[
|
||||
new TestKatana(),
|
||||
new LeatherChest(),
|
||||
new Buckler(),
|
||||
new GoldRing()
|
||||
];
|
||||
|
||||
private static NegativeAttributes GetNegativeAttributes(Item item) => item switch
|
||||
{
|
||||
BaseWeapon weapon => weapon.NegativeAttributes,
|
||||
BaseArmor armor => armor.NegativeAttributes,
|
||||
BaseJewel jewel => jewel.NegativeAttributes,
|
||||
_ => throw new ArgumentException($"Unsupported Prized host: {item.GetType().FullName}", nameof(item))
|
||||
};
|
||||
|
||||
private static void DeleteItems(IEnumerable<Item> items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
item.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private class TestKatana : Katana
|
||||
{
|
||||
}
|
||||
|
||||
private sealed class RecordingPropertyList : IPropertyList
|
||||
{
|
||||
private string _interpolated = string.Empty;
|
||||
|
||||
public List<int> Numbers { get; } = [];
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
}
|
||||
|
||||
public void Add(int number) => Numbers.Add(number);
|
||||
public void Add(int number, string argument) => Numbers.Add(number);
|
||||
public void Add(ReadOnlySpan<char> argument) => Numbers.Add(0);
|
||||
public void Add(int number, ReadOnlySpan<char> argument) => Numbers.Add(number);
|
||||
public void AddChunked(ReadOnlySpan<char> text) => Numbers.Add(0);
|
||||
public OplTextBlock TextBlock() => new(this);
|
||||
public void Add(int number, int value) => Numbers.Add(number);
|
||||
public void AddLocalized(int value) => Numbers.Add(0);
|
||||
public void AddLocalized(int number, int value) => Numbers.Add(number);
|
||||
public void Add(ref IPropertyList.InterpolatedStringHandler handler) => Numbers.Add(0);
|
||||
public void Add(int number, ref IPropertyList.InterpolatedStringHandler handler) => Numbers.Add(number);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +30,37 @@ public partial class BaseArmor
|
|||
_meditate = content.MeditationAllowance ?? (AMA)(-1);
|
||||
_skillBonuses = content.SkillBonuses ?? SkillBonusesDefaultValue();
|
||||
_playerConstructed = content.PlayerConstructed;
|
||||
_negativeAttributes = NegativeAttributesDefaultValue();
|
||||
}
|
||||
|
||||
private void MigrateFrom(V9Content content)
|
||||
{
|
||||
_attributes = content.Attributes ?? AttributesDefaultValue();
|
||||
_armorAttributes = content.ArmorAttributes ?? ArmorAttributesDefaultValue();
|
||||
_physicalBonus = content.PhysicalBonus ?? 0;
|
||||
_fireBonus = content.FireBonus ?? 0;
|
||||
_coldBonus = content.ColdBonus ?? 0;
|
||||
_poisonBonus = content.PoisonBonus ?? 0;
|
||||
_energyBonus = content.EnergyBonus ?? 0;
|
||||
_identified = content.Identified;
|
||||
_maxHitPoints = content.MaxHitPoints ?? 0;
|
||||
_hitPoints = content.HitPoints ?? 0;
|
||||
_crafter = content.Crafter;
|
||||
_quality = content.Quality ?? ArmorQuality.Regular;
|
||||
_durability = content.Durability ?? ArmorDurabilityLevel.Regular;
|
||||
_protectionLevel = content.ProtectionLevel ?? ArmorProtectionLevel.Regular;
|
||||
_resource = content.Resource ?? DefaultResource;
|
||||
_armorBase = content.BaseArmorRating ?? -1;
|
||||
_strBonus = content.StrBonus ?? -1;
|
||||
_dexBonus = content.DexBonus ?? -1;
|
||||
_intBonus = content.IntBonus ?? -1;
|
||||
_strReq = content.StrRequirement ?? -1;
|
||||
_dexReq = content.DexRequirement ?? -1;
|
||||
_intReq = content.IntRequirement ?? -1;
|
||||
_meditate = content.MeditationAllowance ?? (AMA)(-1);
|
||||
_skillBonuses = content.SkillBonuses ?? SkillBonusesDefaultValue();
|
||||
_playerConstructed = content.PlayerConstructed;
|
||||
_negativeAttributes = NegativeAttributesDefaultValue();
|
||||
}
|
||||
|
||||
// Version 7 (pre-codegen)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ using AMT = Server.Items.ArmorMaterialType;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
[SerializationGenerator(9, false)]
|
||||
[SerializationGenerator(10, false)]
|
||||
public abstract partial class BaseArmor
|
||||
: Item, IScissorable, IFactionItem, ICraftable, IWearableDurability, IAosItem, IIdentifiable
|
||||
{
|
||||
|
|
@ -151,6 +151,17 @@ namespace Server.Items
|
|||
[SerializableFieldSaveFlag(24)]
|
||||
private bool ShouldSerializePlayerConstructed() => _playerConstructed;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(25, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private NegativeAttributes _negativeAttributes;
|
||||
|
||||
[SerializableFieldSaveFlag(25)]
|
||||
private bool ShouldSerializeNegativeAttributes() => !_negativeAttributes.IsEmpty;
|
||||
|
||||
[SerializableFieldDefault(25)]
|
||||
private NegativeAttributes NegativeAttributesDefaultValue() => new(this);
|
||||
|
||||
private FactionItem m_FactionState;
|
||||
|
||||
public BaseArmor(int itemID) : base(itemID)
|
||||
|
|
@ -167,6 +178,7 @@ namespace Server.Items
|
|||
|
||||
Attributes = new AosAttributes(this);
|
||||
ArmorAttributes = new AosArmorAttributes(this);
|
||||
NegativeAttributes = new NegativeAttributes(this);
|
||||
SkillBonuses = new AosSkillBonuses(this);
|
||||
}
|
||||
|
||||
|
|
@ -814,6 +826,7 @@ namespace Server.Items
|
|||
|
||||
armor.Attributes = new AosAttributes(newItem, Attributes);
|
||||
armor.ArmorAttributes = new AosArmorAttributes(newItem, ArmorAttributes);
|
||||
armor.NegativeAttributes = new NegativeAttributes(newItem, NegativeAttributes);
|
||||
armor.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses);
|
||||
|
||||
// Set hue again because of resource
|
||||
|
|
@ -1031,6 +1044,8 @@ namespace Server.Items
|
|||
[AfterDeserialization]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
_negativeAttributes ??= NegativeAttributesDefaultValue();
|
||||
|
||||
var m = Parent as Mobile;
|
||||
|
||||
if (Core.AOS && m != null)
|
||||
|
|
@ -1323,6 +1338,7 @@ namespace Server.Items
|
|||
list.Add(1061078, prop); // artifact rarity ~1_val~
|
||||
}
|
||||
|
||||
NegativeAttributes.GetProperties(list);
|
||||
ArmorAttributes.GetProperties(list);
|
||||
|
||||
Attributes.GetProperties(list, luckBonus: GetLuckBonus());
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public enum GemType
|
|||
Diamond
|
||||
}
|
||||
|
||||
[SerializationGenerator(5, false)]
|
||||
[SerializationGenerator(6, false)]
|
||||
public abstract partial class BaseJewel : Item, ICraftable, IAosItem
|
||||
{
|
||||
[EncodedInt]
|
||||
|
|
@ -52,11 +52,20 @@ public abstract partial class BaseJewel : Item, ICraftable, IAosItem
|
|||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private int _gemCount;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(8, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private NegativeAttributes _negativeAttributes;
|
||||
|
||||
[SerializableFieldDefault(8)]
|
||||
private NegativeAttributes NegativeAttributesDefaultValue() => new(this);
|
||||
|
||||
public BaseJewel(int itemID, Layer layer) : base(itemID)
|
||||
{
|
||||
_attributes = new AosAttributes(this);
|
||||
_resistances = new AosElementAttributes(this);
|
||||
_skillBonuses = new AosSkillBonuses(this);
|
||||
NegativeAttributes = new NegativeAttributes(this);
|
||||
_resource = CraftResource.Iron;
|
||||
Hue = CraftResources.GetHue(_resource);
|
||||
_gemType = GemType.None;
|
||||
|
|
@ -321,6 +330,7 @@ public abstract partial class BaseJewel : Item, ICraftable, IAosItem
|
|||
jewel.Attributes = new AosAttributes(newItem, Attributes);
|
||||
jewel.Resistances = new AosElementAttributes(newItem, Resistances);
|
||||
jewel.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses);
|
||||
jewel.NegativeAttributes = new NegativeAttributes(newItem, NegativeAttributes);
|
||||
|
||||
// Set hue again because of resource
|
||||
jewel.Hue = Hue;
|
||||
|
|
@ -389,6 +399,7 @@ public abstract partial class BaseJewel : Item, ICraftable, IAosItem
|
|||
list.Add(1061078, prop); // artifact rarity ~1_val~
|
||||
}
|
||||
|
||||
NegativeAttributes.GetProperties(list);
|
||||
Attributes.GetProperties(list);
|
||||
|
||||
AddResistanceProperties(list);
|
||||
|
|
@ -423,11 +434,27 @@ public abstract partial class BaseJewel : Item, ICraftable, IAosItem
|
|||
_resistances = content.Resistances;
|
||||
_skillBonuses = content.SkillBonuses;
|
||||
// _gemCount defaults to 0
|
||||
_negativeAttributes = NegativeAttributesDefaultValue();
|
||||
}
|
||||
|
||||
private void MigrateFrom(V5Content content)
|
||||
{
|
||||
_maxHitPoints = content.MaxHitPoints;
|
||||
_hitPoints = content.HitPoints;
|
||||
_resource = content.Resource;
|
||||
_gemType = content.GemType;
|
||||
_attributes = content.Attributes;
|
||||
_resistances = content.Resistances;
|
||||
_skillBonuses = content.SkillBonuses;
|
||||
_gemCount = content.GemCount;
|
||||
_negativeAttributes = NegativeAttributesDefaultValue();
|
||||
}
|
||||
|
||||
[AfterDeserialization]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
_negativeAttributes ??= NegativeAttributesDefaultValue();
|
||||
|
||||
var m = Parent as Mobile;
|
||||
|
||||
if (Core.AOS && m != null)
|
||||
|
|
|
|||
|
|
@ -36,5 +36,43 @@ public abstract partial class BaseWeapon
|
|||
_aosElementDamages = content.AosElementDamages ?? AosElementAttributesDefaultValue();
|
||||
_engravedText = content.EngravedText;
|
||||
_extendedWeaponAttributes = ExtendedWeaponAttributesDefaultValue();
|
||||
_negativeAttributes = NegativeAttributesDefaultValue();
|
||||
}
|
||||
|
||||
private void MigrateFrom(V11Content content)
|
||||
{
|
||||
_damageLevel = content.DamageLevel ?? WeaponDamageLevel.Regular;
|
||||
_accuracyLevel = content.AccuracyLevel ?? WeaponAccuracyLevel.Regular;
|
||||
_durabilityLevel = content.DurabilityLevel ?? WeaponDurabilityLevel.Regular;
|
||||
_quality = content.Quality ?? WeaponQuality.Regular;
|
||||
_hitPoints = content.HitPoints ?? 0;
|
||||
_maxHitPoints = content.MaxHitPoints ?? 0;
|
||||
_slayer = content.Slayer ?? SlayerName.None;
|
||||
_poison = content.Poison;
|
||||
_poisonCharges = content.PoisonCharges ?? 0;
|
||||
_crafter = content.Crafter;
|
||||
_identified = content.Identified;
|
||||
_strRequirement = content.StrRequirement ?? -1;
|
||||
_dexRequirement = content.DexRequirement ?? -1;
|
||||
_intRequirement = content.IntRequirement ?? -1;
|
||||
_minDamage = content.MinDamage ?? -1;
|
||||
_maxDamage = content.MaxDamage ?? -1;
|
||||
_hitSound = content.HitSound ?? -1;
|
||||
_missSound = content.MissSound ?? -1;
|
||||
_speed = content.Speed ?? -1;
|
||||
_maxRange = content.MaxRange ?? -1;
|
||||
_skill = content.Skill ?? (SkillName)(-1);
|
||||
_type = content.Type ?? (WeaponType)(-1);
|
||||
_animation = content.Animation ?? (WeaponAnimation)(-1);
|
||||
_resource = content.Resource ?? CraftResource.Iron;
|
||||
_attributes = content.Attributes ?? AttributesDefaultValue();
|
||||
_weaponAttributes = content.WeaponAttributes ?? WeaponAttributesDefaultValue();
|
||||
_playerConstructed = content.PlayerConstructed;
|
||||
_skillBonuses = content.SkillBonuses ?? SkillBonusesDefaultValue();
|
||||
_slayer2 = content.Slayer2 ?? SlayerName.None;
|
||||
_aosElementDamages = content.AosElementDamages ?? AosElementAttributesDefaultValue();
|
||||
_engravedText = content.EngravedText;
|
||||
_extendedWeaponAttributes = content.ExtendedWeaponAttributes ?? ExtendedWeaponAttributesDefaultValue();
|
||||
_negativeAttributes = NegativeAttributesDefaultValue();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public interface ISlayer
|
|||
SlayerName Slayer2 { get; set; }
|
||||
}
|
||||
|
||||
[SerializationGenerator(11, false)]
|
||||
[SerializationGenerator(12, false)]
|
||||
public abstract partial class BaseWeapon
|
||||
: Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability, IAosItem, IIdentifiable
|
||||
{
|
||||
|
|
@ -200,6 +200,15 @@ public abstract partial class BaseWeapon
|
|||
[SerializableFieldDefault(31)]
|
||||
private ExtendedWeaponAttributes ExtendedWeaponAttributesDefaultValue() => new(this);
|
||||
|
||||
// Field 32 intentionally has no save flag; BaseWeapon's legacy save-flag mask is already at the high bit.
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(32, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private NegativeAttributes _negativeAttributes;
|
||||
|
||||
[SerializableFieldDefault(32)]
|
||||
private NegativeAttributes NegativeAttributesDefaultValue() => new(this);
|
||||
|
||||
private FactionItem m_FactionState;
|
||||
private SkillMod m_SkillMod, m_MageMod;
|
||||
|
||||
|
|
@ -228,6 +237,7 @@ public abstract partial class BaseWeapon
|
|||
Attributes = new AosAttributes(this);
|
||||
WeaponAttributes = new AosWeaponAttributes(this);
|
||||
ExtendedWeaponAttributes = new ExtendedWeaponAttributes(this);
|
||||
NegativeAttributes = new NegativeAttributes(this);
|
||||
SkillBonuses = new AosSkillBonuses(this);
|
||||
AosElementDamages = new AosElementAttributes(this);
|
||||
}
|
||||
|
|
@ -945,6 +955,7 @@ public abstract partial class BaseWeapon
|
|||
weap.Attributes = new AosAttributes(newItem, Attributes);
|
||||
weap.AosElementDamages = new AosElementAttributes(newItem, AosElementDamages);
|
||||
weap.ExtendedWeaponAttributes = new ExtendedWeaponAttributes(newItem, ExtendedWeaponAttributes);
|
||||
weap.NegativeAttributes = new NegativeAttributes(newItem, NegativeAttributes);
|
||||
weap.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses);
|
||||
weap.WeaponAttributes = new AosWeaponAttributes(newItem, WeaponAttributes);
|
||||
|
||||
|
|
@ -3062,6 +3073,7 @@ public abstract partial class BaseWeapon
|
|||
list.Add(1072792); // Balanced
|
||||
}
|
||||
|
||||
NegativeAttributes.GetProperties(list);
|
||||
ExtendedWeaponAttributes.GetProperties(list);
|
||||
WeaponAttributes.GetProperties(list);
|
||||
|
||||
|
|
@ -3865,6 +3877,7 @@ public abstract partial class BaseWeapon
|
|||
private void AfterDeserialization()
|
||||
{
|
||||
_extendedWeaponAttributes ??= ExtendedWeaponAttributesDefaultValue();
|
||||
_negativeAttributes ??= NegativeAttributesDefaultValue();
|
||||
|
||||
var parentMobile = Parent as Mobile;
|
||||
|
||||
|
|
|
|||
225
Projects/UOContent/Migrations/Server.Items.BaseArmor.v10.json
generated
Normal file
225
Projects/UOContent/Migrations/Server.Items.BaseArmor.v10.json
generated
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
{
|
||||
"version": 10,
|
||||
"type": "Server.Items.BaseArmor",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Attributes",
|
||||
"type": "Server.AosAttributes",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ArmorAttributes",
|
||||
"type": "Server.AosArmorAttributes",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PhysicalBonus",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "FireBonus",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ColdBonus",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PoisonBonus",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "EnergyBonus",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Identified",
|
||||
"type": "bool",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MaxHitPoints",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "HitPoints",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crafter",
|
||||
"type": "string",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Quality",
|
||||
"type": "Server.Items.ArmorQuality",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Durability",
|
||||
"type": "Server.Items.ArmorDurabilityLevel",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "ProtectionLevel",
|
||||
"type": "Server.Items.ArmorProtectionLevel",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Resource",
|
||||
"type": "Server.Items.CraftResource",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "BaseArmorRating",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "StrBonus",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DexBonus",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "IntBonus",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "StrRequirement",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DexRequirement",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "IntRequirement",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MeditationAllowance",
|
||||
"type": "Server.Items.ArmorMeditationAllowance",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "SkillBonuses",
|
||||
"type": "Server.AosSkillBonuses",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PlayerConstructed",
|
||||
"type": "bool",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NegativeAttributes",
|
||||
"type": "Server.NegativeAttributes",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
72
Projects/UOContent/Migrations/Server.Items.BaseJewel.v6.json
generated
Normal file
72
Projects/UOContent/Migrations/Server.Items.BaseJewel.v6.json
generated
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
{
|
||||
"version": 6,
|
||||
"type": "Server.Items.BaseJewel",
|
||||
"properties": [
|
||||
{
|
||||
"name": "MaxHitPoints",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "HitPoints",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Resource",
|
||||
"type": "Server.Items.CraftResource",
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "GemType",
|
||||
"type": "Server.Items.GemType",
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Attributes",
|
||||
"type": "Server.AosAttributes",
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Resistances",
|
||||
"type": "Server.AosElementAttributes",
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SkillBonuses",
|
||||
"type": "Server.AosSkillBonuses",
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GemCount",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NegativeAttributes",
|
||||
"type": "Server.NegativeAttributes",
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
271
Projects/UOContent/Migrations/Server.Items.BaseWeapon.v12.json
generated
Normal file
271
Projects/UOContent/Migrations/Server.Items.BaseWeapon.v12.json
generated
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
{
|
||||
"version": 12,
|
||||
"type": "Server.Items.BaseWeapon",
|
||||
"properties": [
|
||||
{
|
||||
"name": "DamageLevel",
|
||||
"type": "Server.Items.WeaponDamageLevel",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "AccuracyLevel",
|
||||
"type": "Server.Items.WeaponAccuracyLevel",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "DurabilityLevel",
|
||||
"type": "Server.Items.WeaponDurabilityLevel",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Quality",
|
||||
"type": "Server.Items.WeaponQuality",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "HitPoints",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MaxHitPoints",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Slayer",
|
||||
"type": "Server.Items.SlayerName",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Poison",
|
||||
"type": "Server.Poison",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveUOTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"Poison"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PoisonCharges",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crafter",
|
||||
"type": "string",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Identified",
|
||||
"type": "bool",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "StrRequirement",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DexRequirement",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "IntRequirement",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MinDamage",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MaxDamage",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "HitSound",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MissSound",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Speed",
|
||||
"type": "float",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MaxRange",
|
||||
"type": "int",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Skill",
|
||||
"type": "Server.SkillName",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Type",
|
||||
"type": "Server.Items.WeaponType",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Animation",
|
||||
"type": "Server.Items.WeaponAnimation",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Resource",
|
||||
"type": "Server.Items.CraftResource",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Attributes",
|
||||
"type": "Server.AosAttributes",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "WeaponAttributes",
|
||||
"type": "Server.AosWeaponAttributes",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PlayerConstructed",
|
||||
"type": "bool",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SkillBonuses",
|
||||
"type": "Server.AosSkillBonuses",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Slayer2",
|
||||
"type": "Server.Items.SlayerName",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "AosElementDamages",
|
||||
"type": "Server.AosElementAttributes",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "EngravedText",
|
||||
"type": "string",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ExtendedWeaponAttributes",
|
||||
"type": "Server.ExtendedWeaponAttributes",
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NegativeAttributes",
|
||||
"type": "Server.NegativeAttributes",
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeserializationRequiresParent"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1173,6 +1173,62 @@ namespace Server
|
|||
public override string ToString() => "...";
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum NegativeAttribute
|
||||
{
|
||||
Prized = 0x00000001
|
||||
}
|
||||
|
||||
public sealed class NegativeAttributes : BaseAttributes
|
||||
{
|
||||
public NegativeAttributes(Item owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public NegativeAttributes(Item owner, NegativeAttributes other) : base(owner, other)
|
||||
{
|
||||
}
|
||||
|
||||
public int this[NegativeAttribute attribute]
|
||||
{
|
||||
get => GetValue((int)attribute);
|
||||
set => SetValue((int)attribute, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Prized
|
||||
{
|
||||
get => this[NegativeAttribute.Prized];
|
||||
set => this[NegativeAttribute.Prized] = value;
|
||||
}
|
||||
|
||||
public static bool IsPrized(Item item)
|
||||
{
|
||||
if (!Core.HS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return item switch
|
||||
{
|
||||
BaseWeapon weapon => weapon.NegativeAttributes.Prized != 0,
|
||||
BaseArmor armor => armor.NegativeAttributes.Prized != 0,
|
||||
BaseJewel jewel => jewel.NegativeAttributes.Prized != 0,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
public void GetProperties(IPropertyList list)
|
||||
{
|
||||
if (Core.HS && Prized != 0)
|
||||
{
|
||||
list.Add(1154910); // Prized
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => "...";
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum AosArmorAttribute
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3710,7 +3710,17 @@ namespace Server.Mobiles
|
|||
AutoStabled = null;
|
||||
}
|
||||
|
||||
private static int GetInsuranceCost(Item item) => 600;
|
||||
internal static int GetInsuranceCost(Item item)
|
||||
{
|
||||
var cost = 600;
|
||||
|
||||
if (NegativeAttributes.IsPrized(item))
|
||||
{
|
||||
cost *= 2;
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
private void ToggleItemInsurance()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue