fix: Fixes dupe property copying. Adds IgnoreDupe (#1811)
## Summary ### Changes - Adds `[IgnoreDupe]` and `[SerializedIgnoreDupe]` - Updates all _known_ classes that need the attribute. Some might be missing, please helps us find them! - Adds `Item.Dupe()` command and encapsulates `CopyProperties` and `OnAfterDuped`. This is also overridable. - Updates Dupe command to use the new logic. - Fixes duping multiple kinds of objects that used to be outright broken. ### Bug Fixes - Fixes issue with durability after duping - Fixes issue with hue after duping > [!Note] > **Developer Note** > Customizing how duping an item works now requires two steps: > 1. Add `[IgnoreDupe]` or `[SerializedIgnoreDupe]` to the property/field > 2. Add custom logic in an `OnAfterDuped` override > > When do you need to do this? > *When the property being copied is not a primitive, and you need to manually deep-clone the contents of the property such as with Lists, Dictionaries, or sub classes.*
This commit is contained in:
parent
a8d3d2773e
commit
9c7cb5d778
34 changed files with 502 additions and 248 deletions
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ModernUO.Serialization;
|
||||
using Server.ContextMenus;
|
||||
using Server.Multis;
|
||||
|
|
@ -13,7 +14,7 @@ namespace Server.Items
|
|||
public static readonly TimeSpan EvaluationInterval = TimeSpan.FromDays(1);
|
||||
|
||||
private static readonly Type[] m_Decorations =
|
||||
{
|
||||
[
|
||||
typeof(FishBones),
|
||||
typeof(WaterloggedBoots),
|
||||
typeof(CaptainBlackheartsFishingPole),
|
||||
|
|
@ -23,7 +24,7 @@ namespace Server.Items
|
|||
typeof(IslandStatue),
|
||||
typeof(Shell),
|
||||
typeof(ToyBoat)
|
||||
};
|
||||
];
|
||||
|
||||
private bool m_EvaluateDay;
|
||||
|
||||
|
|
@ -45,16 +46,19 @@ namespace Server.Items
|
|||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private int _vacationLeft;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[InvalidateProperties]
|
||||
[SerializableField(3, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private AquariumState _food;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[InvalidateProperties]
|
||||
[SerializableField(4, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private AquariumState _water;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(5, setter: "private")]
|
||||
private List<int> _events;
|
||||
|
||||
|
|
@ -90,7 +94,7 @@ namespace Server.Items
|
|||
|
||||
_water.Maintain = Utility.RandomMinMax(1, 3);
|
||||
|
||||
_events = new List<int>();
|
||||
_events = [];
|
||||
|
||||
_evaluateTimer = Timer.DelayCall(EvaluationInterval, EvaluationInterval, Evaluate);
|
||||
}
|
||||
|
|
@ -145,9 +149,9 @@ namespace Server.Items
|
|||
public override double DefaultWeight => 10.0;
|
||||
|
||||
private static int[] FishHues =
|
||||
{
|
||||
[
|
||||
0x1C2, 0x1C3, 0x2A3, 0x47E, 0x51D
|
||||
};
|
||||
];
|
||||
|
||||
public override void OnDelete()
|
||||
{
|
||||
|
|
@ -471,6 +475,29 @@ namespace Server.Items
|
|||
}
|
||||
}
|
||||
|
||||
public override void OnAfterDuped(Item newItem)
|
||||
{
|
||||
if (newItem is not Aquarium aquarium)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
aquarium.Food.Added = Food.Added;
|
||||
aquarium.Food.Improve = Food.Improve;
|
||||
aquarium.Food.Maintain = Food.Maintain;
|
||||
aquarium.Food.State = Food.State;
|
||||
|
||||
aquarium.Water.Added = Water.Added;
|
||||
aquarium.Water.Improve = Water.Improve;
|
||||
aquarium.Water.Maintain = Water.Maintain;
|
||||
aquarium.Water.State = Water.State;
|
||||
|
||||
for (var i = 0; i < _events.Count; i++)
|
||||
{
|
||||
aquarium.AddToEvents(_events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void Deserialize(IGenericReader reader, int version)
|
||||
{
|
||||
switch (version)
|
||||
|
|
@ -500,7 +527,7 @@ namespace Server.Items
|
|||
_water = new AquariumState(this);
|
||||
_water.Deserialize(reader);
|
||||
|
||||
_events = new List<int>();
|
||||
_events = [];
|
||||
var count = reader.ReadInt();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
|
|
@ -856,7 +883,8 @@ namespace Server.Items
|
|||
from.PlaySound(0x5A4);
|
||||
}
|
||||
|
||||
public virtual bool AddFish(BaseFish fish) => AddFish(null, fish);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool AddFish(BaseFish fish) => AddFish(null, fish);
|
||||
|
||||
public virtual bool AddFish(Mobile from, BaseFish fish)
|
||||
{
|
||||
|
|
@ -877,16 +905,15 @@ namespace Server.Items
|
|||
|
||||
LiveCreatures += 1;
|
||||
|
||||
from?.SendLocalizedMessage(
|
||||
1073632,
|
||||
$"#{fish.LabelNumber}"
|
||||
); // You add the following creature to your aquarium: ~1_FISH~
|
||||
// You add the following creature to your aquarium: ~1_FISH~
|
||||
from?.SendLocalizedMessage(1073632, $"#{fish.LabelNumber}");
|
||||
|
||||
InvalidateProperties();
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool AddDecoration(Item item) => AddDecoration(null, item);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool AddDecoration(Item item) => AddDecoration(null, item);
|
||||
|
||||
public virtual bool AddDecoration(Mobile from, Item item)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace Server.Items
|
|||
if (_state != value)
|
||||
{
|
||||
_state = Math.Clamp(value, 0, 4);
|
||||
this.MarkDirty();
|
||||
MarkDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ namespace Server.Items
|
|||
[SerializationGenerator(9, false)]
|
||||
public abstract partial class BaseArmor : Item, IScissorable, IFactionItem, ICraftable, IWearableDurability, IAosItem
|
||||
{
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosAttributes _attributes;
|
||||
|
|
@ -23,6 +24,7 @@ namespace Server.Items
|
|||
[SerializableFieldDefault(0)]
|
||||
private AosAttributes AttributesDefaultValue() => new(this);
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(1, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosArmorAttributes _armorAttributes;
|
||||
|
|
@ -128,6 +130,7 @@ namespace Server.Items
|
|||
// Field 22
|
||||
private AMA _meditate = (AMA)(-1);
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(23, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
public AosSkillBonuses _skillBonuses;
|
||||
|
|
@ -788,6 +791,12 @@ namespace Server.Items
|
|||
armor.Attributes = new AosAttributes(newItem, Attributes);
|
||||
armor.ArmorAttributes = new AosArmorAttributes(newItem, ArmorAttributes);
|
||||
armor.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses);
|
||||
|
||||
// Set hue again because of resource
|
||||
armor.Hue = Hue;
|
||||
// Set HP/Max again because of durability
|
||||
armor.HitPoints = HitPoints;
|
||||
armor.MaxHitPoints = MaxHitPoints;
|
||||
}
|
||||
|
||||
public int ComputeStatReq(StatType type)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ namespace Server.Items
|
|||
[SerializationGenerator(5, false)]
|
||||
public partial class BaseBook : Item, ISecurable
|
||||
{
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
|
@ -45,6 +46,7 @@ namespace Server.Items
|
|||
[SerializableFieldSaveFlag(3)]
|
||||
private bool ShouldSerializeWritable() => _writable;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(4, setter: "protected")]
|
||||
private BookPageInfo[] _pages;
|
||||
|
||||
|
|
@ -52,7 +54,7 @@ namespace Server.Items
|
|||
private bool ShouldSerializePages() => DefaultContent?.IsMatch(_pages) != true;
|
||||
|
||||
[SerializableFieldDefault(4)]
|
||||
private BookPageInfo[] PagesDefaultvalue() => DefaultContent?.Copy() ?? Array.Empty<BookPageInfo>();
|
||||
private BookPageInfo[] PagesDefaultValue() => DefaultContent?.Copy() ?? Array.Empty<BookPageInfo>();
|
||||
|
||||
[Constructible]
|
||||
public BaseBook(int itemID, int pageCount = 20, bool writable = true) : this(itemID, null, null, pageCount, writable)
|
||||
|
|
@ -91,6 +93,29 @@ namespace Server.Items
|
|||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int PagesCount => _pages.Length;
|
||||
|
||||
public override void OnAfterDuped(Item newItem)
|
||||
{
|
||||
if (newItem is not BaseBook book)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
book.Pages = new BookPageInfo[book.PagesCount];
|
||||
|
||||
for (var i = 0; i < _pages.Length; ++i)
|
||||
{
|
||||
var oldPage = _pages[i];
|
||||
var oldLines = _pages[i].Lines;
|
||||
var lines = new string[oldPage.Lines.Length];
|
||||
for (var j = 0; j < oldLines.Length; j++)
|
||||
{
|
||||
lines[j] = oldLines[j];
|
||||
}
|
||||
|
||||
book._pages[i] = new BookPageInfo(lines);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual BookContent DefaultContent => null;
|
||||
|
||||
public string ContentAsString
|
||||
|
|
|
|||
|
|
@ -1,35 +1,32 @@
|
|||
using System;
|
||||
namespace Server.Items;
|
||||
|
||||
namespace Server.Items
|
||||
public class BookPageInfo
|
||||
{
|
||||
public class BookPageInfo
|
||||
public BookPageInfo() => Lines = [];
|
||||
|
||||
public BookPageInfo(params string[] lines) => Lines = lines;
|
||||
|
||||
public BookPageInfo(IGenericReader reader)
|
||||
{
|
||||
public BookPageInfo() => Lines = Array.Empty<string>();
|
||||
var length = reader.ReadInt();
|
||||
|
||||
public BookPageInfo(params string[] lines) => Lines = lines;
|
||||
Lines = new string[length];
|
||||
|
||||
public BookPageInfo(IGenericReader reader)
|
||||
for (var i = 0; i < Lines.Length; ++i)
|
||||
{
|
||||
var length = reader.ReadInt();
|
||||
|
||||
Lines = new string[length];
|
||||
|
||||
for (var i = 0; i < Lines.Length; ++i)
|
||||
{
|
||||
Lines[i] = reader.ReadString().Intern();
|
||||
}
|
||||
Lines[i] = reader.ReadString().Intern();
|
||||
}
|
||||
}
|
||||
|
||||
public string[] Lines { get; set; }
|
||||
public string[] Lines { get; set; }
|
||||
|
||||
public void Serialize(IGenericWriter writer)
|
||||
public void Serialize(IGenericWriter writer)
|
||||
{
|
||||
writer.Write(Lines.Length);
|
||||
|
||||
for (var i = 0; i < Lines.Length; ++i)
|
||||
{
|
||||
writer.Write(Lines.Length);
|
||||
|
||||
for (var i = 0; i < Lines.Length; ++i)
|
||||
{
|
||||
writer.Write(Lines[i]);
|
||||
}
|
||||
writer.Write(Lines[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ namespace Server.Items
|
|||
[SerializableFieldSaveFlag(0)]
|
||||
private bool ShouldSerializeResource() => _resource != DefaultResource;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(1, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosAttributes _attributes;
|
||||
|
|
@ -39,6 +40,7 @@ namespace Server.Items
|
|||
[SerializableFieldDefault(1)]
|
||||
private AosAttributes AttributesDefaultValue() => new(this);
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(2, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosArmorAttributes _clothingAttributes;
|
||||
|
|
@ -49,6 +51,7 @@ namespace Server.Items
|
|||
[SerializableFieldDefault(2)]
|
||||
private AosArmorAttributes ClothingAttributesDefaultValue() => new(this);
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(3, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosSkillBonuses _skillBonuses;
|
||||
|
|
@ -59,6 +62,7 @@ namespace Server.Items
|
|||
[SerializableFieldDefault(3)]
|
||||
private AosSkillBonuses SkillBonusesDefaultValue() => new(this);
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(4, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosElementAttributes _resistances;
|
||||
|
|
@ -637,6 +641,12 @@ namespace Server.Items
|
|||
clothing.Resistances = new AosElementAttributes(newItem, Resistances);
|
||||
clothing.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses);
|
||||
clothing.ClothingAttributes = new AosArmorAttributes(newItem, ClothingAttributes);
|
||||
|
||||
// Set hue again because of resource
|
||||
clothing.Hue = Hue;
|
||||
// Set HP/Max again because of durability
|
||||
clothing.HitPoints = HitPoints;
|
||||
clothing.MaxHitPoints = MaxHitPoints;
|
||||
}
|
||||
|
||||
public override bool AllowEquippedCast(Mobile from) =>
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ public partial class GenericHouseDoor : BaseHouseDoor
|
|||
[SerializationGenerator(2, false)]
|
||||
public abstract partial class BaseHouseDoor : BaseDoor, ISecurable
|
||||
{
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ namespace Server.Items;
|
|||
[SerializationGenerator(2, false)]
|
||||
public abstract partial class BaseBoard : Container, ISecurable
|
||||
{
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
|
|
|||
|
|
@ -13,22 +13,28 @@ public partial class MahjongGame : Item, ISecurable
|
|||
public const int MaxPlayers = 4;
|
||||
public const int BaseScore = 30000;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(1, setter: "private")]
|
||||
private MahjongTile[] _tiles;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(2, setter: "private")]
|
||||
private MahjongDealerIndicator _dealerIndicator;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(3, setter: "private")]
|
||||
private MahjongWallBreakIndicator _wallBreakIndicator;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(4, setter: "private")]
|
||||
private MahjongDices _dices;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(5, setter: "private")]
|
||||
private MahjongPlayers _players;
|
||||
|
||||
|
|
|
|||
|
|
@ -32,14 +32,17 @@ public abstract partial class BaseJewel : Item, ICraftable, IAosItem
|
|||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private GemType _gemType;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(4, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosAttributes _attributes;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(5, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosElementAttributes _resistances;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(6, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosSkillBonuses _skillBonuses;
|
||||
|
|
@ -193,6 +196,9 @@ 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);
|
||||
|
||||
// Set hue again because of resource
|
||||
jewel.Hue = Hue;
|
||||
}
|
||||
|
||||
public override void OnAdded(IEntity parent)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ public partial class PlayerBBEast : BasePlayerBB
|
|||
[SerializationGenerator(0, false)]
|
||||
public abstract partial class BasePlayerBB : Item, ISecurable
|
||||
{
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
|
@ -40,10 +41,12 @@ public abstract partial class BasePlayerBB : Item, ISecurable
|
|||
private string _title;
|
||||
|
||||
[CanBeNull]
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(2)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private PlayerBBMessage _greeting;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(3)]
|
||||
private List<PlayerBBMessage> _messages;
|
||||
|
||||
|
|
@ -53,6 +56,25 @@ public abstract partial class BasePlayerBB : Item, ISecurable
|
|||
_level = SecureLevel.Anyone;
|
||||
}
|
||||
|
||||
public override void OnAfterDuped(Item newItem)
|
||||
{
|
||||
if (newItem is not BasePlayerBB board)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_greeting != null)
|
||||
{
|
||||
board.Greeting = new PlayerBBMessage(_greeting.Time, _greeting.Poster, _greeting.Message);
|
||||
}
|
||||
|
||||
for (var i = 0; i < _messages.Count; i++)
|
||||
{
|
||||
var message = _messages[i];
|
||||
board.AddToMessages(new PlayerBBMessage(message.Time, message.Poster, message.Message));
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
|
||||
{
|
||||
base.GetContextMenuEntries(from, list);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ public partial class BaseQuiver : Container, ICraftable, IAosItem
|
|||
{
|
||||
private static Type[] m_Ammo = { typeof(Arrow), typeof(Bolt) };
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosAttributes _attributes;
|
||||
|
|
|
|||
|
|
@ -24,10 +24,12 @@ public partial class Runebook : Item, ISecurable, ICraftable
|
|||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private string _crafter;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(2)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(3, setter: "private")]
|
||||
private List<RunebookEntry> _entries;
|
||||
|
||||
|
|
@ -281,7 +283,7 @@ public partial class Runebook : Item, ISecurable, ICraftable
|
|||
return;
|
||||
}
|
||||
|
||||
book.Entries = new List<RunebookEntry>();
|
||||
book.Entries = [];
|
||||
|
||||
for (var i = 0; i < Entries.Count; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -96,10 +96,12 @@ public partial class Spellbook : Item, ICraftable, ISlayer, IAosItem
|
|||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SlayerName _slayer2;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(5, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosAttributes _attributes;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(6, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosSkillBonuses _skillBonuses;
|
||||
|
|
@ -539,13 +541,6 @@ public partial class Spellbook : Item, ICraftable, ISlayer, IAosItem
|
|||
|
||||
book.Attributes = new AosAttributes(newItem, _attributes);
|
||||
book.SkillBonuses = new AosSkillBonuses(newItem, _skillBonuses);
|
||||
book.Content = _content;
|
||||
book.SpellCount = _spellCount;
|
||||
book.Slayer = _slayer;
|
||||
book.Slayer2 = _slayer2;
|
||||
book.Quality = _quality;
|
||||
book.EngravedText = _engravedText;
|
||||
book.Crafter = _crafter;
|
||||
}
|
||||
|
||||
public override void OnAdded(IEntity parent)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ namespace Server.Items
|
|||
[SerializationGenerator(2, false)]
|
||||
public partial class DyeTub : Item, ISecurable
|
||||
{
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
|
|
|||
|
|
@ -99,9 +99,11 @@ public partial class DawnsMusicBox : Item, ISecurable
|
|||
MusicName.SelimsBar, MusicName.SerpentIsleCombat_U7, MusicName.ValoriaShips
|
||||
};
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0, setter: "private")]
|
||||
private List<MusicName> _tracks;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(1)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ public partial class RoseOfTrinsic : Item, ISecurable
|
|||
[SerializableField(1, setter: "private")]
|
||||
private DateTime _nextSpawnTime;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(2)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
|
@ -34,6 +35,16 @@ public partial class RoseOfTrinsic : Item, ISecurable
|
|||
|
||||
public override int LabelNumber => 1062913; // Rose of Trinsic
|
||||
|
||||
public override void OnAfterDuped(Item newItem)
|
||||
{
|
||||
if (newItem is not RoseOfTrinsic rose)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rose.NextSpawnTime = NextSpawnTime;
|
||||
}
|
||||
|
||||
[SerializableProperty(0)]
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Petals
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ namespace Server.Items;
|
|||
[SerializationGenerator(1)]
|
||||
public partial class TapestryOfSosaria : Item, ISecurable
|
||||
{
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ public partial class SoulStone : Item, ISecurable
|
|||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private string _lastUserName;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(1)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private SecureLevel _level;
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ public partial class BaseTalisman : Item, IAosItem
|
|||
SkillName.Tinkering
|
||||
};
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosAttributes _attributes;
|
||||
|
|
@ -135,6 +136,7 @@ public partial class BaseTalisman : Item, IAosItem
|
|||
[SerializableFieldDefault(0)]
|
||||
private AosAttributes AttributesDefaultValue() => new(this);
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(1, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosSkillBonuses _skillBonuses;
|
||||
|
|
@ -145,6 +147,7 @@ public partial class BaseTalisman : Item, IAosItem
|
|||
[SerializableFieldDefault(1)]
|
||||
private AosSkillBonuses SkillBonusesDefaultValue() => new(this);
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[InvalidateProperties]
|
||||
[SerializableField(2)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
|
|
@ -156,6 +159,7 @@ public partial class BaseTalisman : Item, IAosItem
|
|||
[SerializableFieldDefault(2)]
|
||||
private TalismanAttribute ProtectionDefaultValue() => new();
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[InvalidateProperties]
|
||||
[SerializableField(3)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
|
|
@ -167,6 +171,7 @@ public partial class BaseTalisman : Item, IAosItem
|
|||
[SerializableFieldDefault(3)]
|
||||
private TalismanAttribute KillerDefaultValue() => new();
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[InvalidateProperties]
|
||||
[SerializableField(4)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool ShouldSerializeIdentified() => _identified;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(24, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosAttributes _attributes;
|
||||
|
|
@ -126,6 +127,7 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
[SerializableFieldDefault(24)]
|
||||
private AosAttributes AttributesDefaultValue() => new(this);
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(25, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosWeaponAttributes _weaponAttributes;
|
||||
|
|
@ -145,6 +147,7 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool ShouldSerializePlayerConstructed() => _playerConstructed;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(27, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosSkillBonuses _skillBonuses;
|
||||
|
|
@ -165,6 +168,7 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool ShouldSerializeSlayer2() => _slayer2 != SlayerName.None;
|
||||
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(29, setter: "private")]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
private AosElementAttributes _aosElementDamages;
|
||||
|
|
@ -932,6 +936,12 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
weap.AosElementDamages = new AosElementAttributes(newItem, AosElementDamages);
|
||||
weap.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses);
|
||||
weap.WeaponAttributes = new AosWeaponAttributes(newItem, WeaponAttributes);
|
||||
|
||||
// Set hue again because of resource
|
||||
weap.Hue = Hue;
|
||||
// Set HP/Max again because of durability
|
||||
weap.HitPoints = HitPoints;
|
||||
weap.MaxHitPoints = MaxHitPoints;
|
||||
}
|
||||
|
||||
public int GetDurabilityBonus()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue