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, "isRoot": true,
"tools": { "tools": {
"modernuoschemagenerator": { "modernuoschemagenerator": {
"version": "2.6.4", "version": "2.7.2",
"commands": [ "commands": [
"ModernUOSchemaGenerator" "ModernUOSchemaGenerator"
] ]

View file

@ -38,7 +38,7 @@
<PackageReference Include="Zlib.Bindings" Version="1.11.0" /> <PackageReference Include="Zlib.Bindings" Version="1.11.0" />
<PackageReference Include="ModernUO.Serialization.Annotations" Version="2.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>
<ItemGroup> <ItemGroup>
<AdditionalFiles Include="Migrations/*.v*.json" /> <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 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();
}
}
} }

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

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

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

View file

@ -1,78 +1,64 @@
using ModernUO.Serialization;
using Server.Targeting; 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);
} }
else
public override int LabelNumber => 1072896; // runed switch
public override void OnDoubleClick(Mobile from)
{ {
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. return;
from.Target = new InternalTarget(this);
} }
else
if (o is BaseTalisman talisman)
{ {
from.SendLocalizedMessage(1060640); // The item must be in your backpack to use it. if (talisman.Charges == 0)
}
}
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)
{ {
return; talisman.Charges = talisman.MaxCharges;
} _item.Delete();
from.SendLocalizedMessage(1075100); // The item has been recharged.
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.
}
} }
else 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] Summoner = GetRandomSummoner();
public RandomTalisman() : base(GetRandomItemID())
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) if (Summoner.IsItem)
{ {
MaxCharges = GetRandomCharges(); MaxChargeTime = 60;
MaxChargeTime = 1200;
}
} }
else else
{ {
MaxCharges = Utility.RandomMinMax(10, 50); MaxChargeTime = 1800;
if (Summoner.IsItem)
{
MaxChargeTime = 60;
}
else
{
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();
public override void Serialize(IGenericWriter writer) Skill = GetRandomSkill();
{ ExceptionalBonus = GetRandomExceptional();
base.Serialize(writer); SuccessBonus = GetRandomSuccessful();
Charges = MaxCharges;
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
} }
}
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();
}
}

View file

@ -1,117 +1,72 @@
using System; using System;
using ModernUO.Serialization;
namespace Server.Items namespace Server.Items;
[PropertyObject]
[SerializationGenerator(1, false)]
public partial class TalismanAttribute
{ {
[PropertyObject] [SerializableField(0)]
public class TalismanAttribute [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)
{ {
} _type = copy.Type;
_name = copy.Name;
public TalismanAttribute(TalismanAttribute copy) _amount = copy.Amount;
{
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
} }
} }
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 System.Collections.Generic;
using Server.Mobiles; 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, m_Table = new Dictionary<TalismanSlayerName, Type[]>
Bear, {
Vermin, [TalismanSlayerName.Bear] = new[]
Bat, {
Mage, typeof(GrizzlyBear), typeof(BlackBear), typeof(BrownBear), typeof(PolarBear) // , typeof( Grobu )
Beetle, },
Bird, [TalismanSlayerName.Vermin] = new[]
Ice, {
Flame, typeof(RatmanMage), typeof(RatmanMage), typeof(RatmanArcher), typeof(Barracoon), typeof(Ratman),
Bovine 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; if (m == null || !m_Table.TryGetValue(name, out var types) || types == null)
public static void Initialize()
{ {
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; 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;
using System.Collections.Generic; using System.Collections.Generic;
using ModernUO.Serialization;
using Server.ContextMenus; using Server.ContextMenus;
using Server.Items; 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 list.Add(new TalismanReleaseEntry(this));
}
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();
}
} }
} }
public class SummonedAntLion : BaseTalismanSummon private class TalismanReleaseEntry : ContextMenuEntry
{ {
[Constructible] private readonly Mobile m_Mobile;
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);
writer.WriteEncodedInt(0); // version public TalismanReleaseEntry(Mobile m) : base(6118, 3) => m_Mobile = m;
}
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 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"; Effects.PlaySound(m_Mobile,0x201);
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);
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) => 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( public static bool Summon(
BaseCreature creature, bool controlled, Mobile caster, Point3D p, int sound, BaseCreature creature, bool controlled, Mobile caster, Point3D p, int sound,
TimeSpan duration 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) 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.SummonEnd = Core.Now + duration;
creature.MoveToWorld(p, caster.Map); 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 // 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 static readonly Dictionary<BaseCreature, UnsummonTimer> _timers = new();
private BaseCreature _creature; private BaseCreature _creature;
private Action _onUnsummon;
public static void StopTimer(BaseCreature creature) 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; _creature = creature;
ref var timer = ref CollectionsMarshal.GetValueRefOrAddDefault(_timers, creature, out bool exists); 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 // BaseCreature.OnAfterDelete will remove the creature from the timers table
_creature?.Delete(); _creature?.Delete();
_onUnsummon?.Invoke();
} }
} }

View file

@ -39,7 +39,7 @@
<PackageReference Include="Zstd.Binaries" Version="1.6.0" /> <PackageReference Include="Zstd.Binaries" Version="1.6.0" />
<PackageReference Include="ModernUO.Serialization.Annotations" Version="2.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>
<ItemGroup> <ItemGroup>
<AdditionalFiles Include="Migrations/*.v*.json" /> <AdditionalFiles Include="Migrations/*.v*.json" />