fix: Codegens talismans - Fixes memory leak (#1469)

This commit is contained in:
Kamron Batman 2023-08-23 22:41:48 -07:00 committed by GitHub
parent ca89b8b08b
commit ffb0b24e1a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 1979 additions and 2256 deletions

View file

@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"modernuoschemagenerator": {
"version": "2.6.4",
"version": "2.7.2",
"commands": [
"ModernUOSchemaGenerator"
]

View file

@ -38,7 +38,7 @@
<PackageReference Include="Zlib.Bindings" Version="1.11.0" />
<PackageReference Include="ModernUO.Serialization.Annotations" Version="2.6.0" />
<PackageReference Include="ModernUO.Serialization.Generator" Version="2.6.4" />
<PackageReference Include="ModernUO.Serialization.Generator" Version="2.7.2" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="Migrations/*.v*.json" />

View file

@ -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<Mobile>();
}
_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
}
}

File diff suppressed because it is too large Load diff

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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.
}
}
}
}

View file

@ -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)
{
}
Blessed = GetRandomBlessed();
Slayer = GetRandomSlayer();
Protection = GetRandomProtection();
Killer = GetRandomKiller();
Skill = GetRandomSkill();
ExceptionalBonus = GetRandomExceptional();
SuccessBonus = GetRandomSuccessful();
Charges = MaxCharges;
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
public RandomTalisman(Serial serial) : base(serial)
{
}
writer.Write(0); // version
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
writer.Write(0); // version
}
var version = reader.ReadInt();
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}

View file

@ -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;
}

View file

@ -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<TalismanSlayerName, Type[]> m_Table;
public static void Initialize()
{
None,
Bear,
Vermin,
Bat,
Mage,
Beetle,
Bird,
Ice,
Flame,
Bovine
m_Table = new Dictionary<TalismanSlayerName, Type[]>
{
[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<TalismanSlayerName, Type[]> m_Table;
public static void Initialize()
if (m == null || !m_Table.TryGetValue(name, out var types) || types == null)
{
m_Table = new Dictionary<TalismanSlayerName, Type[]>
{
[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;
}
}

View file

@ -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<ContextMenuEntry> 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<ContextMenuEntry> 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";
}

View file

@ -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"
}
]
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.EnchantedSwitch"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.HollowPrism"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.JeweledFiligree"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.RunedPrism"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.RunedSwitch"
}

View file

@ -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": [
""
]
}
]
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.BaseTalismanSummon"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedAntLion"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedArcticOgreLord"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedBakeKitsune"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedBogling"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedBullFrog"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedChicken"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedCow"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedDoppleganger"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedFrostSpider"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedGreatHart"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedLavaSerpent"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedOrcBrute"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedPanther"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedSheep"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedSkeletalKnight"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedVorpalBunny"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Mobiles.SummonedWailingBanshee"
}

View file

@ -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);

View file

@ -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<BaseCreature, UnsummonTimer> _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();
}
}

View file

@ -39,7 +39,7 @@
<PackageReference Include="Zstd.Binaries" Version="1.6.0" />
<PackageReference Include="ModernUO.Serialization.Annotations" Version="2.6.0" />
<PackageReference Include="ModernUO.Serialization.Generator" Version="2.6.4" />
<PackageReference Include="ModernUO.Serialization.Generator" Version="2.7.2" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="Migrations/*.v*.json" />