Merge pull request #11 from RebirthUO/feat/issue-7-extended-weapon-attributes
feat(items): add extended weapon attributes
This commit is contained in:
commit
dde5fb6d49
9 changed files with 548 additions and 76 deletions
|
|
@ -14,19 +14,19 @@ public class BanePropertyTests
|
|||
private const int BaneCliloc = 1154671;
|
||||
|
||||
[Fact]
|
||||
public void WeaponAttributes_StoresAndDupesBane()
|
||||
public void ExtendedWeaponAttributes_StoresAndDupesBane()
|
||||
{
|
||||
var weapon = new TestKatana();
|
||||
var dupe = new TestKatana();
|
||||
|
||||
try
|
||||
{
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
|
||||
weapon.Dupe(dupe);
|
||||
|
||||
Assert.Equal(1, weapon.WeaponAttributes.Bane);
|
||||
Assert.Equal(1, dupe.WeaponAttributes.Bane);
|
||||
Assert.Equal(1, weapon.ExtendedWeaponAttributes.Bane);
|
||||
Assert.Equal(1, dupe.ExtendedWeaponAttributes.Bane);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -36,23 +36,23 @@ public class BanePropertyTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void WeaponAttributes_GetProperties_GatesBaneTooltipToHighSeas()
|
||||
public void ExtendedWeaponAttributes_GetProperties_GatesBaneTooltipToHighSeas()
|
||||
{
|
||||
var previousExpansion = Core.Expansion;
|
||||
var weapon = new TestKatana();
|
||||
|
||||
try
|
||||
{
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
|
||||
Core.Expansion = Expansion.ML;
|
||||
var preHighSeas = new RecordingPropertyList();
|
||||
weapon.WeaponAttributes.GetProperties(preHighSeas);
|
||||
weapon.ExtendedWeaponAttributes.GetProperties(preHighSeas);
|
||||
Assert.DoesNotContain(preHighSeas.Numbers, number => number == BaneCliloc);
|
||||
|
||||
Core.Expansion = Expansion.HS;
|
||||
var highSeas = new RecordingPropertyList();
|
||||
weapon.WeaponAttributes.GetProperties(highSeas);
|
||||
weapon.ExtendedWeaponAttributes.GetProperties(highSeas);
|
||||
Assert.Contains(highSeas.Numbers, number => number == BaneCliloc);
|
||||
}
|
||||
finally
|
||||
|
|
@ -77,7 +77,7 @@ public class BanePropertyTests
|
|||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
|
||||
Assert.Equal(expected, weapon.GetBaneDamage(defender));
|
||||
}
|
||||
|
|
@ -100,7 +100,7 @@ public class BanePropertyTests
|
|||
try
|
||||
{
|
||||
Core.Expansion = Expansion.ML;
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
AddResistance(defender, ResistanceType.Physical, 70);
|
||||
var before = defender.Hits;
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ public class BanePropertyTests
|
|||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
AddResistance(defender, ResistanceType.Physical, 70);
|
||||
var before = defender.Hits;
|
||||
|
||||
|
|
@ -156,7 +156,7 @@ public class BanePropertyTests
|
|||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
AddResistance(defender, ResistanceType.Physical, 70);
|
||||
var before = defender.Hits;
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ public class BanePropertyTests
|
|||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
weapon.AosElementDamages.Fire = 100;
|
||||
AddResistance(defender, ResistanceType.Physical, 70);
|
||||
AddResistance(defender, ResistanceType.Fire, 0);
|
||||
|
|
@ -214,7 +214,7 @@ public class BanePropertyTests
|
|||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
AddResistance(defender, ResistanceType.Physical, 70);
|
||||
var before = defender.Hits;
|
||||
|
||||
|
|
@ -242,7 +242,7 @@ public class BanePropertyTests
|
|||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
AddResistance(defender, ResistanceType.Physical, 70);
|
||||
WeaponAbility.SetCurrentAbility(attacker, WeaponAbility.ArmorIgnore);
|
||||
var before = defender.Hits;
|
||||
|
|
@ -272,7 +272,7 @@ public class BanePropertyTests
|
|||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
AddResistance(defender, ResistanceType.Physical, 70);
|
||||
var before = defender.Hits;
|
||||
|
||||
|
|
@ -300,7 +300,7 @@ public class BanePropertyTests
|
|||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
var before = defender.Hits;
|
||||
|
||||
weapon.OnSwing(attacker, defender);
|
||||
|
|
@ -327,7 +327,7 @@ public class BanePropertyTests
|
|||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.WeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
AddResistance(defender, ResistanceType.Physical, 70);
|
||||
var before = defender.Hits;
|
||||
|
||||
|
|
@ -357,7 +357,7 @@ public class BanePropertyTests
|
|||
|
||||
BaseRunicTool.ApplyAttributesTo(weapon, false, 0, 25, 100, 100);
|
||||
|
||||
Assert.Equal(0, weapon.WeaponAttributes.Bane);
|
||||
Assert.Equal(0, weapon.ExtendedWeaponAttributes.Bane);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,19 +15,19 @@ public class BattleLustPropertyTests
|
|||
private static readonly DateTime TestNow = new(2035, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
[Fact]
|
||||
public void WeaponAttributes_StoresAndDupesBattleLust()
|
||||
public void ExtendedWeaponAttributes_StoresAndDupesBattleLust()
|
||||
{
|
||||
var weapon = new TestKatana();
|
||||
var dupe = new TestKatana();
|
||||
|
||||
try
|
||||
{
|
||||
weapon.WeaponAttributes.BattleLust = 1;
|
||||
weapon.ExtendedWeaponAttributes.BattleLust = 1;
|
||||
|
||||
weapon.Dupe(dupe);
|
||||
|
||||
Assert.Equal(1, weapon.WeaponAttributes.BattleLust);
|
||||
Assert.Equal(1, dupe.WeaponAttributes.BattleLust);
|
||||
Assert.Equal(1, weapon.ExtendedWeaponAttributes.BattleLust);
|
||||
Assert.Equal(1, dupe.ExtendedWeaponAttributes.BattleLust);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -37,23 +37,23 @@ public class BattleLustPropertyTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void WeaponAttributes_GetProperties_GatesBattleLustTooltipToStygianAbyss()
|
||||
public void ExtendedWeaponAttributes_GetProperties_GatesBattleLustTooltipToStygianAbyss()
|
||||
{
|
||||
var previousExpansion = Core.Expansion;
|
||||
var weapon = new TestKatana();
|
||||
|
||||
try
|
||||
{
|
||||
weapon.WeaponAttributes.BattleLust = 1;
|
||||
weapon.ExtendedWeaponAttributes.BattleLust = 1;
|
||||
|
||||
Core.Expansion = Expansion.ML;
|
||||
var preStygianAbyss = new RecordingPropertyList();
|
||||
weapon.WeaponAttributes.GetProperties(preStygianAbyss);
|
||||
weapon.ExtendedWeaponAttributes.GetProperties(preStygianAbyss);
|
||||
Assert.DoesNotContain(preStygianAbyss.Numbers, number => number == BattleLustCliloc);
|
||||
|
||||
Core.Expansion = Expansion.SA;
|
||||
var stygianAbyss = new RecordingPropertyList();
|
||||
weapon.WeaponAttributes.GetProperties(stygianAbyss);
|
||||
weapon.ExtendedWeaponAttributes.GetProperties(stygianAbyss);
|
||||
Assert.Contains(stygianAbyss.Numbers, number => number == BattleLustCliloc);
|
||||
}
|
||||
finally
|
||||
|
|
@ -277,7 +277,7 @@ public class BattleLustPropertyTests
|
|||
|
||||
ApplyDamage(disarmedWielder, source, BattleLust.DamageThreshold);
|
||||
Assert.Equal(1, BattleLust.GetPoints(disarmedWielder));
|
||||
disarmedWeapon.WeaponAttributes.BattleLust = 0;
|
||||
disarmedWeapon.ExtendedWeaponAttributes.BattleLust = 0;
|
||||
Assert.Equal(0, BattleLust.GetDamageBonus(disarmedWielder, source));
|
||||
Assert.Equal(0, BattleLust.GetPoints(disarmedWielder));
|
||||
}
|
||||
|
|
@ -345,8 +345,8 @@ public class BattleLustPropertyTests
|
|||
ApplyDamage(wielder, source, BattleLust.DamageThreshold);
|
||||
Assert.Equal(1, BattleLust.GetPoints(wielder));
|
||||
|
||||
weapon.WeaponAttributes.BattleLust = 0;
|
||||
weapon.WeaponAttributes.BattleLust = 1;
|
||||
weapon.ExtendedWeaponAttributes.BattleLust = 0;
|
||||
weapon.ExtendedWeaponAttributes.BattleLust = 1;
|
||||
|
||||
Assert.Equal(0, BattleLust.GetPoints(wielder));
|
||||
}
|
||||
|
|
@ -488,7 +488,7 @@ public class BattleLustPropertyTests
|
|||
|
||||
BaseRunicTool.ApplyAttributesTo(weapon, false, 0, 25, 100, 100);
|
||||
|
||||
Assert.Equal(0, weapon.WeaponAttributes.BattleLust);
|
||||
Assert.Equal(0, weapon.ExtendedWeaponAttributes.BattleLust);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -500,7 +500,7 @@ public class BattleLustPropertyTests
|
|||
private static TestKatana EquipBattleLustWeapon(Mobile wielder)
|
||||
{
|
||||
var weapon = new TestKatana();
|
||||
weapon.WeaponAttributes.BattleLust = 1;
|
||||
weapon.ExtendedWeaponAttributes.BattleLust = 1;
|
||||
wielder.AddItem(weapon);
|
||||
return weapon;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using Server;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Xunit;
|
||||
|
||||
namespace UOContent.Tests;
|
||||
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class ExtendedWeaponAttributesTests
|
||||
{
|
||||
[Fact]
|
||||
public void AosWeaponAttribute_DoesNotExposeBaneOrBattleLust()
|
||||
{
|
||||
var names = Enum.GetNames<AosWeaponAttribute>();
|
||||
|
||||
Assert.DoesNotContain("Bane", names);
|
||||
Assert.DoesNotContain("BattleLust", names);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendedWeaponAttribute_UsesFreshLowBits()
|
||||
{
|
||||
Assert.Equal(0x00000001, (int)ExtendedWeaponAttribute.Bane);
|
||||
Assert.Equal(0x00000002, (int)ExtendedWeaponAttribute.BattleLust);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewWeapon_DefaultsExtendedWeaponAttributesEmpty()
|
||||
{
|
||||
var weapon = new TestKatana();
|
||||
|
||||
try
|
||||
{
|
||||
Assert.NotNull(weapon.ExtendedWeaponAttributes);
|
||||
Assert.True(weapon.ExtendedWeaponAttributes.IsEmpty);
|
||||
Assert.Equal(0, weapon.ExtendedWeaponAttributes.Bane);
|
||||
Assert.Equal(0, weapon.ExtendedWeaponAttributes.BattleLust);
|
||||
}
|
||||
finally
|
||||
{
|
||||
weapon.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StormCaller_UsesExtendedBattleLustProperty()
|
||||
{
|
||||
var weapon = new StormCaller();
|
||||
|
||||
try
|
||||
{
|
||||
Assert.Equal(1, weapon.ExtendedWeaponAttributes.BattleLust);
|
||||
}
|
||||
finally
|
||||
{
|
||||
weapon.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendedWeaponAttributes_AreStaffEditableThroughCommandProperties()
|
||||
{
|
||||
var containerProperty = typeof(BaseWeapon).GetProperty(nameof(BaseWeapon.ExtendedWeaponAttributes));
|
||||
Assert.NotNull(containerProperty);
|
||||
var containerCommandProperty = containerProperty.GetCustomAttribute<CommandPropertyAttribute>();
|
||||
Assert.NotNull(containerCommandProperty);
|
||||
Assert.True(containerCommandProperty.CanModify);
|
||||
|
||||
AssertStaffCommandProperty(nameof(ExtendedWeaponAttributes.Bane));
|
||||
AssertStaffCommandProperty(nameof(ExtendedWeaponAttributes.BattleLust));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendedWeaponAttributes_PersistBaneAndBattleLustThroughBaseWeaponSerialization()
|
||||
{
|
||||
var previousExpansion = Core.Expansion;
|
||||
var weapon = new TestKatana();
|
||||
var deserialized = new TestKatana();
|
||||
|
||||
try
|
||||
{
|
||||
Core.Expansion = Expansion.HS;
|
||||
weapon.ExtendedWeaponAttributes.Bane = 1;
|
||||
weapon.ExtendedWeaponAttributes.BattleLust = 1;
|
||||
|
||||
var writer = new BufferWriter(true);
|
||||
weapon.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, deserialized.ExtendedWeaponAttributes.Bane);
|
||||
Assert.Equal(1, deserialized.ExtendedWeaponAttributes.BattleLust);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Core.Expansion = previousExpansion;
|
||||
weapon.Delete();
|
||||
deserialized.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertStaffCommandProperty(string propertyName)
|
||||
{
|
||||
var property = typeof(ExtendedWeaponAttributes).GetProperty(propertyName);
|
||||
Assert.NotNull(property);
|
||||
|
||||
var attribute = property.GetCustomAttribute<CommandPropertyAttribute>();
|
||||
Assert.NotNull(attribute);
|
||||
Assert.Equal(AccessLevel.GameMaster, attribute.ReadLevel);
|
||||
Assert.Equal(AccessLevel.GameMaster, attribute.WriteLevel);
|
||||
}
|
||||
|
||||
private class TestKatana : Katana
|
||||
{
|
||||
public override int ComputeDamage(Mobile attacker, Mobile defender) => 1;
|
||||
public override int AbsorbDamage(Mobile attacker, Mobile defender, int damage) => damage;
|
||||
public override void AddBlood(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
40
Projects/UOContent/Items/Weapons/BaseWeapon.Migrations.cs
Normal file
40
Projects/UOContent/Items/Weapons/BaseWeapon.Migrations.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
namespace Server.Items;
|
||||
|
||||
public abstract partial class BaseWeapon
|
||||
{
|
||||
private void MigrateFrom(V10Content 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 = ExtendedWeaponAttributesDefaultValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ public interface ISlayer
|
|||
SlayerName Slayer2 { get; set; }
|
||||
}
|
||||
|
||||
[SerializationGenerator(10, false)]
|
||||
[SerializationGenerator(11, false)]
|
||||
public abstract partial class BaseWeapon
|
||||
: Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability, IAosItem, IIdentifiable
|
||||
{
|
||||
|
|
@ -191,6 +191,15 @@ public abstract partial class BaseWeapon
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool ShouldSerializeEngravedText() => !string.IsNullOrEmpty(_engravedText);
|
||||
|
||||
// Field 31 intentionally has no save flag; BaseWeapon's legacy save-flag mask is already at the high bit.
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(31, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private ExtendedWeaponAttributes _extendedWeaponAttributes;
|
||||
|
||||
[SerializableFieldDefault(31)]
|
||||
private ExtendedWeaponAttributes ExtendedWeaponAttributesDefaultValue() => new(this);
|
||||
|
||||
private FactionItem m_FactionState;
|
||||
private SkillMod m_SkillMod, m_MageMod;
|
||||
|
||||
|
|
@ -218,6 +227,7 @@ public abstract partial class BaseWeapon
|
|||
|
||||
Attributes = new AosAttributes(this);
|
||||
WeaponAttributes = new AosWeaponAttributes(this);
|
||||
ExtendedWeaponAttributes = new ExtendedWeaponAttributes(this);
|
||||
SkillBonuses = new AosSkillBonuses(this);
|
||||
AosElementDamages = new AosElementAttributes(this);
|
||||
}
|
||||
|
|
@ -934,6 +944,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.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses);
|
||||
weap.WeaponAttributes = new AosWeaponAttributes(newItem, WeaponAttributes);
|
||||
|
||||
|
|
@ -1140,7 +1151,7 @@ public abstract partial class BaseWeapon
|
|||
return;
|
||||
}
|
||||
|
||||
if (WeaponAttributes.BattleLust != 0)
|
||||
if (ExtendedWeaponAttributes.BattleLust != 0)
|
||||
{
|
||||
BattleLust.Clear(m);
|
||||
}
|
||||
|
|
@ -1185,7 +1196,7 @@ public abstract partial class BaseWeapon
|
|||
{
|
||||
base.OnMapChange();
|
||||
|
||||
if ((Map == null || Map == Map.Internal) && Parent is Mobile m && WeaponAttributes.BattleLust != 0)
|
||||
if ((Map == null || Map == Map.Internal) && Parent is Mobile m && ExtendedWeaponAttributes.BattleLust != 0)
|
||||
{
|
||||
BattleLust.Clear(m);
|
||||
}
|
||||
|
|
@ -2395,7 +2406,7 @@ public abstract partial class BaseWeapon
|
|||
|
||||
internal int GetBaneDamage(Mobile defender)
|
||||
{
|
||||
if (!Core.HS || WeaponAttributes.Bane == 0 || defender?.Deleted != false || defender.HitsMax <= 0 ||
|
||||
if (!Core.HS || ExtendedWeaponAttributes.Bane == 0 || defender?.Deleted != false || defender.HitsMax <= 0 ||
|
||||
defender.Hits / (double)defender.HitsMax >= 0.5)
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -3051,6 +3062,7 @@ public abstract partial class BaseWeapon
|
|||
list.Add(1072792); // Balanced
|
||||
}
|
||||
|
||||
ExtendedWeaponAttributes.GetProperties(list);
|
||||
WeaponAttributes.GetProperties(list);
|
||||
|
||||
if (ImmolatingWeaponSpell.IsImmolating(this))
|
||||
|
|
@ -3820,6 +3832,8 @@ public abstract partial class BaseWeapon
|
|||
WeaponAttributes.Deserialize(reader);
|
||||
}
|
||||
|
||||
ExtendedWeaponAttributes = new ExtendedWeaponAttributes(this);
|
||||
|
||||
PlayerConstructed = GetSaveFlag(flags, OldSaveFlag.PlayerConstructed);
|
||||
|
||||
SkillBonuses = new AosSkillBonuses(this);
|
||||
|
|
@ -3850,6 +3864,8 @@ public abstract partial class BaseWeapon
|
|||
[AfterDeserialization]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
_extendedWeaponAttributes ??= ExtendedWeaponAttributesDefaultValue();
|
||||
|
||||
var parentMobile = Parent as Mobile;
|
||||
|
||||
if (UseSkillMod && _accuracyLevel != WeaponAccuracyLevel.Regular && parentMobile != null)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ public static class BattleLust
|
|||
mobile.Map != null &&
|
||||
mobile.Map != Map.Internal &&
|
||||
mobile.Weapon is BaseWeapon weapon &&
|
||||
weapon.WeaponAttributes.BattleLust != 0;
|
||||
weapon.ExtendedWeaponAttributes.BattleLust != 0;
|
||||
|
||||
private static int GetActiveAggressedCount(Mobile mobile)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ public partial class StormCaller : Boomerang
|
|||
public StormCaller()
|
||||
{
|
||||
Hue = 456;
|
||||
//TODO Implement BattleLust
|
||||
//WeaponAttributes.BattleLust = 1;
|
||||
ExtendedWeaponAttributes.BattleLust = 1;
|
||||
WeaponAttributes.HitLightning = 40;
|
||||
WeaponAttributes.HitLowerDefend = 30;
|
||||
Attributes.BonusStr = 5;
|
||||
|
|
|
|||
263
Projects/UOContent/Migrations/Server.Items.BaseWeapon.v11.json
generated
Normal file
263
Projects/UOContent/Migrations/Server.Items.BaseWeapon.v11.json
generated
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
{
|
||||
"version": 11,
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -781,9 +781,7 @@ namespace Server
|
|||
ResistEnergyBonus = 0x00200000,
|
||||
UseBestSkill = 0x00400000,
|
||||
MageWeapon = 0x00800000,
|
||||
DurabilityBonus = 0x01000000,
|
||||
Bane = 0x02000000,
|
||||
BattleLust = 0x04000000
|
||||
DurabilityBonus = 0x01000000
|
||||
}
|
||||
|
||||
public sealed class AosWeaponAttributes : BaseAttributes
|
||||
|
|
@ -977,30 +975,6 @@ namespace Server
|
|||
set => this[AosWeaponAttribute.DurabilityBonus] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Bane
|
||||
{
|
||||
get => this[AosWeaponAttribute.Bane];
|
||||
set => this[AosWeaponAttribute.Bane] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int BattleLust
|
||||
{
|
||||
get => this[AosWeaponAttribute.BattleLust];
|
||||
set
|
||||
{
|
||||
var hadBattleLust = BattleLust != 0;
|
||||
|
||||
this[AosWeaponAttribute.BattleLust] = value;
|
||||
|
||||
if (hadBattleLust && value == 0 && Owner is BaseWeapon { Parent: Mobile m })
|
||||
{
|
||||
Server.Items.BattleLust.Clear(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetValue(Mobile m, AosWeaponAttribute attribute)
|
||||
{
|
||||
if (!Core.AOS)
|
||||
|
|
@ -1042,16 +1016,6 @@ namespace Server
|
|||
{
|
||||
int prop;
|
||||
|
||||
if (Core.HS && Bane != 0)
|
||||
{
|
||||
list.Add(1154671); // Bane
|
||||
}
|
||||
|
||||
if (Core.SA && BattleLust != 0)
|
||||
{
|
||||
list.Add(1113710); // Battle Lust
|
||||
}
|
||||
|
||||
if (UseBestSkill != 0)
|
||||
{
|
||||
list.Add(1060400); // use best weapon skill
|
||||
|
|
@ -1146,6 +1110,69 @@ namespace Server
|
|||
public override string ToString() => "...";
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ExtendedWeaponAttribute
|
||||
{
|
||||
Bane = 0x00000001,
|
||||
BattleLust = 0x00000002
|
||||
}
|
||||
|
||||
public sealed class ExtendedWeaponAttributes : BaseAttributes
|
||||
{
|
||||
public ExtendedWeaponAttributes(Item owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public ExtendedWeaponAttributes(Item owner, ExtendedWeaponAttributes other) : base(owner, other)
|
||||
{
|
||||
}
|
||||
|
||||
public int this[ExtendedWeaponAttribute attribute]
|
||||
{
|
||||
get => GetValue((int)attribute);
|
||||
set => SetValue((int)attribute, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Bane
|
||||
{
|
||||
get => this[ExtendedWeaponAttribute.Bane];
|
||||
set => this[ExtendedWeaponAttribute.Bane] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int BattleLust
|
||||
{
|
||||
get => this[ExtendedWeaponAttribute.BattleLust];
|
||||
set
|
||||
{
|
||||
var hadBattleLust = BattleLust != 0;
|
||||
|
||||
this[ExtendedWeaponAttribute.BattleLust] = value;
|
||||
|
||||
if (hadBattleLust && value == 0 && Owner is BaseWeapon { Parent: Mobile m })
|
||||
{
|
||||
Server.Items.BattleLust.Clear(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GetProperties(IPropertyList list)
|
||||
{
|
||||
if (Core.HS && Bane != 0)
|
||||
{
|
||||
list.Add(1154671); // Bane
|
||||
}
|
||||
|
||||
if (Core.SA && BattleLust != 0)
|
||||
{
|
||||
list.Add(1113710); // Battle Lust
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => "...";
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum AosArmorAttribute
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue