From ffb0b24e1a1828fddff796af8d7b8a4f4566c670 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Wed, 23 Aug 2023 22:41:48 -0700 Subject: [PATCH] fix: Codegens talismans - Fixes memory leak (#1469) --- .config/dotnet-tools.json | 2 +- Projects/Server/Server.csproj | 2 +- .../Talismans/BaseTalisman.Migrations.cs | 132 + .../UOContent/Items/Talismans/BaseTalisman.cs | 2191 ++++++++--------- .../Items/Talismans/Items/EnchantedSwitch.cs | 34 +- .../Items/Talismans/Items/HollowPrism.cs | 34 +- .../Items/Talismans/Items/JeweledFiligree.cs | 34 +- .../Items/Talismans/Items/RunedPrism.cs | 34 +- .../Items/Talismans/Items/RunedSwitch.cs | 102 +- .../Items/Talismans/RandomTalisman.cs | 97 +- .../Items/Talismans/TalismanAttribute.cs | 173 +- .../Items/Talismans/TalismanSlayer.cs | 187 +- .../Items/Talismans/TalismanSummons.cs | 941 +++---- .../Server.Items.BaseTalisman.v1.json | 132 + .../Server.Items.EnchantedSwitch.v0.json | 4 + .../Server.Items.HollowPrism.v0.json | 4 + .../Server.Items.JeweledFiligree.v0.json | 4 + .../Server.Items.RunedPrism.v0.json | 4 + .../Server.Items.RunedSwitch.v0.json | 4 + .../Server.Items.TalismanAttribute.v1.json | 27 + .../Server.Mobiles.BaseTalismanSummon.v0.json | 4 + .../Server.Mobiles.SummonedAntLion.v0.json | 4 + ...ver.Mobiles.SummonedArcticOgreLord.v0.json | 4 + ...Server.Mobiles.SummonedBakeKitsune.v0.json | 4 + .../Server.Mobiles.SummonedBogling.v0.json | 4 + .../Server.Mobiles.SummonedBullFrog.v0.json | 4 + .../Server.Mobiles.SummonedChicken.v0.json | 4 + .../Server.Mobiles.SummonedCow.v0.json | 4 + ...erver.Mobiles.SummonedDoppleganger.v0.json | 4 + ...Server.Mobiles.SummonedFrostSpider.v0.json | 4 + .../Server.Mobiles.SummonedGreatHart.v0.json | 4 + ...Server.Mobiles.SummonedLavaSerpent.v0.json | 4 + .../Server.Mobiles.SummonedOrcBrute.v0.json | 4 + .../Server.Mobiles.SummonedPanther.v0.json | 4 + .../Server.Mobiles.SummonedSheep.v0.json | 4 + ...ver.Mobiles.SummonedSkeletalKnight.v0.json | 4 + ...Server.Mobiles.SummonedVorpalBunny.v0.json | 4 + ...ver.Mobiles.SummonedWailingBanshee.v0.json | 4 + Projects/UOContent/Mobiles/BaseCreature.cs | 14 +- Projects/UOContent/Spells/UnsummonTimer.cs | 5 +- Projects/UOContent/UOContent.csproj | 2 +- 41 files changed, 1979 insertions(+), 2256 deletions(-) create mode 100644 Projects/UOContent/Items/Talismans/BaseTalisman.Migrations.cs create mode 100644 Projects/UOContent/Migrations/Server.Items.BaseTalisman.v1.json create mode 100644 Projects/UOContent/Migrations/Server.Items.EnchantedSwitch.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.HollowPrism.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.JeweledFiligree.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.RunedPrism.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.RunedSwitch.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.TalismanAttribute.v1.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.BaseTalismanSummon.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedAntLion.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedArcticOgreLord.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedBakeKitsune.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedBogling.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedBullFrog.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedChicken.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedCow.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedDoppleganger.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedFrostSpider.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedGreatHart.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedLavaSerpent.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedOrcBrute.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedPanther.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedSheep.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedSkeletalKnight.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedVorpalBunny.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.SummonedWailingBanshee.v0.json diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index f65370008..ab09f794e 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "modernuoschemagenerator": { - "version": "2.6.4", + "version": "2.7.2", "commands": [ "ModernUOSchemaGenerator" ] diff --git a/Projects/Server/Server.csproj b/Projects/Server/Server.csproj index 8e89619b7..2d8266899 100755 --- a/Projects/Server/Server.csproj +++ b/Projects/Server/Server.csproj @@ -38,7 +38,7 @@ - + diff --git a/Projects/UOContent/Items/Talismans/BaseTalisman.Migrations.cs b/Projects/UOContent/Items/Talismans/BaseTalisman.Migrations.cs new file mode 100644 index 000000000..67329d83f --- /dev/null +++ b/Projects/UOContent/Items/Talismans/BaseTalisman.Migrations.cs @@ -0,0 +1,132 @@ +using System; + +namespace Server.Items; + +public partial class BaseTalisman +{ + private void Deserialize(IGenericReader reader, int version) + { + var flags = (OldSaveFlag)reader.ReadEncodedInt(); + + Attributes = new AosAttributes(this); + if (GetOldSaveFlag(flags, OldSaveFlag.Attributes)) + { + Attributes.Deserialize(reader); + } + + SkillBonuses = new AosSkillBonuses(this); + if (GetOldSaveFlag(flags, OldSaveFlag.SkillBonuses)) + { + SkillBonuses.Deserialize(reader); + } + + // Backward compatibility + if (GetOldSaveFlag(flags, OldSaveFlag.Owner)) + { + BlessedFor = reader.ReadEntity(); + } + + _protection = new TalismanAttribute(); + if (GetOldSaveFlag(flags, OldSaveFlag.Protection)) + { + _protection.Deserialize(reader); + } + + _killer = new TalismanAttribute(); + if (GetOldSaveFlag(flags, OldSaveFlag.Killer)) + { + _killer.Deserialize(reader); + } + + _summoner = new TalismanAttribute(); + if (GetOldSaveFlag(flags, OldSaveFlag.Summoner)) + { + _summoner.Deserialize(reader); + } + + if (GetOldSaveFlag(flags, OldSaveFlag.Removal)) + { + _removal = (TalismanRemoval)reader.ReadEncodedInt(); + } + + if (GetOldSaveFlag(flags, OldSaveFlag.OldKarmaLoss)) + { + Attributes.IncreasedKarmaLoss = reader.ReadEncodedInt(); + } + + if (GetOldSaveFlag(flags, OldSaveFlag.Skill)) + { + _skill = (SkillName)reader.ReadEncodedInt(); + } + + if (GetOldSaveFlag(flags, OldSaveFlag.SuccessBonus)) + { + _successBonus = reader.ReadEncodedInt(); + } + + if (GetOldSaveFlag(flags, OldSaveFlag.ExceptionalBonus)) + { + _exceptionalBonus = reader.ReadEncodedInt(); + } + + if (GetOldSaveFlag(flags, OldSaveFlag.MaxCharges)) + { + _maxCharges = reader.ReadEncodedInt(); + } + + if (GetOldSaveFlag(flags, OldSaveFlag.Charges)) + { + _charges = reader.ReadEncodedInt(); + } + + if (GetOldSaveFlag(flags, OldSaveFlag.MaxChargeTime)) + { + _maxChargeTime = reader.ReadEncodedInt(); + } + + if (GetOldSaveFlag(flags, OldSaveFlag.ChargeTime)) + { + _chargeTime = reader.ReadEncodedInt(); + } + + if (GetOldSaveFlag(flags, OldSaveFlag.Slayer)) + { + _slayer = (TalismanSlayerName)reader.ReadEncodedInt(); + } + + _blessed = GetOldSaveFlag(flags, OldSaveFlag.Blessed); + } + + private static void SetOldSaveFlag(ref OldSaveFlag flags, OldSaveFlag toSet, bool setIf) + { + if (setIf) + { + flags |= toSet; + } + } + + private static bool GetOldSaveFlag(OldSaveFlag flags, OldSaveFlag toGet) => (flags & toGet) != 0; + + [Flags] + private enum OldSaveFlag + { + None = 0x00000000, + Attributes = 0x00000001, + SkillBonuses = 0x00000002, + Owner = 0x00000004, + Protection = 0x00000008, + Killer = 0x00000010, + Summoner = 0x00000020, + Removal = 0x00000040, + OldKarmaLoss = 0x00000080, + Skill = 0x00000100, + SuccessBonus = 0x00000200, + ExceptionalBonus = 0x00000400, + MaxCharges = 0x00000800, + Charges = 0x00001000, + MaxChargeTime = 0x00002000, + ChargeTime = 0x00004000, + Blessed = 0x00008000, + Slayer = 0x00010000 + } +} diff --git a/Projects/UOContent/Items/Talismans/BaseTalisman.cs b/Projects/UOContent/Items/Talismans/BaseTalisman.cs index a28f9e814..943de5041 100644 --- a/Projects/UOContent/Items/Talismans/BaseTalisman.cs +++ b/Projects/UOContent/Items/Talismans/BaseTalisman.cs @@ -1,4 +1,5 @@ using System; +using ModernUO.Serialization; using Server.Mobiles; using Server.Spells.Fifth; using Server.Spells.First; @@ -8,520 +9,496 @@ using Server.Spells.Second; using Server.Targeting; using Server.Utilities; -namespace Server.Items +namespace Server.Items; + +public enum TalismanRemoval { - public enum TalismanRemoval + None = 0, + Ward = 390, + Damage = 404, + Curse = 407, + Wildfire = 2843 +} + +[SerializationGenerator(1, false)] +public partial class BaseTalisman : Item, IAosItem +{ + private static readonly int[] _itemIDs = + { + 0x2F58, 0x2F59, 0x2F5A, 0x2F5B + }; + + private static readonly Type[] _summons = + { + typeof(SummonedAntLion), + typeof(SummonedCow), + typeof(SummonedLavaSerpent), + typeof(SummonedOrcBrute), + typeof(SummonedFrostSpider), + typeof(SummonedPanther), + typeof(SummonedDoppleganger), + typeof(SummonedGreatHart), + typeof(SummonedBullFrog), + typeof(SummonedArcticOgreLord), + typeof(SummonedBogling), + typeof(SummonedBakeKitsune), + typeof(SummonedSheep), + typeof(SummonedSkeletalKnight), + typeof(SummonedWailingBanshee), + typeof(SummonedChicken), + typeof(SummonedVorpalBunny), + + typeof(Board), + typeof(IronIngot), + typeof(Bandage) + }; + + private static readonly int[] _summonLabels = + { + 1075211, // Ant Lion + 1072494, // Cow + 1072434, // Lava Serpent + 1072414, // Orc Brute + 1072476, // Frost Spider + 1029653, // Panther + 1029741, // Doppleganger + 1018292, // great hart + 1028496, // bullfrog + 1018227, // arctic ogre lord + 1029735, // Bogling + 1030083, // bake-kitsune + 1018285, // sheep + 1018239, // skeletal knight + 1072399, // Wailing Banshee + 1072459, // Chicken + 1072401, // Vorpal Bunny + + 1015101, // Boards + 1044036, // Ingots + 1023817 // clean bandage + }; + + private static readonly Type[] _killers = + { + typeof(OrcBomber), typeof(OrcBrute), typeof(SewerRat), typeof(Rat), typeof(GiantRat), + typeof(Ratman), typeof(RatmanArcher), typeof(GiantSpider), typeof(FrostSpider), typeof(GiantBlackWidow), + typeof(DreadSpider), typeof(SilverSerpent), typeof(DeepSeaSerpent), typeof(GiantSerpent), typeof(Snake), + typeof(IceSnake), typeof(IceSerpent), typeof(LavaSerpent), typeof(LavaSnake), typeof(Yamandon), + typeof(StrongMongbat), typeof(Mongbat), typeof(VampireBat), typeof(Lich), typeof(EvilMage), + typeof(LichLord), typeof(EvilMageLord), typeof(SkeletalMage), typeof(KhaldunZealot), typeof(AncientLich), + typeof(JukaMage), typeof(MeerMage), typeof(Beetle), typeof(DeathwatchBeetle), typeof(RuneBeetle), + typeof(FireBeetle), typeof(DeathwatchBeetleHatchling), typeof(Bird), typeof(Chicken), typeof(Eagle), + typeof(TropicalBird), typeof(Phoenix), typeof(DesertOstard), typeof(FrenziedOstard), typeof(ForestOstard), + typeof(Crane), typeof(SnowLeopard), typeof(IceFiend), typeof(FrostOoze), typeof(FrostTroll), + typeof(IceElemental), typeof(SnowElemental), typeof(GiantIceWorm), typeof(LadyOfTheSnow), typeof(FireElemental), + typeof(FireSteed), typeof(HellHound), typeof(HellCat), typeof(PredatorHellCat), typeof(LavaLizard), + typeof(FireBeetle), typeof(Cow), typeof(Bull), typeof(Gaman) // , typeof( Minotaur) + // TODO Meraktus, Tormented Minotaur, Minotaur + }; + + private static readonly int[] _killerLabels = + { + 1072413, 1072414, 1072418, 1072419, 1072420, + 1072421, 1072423, 1072424, 1072425, 1072426, + 1072427, 1072428, 1072429, 1072430, 1072431, + 1072432, 1072433, 1072434, 1072435, 1072438, + 1072440, 1072441, 1072443, 1072444, 1072445, + 1072446, 1072447, 1072448, 1072449, 1072450, + 1072451, 1072452, 1072453, 1072454, 1072455, + 1072456, 1072457, 1072458, 1072459, 1072461, + 1072462, 1072465, 1072468, 1072469, 1072470, + 1072473, 1072474, 1072477, 1072478, 1072479, + 1072480, 1072481, 1072483, 1072485, 1072486, + 1072487, 1072489, 1072490, 1072491, 1072492, + 1072493, 1072494, 1072495, 1072498 + }; + + private static readonly SkillName[] _skills = + { + SkillName.Alchemy, + SkillName.Blacksmith, + SkillName.Carpentry, + SkillName.Cartography, + SkillName.Cooking, + SkillName.Fletching, + SkillName.Inscribe, + SkillName.Tailoring, + SkillName.Tinkering + }; + + [SerializableField(0, setter: "private")] + [SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)] + private AosAttributes _attributes; + + [SerializableFieldSaveFlag(0)] + public bool ShouldSerializeAttributes() => !_attributes.IsEmpty; + + [SerializableFieldDefault(0)] + private AosAttributes AttributesDefaultValue() => new(this); + + [SerializableField(1, setter: "private")] + [SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)] + private AosSkillBonuses _skillBonuses; + + [SerializableFieldSaveFlag(1)] + public bool ShouldSerializeSkillBonuses() => !_skillBonuses.IsEmpty; + + [SerializableFieldDefault(1)] + private AosSkillBonuses SkillBonusesDefaultValue() => new(this); + + [InvalidateProperties] + [SerializableField(2)] + [SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)] + private TalismanAttribute _protection; + + [SerializableFieldSaveFlag(2)] + public bool ShouldSerializeProtection() => !_protection.IsEmpty; + + [SerializableFieldDefault(2)] + private TalismanAttribute ProtectionDefaultValue() => new(); + + [InvalidateProperties] + [SerializableField(3)] + [SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)] + private TalismanAttribute _killer; + + [SerializableFieldSaveFlag(3)] + public bool ShouldSerializeKiller() => !_killer.IsEmpty; + + [SerializableFieldDefault(3)] + private TalismanAttribute KillerDefaultValue() => new(); + + [InvalidateProperties] + [SerializableField(4)] + [SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)] + private TalismanAttribute _summoner; + + [SerializableFieldSaveFlag(4)] + public bool ShouldSerializeSummoner() => !_summoner.IsEmpty; + + [SerializableFieldDefault(4)] + private TalismanAttribute SummonerDefaultValue() => new(); + + [InvalidateProperties] + [SerializableField(5)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private TalismanRemoval _removal; + + [SerializableFieldSaveFlag(5)] + public bool ShouldSerializeRemoval() => _removal != TalismanRemoval.None; + + [InvalidateProperties] + [SerializableField(6)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private SkillName _skill; + + [SerializableFieldSaveFlag(6)] + public bool ShouldSerializeSkill() => (int)_skill != 0; + + [EncodedInt] + [InvalidateProperties] + [SerializableField(7)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _successBonus; + + [SerializableFieldSaveFlag(7)] + public bool ShouldSerializeSuccessBonus() => _successBonus != 0; + + [EncodedInt] + [InvalidateProperties] + [SerializableField(8)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _exceptionalBonus; + + [SerializableFieldSaveFlag(8)] + public bool ShouldSerializeExceptionalBonus() => _exceptionalBonus != 0; + + [EncodedInt] + [InvalidateProperties] + [SerializableField(9)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _maxCharges; + + [SerializableFieldSaveFlag(9)] + public bool ShouldSerializeMaxCharges() => _maxCharges != 0; + + [EncodedInt] + [InvalidateProperties] + [SerializableField(11)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _maxChargeTime; + + [SerializableFieldSaveFlag(11)] + public bool ShouldSerializeMaxChargeTime() => _maxChargeTime != 0; + + [EncodedInt] + [InvalidateProperties] + [SerializableField(12)] + private int _chargeTime; + + [SerializableFieldSaveFlag(12)] + public bool ShouldSerializeChargeTime() => _chargeTime != 0; + + [InvalidateProperties] + [SerializableField(13)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private bool _blessed; + + [SerializableFieldSaveFlag(13)] + public bool ShouldSerializeBlessed() => _blessed; + + [InvalidateProperties] + [SerializableField(14)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private TalismanSlayerName _slayer; + + [SerializableFieldSaveFlag(14)] + public bool ShouldSerializeSlayer() => _slayer != TalismanSlayerName.None; + + private Mobile _creature; + + + private TimerExecutionToken _timerToken; + + public BaseTalisman() : this(GetRandomItemID()) { - None = 0, - Ward = 390, - Damage = 404, - Curse = 407, - Wildfire = 2843 } - public class BaseTalisman : Item, IAosItem + public BaseTalisman(int itemID) : base(itemID) { - private static readonly int[] m_ItemIDs = + Layer = Layer.Talisman; + Weight = 1.0; + + _protection = new TalismanAttribute(); + _killer = new TalismanAttribute(); + _summoner = new TalismanAttribute(); + Attributes = new AosAttributes(this); + SkillBonuses = new AosSkillBonuses(this); + } + + public override int LabelNumber => 1071023; // Talisman + public virtual bool ForceShowName => false; // used to override default summoner/removal name + + [SerializableProperty(10)] + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => _charges; + set { - 0x2F58, 0x2F59, 0x2F5A, 0x2F5B - }; + _charges = value; - private static readonly Type[] m_Summons = - { - typeof(SummonedAntLion), - typeof(SummonedCow), - typeof(SummonedLavaSerpent), - typeof(SummonedOrcBrute), - typeof(SummonedFrostSpider), - typeof(SummonedPanther), - typeof(SummonedDoppleganger), - typeof(SummonedGreatHart), - typeof(SummonedBullFrog), - typeof(SummonedArcticOgreLord), - typeof(SummonedBogling), - typeof(SummonedBakeKitsune), - typeof(SummonedSheep), - typeof(SummonedSkeletalKnight), - typeof(SummonedWailingBanshee), - typeof(SummonedChicken), - typeof(SummonedVorpalBunny), - - typeof(Board), - typeof(IronIngot), - typeof(Bandage) - }; - - private static readonly int[] m_SummonLabels = - { - 1075211, // Ant Lion - 1072494, // Cow - 1072434, // Lava Serpent - 1072414, // Orc Brute - 1072476, // Frost Spider - 1029653, // Panther - 1029741, // Doppleganger - 1018292, // great hart - 1028496, // bullfrog - 1018227, // arctic ogre lord - 1029735, // Bogling - 1030083, // bake-kitsune - 1018285, // sheep - 1018239, // skeletal knight - 1072399, // Wailing Banshee - 1072459, // Chicken - 1072401, // Vorpal Bunny - - 1015101, // Boards - 1044036, // Ingots - 1023817 // clean bandage - }; - - private static readonly Type[] m_Killers = - { - typeof(OrcBomber), typeof(OrcBrute), typeof(SewerRat), typeof(Rat), typeof(GiantRat), - typeof(Ratman), typeof(RatmanArcher), typeof(GiantSpider), typeof(FrostSpider), typeof(GiantBlackWidow), - typeof(DreadSpider), typeof(SilverSerpent), typeof(DeepSeaSerpent), typeof(GiantSerpent), typeof(Snake), - typeof(IceSnake), typeof(IceSerpent), typeof(LavaSerpent), typeof(LavaSnake), typeof(Yamandon), - typeof(StrongMongbat), typeof(Mongbat), typeof(VampireBat), typeof(Lich), typeof(EvilMage), - typeof(LichLord), typeof(EvilMageLord), typeof(SkeletalMage), typeof(KhaldunZealot), typeof(AncientLich), - typeof(JukaMage), typeof(MeerMage), typeof(Beetle), typeof(DeathwatchBeetle), typeof(RuneBeetle), - typeof(FireBeetle), typeof(DeathwatchBeetleHatchling), typeof(Bird), typeof(Chicken), typeof(Eagle), - typeof(TropicalBird), typeof(Phoenix), typeof(DesertOstard), typeof(FrenziedOstard), typeof(ForestOstard), - typeof(Crane), typeof(SnowLeopard), typeof(IceFiend), typeof(FrostOoze), typeof(FrostTroll), - typeof(IceElemental), typeof(SnowElemental), typeof(GiantIceWorm), typeof(LadyOfTheSnow), typeof(FireElemental), - typeof(FireSteed), typeof(HellHound), typeof(HellCat), typeof(PredatorHellCat), typeof(LavaLizard), - typeof(FireBeetle), typeof(Cow), typeof(Bull), typeof(Gaman) // , typeof( Minotaur) - // TODO Meraktus, Tormented Minotaur, Minotaur - }; - - private static readonly int[] m_KillerLabels = - { - 1072413, 1072414, 1072418, 1072419, 1072420, - 1072421, 1072423, 1072424, 1072425, 1072426, - 1072427, 1072428, 1072429, 1072430, 1072431, - 1072432, 1072433, 1072434, 1072435, 1072438, - 1072440, 1072441, 1072443, 1072444, 1072445, - 1072446, 1072447, 1072448, 1072449, 1072450, - 1072451, 1072452, 1072453, 1072454, 1072455, - 1072456, 1072457, 1072458, 1072459, 1072461, - 1072462, 1072465, 1072468, 1072469, 1072470, - 1072473, 1072474, 1072477, 1072478, 1072479, - 1072480, 1072481, 1072483, 1072485, 1072486, - 1072487, 1072489, 1072490, 1072491, 1072492, - 1072493, 1072494, 1072495, 1072498 - }; - - private static readonly SkillName[] m_Skills = - { - SkillName.Alchemy, - SkillName.Blacksmith, - SkillName.Carpentry, - SkillName.Cartography, - SkillName.Cooking, - SkillName.Fletching, - SkillName.Inscribe, - SkillName.Tailoring, - SkillName.Tinkering - }; - - private bool m_Blessed; - private int m_Charges; - private int m_ChargeTime; - private Mobile m_Creature; - private int m_ExceptionalBonus; - private TalismanAttribute m_Killer; - - private int m_MaxCharges; - private int m_MaxChargeTime; - - private TalismanAttribute m_Protection; - private TalismanRemoval m_Removal; - - private SkillName m_Skill; - - private TalismanSlayerName m_Slayer; - private int m_SuccessBonus; - - private TalismanAttribute m_Summoner; - - private TimerExecutionToken _timerToken; - - public BaseTalisman() - : this(GetRandomItemID()) - { - } - - public BaseTalisman(int itemID) - : base(itemID) - { - Layer = Layer.Talisman; - Weight = 1.0; - - m_Protection = new TalismanAttribute(); - m_Killer = new TalismanAttribute(); - m_Summoner = new TalismanAttribute(); - Attributes = new AosAttributes(this); - SkillBonuses = new AosSkillBonuses(this); - } - - public BaseTalisman(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1071023; // Talisman - public virtual bool ForceShowName => false; // used to override default summoner/removal name - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxCharges - { - get => m_MaxCharges; - set + if (_chargeTime > 0) { - m_MaxCharges = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = value; - - if (m_ChargeTime > 0) - { - StartTimer(); - } - - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxChargeTime - { - get => m_MaxChargeTime; - set - { - m_MaxChargeTime = value; - InvalidateProperties(); - } - } - - public int ChargeTime - { - get => m_ChargeTime; - set - { - m_ChargeTime = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Blessed - { - get => m_Blessed; - set - { - m_Blessed = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public TalismanSlayerName Slayer - { - get => m_Slayer; - set - { - m_Slayer = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public TalismanAttribute Summoner - { - get => m_Summoner; - set - { - m_Summoner = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public TalismanRemoval Removal - { - get => m_Removal; - set - { - m_Removal = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public TalismanAttribute Protection - { - get => m_Protection; - set - { - m_Protection = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public TalismanAttribute Killer - { - get => m_Killer; - set - { - m_Killer = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName Skill - { - get => m_Skill; - set - { - m_Skill = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SuccessBonus - { - get => m_SuccessBonus; - set - { - m_SuccessBonus = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ExceptionalBonus - { - get => m_ExceptionalBonus; - set - { - m_ExceptionalBonus = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster, canModify: true)] - public AosAttributes Attributes { get; private set; } - - [CommandProperty(AccessLevel.GameMaster, canModify: true)] - public AosSkillBonuses SkillBonuses { get; private set; } - - public static void Initialize() - { - CommandSystem.Register("RandomTalisman", AccessLevel.GameMaster, RandomTalisman_OnCommand); - } - - [Usage("RandomTalisman "), Description("Generates random talismans in your backpack.")] - public static void RandomTalisman_OnCommand(CommandEventArgs e) - { - var m = e.Mobile; - var count = e.GetInt32(0); - - for (var i = 0; i < count; i++) - { - m.AddToBackpack(Loot.RandomTalisman()); - } - } - - public override void OnAfterDuped(Item newItem) - { - if (newItem is not BaseTalisman talisman) - { - return; - } - - talisman.m_Summoner = new TalismanAttribute(m_Summoner); - talisman.m_Protection = new TalismanAttribute(m_Protection); - talisman.m_Killer = new TalismanAttribute(m_Killer); - talisman.Attributes = new AosAttributes(newItem, Attributes); - talisman.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses); - } - - public override bool CanEquip(Mobile from) - { - if (BlessedFor != null && BlessedFor != from) - { - from.SendLocalizedMessage(1010437); // You are not the owner. - return false; - } - - return base.CanEquip(from); - } - - public override void OnAdded(IEntity parent) - { - if (parent is Mobile from) - { - SkillBonuses.AddTo(from); - Attributes.AddStatBonuses(from); - - if (m_Blessed && BlessedFor == null) - { - BlessedFor = from; - LootType = LootType.Blessed; - } - - if (m_ChargeTime > 0) - { - m_ChargeTime = m_MaxChargeTime; - StartTimer(); - } + StartTimer(); } InvalidateProperties(); + this.MarkDirty(); + } + } + + [SerializableFieldSaveFlag(10)] + public bool ShouldSerializeCharges() => _charges != 0; + + public static void Initialize() + { + CommandSystem.Register("RandomTalisman", AccessLevel.GameMaster, RandomTalisman_OnCommand); + } + + [Usage("RandomTalisman "), Description("Generates random talismans in your backpack.")] + public static void RandomTalisman_OnCommand(CommandEventArgs e) + { + var m = e.Mobile; + var count = e.GetInt32(0); + + for (var i = 0; i < count; i++) + { + m.AddToBackpack(Loot.RandomTalisman()); + } + } + + public override void OnAfterDuped(Item newItem) + { + if (newItem is not BaseTalisman talisman) + { + return; } - public override void OnRemoved(IEntity parent) - { - if (parent is Mobile from) - { - SkillBonuses.Remove(); - Attributes.RemoveStatBonuses(from); + talisman._summoner = new TalismanAttribute(_summoner); + talisman._protection = new TalismanAttribute(_protection); + talisman._killer = new TalismanAttribute(_killer); + talisman.Attributes = new AosAttributes(newItem, Attributes); + talisman.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses); + } - if (m_Creature?.Deleted == false) + public override bool CanEquip(Mobile from) + { + if (BlessedFor != null && BlessedFor != from) + { + from.SendLocalizedMessage(1010437); // You are not the owner. + return false; + } + + return base.CanEquip(from); + } + + public override void OnAdded(IEntity parent) + { + if (parent is Mobile from) + { + SkillBonuses.AddTo(from); + Attributes.AddStatBonuses(from); + + if (_blessed && BlessedFor == null) + { + BlessedFor = from; + LootType = LootType.Blessed; + } + + if (_chargeTime > 0) + { + _chargeTime = _maxChargeTime; + StartTimer(); + } + } + + InvalidateProperties(); + } + + public override void OnRemoved(IEntity parent) + { + if (parent is Mobile from) + { + SkillBonuses.Remove(); + Attributes.RemoveStatBonuses(from); + + if (_creature?.Deleted == false) + { + Effects.SendLocationParticles( + EffectItem.Create(_creature.Location, _creature.Map, EffectItem.DefaultDuration), + 0x3728, + 8, + 20, + 5042 + ); + Effects.PlaySound(_creature, 0x201); + + _creature.Delete(); + } + + StopTimer(); + } + + InvalidateProperties(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Talisman != this) + { + from.SendLocalizedMessage(502641); // You must equip this item to use it. + return; + } + + if (_chargeTime > 0) + { + // You must wait ~1_val~ seconds for this to recharge. + from.SendLocalizedMessage(1074882, _chargeTime.ToString()); + return; + } + + if (_charges == 0 && _maxCharges > 0) + { + from.SendLocalizedMessage(1042544); // This item is out of charges. + return; + } + + var type = GetSummoner(); + + if (_summoner?.IsEmpty == false) + { + type = _summoner.Type; + } + + if (type != null) + { + IEntity entity; + + try + { + entity = type.CreateInstance(); + } + catch + { + entity = null; + } + + if (entity is Item item) + { + var count = 1; + + if (_summoner?.Amount > 1) { - Effects.SendLocationParticles( - EffectItem.Create(m_Creature.Location, m_Creature.Map, EffectItem.DefaultDuration), - 0x3728, - 8, - 20, - 5042 + if (item.Stackable) + { + item.Amount = _summoner.Amount; + } + else + { + count = _summoner.Amount; + } + } + + if (from.Backpack == null || count * item.Weight > from.Backpack.MaxWeight || + from.Backpack.Items.Count + count > from.Backpack.MaxItems) + { + from.SendLocalizedMessage(500720); // You don't have enough room in your backpack! + item.Delete(); + return; + } + + for (var i = 0; i < count; i++) + { + from.PlaceInBackpack(item); + + if (i + 1 < count) + { + item = type.CreateInstance(); + } + } + + if (item is Board) + { + from.SendLocalizedMessage(1075000); // You have been given some wooden boards. + } + else if (item is IronIngot) + { + from.SendLocalizedMessage(1075001); // You have been given some ingots. + } + else if (item is Bandage) + { + from.SendLocalizedMessage(1075002); // You have been given some clean bandages. + } + else if (_summoner?.Name != null) + { + from.SendLocalizedMessage( + 1074853, // You have been given ~1_name~ + _summoner.Name.Number > 0 ? $"#{_summoner.Name}" : _summoner.Name.String ); - Effects.PlaySound(m_Creature, 0x201); - - m_Creature.Delete(); + } + } + else if (entity is BaseCreature mob) + { + if (_creature?.Deleted == false) + { + from.SendLocalizedMessage(1074270); // You have too many followers to summon another one. + mob.Delete(); + return; } - StopTimer(); - } - - InvalidateProperties(); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.Talisman != this) - { - from.SendLocalizedMessage(502641); // You must equip this item to use it. - return; - } - - if (m_ChargeTime > 0) - { - from.SendLocalizedMessage( - 1074882, - m_ChargeTime.ToString() - ); // You must wait ~1_val~ seconds for this to recharge. - return; - } - - if (m_Charges == 0 && m_MaxCharges > 0) - { - from.SendLocalizedMessage(1042544); // This item is out of charges. - return; - } - - var type = GetSummoner(); - - if (m_Summoner?.IsEmpty == false) - { - type = m_Summoner.Type; - } - - if (type != null) - { - IEntity entity; - - try + if (BaseCreature.Summon(mob, from, from.Location, mob.BaseSoundID, TimeSpan.FromMinutes(10))) { - entity = type.CreateInstance(); - } - catch - { - entity = null; - } - - if (entity is Item item) - { - var count = 1; - - if (m_Summoner?.Amount > 1) - { - if (item.Stackable) - { - item.Amount = m_Summoner.Amount; - } - else - { - count = m_Summoner.Amount; - } - } - - if (from.Backpack == null || count * item.Weight > from.Backpack.MaxWeight || - from.Backpack.Items.Count + count > from.Backpack.MaxItems) - { - from.SendLocalizedMessage(500720); // You don't have enough room in your backpack! - item.Delete(); - return; - } - - for (var i = 0; i < count; i++) - { - from.PlaceInBackpack(item); - - if (i + 1 < count) - { - item = type.CreateInstance(); - } - } - - if (item is Board) - { - from.SendLocalizedMessage(1075000); // You have been given some wooden boards. - } - else if (item is IronIngot) - { - from.SendLocalizedMessage(1075001); // You have been given some ingots. - } - else if (item is Bandage) - { - from.SendLocalizedMessage(1075002); // You have been given some clean bandages. - } - else if (m_Summoner?.Name != null) - { - from.SendLocalizedMessage(1074853, m_Summoner.Name.ToString()); // You have been given ~1_name~ - } - } - else if (entity is BaseCreature mob) - { - if (m_Creature?.Deleted == false || from.Followers + mob.ControlSlots > from.FollowersMax) - { - from.SendLocalizedMessage(1074270); // You have too many followers to summon another one. - mob.Delete(); - return; - } - - BaseCreature.Summon(mob, from, from.Location, mob.BaseSoundID, TimeSpan.FromMinutes(10)); Effects.SendLocationParticles( EffectItem.Create(mob.Location, mob.Map, EffectItem.DefaultDuration), 0x3728, @@ -533,808 +510,588 @@ namespace Server.Items mob.Summoned = false; mob.ControlOrder = OrderType.Friend; - m_Creature = mob; + _creature = mob; } - else - { - entity?.Delete(); - } - - OnAfterUse(from); - } - - if (m_Removal != TalismanRemoval.None) - { - from.Target = new TalismanTarget(this); - } - } - - public override void AddNameProperty(IPropertyList list) - { - if (ForceShowName) - { - base.AddNameProperty(list); - } - else if (m_Summoner?.IsEmpty == false) - { - var name = m_Summoner?.Name; - if (name?.Number > 0) - { - list.Add(1072400, name.Number); // Talisman of ~1_name~ Summoning - } - else - { - list.Add(1072400, name?.String ?? "Unknown"); // Talisman of ~1_name~ Summoning - } - } - else if (m_Removal != TalismanRemoval.None) - { - list.AddLocalized(1072389, 1072000 + (int)m_Removal); // Talisman of ~1_name~ } else { - base.AddNameProperty(list); + entity?.Delete(); + } + + OnAfterUse(from); + } + + if (_removal != TalismanRemoval.None) + { + from.Target = new TalismanTarget(this); + } + } + + public override void AddNameProperty(IPropertyList list) + { + if (ForceShowName) + { + base.AddNameProperty(list); + } + else if (_summoner?.IsEmpty == false) + { + var name = _summoner?.Name; + if (name?.Number > 0) + { + list.Add(1072400, name.Number); // Talisman of ~1_name~ Summoning + } + else + { + list.Add(1072400, name?.String ?? "Unknown"); // Talisman of ~1_name~ Summoning + } + } + else if (_removal != TalismanRemoval.None) + { + list.AddLocalized(1072389, 1072000 + (int)_removal); // Talisman of ~1_name~ + } + else + { + base.AddNameProperty(list); + } + } + + public override void GetProperties(IPropertyList list) + { + base.GetProperties(list); + + if (Blessed) + { + if (BlessedFor != null) + { + // Owned by ~1_name~ + list.Add(1072304,BlessedFor.Name.DefaultIfNullOrEmpty("Unnamed Warrior")); + } + else + { + list.Add(1072304, "Nobody"); // Owned by ~1_name~ } } - public override void GetProperties(IPropertyList list) + if (Parent is Mobile && _maxChargeTime > 0) { - base.GetProperties(list); - - if (Blessed) + if (_chargeTime > 0) { - if (BlessedFor != null) - { - list.Add( - 1072304, - !string.IsNullOrEmpty(BlessedFor.Name) ? BlessedFor.Name : "Unnamed Warrior" - ); // Owned by ~1_name~ - } - else - { - list.Add(1072304, "Nobody"); // Owned by ~1_name~ - } + list.Add(1074884, _chargeTime); // Charge time left: ~1_val~ } - - if (Parent is Mobile && m_MaxChargeTime > 0) + else { - if (m_ChargeTime > 0) - { - list.Add(1074884, m_ChargeTime); // Charge time left: ~1_val~ - } - else - { - list.Add(1074883); // Fully Charged - } - } - - list.Add(1075085); // Requirement: Mondain's Legacy - - if (m_Killer?.IsEmpty == false && m_Killer.Amount > 0) - { - list.Add( - 1072388, // ~1_NAME~ Killer: +~2_val~% - $"{m_Killer.Name ?? "Unknown"}\t{m_Killer.Amount}" - ); - } - - if (m_Protection?.IsEmpty == false && m_Protection.Amount > 0) - { - list.Add( - 1072387, // ~1_NAME~ Protection: +~2_val~% - $"{m_Protection.Name ?? "Unknown"}\t{m_Protection.Amount}" - ); - } - - if (m_ExceptionalBonus != 0) - { - list.Add( - 1072395, // ~1_NAME~ Exceptional Bonus: ~2_val~% - $"{AosSkillBonuses.GetLabel(m_Skill):#}\t{m_ExceptionalBonus}" - ); - } - - if (m_SuccessBonus != 0) - { - list.Add( - 1072394, // ~1_NAME~ Bonus: ~2_val~% - $"{AosSkillBonuses.GetLabel(m_Skill):#}\t{m_SuccessBonus}" - ); - } - - SkillBonuses.GetProperties(list); - - int prop; - - if ((prop = Attributes.WeaponDamage) != 0) - { - list.Add(1060401, prop); // damage increase ~1_val~% - } - - if ((prop = Attributes.DefendChance) != 0) - { - list.Add(1060408, prop); // defense chance increase ~1_val~% - } - - if ((prop = Attributes.BonusDex) != 0) - { - list.Add(1060409, prop); // dexterity bonus ~1_val~ - } - - if ((prop = Attributes.EnhancePotions) != 0) - { - list.Add(1060411, prop); // enhance potions ~1_val~% - } - - if ((prop = Attributes.CastRecovery) != 0) - { - list.Add(1060412, prop); // faster cast recovery ~1_val~ - } - - if ((prop = Attributes.CastSpeed) != 0) - { - list.Add(1060413, prop); // faster casting ~1_val~ - } - - if ((prop = Attributes.AttackChance) != 0) - { - list.Add(1060415, prop); // hit chance increase ~1_val~% - } - - if ((prop = Attributes.BonusHits) != 0) - { - list.Add(1060431, prop); // hit point increase ~1_val~ - } - - if ((prop = Attributes.BonusInt) != 0) - { - list.Add(1060432, prop); // intelligence bonus ~1_val~ - } - - if ((prop = Attributes.LowerManaCost) != 0) - { - list.Add(1060433, prop); // lower mana cost ~1_val~% - } - - if ((prop = Attributes.LowerRegCost) != 0) - { - list.Add(1060434, prop); // lower reagent cost ~1_val~% - } - - if ((prop = Attributes.Luck) != 0) - { - list.Add(1060436, prop); // luck ~1_val~ - } - - if ((prop = Attributes.BonusMana) != 0) - { - list.Add(1060439, prop); // mana increase ~1_val~ - } - - if ((prop = Attributes.RegenMana) != 0) - { - list.Add(1060440, prop); // mana regeneration ~1_val~ - } - - if (Attributes.NightSight != 0) - { - list.Add(1060441); // night sight - } - - if ((prop = Attributes.ReflectPhysical) != 0) - { - list.Add(1060442, prop); // reflect physical damage ~1_val~% - } - - if ((prop = Attributes.RegenStam) != 0) - { - list.Add(1060443, prop); // stamina regeneration ~1_val~ - } - - if ((prop = Attributes.RegenHits) != 0) - { - list.Add(1060444, prop); // hit point regeneration ~1_val~ - } - - if (Attributes.SpellChanneling != 0) - { - list.Add(1060482); // spell channeling - } - - if ((prop = Attributes.SpellDamage) != 0) - { - list.Add(1060483, prop); // spell damage increase ~1_val~% - } - - if ((prop = Attributes.BonusStam) != 0) - { - list.Add(1060484, prop); // stamina increase ~1_val~ - } - - if ((prop = Attributes.BonusStr) != 0) - { - list.Add(1060485, prop); // strength bonus ~1_val~ - } - - if ((prop = Attributes.WeaponSpeed) != 0) - { - list.Add(1060486, prop); // swing speed increase ~1_val~% - } - - if (Core.ML && (prop = Attributes.IncreasedKarmaLoss) != 0) - { - list.Add(1075210, prop); // Increased Karma Loss ~1val~% - } - - if (m_MaxCharges > 0) - { - list.Add(1060741, m_Charges); // charges: ~1_val~ - } - - if (m_Slayer != TalismanSlayerName.None) - { - list.Add(1072503 + (int)m_Slayer); + list.Add(1074883); // Fully Charged } } - private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) + list.Add(1075085); // Requirement: Mondain's Legacy + + if (_killer?.IsEmpty == false && _killer.Amount > 0) { - if (setIf) - { - flags |= toSet; - } + // ~1_NAME~ Killer: +~2_val~% + list.Add(1072388, $"{_killer.Name ?? "Unknown"}\t{_killer.Amount}"); } - private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; - - public override void Serialize(IGenericWriter writer) + if (_protection?.IsEmpty == false && _protection.Amount > 0) { - base.Serialize(writer); - - writer.Write(0); // version - - var flags = SaveFlag.None; - - SetSaveFlag(ref flags, SaveFlag.Attributes, !Attributes.IsEmpty); - SetSaveFlag(ref flags, SaveFlag.SkillBonuses, !SkillBonuses.IsEmpty); - SetSaveFlag(ref flags, SaveFlag.Protection, m_Protection?.IsEmpty == false); - SetSaveFlag(ref flags, SaveFlag.Killer, m_Killer?.IsEmpty == false); - SetSaveFlag(ref flags, SaveFlag.Summoner, m_Summoner?.IsEmpty == false); - SetSaveFlag(ref flags, SaveFlag.Removal, m_Removal != TalismanRemoval.None); - SetSaveFlag(ref flags, SaveFlag.Skill, (int)m_Skill != 0); - SetSaveFlag(ref flags, SaveFlag.SuccessBonus, m_SuccessBonus != 0); - SetSaveFlag(ref flags, SaveFlag.ExceptionalBonus, m_ExceptionalBonus != 0); - SetSaveFlag(ref flags, SaveFlag.MaxCharges, m_MaxCharges != 0); - SetSaveFlag(ref flags, SaveFlag.Charges, m_Charges != 0); - SetSaveFlag(ref flags, SaveFlag.MaxChargeTime, m_MaxChargeTime != 0); - SetSaveFlag(ref flags, SaveFlag.ChargeTime, m_ChargeTime != 0); - SetSaveFlag(ref flags, SaveFlag.Blessed, m_Blessed); - SetSaveFlag(ref flags, SaveFlag.Slayer, m_Slayer != TalismanSlayerName.None); - - writer.WriteEncodedInt((int)flags); - - if (GetSaveFlag(flags, SaveFlag.Attributes)) - { - Attributes.Serialize(writer); - } - - if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) - { - SkillBonuses.Serialize(writer); - } - - if (GetSaveFlag(flags, SaveFlag.Protection)) - { - Protection.Serialize(writer); - } - - if (GetSaveFlag(flags, SaveFlag.Killer)) - { - Killer.Serialize(writer); - } - - if (GetSaveFlag(flags, SaveFlag.Summoner)) - { - Summoner.Serialize(writer); - } - - if (GetSaveFlag(flags, SaveFlag.Removal)) - { - writer.WriteEncodedInt((int)m_Removal); - } - - if (GetSaveFlag(flags, SaveFlag.Skill)) - { - writer.WriteEncodedInt((int)m_Skill); - } - - if (GetSaveFlag(flags, SaveFlag.SuccessBonus)) - { - writer.WriteEncodedInt(m_SuccessBonus); - } - - if (GetSaveFlag(flags, SaveFlag.ExceptionalBonus)) - { - writer.WriteEncodedInt(m_ExceptionalBonus); - } - - if (GetSaveFlag(flags, SaveFlag.MaxCharges)) - { - writer.WriteEncodedInt(m_MaxCharges); - } - - if (GetSaveFlag(flags, SaveFlag.Charges)) - { - writer.WriteEncodedInt(m_Charges); - } - - if (GetSaveFlag(flags, SaveFlag.MaxChargeTime)) - { - writer.WriteEncodedInt(m_MaxChargeTime); - } - - if (GetSaveFlag(flags, SaveFlag.ChargeTime)) - { - writer.WriteEncodedInt(m_ChargeTime); - } - - if (GetSaveFlag(flags, SaveFlag.Slayer)) - { - writer.WriteEncodedInt((int)m_Slayer); - } + // ~1_NAME~ Protection: +~2_val~% + list.Add(1072387, $"{_protection.Name ?? "Unknown"}\t{_protection.Amount}"); } - public override void Deserialize(IGenericReader reader) + if (_exceptionalBonus != 0) { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - var flags = (SaveFlag)reader.ReadEncodedInt(); - - Attributes = new AosAttributes(this); - if (GetSaveFlag(flags, SaveFlag.Attributes)) - { - Attributes.Deserialize(reader); - } - - SkillBonuses = new AosSkillBonuses(this); - if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) - { - SkillBonuses.Deserialize(reader); - } - - // Backward compatibility - if (GetSaveFlag(flags, SaveFlag.Owner)) - { - BlessedFor = reader.ReadEntity(); - } - - m_Protection = GetSaveFlag(flags, SaveFlag.Protection) - ? new TalismanAttribute(reader) - : new TalismanAttribute(); - m_Killer = GetSaveFlag(flags, SaveFlag.Killer) - ? new TalismanAttribute(reader) - : new TalismanAttribute(); - m_Summoner = GetSaveFlag(flags, SaveFlag.Summoner) - ? new TalismanAttribute(reader) - : new TalismanAttribute(); - - if (GetSaveFlag(flags, SaveFlag.Removal)) - { - m_Removal = (TalismanRemoval)reader.ReadEncodedInt(); - } - - if (GetSaveFlag(flags, SaveFlag.OldKarmaLoss)) - { - Attributes.IncreasedKarmaLoss = reader.ReadEncodedInt(); - } - - if (GetSaveFlag(flags, SaveFlag.Skill)) - { - m_Skill = (SkillName)reader.ReadEncodedInt(); - } - - if (GetSaveFlag(flags, SaveFlag.SuccessBonus)) - { - m_SuccessBonus = reader.ReadEncodedInt(); - } - - if (GetSaveFlag(flags, SaveFlag.ExceptionalBonus)) - { - m_ExceptionalBonus = reader.ReadEncodedInt(); - } - - if (GetSaveFlag(flags, SaveFlag.MaxCharges)) - { - m_MaxCharges = reader.ReadEncodedInt(); - } - - if (GetSaveFlag(flags, SaveFlag.Charges)) - { - m_Charges = reader.ReadEncodedInt(); - } - - if (GetSaveFlag(flags, SaveFlag.MaxChargeTime)) - { - m_MaxChargeTime = reader.ReadEncodedInt(); - } - - if (GetSaveFlag(flags, SaveFlag.ChargeTime)) - { - m_ChargeTime = reader.ReadEncodedInt(); - } - - if (GetSaveFlag(flags, SaveFlag.Slayer)) - { - m_Slayer = (TalismanSlayerName)reader.ReadEncodedInt(); - } - - m_Blessed = GetSaveFlag(flags, SaveFlag.Blessed); - - if (Parent is Mobile m) - { - Attributes.AddStatBonuses(m); - SkillBonuses.AddTo(m); - - if (m_ChargeTime > 0) - { - StartTimer(); - } - } + // ~1_NAME~ Exceptional Bonus: ~2_val~% + list.Add(1072395,$"{AosSkillBonuses.GetLabel(_skill):#}\t{_exceptionalBonus}"); } - public virtual void OnAfterUse(Mobile m) + if (_successBonus != 0) { - m_ChargeTime = m_MaxChargeTime; + // ~1_NAME~ Bonus: ~2_val~% + list.Add(1072394,$"{AosSkillBonuses.GetLabel(_skill):#}\t{_successBonus}"); + } - if (m_Charges > 0 && m_MaxCharges > 0) - { - m_Charges -= 1; - } + SkillBonuses.GetProperties(list); - if (m_ChargeTime > 0) + int prop; + + if ((prop = Attributes.WeaponDamage) != 0) + { + list.Add(1060401, prop); // damage increase ~1_val~% + } + + if ((prop = Attributes.DefendChance) != 0) + { + list.Add(1060408, prop); // defense chance increase ~1_val~% + } + + if ((prop = Attributes.BonusDex) != 0) + { + list.Add(1060409, prop); // dexterity bonus ~1_val~ + } + + if ((prop = Attributes.EnhancePotions) != 0) + { + list.Add(1060411, prop); // enhance potions ~1_val~% + } + + if ((prop = Attributes.CastRecovery) != 0) + { + list.Add(1060412, prop); // faster cast recovery ~1_val~ + } + + if ((prop = Attributes.CastSpeed) != 0) + { + list.Add(1060413, prop); // faster casting ~1_val~ + } + + if ((prop = Attributes.AttackChance) != 0) + { + list.Add(1060415, prop); // hit chance increase ~1_val~% + } + + if ((prop = Attributes.BonusHits) != 0) + { + list.Add(1060431, prop); // hit point increase ~1_val~ + } + + if ((prop = Attributes.BonusInt) != 0) + { + list.Add(1060432, prop); // intelligence bonus ~1_val~ + } + + if ((prop = Attributes.LowerManaCost) != 0) + { + list.Add(1060433, prop); // lower mana cost ~1_val~% + } + + if ((prop = Attributes.LowerRegCost) != 0) + { + list.Add(1060434, prop); // lower reagent cost ~1_val~% + } + + if ((prop = Attributes.Luck) != 0) + { + list.Add(1060436, prop); // luck ~1_val~ + } + + if ((prop = Attributes.BonusMana) != 0) + { + list.Add(1060439, prop); // mana increase ~1_val~ + } + + if ((prop = Attributes.RegenMana) != 0) + { + list.Add(1060440, prop); // mana regeneration ~1_val~ + } + + if (Attributes.NightSight != 0) + { + list.Add(1060441); // night sight + } + + if ((prop = Attributes.ReflectPhysical) != 0) + { + list.Add(1060442, prop); // reflect physical damage ~1_val~% + } + + if ((prop = Attributes.RegenStam) != 0) + { + list.Add(1060443, prop); // stamina regeneration ~1_val~ + } + + if ((prop = Attributes.RegenHits) != 0) + { + list.Add(1060444, prop); // hit point regeneration ~1_val~ + } + + if (Attributes.SpellChanneling != 0) + { + list.Add(1060482); // spell channeling + } + + if ((prop = Attributes.SpellDamage) != 0) + { + list.Add(1060483, prop); // spell damage increase ~1_val~% + } + + if ((prop = Attributes.BonusStam) != 0) + { + list.Add(1060484, prop); // stamina increase ~1_val~ + } + + if ((prop = Attributes.BonusStr) != 0) + { + list.Add(1060485, prop); // strength bonus ~1_val~ + } + + if ((prop = Attributes.WeaponSpeed) != 0) + { + list.Add(1060486, prop); // swing speed increase ~1_val~% + } + + if (Core.ML && (prop = Attributes.IncreasedKarmaLoss) != 0) + { + list.Add(1075210, prop); // Increased Karma Loss ~1val~% + } + + if (_maxCharges > 0) + { + list.Add(1060741, _charges); // charges: ~1_val~ + } + + if (_slayer != TalismanSlayerName.None) + { + list.Add(1072503 + (int)_slayer); + } + } + + [AfterDeserialization] + private void AfterDeserialization() + { + if (Parent is Mobile m) + { + Attributes.AddStatBonuses(m); + SkillBonuses.AddTo(m); + + if (_chargeTime > 0) { StartTimer(); } + } + } - InvalidateProperties(); + public override void OnDelete() + { + _creature?.Delete(); // Will stop the unsummon timer on OnAfterDelete() + } + + public virtual void OnAfterUse(Mobile m) + { + _chargeTime = _maxChargeTime; + + if (_charges > 0 && _maxCharges > 0) + { + _charges -= 1; } - public virtual Type GetSummoner() => null; - - public virtual void SetSummoner(Type type, TextDefinition name) + if (_chargeTime > 0) { - m_Summoner = new TalismanAttribute(type, name); + StartTimer(); } - public virtual void SetProtection(Type type, TextDefinition name, int amount) + InvalidateProperties(); + } + + public virtual Type GetSummoner() => null; + + public virtual void SetSummoner(Type type, TextDefinition name) + { + _summoner = new TalismanAttribute(type, name); + } + + public virtual void SetProtection(Type type, TextDefinition name, int amount) + { + _protection = new TalismanAttribute(type, name, amount); + } + + public virtual void SetKiller(Type type, TextDefinition name, int amount) + { + _killer = new TalismanAttribute(type, name, amount); + } + + public virtual void StartTimer() + { + if (!_timerToken.Running) { - m_Protection = new TalismanAttribute(type, name, amount); + Timer.StartTimer(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10), Slice, out _timerToken); + } + } + + public virtual void StopTimer() + { + _timerToken.Cancel(); + } + + public virtual void Slice() + { + if (Deleted) + { + StopTimer(); + return; } - public virtual void SetKiller(Type type, TextDefinition name, int amount) + if (_chargeTime - 10 > 0) { - m_Killer = new TalismanAttribute(type, name, amount); + _chargeTime -= 10; + } + else + { + _chargeTime = 0; + + StopTimer(); } - public virtual void StartTimer() + InvalidateProperties(); + } + + public static int GetRandomItemID() => _itemIDs.RandomElement(); + + public static Type GetRandomSummonType() => _summons.RandomElement(); + + public static TalismanAttribute GetRandomSummoner() + { + if (Utility.RandomDouble() < 0.975) { - if (!_timerToken.Running) + return new TalismanAttribute(); + } + + var num = Utility.Random(_summons.Length); + + return num > 14 + ? new TalismanAttribute(_summons[num], _summonLabels[num], 10) + : new TalismanAttribute(_summons[num], _summonLabels[num]); + } + + public static TalismanRemoval GetRandomRemoval() + { + if (Utility.RandomDouble() < 0.65) + { + return (TalismanRemoval)Utility.RandomList(390, 404, 407); + } + + return TalismanRemoval.None; + } + + public static TalismanAttribute GetRandomKiller() => GetRandomKiller(true); + + public static TalismanAttribute GetRandomKiller(bool includingNone) + { + if (includingNone && Utility.RandomBool()) + { + return new TalismanAttribute(); + } + + var num = Utility.Random(_killers.Length); + + return new TalismanAttribute(_killers[num], _killerLabels[num], Utility.RandomMinMax(10, 100)); + } + + public static TalismanAttribute GetRandomProtection() => GetRandomProtection(true); + + public static TalismanAttribute GetRandomProtection(bool includingNone) + { + if (includingNone && Utility.RandomBool()) + { + return new TalismanAttribute(); + } + + var num = Utility.Random(_killers.Length); + + return new TalismanAttribute(_killers[num], _killerLabels[num], Utility.RandomMinMax(5, 60)); + } + + public static SkillName GetRandomSkill() => _skills.RandomElement(); + + public static int GetRandomExceptional() + { + if (Utility.RandomDouble() < 0.3) + { + var num = 40 - Math.Log(Utility.RandomMinMax(7, 403)) * 5; + + return (int)Math.Round(num); + } + + return 0; + } + + public static int GetRandomSuccessful() + { + if (Utility.RandomDouble() < 0.75) + { + var num = 40 - Math.Log(Utility.RandomMinMax(7, 403)) * 5; + + return (int)Math.Round(num); + } + + return 0; + } + + public static bool GetRandomBlessed() => Utility.RandomDouble() < 0.02; + + public static TalismanSlayerName GetRandomSlayer() => Utility.RandomDouble() < 0.01 + ? (TalismanSlayerName)Utility.RandomMinMax(1, 9) + : TalismanSlayerName.None; + + public static int GetRandomCharges() => Utility.RandomBool() ? Utility.RandomMinMax(10, 50) : 0; + + private class TalismanTarget : Target + { + private readonly BaseTalisman m_Talisman; + + public TalismanTarget(BaseTalisman talisman) + : base(12, false, TargetFlags.Beneficial) => + m_Talisman = talisman; + + protected override void OnTarget(Mobile from, object o) + { + if (m_Talisman?.Deleted != false) { - Timer.StartTimer(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10), Slice, out _timerToken); - } - } - - public virtual void StopTimer() - { - _timerToken.Cancel(); - } - - public virtual void Slice() - { - if (Deleted) - { - StopTimer(); return; } - if (m_ChargeTime - 10 > 0) + if (from.Talisman != m_Talisman) { - m_ChargeTime -= 10; - } - else - { - m_ChargeTime = 0; - - StopTimer(); + from.SendLocalizedMessage(502641); // You must equip this item to use it. + return; } - InvalidateProperties(); - } - - public static int GetRandomItemID() => m_ItemIDs.RandomElement(); - - public static Type GetRandomSummonType() => m_Summons.RandomElement(); - - public static TalismanAttribute GetRandomSummoner() - { - if (Utility.RandomDouble() < 0.975) + if (o is not Mobile target) { - return new TalismanAttribute(); + from.SendLocalizedMessage(1046439); // That is not a valid target. + return; } - var num = Utility.Random(m_Summons.Length); - - return num > 14 - ? new TalismanAttribute(m_Summons[num], m_SummonLabels[num], 10) - : new TalismanAttribute(m_Summons[num], m_SummonLabels[num]); - } - - public static TalismanRemoval GetRandomRemoval() - { - if (Utility.RandomDouble() < 0.65) + if (m_Talisman.ChargeTime > 0) { - return (TalismanRemoval)Utility.RandomList(390, 404, 407); + from.SendLocalizedMessage( + 1074882, // You must wait ~1_val~ seconds for this to recharge. + m_Talisman.ChargeTime.ToString() + ); + return; } - return TalismanRemoval.None; - } - - public static TalismanAttribute GetRandomKiller() => GetRandomKiller(true); - - public static TalismanAttribute GetRandomKiller(bool includingNone) - { - if (includingNone && Utility.RandomBool()) + if (m_Talisman.Charges == 0 && m_Talisman.MaxCharges > 0) { - return new TalismanAttribute(); + from.SendLocalizedMessage(1042544); // This item is out of charges. + return; } - var num = Utility.Random(m_Killers.Length); - - return new TalismanAttribute(m_Killers[num], m_KillerLabels[num], Utility.RandomMinMax(10, 100)); - } - - public static TalismanAttribute GetRandomProtection() => GetRandomProtection(true); - - public static TalismanAttribute GetRandomProtection(bool includingNone) - { - if (includingNone && Utility.RandomBool()) + switch (m_Talisman.Removal) { - return new TalismanAttribute(); - } + case TalismanRemoval.Curse: + target.PlaySound(0xF6); + target.PlaySound(0x1F7); + target.FixedParticles(0x3709, 1, 30, 9963, 13, 3, EffectLayer.Head); - var num = Utility.Random(m_Killers.Length); - - return new TalismanAttribute(m_Killers[num], m_KillerLabels[num], Utility.RandomMinMax(5, 60)); - } - - public static SkillName GetRandomSkill() => m_Skills.RandomElement(); - - public static int GetRandomExceptional() - { - if (Utility.RandomDouble() < 0.3) - { - var num = 40 - Math.Log(Utility.RandomMinMax(7, 403)) * 5; - - return (int)Math.Round(num); - } - - return 0; - } - - public static int GetRandomSuccessful() - { - if (Utility.RandomDouble() < 0.75) - { - var num = 40 - Math.Log(Utility.RandomMinMax(7, 403)) * 5; - - return (int)Math.Round(num); - } - - return 0; - } - - public static bool GetRandomBlessed() => Utility.RandomDouble() < 0.02; - - public static TalismanSlayerName GetRandomSlayer() => Utility.RandomDouble() < 0.01 - ? (TalismanSlayerName)Utility.RandomMinMax(1, 9) - : TalismanSlayerName.None; - - public static int GetRandomCharges() => Utility.RandomBool() ? Utility.RandomMinMax(10, 50) : 0; - - [Flags] - private enum SaveFlag - { - None = 0x00000000, - Attributes = 0x00000001, - SkillBonuses = 0x00000002, - Owner = 0x00000004, - Protection = 0x00000008, - Killer = 0x00000010, - Summoner = 0x00000020, - Removal = 0x00000040, - OldKarmaLoss = 0x00000080, - Skill = 0x00000100, - SuccessBonus = 0x00000200, - ExceptionalBonus = 0x00000400, - MaxCharges = 0x00000800, - Charges = 0x00001000, - MaxChargeTime = 0x00002000, - ChargeTime = 0x00004000, - Blessed = 0x00008000, - Slayer = 0x00010000 - } - - private class TalismanTarget : Target - { - private readonly BaseTalisman m_Talisman; - - public TalismanTarget(BaseTalisman talisman) - : base(12, false, TargetFlags.Beneficial) => - m_Talisman = talisman; - - protected override void OnTarget(Mobile from, object o) - { - if (m_Talisman?.Deleted != false) - { - return; - } - - if (from.Talisman != m_Talisman) - { - from.SendLocalizedMessage(502641); // You must equip this item to use it. - return; - } - - if (o is not Mobile target) - { - from.SendLocalizedMessage(1046439); // That is not a valid target. - return; - } - - if (m_Talisman.ChargeTime > 0) - { - from.SendLocalizedMessage( - 1074882, // You must wait ~1_val~ seconds for this to recharge. - m_Talisman.ChargeTime.ToString() + IEntity mfrom = new Entity( + Serial.Zero, + new Point3D(target.X, target.Y, target.Z - 10), + from.Map + ); + IEntity mto = new Entity(Serial.Zero, new Point3D(target.X, target.Y, target.Z + 50), from.Map); + Effects.SendMovingParticles( + mfrom, + mto, + 0x2255, + 1, + 0, + false, + false, + 13, + 3, + 9501, + 1, + 0, + EffectLayer.Head, + 0x100 ); - return; - } - if (m_Talisman.Charges == 0 && m_Talisman.MaxCharges > 0) - { - from.SendLocalizedMessage(1042544); // This item is out of charges. - return; - } + var mod = target.GetStatMod("[Magic] Str Curse"); + if (mod?.Offset < 0) + { + target.RemoveStatMod("[Magic] Str Curse"); + } - switch (m_Talisman.Removal) - { - case TalismanRemoval.Curse: - target.PlaySound(0xF6); - target.PlaySound(0x1F7); - target.FixedParticles(0x3709, 1, 30, 9963, 13, 3, EffectLayer.Head); + mod = target.GetStatMod("[Magic] Dex Curse"); + if (mod?.Offset < 0) + { + target.RemoveStatMod("[Magic] Dex Curse"); + } - IEntity mfrom = new Entity( - Serial.Zero, - new Point3D(target.X, target.Y, target.Z - 10), - from.Map - ); - IEntity mto = new Entity(Serial.Zero, new Point3D(target.X, target.Y, target.Z + 50), from.Map); - Effects.SendMovingParticles( - mfrom, - mto, - 0x2255, - 1, - 0, - false, - false, - 13, - 3, - 9501, - 1, - 0, - EffectLayer.Head, - 0x100 - ); + mod = target.GetStatMod("[Magic] Int Curse"); + if (mod?.Offset < 0) + { + target.RemoveStatMod("[Magic] Int Curse"); + } - var mod = target.GetStatMod("[Magic] Str Curse"); - if (mod?.Offset < 0) - { - target.RemoveStatMod("[Magic] Str Curse"); - } + target.Paralyzed = false; - mod = target.GetStatMod("[Magic] Dex Curse"); - if (mod?.Offset < 0) - { - target.RemoveStatMod("[Magic] Dex Curse"); - } + EvilOmenSpell.EndEffect(target); + StrangleSpell.RemoveCurse(target); + CorpseSkinSpell.RemoveCurse(target); + CurseSpell.RemoveEffect(target); - mod = target.GetStatMod("[Magic] Int Curse"); - if (mod?.Offset < 0) - { - target.RemoveStatMod("[Magic] Int Curse"); - } + BuffInfo.RemoveBuff(target, BuffIcon.Clumsy); + BuffInfo.RemoveBuff(target, BuffIcon.FeebleMind); + BuffInfo.RemoveBuff(target, BuffIcon.Weaken); + BuffInfo.RemoveBuff(target, BuffIcon.MassCurse); - target.Paralyzed = false; + target.SendLocalizedMessage(1072408); // Any curses on you have been lifted - EvilOmenSpell.EndEffect(target); - StrangleSpell.RemoveCurse(target); - CorpseSkinSpell.RemoveCurse(target); - CurseSpell.RemoveEffect(target); + if (target != from) + { + from.SendLocalizedMessage(1072409); // Your targets curses have been lifted + } - BuffInfo.RemoveBuff(target, BuffIcon.Clumsy); - BuffInfo.RemoveBuff(target, BuffIcon.FeebleMind); - BuffInfo.RemoveBuff(target, BuffIcon.Weaken); - BuffInfo.RemoveBuff(target, BuffIcon.MassCurse); + break; + case TalismanRemoval.Damage: + target.PlaySound(0x201); + Effects.SendLocationParticles( + EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), + 0x3728, + 1, + 13, + 0x834, + 0, + 0x13B2, + 0 + ); - target.SendLocalizedMessage(1072408); // Any curses on you have been lifted + BleedAttack.EndBleed(target, true); + MortalStrike.EndWound(target); - if (target != from) - { - from.SendLocalizedMessage(1072409); // Your targets curses have been lifted - } + BuffInfo.RemoveBuff(target, BuffIcon.Bleed); + BuffInfo.RemoveBuff(target, BuffIcon.MortalStrike); - break; - case TalismanRemoval.Damage: - target.PlaySound(0x201); - Effects.SendLocationParticles( - EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), - 0x3728, - 1, - 13, - 0x834, - 0, - 0x13B2, - 0 - ); + target.SendLocalizedMessage(1072405); // Your lasting damage effects have been removed! - BleedAttack.EndBleed(target, true); - MortalStrike.EndWound(target); + if (target != from) + { + from.SendLocalizedMessage(1072406); // Your Targets lasting damage effects have been removed! + } - BuffInfo.RemoveBuff(target, BuffIcon.Bleed); - BuffInfo.RemoveBuff(target, BuffIcon.MortalStrike); + break; + case TalismanRemoval.Ward: + target.PlaySound(0x201); + Effects.SendLocationParticles( + EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), + 0x3728, + 1, + 13, + 0x834, + 0, + 0x13B2, + 0 + ); - target.SendLocalizedMessage(1072405); // Your lasting damage effects have been removed! + MagicReflectSpell.EndReflect(target); + ReactiveArmorSpell.EndArmor(target); + ProtectionSpell.EndProtection(target); - if (target != from) - { - from.SendLocalizedMessage(1072406); // Your Targets lasting damage effects have been removed! - } + target.SendLocalizedMessage(1072402); // Your wards have been removed! - break; - case TalismanRemoval.Ward: - target.PlaySound(0x201); - Effects.SendLocationParticles( - EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), - 0x3728, - 1, - 13, - 0x834, - 0, - 0x13B2, - 0 - ); + if (target != from) + { + from.SendLocalizedMessage(1072403); // Your target's wards have been removed! + } - MagicReflectSpell.EndReflect(target); - ReactiveArmorSpell.EndArmor(target); - ProtectionSpell.EndProtection(target); - - target.SendLocalizedMessage(1072402); // Your wards have been removed! - - if (target != from) - { - from.SendLocalizedMessage(1072403); // Your target's wards have been removed! - } - - break; - case TalismanRemoval.Wildfire: - // TODO - break; - } - - m_Talisman.OnAfterUse(from); + break; + case TalismanRemoval.Wildfire: + // TODO + break; } + + m_Talisman.OnAfterUse(from); } } } diff --git a/Projects/UOContent/Items/Talismans/Items/EnchantedSwitch.cs b/Projects/UOContent/Items/Talismans/Items/EnchantedSwitch.cs index a012f8a29..0258a5feb 100644 --- a/Projects/UOContent/Items/Talismans/Items/EnchantedSwitch.cs +++ b/Projects/UOContent/Items/Talismans/Items/EnchantedSwitch.cs @@ -1,28 +1,12 @@ -namespace Server.Items +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class EnchantedSwitch : Item { - public class EnchantedSwitch : Item - { - [Constructible] - public EnchantedSwitch() : base(0x2F5C) => Weight = 1.0; + [Constructible] + public EnchantedSwitch() : base(0x2F5C) => Weight = 1.0; - public EnchantedSwitch(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072893; // enchanted switch - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } - } + public override int LabelNumber => 1072893; // enchanted switch } diff --git a/Projects/UOContent/Items/Talismans/Items/HollowPrism.cs b/Projects/UOContent/Items/Talismans/Items/HollowPrism.cs index f073fb27e..7f58dcfa5 100644 --- a/Projects/UOContent/Items/Talismans/Items/HollowPrism.cs +++ b/Projects/UOContent/Items/Talismans/Items/HollowPrism.cs @@ -1,28 +1,12 @@ -namespace Server.Items +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class HollowPrism : Item { - public class HollowPrism : Item - { - [Constructible] - public HollowPrism() : base(0x2F5D) => Weight = 1.0; + [Constructible] + public HollowPrism() : base(0x2F5D) => Weight = 1.0; - public HollowPrism(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072895; // hollow prism - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } - } + public override int LabelNumber => 1072895; // hollow prism } diff --git a/Projects/UOContent/Items/Talismans/Items/JeweledFiligree.cs b/Projects/UOContent/Items/Talismans/Items/JeweledFiligree.cs index ebfc68296..8164dc22e 100644 --- a/Projects/UOContent/Items/Talismans/Items/JeweledFiligree.cs +++ b/Projects/UOContent/Items/Talismans/Items/JeweledFiligree.cs @@ -1,28 +1,12 @@ -namespace Server.Items +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class JeweledFiligree : Item { - public class JeweledFiligree : Item - { - [Constructible] - public JeweledFiligree() : base(0x2F5E) => Weight = 1.0; + [Constructible] + public JeweledFiligree() : base(0x2F5E) => Weight = 1.0; - public JeweledFiligree(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072894; // jeweled filigree - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } - } + public override int LabelNumber => 1072894; // jeweled filigree } diff --git a/Projects/UOContent/Items/Talismans/Items/RunedPrism.cs b/Projects/UOContent/Items/Talismans/Items/RunedPrism.cs index 5dde27609..af7429967 100644 --- a/Projects/UOContent/Items/Talismans/Items/RunedPrism.cs +++ b/Projects/UOContent/Items/Talismans/Items/RunedPrism.cs @@ -1,28 +1,12 @@ -namespace Server.Items +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class RunedPrism : Item { - public class RunedPrism : Item - { - [Constructible] - public RunedPrism() : base(0x2F57) => Weight = 1.0; + [Constructible] + public RunedPrism() : base(0x2F57) => Weight = 1.0; - public RunedPrism(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073465; // runed prism - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } - } + public override int LabelNumber => 1073465; // runed prism } diff --git a/Projects/UOContent/Items/Talismans/Items/RunedSwitch.cs b/Projects/UOContent/Items/Talismans/Items/RunedSwitch.cs index c791f8d7e..bc1c741c4 100644 --- a/Projects/UOContent/Items/Talismans/Items/RunedSwitch.cs +++ b/Projects/UOContent/Items/Talismans/Items/RunedSwitch.cs @@ -1,78 +1,64 @@ +using ModernUO.Serialization; using Server.Targeting; -namespace Server.Items +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class RunedSwitch : Item { - public class RunedSwitch : Item + [Constructible] + public RunedSwitch() : base(0x2F61) => Weight = 1.0; + + public RunedSwitch(Serial serial) : base(serial) { - [Constructible] - public RunedSwitch() : base(0x2F61) => Weight = 1.0; + } - public RunedSwitch(Serial serial) : base(serial) + public override int LabelNumber => 1072896; // runed switch + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) { + from.SendLocalizedMessage(1075101); // Please select an item to recharge. + from.Target = new InternalTarget(this); } - - public override int LabelNumber => 1072896; // runed switch - - public override void OnDoubleClick(Mobile from) + else { - if (IsChildOf(from.Backpack)) + from.SendLocalizedMessage(1060640); // The item must be in your backpack to use it. + } + } + + private class InternalTarget : Target + { + private readonly RunedSwitch _item; + + public InternalTarget(RunedSwitch item) : base(0, false, TargetFlags.None) => _item = item; + + protected override void OnTarget(Mobile from, object o) + { + if (_item?.Deleted != false) { - from.SendLocalizedMessage(1075101); // Please select an item to recharge. - from.Target = new InternalTarget(this); + return; } - else + + if (o is BaseTalisman talisman) { - from.SendLocalizedMessage(1060640); // The item must be in your backpack to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } - - private class InternalTarget : Target - { - private readonly RunedSwitch m_Item; - - public InternalTarget(RunedSwitch item) : base(0, false, TargetFlags.None) => m_Item = item; - - protected override void OnTarget(Mobile from, object o) - { - if (m_Item?.Deleted != false) + if (talisman.Charges == 0) { - return; - } - - if (o is BaseTalisman talisman) - { - if (talisman.Charges == 0) - { - talisman.Charges = talisman.MaxCharges; - m_Item.Delete(); - from.SendLocalizedMessage(1075100); // The item has been recharged. - } - else - { - from.SendLocalizedMessage( - 1075099 - ); // You cannot recharge that item until all of its current charges have been used. - } + talisman.Charges = talisman.MaxCharges; + _item.Delete(); + from.SendLocalizedMessage(1075100); // The item has been recharged. } else { - from.SendLocalizedMessage(1046439); // That is not a valid target. + // You cannot recharge that item until all of its current charges have been used. + from.SendLocalizedMessage(1075099); } } + else + { + from.SendLocalizedMessage(1046439); // That is not a valid target. + } } } } diff --git a/Projects/UOContent/Items/Talismans/RandomTalisman.cs b/Projects/UOContent/Items/Talismans/RandomTalisman.cs index 2d552f45f..95e613363 100644 --- a/Projects/UOContent/Items/Talismans/RandomTalisman.cs +++ b/Projects/UOContent/Items/Talismans/RandomTalisman.cs @@ -1,62 +1,61 @@ -namespace Server.Items +namespace Server.Items; + +public class RandomTalisman : BaseTalisman { - public class RandomTalisman : BaseTalisman + [Constructible] + public RandomTalisman() : base(GetRandomItemID()) { - [Constructible] - public RandomTalisman() : base(GetRandomItemID()) + Summoner = GetRandomSummoner(); + + if (Summoner.IsEmpty) { - Summoner = GetRandomSummoner(); + Removal = GetRandomRemoval(); - if (Summoner.IsEmpty) + if (Removal != TalismanRemoval.None) { - Removal = GetRandomRemoval(); + MaxCharges = GetRandomCharges(); + MaxChargeTime = 1200; + } + } + else + { + MaxCharges = Utility.RandomMinMax(10, 50); - if (Removal != TalismanRemoval.None) - { - MaxCharges = GetRandomCharges(); - MaxChargeTime = 1200; - } + if (Summoner.IsItem) + { + MaxChargeTime = 60; } else { - MaxCharges = Utility.RandomMinMax(10, 50); - - if (Summoner.IsItem) - { - MaxChargeTime = 60; - } - else - { - MaxChargeTime = 1800; - } + MaxChargeTime = 1800; } - - Blessed = GetRandomBlessed(); - Slayer = GetRandomSlayer(); - Protection = GetRandomProtection(); - Killer = GetRandomKiller(); - Skill = GetRandomSkill(); - ExceptionalBonus = GetRandomExceptional(); - SuccessBonus = GetRandomSuccessful(); - Charges = MaxCharges; } - public RandomTalisman(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } + Blessed = GetRandomBlessed(); + Slayer = GetRandomSlayer(); + Protection = GetRandomProtection(); + Killer = GetRandomKiller(); + Skill = GetRandomSkill(); + ExceptionalBonus = GetRandomExceptional(); + SuccessBonus = GetRandomSuccessful(); + Charges = MaxCharges; } -} + + public RandomTalisman(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + var version = reader.ReadInt(); + } +} \ No newline at end of file diff --git a/Projects/UOContent/Items/Talismans/TalismanAttribute.cs b/Projects/UOContent/Items/Talismans/TalismanAttribute.cs index 90871bf11..e1a7ad6ec 100644 --- a/Projects/UOContent/Items/Talismans/TalismanAttribute.cs +++ b/Projects/UOContent/Items/Talismans/TalismanAttribute.cs @@ -1,117 +1,72 @@ using System; +using ModernUO.Serialization; -namespace Server.Items +namespace Server.Items; + +[PropertyObject] +[SerializationGenerator(1, false)] +public partial class TalismanAttribute { - [PropertyObject] - public class TalismanAttribute + [SerializableField(0)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private Type _type; + + [SerializableField(1)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private TextDefinition _name; + + [SerializableField(2)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _amount; + + public TalismanAttribute() : this(null, null) { - public TalismanAttribute() : this(null, 0) + } + + public TalismanAttribute(TalismanAttribute copy) + { + if (copy != null) { - } - - public TalismanAttribute(TalismanAttribute copy) - { - if (copy != null) - { - Type = copy.Type; - Name = copy.Name; - Amount = copy.Amount; - } - } - - public TalismanAttribute(Type type, TextDefinition name, int amount = 0) - { - Type = type; - Name = name; - Amount = amount; - } - - public TalismanAttribute(IGenericReader reader) - { - var version = reader.ReadInt(); - - var flags = (SaveFlag)reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.Type)) - { - Type = AssemblyHandler.FindTypeByFullName(reader.ReadString()); - } - - if (GetSaveFlag(flags, SaveFlag.Name)) - { - Name = reader.ReadTextDefinition(); - } - - if (GetSaveFlag(flags, SaveFlag.Amount)) - { - Amount = reader.ReadEncodedInt(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Type Type { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public TextDefinition Name { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Amount { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsEmpty => Type == null; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsItem => Type?.Namespace == "Server.Items"; - - public override string ToString() => Type?.Name ?? "None"; - - private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) - { - if (setIf) - { - flags |= toSet; - } - } - - private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; - - public virtual void Serialize(IGenericWriter writer) - { - writer.Write(0); // version - - var flags = SaveFlag.None; - - SetSaveFlag(ref flags, SaveFlag.Type, Type != null); - SetSaveFlag(ref flags, SaveFlag.Name, Name != null); - SetSaveFlag(ref flags, SaveFlag.Amount, Amount != 0); - - writer.WriteEncodedInt((int)flags); - - if (GetSaveFlag(flags, SaveFlag.Type)) - { - writer.Write(Type!.FullName); - } - - if (GetSaveFlag(flags, SaveFlag.Name)) - { - writer.Write(Name); - } - - if (GetSaveFlag(flags, SaveFlag.Amount)) - { - writer.WriteEncodedInt(Amount); - } - } - - public int DamageBonus(Mobile to) => to?.GetType() == Type ? Amount : 0; - - [Flags] - private enum SaveFlag - { - None = 0x00000000, - Type = 0x00000001, - Name = 0x00000002, - Amount = 0x00000004 + _type = copy.Type; + _name = copy.Name; + _amount = copy.Amount; } } + + public TalismanAttribute(Type type, TextDefinition name, int amount = 0) + { + _type = type; + _name = name; + _amount = amount; + } + + private void Deserialize(IGenericReader reader, int version) + { + var flags = reader.ReadEncodedInt(); + + if ((flags & 0x1) != 0) + { + _type = AssemblyHandler.FindTypeByFullName(reader.ReadString()); + } + + if ((flags & 0x2) != 0) + { + _name = reader.ReadTextDefinition(); + } + + if ((flags & 0x4) != 0) + { + _amount = reader.ReadEncodedInt(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsEmpty => _type == null; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsItem => _type.IsAssignableTo(typeof(Item)); + + public override string ToString() => _type?.Name ?? "None"; + + public int DamageBonus(Mobile to) => to?.GetType() == _type ? _amount : 0; } diff --git a/Projects/UOContent/Items/Talismans/TalismanSlayer.cs b/Projects/UOContent/Items/Talismans/TalismanSlayer.cs index 7456ec9b9..2d1611ba8 100644 --- a/Projects/UOContent/Items/Talismans/TalismanSlayer.cs +++ b/Projects/UOContent/Items/Talismans/TalismanSlayer.cs @@ -2,106 +2,105 @@ using System; using System.Collections.Generic; using Server.Mobiles; -namespace Server.Items +namespace Server.Items; + +public enum TalismanSlayerName { - public enum TalismanSlayerName + None, + Bear, + Vermin, + Bat, + Mage, + Beetle, + Bird, + Ice, + Flame, + Bovine +} + +public static class TalismanSlayer +{ + private static Dictionary m_Table; + + public static void Initialize() { - None, - Bear, - Vermin, - Bat, - Mage, - Beetle, - Bird, - Ice, - Flame, - Bovine + m_Table = new Dictionary + { + [TalismanSlayerName.Bear] = new[] + { + typeof(GrizzlyBear), typeof(BlackBear), typeof(BrownBear), typeof(PolarBear) // , typeof( Grobu ) + }, + [TalismanSlayerName.Vermin] = new[] + { + typeof(RatmanMage), typeof(RatmanMage), typeof(RatmanArcher), typeof(Barracoon), typeof(Ratman), + typeof(SewerRat), + typeof(Rat), typeof(GiantRat) // , typeof( Chiikkaha ) + }, + [TalismanSlayerName.Bat] = new[] { typeof(Mongbat), typeof(StrongMongbat), typeof(VampireBat) }, + [TalismanSlayerName.Mage] = + new[] + { + typeof(EvilMage), typeof(EvilMageLord), typeof(AncientLich), typeof(Lich), typeof(LichLord), + typeof(SkeletalMage), typeof(BoneMagi), typeof(OrcishMage), typeof(KhaldunZealot), typeof(JukaMage) + }, + [TalismanSlayerName.Beetle] = + new[] + { + typeof(Beetle), typeof(RuneBeetle), typeof(FireBeetle), typeof(DeathwatchBeetle), + typeof(DeathwatchBeetleHatchling) + }, + [TalismanSlayerName.Bird] = new[] + { + typeof(Bird), typeof(TropicalBird), typeof(Chicken), typeof(Crane), typeof(DesertOstard), typeof(Eagle), + typeof(ForestOstard), typeof(FrenziedOstard), + typeof(Phoenix), /*typeof( Pyre ), typeof( Swoop ), typeof( Saliva ),*/ typeof(Harpy), + typeof(StoneHarpy) // ????? + }, + [TalismanSlayerName.Ice] = new[] + { + typeof(ArcticOgreLord), typeof(IceElemental), typeof(SnowElemental), typeof(FrostOoze), + typeof(IceFiend), /*typeof( UnfrozenMummy ),*/ typeof(FrostSpider), typeof(LadyOfTheSnow), + typeof(FrostTroll), + + // TODO WinterReaper, check + typeof(IceSnake), typeof(SnowLeopard), typeof(PolarBear), typeof(IceSerpent), typeof(GiantIceWorm) + }, + [TalismanSlayerName.Flame] = new[] + { + typeof(FireBeetle), typeof(HellHound), typeof(LavaSerpent), typeof(FireElemental), + typeof(PredatorHellCat), + typeof(Phoenix), typeof(FireGargoyle), typeof(HellCat), + /*typeof( Pyre ),*/ typeof(FireSteed), typeof(LavaLizard), + + // TODO check + typeof(LavaSnake) + }, + [TalismanSlayerName.Bovine] = new[] + { + typeof(Cow), typeof(Bull), + typeof(Gaman) /*, typeof( MinotaurCaptain ), typeof( MinotaurScout ), typeof( Minotaur ) */ + // TODO TormentedMinotaur + } + }; } - public static class TalismanSlayer + public static bool Slays(TalismanSlayerName name, Mobile m) { - private static Dictionary m_Table; - - public static void Initialize() + if (m == null || !m_Table.TryGetValue(name, out var types) || types == null) { - m_Table = new Dictionary - { - [TalismanSlayerName.Bear] = new[] - { - typeof(GrizzlyBear), typeof(BlackBear), typeof(BrownBear), typeof(PolarBear) // , typeof( Grobu ) - }, - [TalismanSlayerName.Vermin] = new[] - { - typeof(RatmanMage), typeof(RatmanMage), typeof(RatmanArcher), typeof(Barracoon), typeof(Ratman), - typeof(SewerRat), - typeof(Rat), typeof(GiantRat) // , typeof( Chiikkaha ) - }, - [TalismanSlayerName.Bat] = new[] { typeof(Mongbat), typeof(StrongMongbat), typeof(VampireBat) }, - [TalismanSlayerName.Mage] = - new[] - { - typeof(EvilMage), typeof(EvilMageLord), typeof(AncientLich), typeof(Lich), typeof(LichLord), - typeof(SkeletalMage), typeof(BoneMagi), typeof(OrcishMage), typeof(KhaldunZealot), typeof(JukaMage) - }, - [TalismanSlayerName.Beetle] = - new[] - { - typeof(Beetle), typeof(RuneBeetle), typeof(FireBeetle), typeof(DeathwatchBeetle), - typeof(DeathwatchBeetleHatchling) - }, - [TalismanSlayerName.Bird] = new[] - { - typeof(Bird), typeof(TropicalBird), typeof(Chicken), typeof(Crane), typeof(DesertOstard), typeof(Eagle), - typeof(ForestOstard), typeof(FrenziedOstard), - typeof(Phoenix), /*typeof( Pyre ), typeof( Swoop ), typeof( Saliva ),*/ typeof(Harpy), - typeof(StoneHarpy) // ????? - }, - [TalismanSlayerName.Ice] = new[] - { - typeof(ArcticOgreLord), typeof(IceElemental), typeof(SnowElemental), typeof(FrostOoze), - typeof(IceFiend), /*typeof( UnfrozenMummy ),*/ typeof(FrostSpider), typeof(LadyOfTheSnow), - typeof(FrostTroll), - - // TODO WinterReaper, check - typeof(IceSnake), typeof(SnowLeopard), typeof(PolarBear), typeof(IceSerpent), typeof(GiantIceWorm) - }, - [TalismanSlayerName.Flame] = new[] - { - typeof(FireBeetle), typeof(HellHound), typeof(LavaSerpent), typeof(FireElemental), - typeof(PredatorHellCat), - typeof(Phoenix), typeof(FireGargoyle), typeof(HellCat), - /*typeof( Pyre ),*/ typeof(FireSteed), typeof(LavaLizard), - - // TODO check - typeof(LavaSnake) - }, - [TalismanSlayerName.Bovine] = new[] - { - typeof(Cow), typeof(Bull), - typeof(Gaman) /*, typeof( MinotaurCaptain ), typeof( MinotaurScout ), typeof( Minotaur ) */ - // TODO TormentedMinotaur - } - }; - } - - public static bool Slays(TalismanSlayerName name, Mobile m) - { - if (m == null || !m_Table.TryGetValue(name, out var types) || types == null) - { - return false; - } - - var type = m.GetType(); - - for (var i = 0; i < types.Length; i++) - { - if (types[i].IsAssignableFrom(type)) - { - return true; - } - } - return false; } + + var type = m.GetType(); + + for (var i = 0; i < types.Length; i++) + { + if (types[i].IsAssignableFrom(type)) + { + return true; + } + } + + return false; } -} +} \ No newline at end of file diff --git a/Projects/UOContent/Items/Talismans/TalismanSummons.cs b/Projects/UOContent/Items/Talismans/TalismanSummons.cs index fc74d6fed..9ca06f0d9 100644 --- a/Projects/UOContent/Items/Talismans/TalismanSummons.cs +++ b/Projects/UOContent/Items/Talismans/TalismanSummons.cs @@ -1,644 +1,339 @@ using System; using System.Collections.Generic; +using ModernUO.Serialization; using Server.ContextMenus; using Server.Items; -namespace Server.Mobiles +namespace Server.Mobiles; + +[SerializationGenerator(0)] +public partial class BaseTalismanSummon : BaseCreature { - public class BaseTalismanSummon : BaseCreature + // public override bool IsInvulnerable => true; // TODO: Wailing banshees are NOT invulnerable, are any of the others? + + public BaseTalismanSummon() : base(AIType.AI_Melee, FightMode.None) { - // public override bool IsInvulnerable => true; // TODO: Wailing banshees are NOT invulnerable, are any of the others? + // TODO: Stats/skills + } - public BaseTalismanSummon() : base(AIType.AI_Melee, FightMode.None) + public override bool Commandable => false; + public override bool InitialInnocent => true; + + public override void AddCustomContextEntries(Mobile from, List list) + { + if (from.Alive && ControlMaster == from) { - // TODO: Stats/skills - } - - public BaseTalismanSummon(Serial serial) : base(serial) - { - } - - public override bool Commandable => false; - public override bool InitialInnocent => true; - - public override void AddCustomContextEntries(Mobile from, List list) - { - if (from.Alive && ControlMaster == from) - { - list.Add(new TalismanReleaseEntry(this)); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - - private class TalismanReleaseEntry : ContextMenuEntry - { - private readonly Mobile m_Mobile; - - public TalismanReleaseEntry(Mobile m) : base(6118, 3) => m_Mobile = m; - - public override void OnClick() - { - Effects.SendLocationParticles( - EffectItem.Create(m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration), - 0x3728, - 8, - 20, - 5042 - ); - - Effects.PlaySound(m_Mobile,0x201); - - m_Mobile.Delete(); - } + list.Add(new TalismanReleaseEntry(this)); } } - public class SummonedAntLion : BaseTalismanSummon + private class TalismanReleaseEntry : ContextMenuEntry { - [Constructible] - public SummonedAntLion() - { - Body = 787; - BaseSoundID = 1006; - } - - public SummonedAntLion(Serial serial) : base(serial) - { - } - - public override string DefaultName => "an ant lion"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedArcticOgreLord : BaseTalismanSummon - { - [Constructible] - public SummonedArcticOgreLord() - { - Body = 135; - BaseSoundID = 427; - } - - public SummonedArcticOgreLord(Serial serial) : base(serial) - { - } - - public override string DefaultName => "an arctic ogre lord"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedBakeKitsune : BaseTalismanSummon - { - [Constructible] - public SummonedBakeKitsune() - { - Body = 246; - BaseSoundID = 0x4DD; - } - - public SummonedBakeKitsune(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a bake kitsune"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedBogling : BaseTalismanSummon - { - [Constructible] - public SummonedBogling() - { - Body = 779; - BaseSoundID = 422; - } - - public SummonedBogling(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a bogling"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedBullFrog : BaseTalismanSummon - { - [Constructible] - public SummonedBullFrog() - { - Body = 81; - Hue = Utility.RandomList(0x5AC, 0x5A3, 0x59A, 0x591, 0x588, 0x57F); - BaseSoundID = 0x266; - } - - public SummonedBullFrog(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a bull frog"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); + private readonly Mobile m_Mobile; - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedChicken : BaseTalismanSummon - { - [Constructible] - public SummonedChicken() - { - Body = 0xD0; - BaseSoundID = 0x6E; - } - - public SummonedChicken(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a chicken"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedCow : BaseTalismanSummon - { - [Constructible] - public SummonedCow() - { - Body = Utility.RandomList(0xD8, 0xE7); - BaseSoundID = 0x78; - } - - public SummonedCow(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a cow"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedDoppleganger : BaseTalismanSummon - { - [Constructible] - public SummonedDoppleganger() - { - Body = 0x309; - BaseSoundID = 0x451; - } - - public SummonedDoppleganger(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a doppleganger"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedFrostSpider : BaseTalismanSummon - { - [Constructible] - public SummonedFrostSpider() - { - Body = 20; - BaseSoundID = 0x388; - } - - public SummonedFrostSpider(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a frost spider"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedGreatHart : BaseTalismanSummon - { - [Constructible] - public SummonedGreatHart() - { - Body = 0xEA; - BaseSoundID = 0x82; - } + public TalismanReleaseEntry(Mobile m) : base(6118, 3) => m_Mobile = m; - public SummonedGreatHart(Serial serial) : base(serial) + public override void OnClick() { - } + Effects.SendLocationParticles( + EffectItem.Create(m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration), + 0x3728, + 8, + 20, + 5042 + ); - public override string DefaultName => "a great hart"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedLavaSerpent : BaseTalismanSummon - { - [Constructible] - public SummonedLavaSerpent() - { - Body = 90; - BaseSoundID = 219; - } - - public SummonedLavaSerpent(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a lava serpent"; - - public override void OnThink() - { - /* - if (m_NextWave < Core.Now) - AreaHeatDamage(); - */ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - - /* - // An area attack that only damages staff, wtf? - - private DateTime m_NextWave; - - public void AreaHeatDamage() - { - Mobile mob = ControlMaster; - - if (mob != null) - { - if (mob.InRange( Location, 2 )) - { - if (mob.AccessLevel != AccessLevel.Player) - { - AOS.Damage( mob, Utility.Random( 2, 3 ), 0, 100, 0, 0, 0 ); - mob.SendLocalizedMessage( 1008112 ); // The intense heat is damaging you! - } - } - - GuardedRegion r = Region as GuardedRegion; - - if (r != null && mob.Alive) - { - foreach ( Mobile m in GetMobilesInRange( 2 ) ) - { - if (!mob.CanBeHarmful( m )) - mob.CriminalAction( false ); - } - } - } - - m_NextWave = Core.Now + TimeSpan.FromSeconds( 3 ); - } - */ - } - - public class SummonedOrcBrute : BaseTalismanSummon - { - [Constructible] - public SummonedOrcBrute() - { - Body = 189; - BaseSoundID = 0x45A; - } - - public SummonedOrcBrute(Serial serial) : base(serial) - { - } - - public override string DefaultName => "an orc brute"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedPanther : BaseTalismanSummon - { - [Constructible] - public SummonedPanther() - { - Body = 0xD6; - Hue = 0x901; - BaseSoundID = 0x462; - } - - public SummonedPanther(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a panther"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedSheep : BaseTalismanSummon - { - [Constructible] - public SummonedSheep() - { - Body = 0xCF; - BaseSoundID = 0xD6; - } - - public SummonedSheep(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a sheep"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedSkeletalKnight : BaseTalismanSummon - { - [Constructible] - public SummonedSkeletalKnight() - { - Body = 147; - BaseSoundID = 451; - } - - public SummonedSkeletalKnight(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a skeletal knight"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedVorpalBunny : BaseTalismanSummon - { - [Constructible] - public SummonedVorpalBunny() - { - Body = 205; - Hue = 0x480; - BaseSoundID = 0xC9; - - Timer.StartTimer(TimeSpan.FromMinutes(30.0), BeginTunnel); - } - - public SummonedVorpalBunny(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a vorpal bunny"; - - public virtual void BeginTunnel() - { - if (Deleted) - { - return; - } - - new VorpalBunny.BunnyHole().MoveToWorld(Location, Map); - Frozen = true; - - // * The bunny begins to dig a tunnel back to its underground lair * - Say(1114450); - PlaySound(0x247); - - Timer.StartTimer(TimeSpan.FromSeconds(5.0), Delete); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } - } - - public class SummonedWailingBanshee : BaseTalismanSummon - { - [Constructible] - public SummonedWailingBanshee() - { - Body = 310; - BaseSoundID = 0x482; - } - - public SummonedWailingBanshee(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a wailing banshee"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); + Effects.PlaySound(m_Mobile,0x201); - var version = reader.ReadEncodedInt(); + m_Mobile.Delete(); } } } + +[SerializationGenerator(0)] +public partial class SummonedAntLion : BaseTalismanSummon +{ + [Constructible] + public SummonedAntLion() + { + Body = 787; + BaseSoundID = 1006; + } + + public override string DefaultName => "an ant lion"; +} + + +[SerializationGenerator(0)] +public partial class SummonedArcticOgreLord : BaseTalismanSummon +{ + [Constructible] + public SummonedArcticOgreLord() + { + Body = 135; + BaseSoundID = 427; + } + + public override string DefaultName => "an arctic ogre lord"; +} + +[SerializationGenerator(0)] +public partial class SummonedBakeKitsune : BaseTalismanSummon +{ + [Constructible] + public SummonedBakeKitsune() + { + Body = 246; + BaseSoundID = 0x4DD; + } + + public override string DefaultName => "a bake kitsune"; +} + +[SerializationGenerator(0)] +public partial class SummonedBogling : BaseTalismanSummon +{ + [Constructible] + public SummonedBogling() + { + Body = 779; + BaseSoundID = 422; + } + + public override string DefaultName => "a bogling"; +} + +[SerializationGenerator(0)] +public partial class SummonedBullFrog : BaseTalismanSummon +{ + [Constructible] + public SummonedBullFrog() + { + Body = 81; + Hue = Utility.RandomList(0x5AC, 0x5A3, 0x59A, 0x591, 0x588, 0x57F); + BaseSoundID = 0x266; + } + + public override string DefaultName => "a bull frog"; +} + +[SerializationGenerator(0)] +public partial class SummonedChicken : BaseTalismanSummon +{ + [Constructible] + public SummonedChicken() + { + Body = 0xD0; + BaseSoundID = 0x6E; + } + + public override string DefaultName => "a chicken"; +} + +[SerializationGenerator(0)] +public partial class SummonedCow : BaseTalismanSummon +{ + [Constructible] + public SummonedCow() + { + Body = Utility.RandomList(0xD8, 0xE7); + BaseSoundID = 0x78; + } + + public override string DefaultName => "a cow"; +} + +[SerializationGenerator(0)] +public partial class SummonedDoppleganger : BaseTalismanSummon +{ + [Constructible] + public SummonedDoppleganger() + { + Body = 0x309; + BaseSoundID = 0x451; + } + + public override string DefaultName => "a doppleganger"; +} + +[SerializationGenerator(0)] +public partial class SummonedFrostSpider : BaseTalismanSummon +{ + [Constructible] + public SummonedFrostSpider() + { + Body = 20; + BaseSoundID = 0x388; + } + + public override string DefaultName => "a frost spider"; +} + +[SerializationGenerator(0)] +public partial class SummonedGreatHart : BaseTalismanSummon +{ + [Constructible] + public SummonedGreatHart() + { + Body = 0xEA; + BaseSoundID = 0x82; + } + + public override string DefaultName => "a great hart"; +} + +[SerializationGenerator(0)] +public partial class SummonedLavaSerpent : BaseTalismanSummon +{ + [Constructible] + public SummonedLavaSerpent() + { + Body = 90; + BaseSoundID = 219; + } + + public override string DefaultName => "a lava serpent"; + + public override void OnThink() + { + /* + if (m_NextWave < Core.Now) + AreaHeatDamage(); + */ + } + + /* + // An area attack that only damages staff, wtf? + + private DateTime m_NextWave; + + public void AreaHeatDamage() + { + Mobile mob = ControlMaster; + + if (mob != null) + { + if (mob.InRange( Location, 2 )) + { + if (mob.AccessLevel != AccessLevel.Player) + { + AOS.Damage( mob, Utility.Random( 2, 3 ), 0, 100, 0, 0, 0 ); + mob.SendLocalizedMessage( 1008112 ); // The intense heat is damaging you! + } + } + + GuardedRegion r = Region as GuardedRegion; + + if (r != null && mob.Alive) + { + foreach ( Mobile m in GetMobilesInRange( 2 ) ) + { + if (!mob.CanBeHarmful( m )) + mob.CriminalAction( false ); + } + } + } + + m_NextWave = Core.Now + TimeSpan.FromSeconds( 3 ); + } + */ +} + +[SerializationGenerator(0)] +public partial class SummonedOrcBrute : BaseTalismanSummon +{ + [Constructible] + public SummonedOrcBrute() + { + Body = 189; + BaseSoundID = 0x45A; + } + + public override string DefaultName => "an orc brute"; +} + +[SerializationGenerator(0)] +public partial class SummonedPanther : BaseTalismanSummon +{ + [Constructible] + public SummonedPanther() + { + Body = 0xD6; + Hue = 0x901; + BaseSoundID = 0x462; + } + + public override string DefaultName => "a panther"; +} + +[SerializationGenerator(0)] +public partial class SummonedSheep : BaseTalismanSummon +{ + [Constructible] + public SummonedSheep() + { + Body = 0xCF; + BaseSoundID = 0xD6; + } + + public override string DefaultName => "a sheep"; +} + +[SerializationGenerator(0)] +public partial class SummonedSkeletalKnight : BaseTalismanSummon +{ + [Constructible] + public SummonedSkeletalKnight() + { + Body = 147; + BaseSoundID = 451; + } + + public override string DefaultName => "a skeletal knight"; +} + +[SerializationGenerator(0)] +public partial class SummonedVorpalBunny : BaseTalismanSummon +{ + [Constructible] + public SummonedVorpalBunny() + { + Body = 205; + Hue = 0x480; + BaseSoundID = 0xC9; + + Timer.StartTimer(TimeSpan.FromMinutes(30.0), BeginTunnel); + } + + public override string DefaultName => "a vorpal bunny"; + + public virtual void BeginTunnel() + { + if (Deleted) + { + return; + } + + new VorpalBunny.BunnyHole().MoveToWorld(Location, Map); + Frozen = true; + + // * The bunny begins to dig a tunnel back to its underground lair * + Say(1114450); + PlaySound(0x247); + + Timer.StartTimer(TimeSpan.FromSeconds(5.0), Delete); + } +} + +[SerializationGenerator(0)] +public partial class SummonedWailingBanshee : BaseTalismanSummon +{ + [Constructible] + public SummonedWailingBanshee() + { + Body = 310; + BaseSoundID = 0x482; + } + + public override string DefaultName => "a wailing banshee"; +} diff --git a/Projects/UOContent/Migrations/Server.Items.BaseTalisman.v1.json b/Projects/UOContent/Migrations/Server.Items.BaseTalisman.v1.json new file mode 100644 index 000000000..958652db9 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.BaseTalisman.v1.json @@ -0,0 +1,132 @@ +{ + "version": 1, + "type": "Server.Items.BaseTalisman", + "properties": [ + { + "name": "Attributes", + "type": "Server.AosAttributes", + "usesSaveFlag": true, + "rule": "RawSerializableMigrationRule", + "ruleArguments": [ + "DeserializationRequiresParent" + ] + }, + { + "name": "SkillBonuses", + "type": "Server.AosSkillBonuses", + "usesSaveFlag": true, + "rule": "RawSerializableMigrationRule", + "ruleArguments": [ + "DeserializationRequiresParent" + ] + }, + { + "name": "Protection", + "type": "Server.Items.TalismanAttribute", + "usesSaveFlag": true, + "rule": "RawSerializableMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Killer", + "type": "Server.Items.TalismanAttribute", + "usesSaveFlag": true, + "rule": "RawSerializableMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Summoner", + "type": "Server.Items.TalismanAttribute", + "usesSaveFlag": true, + "rule": "RawSerializableMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Removal", + "type": "Server.Items.TalismanRemoval", + "usesSaveFlag": true, + "rule": "EnumMigrationRule" + }, + { + "name": "Skill", + "type": "Server.SkillName", + "usesSaveFlag": true, + "rule": "EnumMigrationRule" + }, + { + "name": "SuccessBonus", + "type": "int", + "usesSaveFlag": true, + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "EncodedInt" + ] + }, + { + "name": "ExceptionalBonus", + "type": "int", + "usesSaveFlag": true, + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "EncodedInt" + ] + }, + { + "name": "MaxCharges", + "type": "int", + "usesSaveFlag": true, + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "EncodedInt" + ] + }, + { + "name": "Charges", + "type": "int", + "usesSaveFlag": true, + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "MaxChargeTime", + "type": "int", + "usesSaveFlag": true, + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "EncodedInt" + ] + }, + { + "name": "ChargeTime", + "type": "int", + "usesSaveFlag": true, + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "EncodedInt" + ] + }, + { + "name": "Blessed", + "type": "bool", + "usesSaveFlag": true, + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Slayer", + "type": "Server.Items.TalismanSlayerName", + "usesSaveFlag": true, + "rule": "EnumMigrationRule" + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.EnchantedSwitch.v0.json b/Projects/UOContent/Migrations/Server.Items.EnchantedSwitch.v0.json new file mode 100644 index 000000000..e9195676d --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.EnchantedSwitch.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.EnchantedSwitch" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.HollowPrism.v0.json b/Projects/UOContent/Migrations/Server.Items.HollowPrism.v0.json new file mode 100644 index 000000000..d9f0dd2ad --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.HollowPrism.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.HollowPrism" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.JeweledFiligree.v0.json b/Projects/UOContent/Migrations/Server.Items.JeweledFiligree.v0.json new file mode 100644 index 000000000..1093f0971 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.JeweledFiligree.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.JeweledFiligree" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.RunedPrism.v0.json b/Projects/UOContent/Migrations/Server.Items.RunedPrism.v0.json new file mode 100644 index 000000000..cce7ff6a7 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.RunedPrism.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.RunedPrism" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.RunedSwitch.v0.json b/Projects/UOContent/Migrations/Server.Items.RunedSwitch.v0.json new file mode 100644 index 000000000..b258cff0f --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.RunedSwitch.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.RunedSwitch" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.TalismanAttribute.v1.json b/Projects/UOContent/Migrations/Server.Items.TalismanAttribute.v1.json new file mode 100644 index 000000000..7fda238bd --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.TalismanAttribute.v1.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "type": "Server.Items.TalismanAttribute", + "properties": [ + { + "name": "Type", + "type": "System.Type", + "rule": "PrimitiveTypeMigrationRule" + }, + { + "name": "Name", + "type": "Server.TextDefinition", + "rule": "PrimitiveUOTypeMigrationRule", + "ruleArguments": [ + "TextDefinition" + ] + }, + { + "name": "Amount", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.BaseTalismanSummon.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.BaseTalismanSummon.v0.json new file mode 100644 index 000000000..ad0cd092f --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.BaseTalismanSummon.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.BaseTalismanSummon" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedAntLion.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedAntLion.v0.json new file mode 100644 index 000000000..d66bd920f --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedAntLion.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedAntLion" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedArcticOgreLord.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedArcticOgreLord.v0.json new file mode 100644 index 000000000..8c890ef68 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedArcticOgreLord.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedArcticOgreLord" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedBakeKitsune.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedBakeKitsune.v0.json new file mode 100644 index 000000000..136150103 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedBakeKitsune.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedBakeKitsune" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedBogling.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedBogling.v0.json new file mode 100644 index 000000000..576812fef --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedBogling.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedBogling" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedBullFrog.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedBullFrog.v0.json new file mode 100644 index 000000000..627ecd768 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedBullFrog.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedBullFrog" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedChicken.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedChicken.v0.json new file mode 100644 index 000000000..d5f80998f --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedChicken.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedChicken" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedCow.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedCow.v0.json new file mode 100644 index 000000000..21cb9943e --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedCow.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedCow" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedDoppleganger.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedDoppleganger.v0.json new file mode 100644 index 000000000..82bd2ab1e --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedDoppleganger.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedDoppleganger" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedFrostSpider.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedFrostSpider.v0.json new file mode 100644 index 000000000..962965c49 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedFrostSpider.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedFrostSpider" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedGreatHart.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedGreatHart.v0.json new file mode 100644 index 000000000..e0ad895a7 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedGreatHart.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedGreatHart" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedLavaSerpent.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedLavaSerpent.v0.json new file mode 100644 index 000000000..40a2faa8d --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedLavaSerpent.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedLavaSerpent" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedOrcBrute.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedOrcBrute.v0.json new file mode 100644 index 000000000..cbe7f4051 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedOrcBrute.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedOrcBrute" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedPanther.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedPanther.v0.json new file mode 100644 index 000000000..eef43e5ab --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedPanther.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedPanther" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedSheep.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedSheep.v0.json new file mode 100644 index 000000000..8dddbbe9f --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedSheep.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedSheep" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedSkeletalKnight.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedSkeletalKnight.v0.json new file mode 100644 index 000000000..19d4a61df --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedSkeletalKnight.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedSkeletalKnight" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedVorpalBunny.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedVorpalBunny.v0.json new file mode 100644 index 000000000..c5eb201f7 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedVorpalBunny.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedVorpalBunny" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.SummonedWailingBanshee.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.SummonedWailingBanshee.v0.json new file mode 100644 index 000000000..3be95d281 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.SummonedWailingBanshee.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.SummonedWailingBanshee" +} \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/BaseCreature.cs b/Projects/UOContent/Mobiles/BaseCreature.cs index 18a62c945..ffc515223 100644 --- a/Projects/UOContent/Mobiles/BaseCreature.cs +++ b/Projects/UOContent/Mobiles/BaseCreature.cs @@ -3515,11 +3515,21 @@ namespace Server.Mobiles } public static bool Summon(BaseCreature creature, Mobile caster, Point3D p, int sound, TimeSpan duration) => - Summon(creature, true, caster, p, sound, duration); + Summon(creature, true, caster, p, sound, duration, null); + + public static bool Summon( + BaseCreature creature, Mobile caster, Point3D p, int sound, TimeSpan duration, + Action onUnsummon + ) => Summon(creature, true, caster, p, sound, duration, onUnsummon); public static bool Summon( BaseCreature creature, bool controlled, Mobile caster, Point3D p, int sound, TimeSpan duration + ) => Summon(creature, controlled, caster, p, sound, duration, null); + + public static bool Summon( + BaseCreature creature, bool controlled, Mobile caster, Point3D p, int sound, + TimeSpan duration, Action onUnsummon ) { if (caster.Followers + creature.ControlSlots > caster.FollowersMax) @@ -3556,7 +3566,7 @@ namespace Server.Mobiles } } - new UnsummonTimer(creature, duration).Start(); + new UnsummonTimer(creature, duration, onUnsummon).Start(); creature.SummonEnd = Core.Now + duration; creature.MoveToWorld(p, caster.Map); diff --git a/Projects/UOContent/Spells/UnsummonTimer.cs b/Projects/UOContent/Spells/UnsummonTimer.cs index e34623a9f..18e1c96be 100644 --- a/Projects/UOContent/Spells/UnsummonTimer.cs +++ b/Projects/UOContent/Spells/UnsummonTimer.cs @@ -10,6 +10,7 @@ public class UnsummonTimer : Timer // Track timers since some of them are really long and might hold references to long dead/deleted mobs private static readonly Dictionary _timers = new(); private BaseCreature _creature; + private Action _onUnsummon; public static void StopTimer(BaseCreature creature) { @@ -19,8 +20,9 @@ public class UnsummonTimer : Timer } } - public UnsummonTimer(BaseCreature creature, TimeSpan delay) : base(delay) + public UnsummonTimer(BaseCreature creature, TimeSpan delay, Action onUnsummon = null) : base(delay) { + _onUnsummon = onUnsummon; _creature = creature; ref var timer = ref CollectionsMarshal.GetValueRefOrAddDefault(_timers, creature, out bool exists); @@ -36,5 +38,6 @@ public class UnsummonTimer : Timer { // BaseCreature.OnAfterDelete will remove the creature from the timers table _creature?.Delete(); + _onUnsummon?.Invoke(); } } diff --git a/Projects/UOContent/UOContent.csproj b/Projects/UOContent/UOContent.csproj index dd16d48b3..e664a7d8c 100755 --- a/Projects/UOContent/UOContent.csproj +++ b/Projects/UOContent/UOContent.csproj @@ -39,7 +39,7 @@ - +