fix: Moves containers/bods/traps/etc to serialization generator (#2310)

This commit is contained in:
Kamron Batman 2026-01-07 21:55:55 -08:00 committed by GitHub
parent f4a87a8629
commit c14f361de1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 950 additions and 1199 deletions

View file

@ -1,13 +1,17 @@
using ModernUO.Serialization;
using Server.Accounting;
using Server.Network;
namespace Server.Items;
public class BankBox : Container
[SerializationGenerator(0, false)]
public partial class BankBox : Container
{
public BankBox(Serial serial) : base(serial)
{
}
[SerializableField(0, setter: "private")]
private Mobile _owner;
[SerializableField(1, setter: "private")]
private bool _opened;
public BankBox(Mobile owner) : base(0xE7C)
{
@ -20,10 +24,6 @@ public class BankBox : Container
public override bool IsVirtualItem => true;
public Mobile Owner { get; private set; }
public bool Opened { get; private set; }
public static bool SendDeleteOnClose { get; set; }
public void Open()
@ -45,38 +45,9 @@ public class BankBox : Container
}
}
public override void Serialize(IGenericWriter writer)
[AfterDeserialization]
private void AfterDeserialization()
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(Owner);
writer.Write(Opened);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
switch (version)
{
case 0:
{
Owner = reader.ReadEntity<Mobile>();
Opened = reader.ReadBool();
break;
}
}
if (ItemID == 0xE41)
{
ItemID = 0xE7C;
}
if (Owner == null)
{
Timer.DelayCall(Delete);

View file

@ -1,9 +1,11 @@
using ModernUO.Serialization;
using Server.Accounting;
using Server.Network;
namespace Server.Items;
public class SecureTradeContainer : Container
[SerializationGenerator(0, false)]
public partial class SecureTradeContainer : Container
{
public SecureTradeContainer(SecureTrade trade) : base(0x1E5E)
{
@ -12,10 +14,6 @@ public class SecureTradeContainer : Container
Movable = false;
}
public SecureTradeContainer(Serial serial) : base(serial)
{
}
public SecureTrade Trade { get; }
public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight)
@ -95,18 +93,4 @@ public class SecureTradeContainer : Container
child is VirtualCheck
? AccountGold.Enabled && m.NetState is not { NewSecureTrading: true }
: base.IsChildVisibleTo(m, child);
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

@ -0,0 +1,19 @@
{
"version": 0,
"type": "Server.Items.BankBox",
"properties": [
{
"name": "Owner",
"type": "Server.Mobile",
"rule": "SerializableInterfaceMigrationRule"
},
{
"name": "Opened",
"type": "bool",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
""
]
}
]
}

View file

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

View file

@ -13,8 +13,7 @@ namespace Server.Engines.BulkOrders
public LargeBOD(
int hue, int amountMax, bool requireExeptional, BulkMaterialType material, LargeBulkEntry[] entries
) : base(hue, amountMax, requireExeptional, material) =>
_entries = entries;
) : base(hue, amountMax, requireExeptional, material) => _entries = entries;
public LargeBOD()
{

View file

@ -1,232 +1,162 @@
using System;
using ModernUO.Serialization;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.BulkOrders
namespace Server.Engines.BulkOrders;
[SerializationGenerator(0, false)]
public abstract partial class SmallBOD : BaseBOD
{
public abstract class SmallBOD : BaseBOD
[InvalidateProperties]
[SerializableField(0)]
[SerializedCommandProperty(AccessLevel.GameMaster)]
private int _amountCur;
[SerializableField(1)]
[SerializedCommandProperty(AccessLevel.GameMaster)]
private Type _type;
[InvalidateProperties]
[SerializableField(2)]
[SerializedCommandProperty(AccessLevel.GameMaster)]
private int _number;
[SerializableField(3)]
[SerializedCommandProperty(AccessLevel.GameMaster)]
private int _graphic;
public SmallBOD(
int hue, int amountCur, int amountMax, Type type, int number, int graphic, bool requireExeptional,
BulkMaterialType material
) : base(hue, amountMax, requireExeptional, material)
{
private int m_AmountCur;
private int m_Number;
_type = type;
_graphic = graphic;
_amountCur = amountCur;
_number = number;
}
public SmallBOD(
int hue, int amountCur, int amountMax, Type type, int number, int graphic, bool requireExeptional,
BulkMaterialType material
) : base(hue, amountMax, requireExeptional, material)
public SmallBOD()
{
}
[CommandProperty(AccessLevel.GameMaster)]
public override bool Complete => _amountCur == AmountMax;
public override int LabelNumber => 1045151; // a bulk order deed
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1060654); // small bulk order
if (RequireExceptional)
{
Type = type;
Graphic = graphic;
m_AmountCur = amountCur;
m_Number = number;
list.Add(1045141); // All items must be exceptional.
}
public SmallBOD()
if (Material != BulkMaterialType.None)
{
list.Add(SmallBODGump.GetMaterialNumberFor(Material)); // All items must be made with x material.
}
public SmallBOD(Serial serial) : base(serial)
{
}
list.Add(1060656, AmountMax); // amount to make: ~1_val~
list.Add(1060658, $"{_number:#}\t{_amountCur}"); // ~1_val~: ~2_val~
}
[CommandProperty(AccessLevel.GameMaster)]
public int AmountCur
public override void OnDoubleClick(Mobile from)
{
if (IsChildOf(from.Backpack) || InSecureTrade || RootParent is PlayerVendor)
{
get => m_AmountCur;
set
from.SendGump(new SmallBODGump(this));
}
else
{
from.SendLocalizedMessage(1045156); // You must have the deed in your backpack to use it.
}
}
public override void OnDoubleClickNotAccessible(Mobile from)
{
OnDoubleClick(from);
}
public override void OnDoubleClickSecureTrade(Mobile from)
{
OnDoubleClick(from);
}
public static BulkMaterialType GetMaterial(CraftResource resource)
{
return resource switch
{
CraftResource.DullCopper => BulkMaterialType.DullCopper,
CraftResource.ShadowIron => BulkMaterialType.ShadowIron,
CraftResource.Copper => BulkMaterialType.Copper,
CraftResource.Bronze => BulkMaterialType.Bronze,
CraftResource.Gold => BulkMaterialType.Gold,
CraftResource.Agapite => BulkMaterialType.Agapite,
CraftResource.Verite => BulkMaterialType.Verite,
CraftResource.Valorite => BulkMaterialType.Valorite,
CraftResource.SpinedLeather => BulkMaterialType.Spined,
CraftResource.HornedLeather => BulkMaterialType.Horned,
CraftResource.BarbedLeather => BulkMaterialType.Barbed,
_ => BulkMaterialType.None
};
}
public override void EndCombine(Mobile from, Item item)
{
var objectType = item.GetType();
if (_amountCur >= AmountMax)
{
// The maximum amount of requested items have already been combined to this deed.
from.SendLocalizedMessage(1045166);
return;
}
var armor = item as BaseArmor;
var clothing = item as BaseClothing;
var weapon = item as BaseWeapon;
if (Type == null || objectType != Type && !objectType.IsSubclassOf(Type) || armor == null && clothing == null && weapon == null)
{
from.SendLocalizedMessage(1045169); // The item is not in the request.
}
else
{
var material = GetMaterial(armor?.Resource ?? clothing?.Resource ?? CraftResource.None);
if (Material >= BulkMaterialType.DullCopper && Material <= BulkMaterialType.Valorite && material != Material)
{
m_AmountCur = value;
InvalidateProperties();
from.SendLocalizedMessage(1045168); // The item is not made from the requested ore.
}
}
[CommandProperty(AccessLevel.GameMaster)]
public Type Type { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int Number
{
get => m_Number;
set
else if (Material >= BulkMaterialType.Spined && Material <= BulkMaterialType.Barbed && material != Material)
{
m_Number = value;
InvalidateProperties();
from.SendLocalizedMessage(1049352); // The item is not made from the requested leather type.
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int Graphic { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public override bool Complete => m_AmountCur == AmountMax;
public override int LabelNumber => 1045151; // a bulk order deed
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1060654); // small bulk order
if (RequireExceptional)
else if (RequireExceptional && (armor?.Quality == ArmorQuality.Exceptional ||
clothing?.Quality == ClothingQuality.Exceptional ||
weapon?.Quality == WeaponQuality.Exceptional))
{
list.Add(1045141); // All items must be exceptional.
from.SendLocalizedMessage(1045167); // The item must be exceptional.
}
if (Material != BulkMaterialType.None)
else
{
list.Add(SmallBODGump.GetMaterialNumberFor(Material)); // All items must be made with x material.
}
item.Delete();
++AmountCur;
list.Add(1060656, AmountMax); // amount to make: ~1_val~
list.Add(1060658, $"{m_Number:#}\t{m_AmountCur}"); // ~1_val~: ~2_val~
}
public override void OnDoubleClick(Mobile from)
{
if (IsChildOf(from.Backpack) || InSecureTrade || RootParent is PlayerVendor)
{
from.SendLocalizedMessage(1045170); // The item has been combined with the deed.
from.SendGump(new SmallBODGump(this));
}
else
{
from.SendLocalizedMessage(1045156); // You must have the deed in your backpack to use it.
}
}
public override void OnDoubleClickNotAccessible(Mobile from)
{
OnDoubleClick(from);
}
public override void OnDoubleClickSecureTrade(Mobile from)
{
OnDoubleClick(from);
}
public static BulkMaterialType GetMaterial(CraftResource resource)
{
return resource switch
{
CraftResource.DullCopper => BulkMaterialType.DullCopper,
CraftResource.ShadowIron => BulkMaterialType.ShadowIron,
CraftResource.Copper => BulkMaterialType.Copper,
CraftResource.Bronze => BulkMaterialType.Bronze,
CraftResource.Gold => BulkMaterialType.Gold,
CraftResource.Agapite => BulkMaterialType.Agapite,
CraftResource.Verite => BulkMaterialType.Verite,
CraftResource.Valorite => BulkMaterialType.Valorite,
CraftResource.SpinedLeather => BulkMaterialType.Spined,
CraftResource.HornedLeather => BulkMaterialType.Horned,
CraftResource.BarbedLeather => BulkMaterialType.Barbed,
_ => BulkMaterialType.None
};
}
public override void EndCombine(Mobile from, Item item)
{
var objectType = item.GetType();
if (m_AmountCur >= AmountMax)
{
// The maximum amount of requested items have already been combined to this deed.
from.SendLocalizedMessage(1045166);
}
else if (Type == null || objectType != Type && !objectType.IsSubclassOf(Type) ||
item is not BaseWeapon && item is not BaseArmor && item is not BaseClothing)
{
from.SendLocalizedMessage(1045169); // The item is not in the request.
}
else
{
var armor = item as BaseArmor;
var clothing = item as BaseClothing;
var material = GetMaterial(armor?.Resource ?? clothing?.Resource ?? CraftResource.None);
if (Material >= BulkMaterialType.DullCopper && Material <= BulkMaterialType.Valorite &&
material != Material)
if (_amountCur < AmountMax)
{
from.SendLocalizedMessage(1045168); // The item is not made from the requested ore.
BeginCombine(from);
}
else if (Material >= BulkMaterialType.Spined && Material <= BulkMaterialType.Barbed &&
material != Material)
{
from.SendLocalizedMessage(1049352); // The item is not made from the requested leather type.
}
else
{
bool isExceptional;
if (item is BaseWeapon weapon)
{
isExceptional = weapon.Quality == WeaponQuality.Exceptional;
}
else if (armor != null)
{
isExceptional = armor.Quality == ArmorQuality.Exceptional;
}
else
{
isExceptional = clothing.Quality == ClothingQuality.Exceptional;
}
if (RequireExceptional && !isExceptional)
{
from.SendLocalizedMessage(1045167); // The item must be exceptional.
}
else
{
item.Delete();
++AmountCur;
from.SendLocalizedMessage(1045170); // The item has been combined with the deed.
from.SendGump(new SmallBODGump(this));
if (m_AmountCur < AmountMax)
{
BeginCombine(from);
}
}
}
}
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(m_AmountCur);
writer.Write(Type?.FullName);
writer.Write(m_Number);
writer.Write(Graphic);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
switch (version)
{
case 0:
{
m_AmountCur = reader.ReadInt();
var type = reader.ReadString();
if (type != null)
{
Type = AssemblyHandler.FindTypeByFullName(type);
}
m_Number = reader.ReadInt();
Graphic = reader.ReadInt();
break;
}
}
}
}

View file

@ -101,7 +101,7 @@ public partial class RaiseSwitch : Item
}
}
[AfterDeserialization]
[AfterDeserialization(false)]
private void AfterDeserialization()
{
Reset();
@ -109,38 +109,31 @@ public partial class RaiseSwitch : Item
private class ResetTimer : Timer
{
private readonly RaiseSwitch m_RaiseSwitch;
private readonly RaiseSwitch _raiseSwitch;
public ResetTimer(RaiseSwitch raiseSwitch, TimeSpan delay) : base(delay)
{
m_RaiseSwitch = raiseSwitch;
}
public ResetTimer(RaiseSwitch raiseSwitch, TimeSpan delay) : base(delay) => _raiseSwitch = raiseSwitch;
protected override void OnTick()
{
if (m_RaiseSwitch.Deleted)
if (_raiseSwitch.Deleted)
{
return;
}
m_RaiseSwitch._resetTimer = null;
m_RaiseSwitch.Reset();
_raiseSwitch._resetTimer = null;
_raiseSwitch.Reset();
}
}
}
public class DisappearingRaiseSwitch : RaiseSwitch
[SerializationGenerator(0)]
public partial class DisappearingRaiseSwitch : RaiseSwitch
{
[Constructible]
public DisappearingRaiseSwitch() : base(0x108F)
{
}
public DisappearingRaiseSwitch(Serial serial) : base(serial)
{
}
public int CurrentRange => Visible ? 3 : 2;
public override bool HandlesOnMovement => true;
@ -177,6 +170,7 @@ public class DisappearingRaiseSwitch : RaiseSwitch
}
}
[AfterDeserialization(false)]
public void Refresh()
{
foreach (var mob in GetMobilesInRange(CurrentRange))
@ -188,25 +182,4 @@ public class DisappearingRaiseSwitch : RaiseSwitch
}
}
}
public override void Serialize(IGenericWriter writer)
{
if (RaisableItem?.Deleted == true)
{
RaisableItem = null;
}
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadEncodedInt();
Timer.StartTimer(Refresh);
}
}

View file

@ -202,7 +202,8 @@ public class TheJoysOfLife : MLQuest
}
[QuesterName("Maul")]
public class MaulTheBear : GrizzlyBear
[SerializationGenerator(0, false)]
public partial class MaulTheBear : GrizzlyBear
{
[Constructible]
public MaulTheBear()
@ -212,30 +213,12 @@ public class MaulTheBear : GrizzlyBear
Tamable = false;
}
public MaulTheBear(Serial serial)
: base(serial)
{
}
public override bool IsInvulnerable => true;
public override string DefaultName => "Maul";
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 class Strongroot : Treefellow
[SerializationGenerator(0, false)]
public partial class Strongroot : Treefellow
{
[Constructible]
public Strongroot()
@ -244,27 +227,8 @@ public class Strongroot : Treefellow
FightMode = FightMode.None;
}
public Strongroot(Serial serial)
: base(serial)
{
}
public override bool IsInvulnerable => true;
public override string DefaultName => "Strongroot";
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();
}
}
[SerializationGenerator(0, false)]

View file

@ -104,18 +104,14 @@ public class GuileIrkAndSpite : MLQuest
}
}
public class Lissbet : BaseEscortable
[SerializationGenerator(0, false)]
public partial class Lissbet : BaseEscortable
{
[Constructible]
public Lissbet()
{
}
public Lissbet(Serial serial)
: base(serial)
{
}
public override bool StaticMLQuester => true;
public override bool InitialInnocent => true;
public override string DefaultName => "Lissbet";
@ -156,20 +152,6 @@ public class Lissbet : BaseEscortable
AddItem(new FancyShirt(Utility.RandomYellowHue()));
AddItem(new Sandals());
}
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();
}
}
[SerializationGenerator(0, false)]

View file

@ -642,7 +642,8 @@ public class ItsHammerTime : MLQuest
}
}
public class Aelorn : KeeperOfChivalry
[SerializationGenerator(0, false)]
public partial class Aelorn : KeeperOfChivalry
{
[Constructible]
public Aelorn()
@ -667,11 +668,6 @@ public class Aelorn : KeeperOfChivalry
SetSkill(SkillName.Chivalry, 120.0);
}
public Aelorn(Serial serial)
: base(serial)
{
}
public override string DefaultName => "Aelorn";
public override bool CanShout => true;
@ -691,20 +687,6 @@ public class Aelorn : KeeperOfChivalry
AddItem(new PlateGorget());
AddItem(new OrderShield());
}
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();
}
}
[SerializationGenerator(0, false)]

View file

@ -1,144 +1,130 @@
using System;
using ModernUO.Serialization;
using Server.Engines.MLQuests.Gumps;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.MLQuests.Mobiles
namespace Server.Engines.MLQuests.Mobiles;
[SerializationGenerator(0)]
public partial class SirHelper : Mage
{
public class SirHelper : Mage
private static readonly Gump m_Gump = new InfoNPCGump(1078029, 1078028);
private static readonly TimeSpan m_ShoutDelay = TimeSpan.FromSeconds(20);
private static readonly TimeSpan
m_ShoutCooldown = TimeSpan.FromDays(1); // TODO: Verify, could be a lot longer... or until a restart even
private DateTime m_NextShout;
[Constructible]
public SirHelper()
{
private static readonly Gump m_Gump = new InfoNPCGump(1078029, 1078028);
private static readonly TimeSpan m_ShoutDelay = TimeSpan.FromSeconds(20);
Title = "the Profession Guide"; // TODO: Don't display in paperdoll
private static readonly TimeSpan
m_ShoutCooldown = TimeSpan.FromDays(1); // TODO: Verify, could be a lot longer... or until a restart even
Hue = 0x83EA;
private DateTime m_NextShout;
Direction = Direction.South;
Frozen = true;
}
[Constructible]
public SirHelper()
public override string DefaultName => "Sir Helper";
public override bool IsActiveVendor => false;
public override void InitSBInfo()
{
}
public override bool GetGender() => false;
public override void CheckMorph()
{
}
public override void InitOutfit()
{
HairItemID = 0x203C;
FacialHairItemID = 0x204D;
HairHue = FacialHairHue = 0x8A7;
AddItem(new Sandals());
AddItem(new Cloak
{
Title = "the Profession Guide"; // TODO: Don't display in paperdoll
ItemID = 0x26AD,
Hue = 0x455
});
Hue = 0x83EA;
AddItem(new Robe
{
ItemID = 0x26AE,
Hue = 0x4AB
});
Direction = Direction.South;
Frozen = true;
AddItem(new Backpack
{
Movable = false
});
}
public override void OnDoubleClick(Mobile from)
{
if (from.BeginAction(this))
{
Timer.StartTimer(m_ShoutCooldown, () => EndLock(from));
}
public SirHelper(Serial serial)
: base(serial)
MLQuestSystem.TurnToFace(this, from);
from.SendGump(m_Gump);
// Paperdoll doesn't open
// base.OnDoubleClick( from );
}
public override void OnThink()
{
base.OnThink();
if (m_NextShout > Core.Now)
{
return;
}
public override string DefaultName => "Sir Helper";
public override bool IsActiveVendor => false;
var buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLocalizedLength("")].InitializePacket();
public override void InitSBInfo()
foreach (var state in GetClientsInRange(12))
{
}
var m = state.Mobile;
public override bool GetGender() => false;
public override void CheckMorph()
{
}
public override void InitOutfit()
{
HairItemID = 0x203C;
FacialHairItemID = 0x204D;
HairHue = FacialHairHue = 0x8A7;
AddItem(new Sandals());
Item item;
item = new Cloak();
item.ItemID = 0x26AD;
item.Hue = 0x455;
AddItem(item);
item = new Robe();
item.ItemID = 0x26AE;
item.Hue = 0x4AB;
AddItem(item);
item = new Backpack();
item.Movable = false;
AddItem(item);
}
public override void OnDoubleClick(Mobile from)
{
if (from.CanBeginAction(this))
if (m.CanSee(this) && m.InLOS(this) && m.CanBeginAction(this))
{
from.BeginAction(this);
Timer.StartTimer(m_ShoutCooldown, () => EndLock(from));
}
// Double Click On Me For Help!
var length = OutgoingMessagePackets.CreateMessageLocalized(
buffer, Serial, Body, MessageType.Regular, 946, 3, 1078099, Name
);
MLQuestSystem.TurnToFace(this, from);
from.SendGump(m_Gump);
// Paperdoll doesn't open
// base.OnDoubleClick( from );
}
public override void OnThink()
{
base.OnThink();
if (m_NextShout > Core.Now)
{
return;
}
var buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLocalizedLength("")].InitializePacket();
foreach (var state in GetClientsInRange(12))
{
var m = state.Mobile;
if (m.CanSee(this) && m.InLOS(this) && m.CanBeginAction(this))
if (length != buffer.Length)
{
// Double Click On Me For Help!
var length = OutgoingMessagePackets.CreateMessageLocalized(
buffer, Serial, Body, MessageType.Regular, 946, 3, 1078099, Name
);
if (length != buffer.Length)
{
buffer = buffer[..length];
}
state.Send(buffer);
buffer = buffer[..length];
}
state.Send(buffer);
}
m_NextShout = Core.Now + m_ShoutDelay;
}
private void EndLock(Mobile m)
{
m.EndAction(this);
}
m_NextShout = Core.Now + m_ShoutDelay;
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
private void EndLock(Mobile m)
{
m.EndAction(this);
}
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
Frozen = true;
}
[AfterDeserialization]
private void AfterDeserialization()
{
Frozen = true;
}
}

View file

@ -85,80 +85,29 @@ public partial class CharacterStatueMaker : Item, IRewardItem
}
}
public class MarbleStatueMaker : CharacterStatueMaker
[SerializationGenerator(0)]
public partial class MarbleStatueMaker : CharacterStatueMaker
{
[Constructible]
public MarbleStatueMaker() : base(StatueType.Marble)
{
}
public MarbleStatueMaker(Serial serial) : base(serial)
{
}
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 JadeStatueMaker : CharacterStatueMaker
[SerializationGenerator(0)]
public partial class JadeStatueMaker : CharacterStatueMaker
{
[Constructible]
public JadeStatueMaker() : base(StatueType.Jade)
{
}
public JadeStatueMaker(Serial serial) : base(serial)
{
}
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 BronzeStatueMaker : CharacterStatueMaker
[SerializationGenerator(0)]
public partial class BronzeStatueMaker : CharacterStatueMaker
{
[Constructible]
public BronzeStatueMaker() : base(StatueType.Bronze)
{
}
public BronzeStatueMaker(Serial serial) : base(serial)
{
}
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();
}
}

View file

@ -1,184 +1,162 @@
using System;
using ModernUO.Serialization;
using Server.Engines.Craft;
using Server.Multis;
using Server.Spells;
using Server.Targeting;
namespace Server.Items
namespace Server.Items;
[Flippable(0x14F0, 0x14EF)]
[SerializationGenerator(2)]
public abstract partial class BaseAddonContainerDeed : Item, ICraftable
{
[Flippable(0x14F0, 0x14EF)]
public abstract class BaseAddonContainerDeed : Item, ICraftable
public BaseAddonContainerDeed() : base(0x14F0)
{
private CraftResource m_Resource;
public BaseAddonContainerDeed() : base(0x14F0)
if (!Core.AOS)
{
if (!Core.AOS)
LootType = LootType.Newbied;
}
}
public override double DefaultWeight => 1.0;
public abstract BaseAddonContainer Addon { get; }
[SerializableProperty(0)]
[CommandProperty(AccessLevel.GameMaster)]
public CraftResource Resource
{
get => _resource;
set
{
if (_resource != value)
{
LootType = LootType.Newbied;
_resource = value;
Hue = CraftResources.GetHue(_resource);
InvalidateProperties();
this.MarkDirty();
}
}
}
public BaseAddonContainerDeed(Serial serial) : base(serial)
public virtual int OnCraft(
int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes,
BaseTool tool, CraftItem craftItem, int resHue
)
{
var resourceType = typeRes ?? craftItem.Resources[0].ItemType;
Resource = CraftResources.GetFromType(resourceType);
var context = craftSystem.GetContext(from);
if (context?.DoNotColor == true)
{
Hue = 0;
}
public override double DefaultWeight => 1.0;
return quality;
}
public abstract BaseAddonContainer Addon { get; }
private void Deserialize(IGenericReader reader, int version)
{
_resource = (CraftResource)reader.ReadInt();
}
[CommandProperty(AccessLevel.GameMaster)]
public CraftResource Resource
public override void OnDoubleClick(Mobile from)
{
if (IsChildOf(from.Backpack))
{
get => m_Resource;
set
{
if (m_Resource != value)
{
m_Resource = value;
Hue = CraftResources.GetHue(m_Resource);
from.Target = new InternalTarget(this);
}
else
{
from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used.
}
}
InvalidateProperties();
}
}
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
if (!CraftResources.IsStandard(_resource))
{
list.Add(CraftResources.GetLocalizationNumber(_resource));
}
}
private class InternalTarget : Target
{
private readonly BaseAddonContainerDeed m_Deed;
public InternalTarget(BaseAddonContainerDeed deed) : base(-1, true, TargetFlags.None)
{
m_Deed = deed;
CheckLOS = false;
}
public virtual int OnCraft(
int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes,
BaseTool tool, CraftItem craftItem, int resHue
)
protected override void OnTarget(Mobile from, object targeted)
{
var resourceType = typeRes ?? craftItem.Resources[0].ItemType;
var p = targeted as IPoint3D;
var map = from.Map;
Resource = CraftResources.GetFromType(resourceType);
var context = craftSystem.GetContext(from);
if (context?.DoNotColor == true)
if (p == null || map == null || m_Deed.Deleted)
{
Hue = 0;
return;
}
return quality;
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
// version 1
writer.Write((int)m_Resource);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
m_Resource = version switch
if (!m_Deed.IsChildOf(from.Backpack))
{
1 => (CraftResource)reader.ReadInt(),
_ => m_Resource
};
}
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
return;
}
public override void OnDoubleClick(Mobile from)
{
if (IsChildOf(from.Backpack))
var addon = m_Deed.Addon;
addon.Resource = m_Deed.Resource;
SpellHelper.GetSurfaceTop(ref p);
BaseHouse house = null;
var res = addon.CouldFit(p, map, from, ref house);
if (res == AddonFitResult.Valid)
{
from.Target = new InternalTarget(this);
addon.MoveToWorld(new Point3D(p), map);
}
else if (res == AddonFitResult.Blocked)
{
from.SendLocalizedMessage(500269); // You cannot build that there.
}
else if (res == AddonFitResult.NotInHouse)
{
from.SendLocalizedMessage(500274); // You can only place this in a house that you own!
}
else if (res == AddonFitResult.DoorsNotClosed)
{
from.SendMessage("You must close all house doors before placing this.");
}
else if (res == AddonFitResult.DoorTooClose)
{
from.SendLocalizedMessage(500271); // You cannot build near the door.
}
else if (res == AddonFitResult.NoWall)
{
from.SendLocalizedMessage(500268); // This object needs to be mounted on something.
}
if (res == AddonFitResult.Valid)
{
m_Deed.Delete();
house.Addons.Add(addon);
house.AddSecure(from, addon);
}
else
{
from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used.
}
}
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
if (!CraftResources.IsStandard(m_Resource))
{
list.Add(CraftResources.GetLocalizationNumber(m_Resource));
}
}
private class InternalTarget : Target
{
private readonly BaseAddonContainerDeed m_Deed;
public InternalTarget(BaseAddonContainerDeed deed) : base(-1, true, TargetFlags.None)
{
m_Deed = deed;
CheckLOS = false;
}
protected override void OnTarget(Mobile from, object targeted)
{
var p = targeted as IPoint3D;
var map = from.Map;
if (p == null || map == null || m_Deed.Deleted)
{
return;
}
if (m_Deed.IsChildOf(from.Backpack))
{
var addon = m_Deed.Addon;
addon.Resource = m_Deed.Resource;
SpellHelper.GetSurfaceTop(ref p);
BaseHouse house = null;
var res = addon.CouldFit(p, map, from, ref house);
if (res == AddonFitResult.Valid)
{
addon.MoveToWorld(new Point3D(p), map);
}
else if (res == AddonFitResult.Blocked)
{
from.SendLocalizedMessage(500269); // You cannot build that there.
}
else if (res == AddonFitResult.NotInHouse)
{
from.SendLocalizedMessage(500274); // You can only place this in a house that you own!
}
else if (res == AddonFitResult.DoorsNotClosed)
{
from.SendMessage("You must close all house doors before placing this.");
}
else if (res == AddonFitResult.DoorTooClose)
{
from.SendLocalizedMessage(500271); // You cannot build near the door.
}
else if (res == AddonFitResult.NoWall)
{
from.SendLocalizedMessage(500268); // This object needs to be mounted on something.
}
if (res == AddonFitResult.Valid)
{
m_Deed.Delete();
house.Addons.Add(addon);
house.AddSecure(from, addon);
}
else
{
addon.Delete();
}
}
else
{
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
}
addon.Delete();
}
}
}

View file

@ -1,6 +1,9 @@
using ModernUO.Serialization;
namespace Server.Items;
public class RandomTalisman : BaseTalisman
[SerializationGenerator(0, false)]
public partial class RandomTalisman : BaseTalisman
{
[Constructible]
public RandomTalisman() : base(GetRandomItemID())
@ -40,22 +43,4 @@ public class RandomTalisman : BaseTalisman
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();
}
}
}

View file

@ -1,4 +1,5 @@
using System;
using ModernUO.Serialization;
using Server.Spells;
namespace Server.Items;
@ -11,31 +12,25 @@ public enum SawTrapType
NorthFloor
}
public class SawTrap : BaseTrap
[SerializationGenerator(0, false)]
public partial class SawTrap : BaseTrap
{
[Constructible]
public SawTrap(SawTrapType type = SawTrapType.NorthFloor) : base(GetBaseID(type))
{
}
public SawTrap(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public SawTrapType Type
{
get
get => ItemID switch
{
return ItemID switch
{
0x1103 => SawTrapType.NorthWall,
0x1116 => SawTrapType.WestWall,
0x11AC => SawTrapType.NorthFloor,
0x11B1 => SawTrapType.WestFloor,
_ => SawTrapType.NorthWall
};
}
0x1103 => SawTrapType.NorthWall,
0x1116 => SawTrapType.WestWall,
0x11AC => SawTrapType.NorthFloor,
0x11B1 => SawTrapType.WestFloor,
_ => SawTrapType.NorthWall
};
set => ItemID = GetBaseID(value);
}
@ -44,9 +39,8 @@ public class SawTrap : BaseTrap
public override int PassiveTriggerRange => 0;
public override TimeSpan ResetDelay => TimeSpan.FromSeconds(0.0);
public static int GetBaseID(SawTrapType type)
{
return type switch
public static int GetBaseID(SawTrapType type) =>
type switch
{
SawTrapType.NorthWall => 0x1103,
SawTrapType.WestWall => 0x1116,
@ -54,7 +48,6 @@ public class SawTrap : BaseTrap
SawTrapType.WestFloor => 0x11B1,
_ => 0
};
}
public override void OnTrigger(Mobile from)
{
@ -70,18 +63,4 @@ public class SawTrap : BaseTrap
from.LocalOverheadMessage(MessageType.Regular, 0x22, 500853); // You stepped onto a blade trap!
}
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

@ -0,0 +1,35 @@
{
"version": 0,
"type": "Server.Engines.BulkOrders.SmallBOD",
"properties": [
{
"name": "AmountCur",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
""
]
},
{
"name": "Type",
"type": "System.Type",
"rule": "PrimitiveTypeMigrationRule"
},
{
"name": "Number",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
""
]
},
{
"name": "Graphic",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
""
]
}
]
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Engines.MLQuests.Definitions.Aelorn"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Engines.MLQuests.Definitions.Lissbet"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Engines.MLQuests.Definitions.MaulTheBear"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Engines.MLQuests.Definitions.Strongroot"
}

View file

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

View file

@ -0,0 +1,11 @@
{
"version": 2,
"type": "Server.Items.BaseAddonContainerDeed",
"properties": [
{
"name": "Resource",
"type": "Server.Items.CraftResource",
"rule": "EnumMigrationRule"
}
]
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Misc.WeatherMap"
}

View file

@ -0,0 +1,15 @@
{
"version": 0,
"type": "Server.Mobiles.GenericBuyInfo.DisplayCache",
"properties": [
{
"name": "Mobiles",
"type": "System.Collections.Generic.List\u003CServer.Mobile\u003E",
"rule": "ListMigrationRule",
"ruleArguments": [
"Server.Mobile",
"SerializableInterfaceMigrationRule"
]
}
]
}

View file

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

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Multis.BaseHouse.TransferItem"
}

View file

@ -1,245 +1,135 @@
using System;
using System.Collections.Generic;
using ModernUO.Serialization;
using Server.Items;
using Server.Network;
namespace Server.Misc
namespace Server.Misc;
public partial class Weather
{
public class Weather
private static Map[] m_Facets;
private static readonly Dictionary<Map, List<Weather>> m_WeatherByFacet = new();
private bool m_Active;
private bool m_ExtremeTemperature;
private int m_Stage;
public Weather(
Map facet, Rectangle2D[] area, int temperature, int chanceOfPrecipitation, int chanceOfExtremeTemperature,
TimeSpan interval
)
{
private static Map[] m_Facets;
private static readonly Dictionary<Map, List<Weather>> m_WeatherByFacet = new();
private bool m_Active;
private bool m_ExtremeTemperature;
Facet = facet;
Area = area;
Temperature = temperature;
ChanceOfPrecipitation = chanceOfPrecipitation;
ChanceOfExtremeTemperature = chanceOfExtremeTemperature;
private int m_Stage;
var list = GetWeatherList(facet);
public Weather(
Map facet, Rectangle2D[] area, int temperature, int chanceOfPrecipitation, int chanceOfExtremeTemperature,
TimeSpan interval
)
list?.Add(this);
Timer.DelayCall(
TimeSpan.FromSeconds((0.2 + Utility.RandomDouble() * 0.8) * interval.TotalSeconds),
interval,
OnTick
);
}
public Map Facet { get; }
public Rectangle2D[] Area { get; set; }
public int Temperature { get; set; }
public int ChanceOfPrecipitation { get; set; }
public int ChanceOfExtremeTemperature { get; set; }
// For dynamic weather:
public Rectangle2D Bounds { get; set; }
public int MoveSpeed { get; set; }
public int MoveAngleX { get; set; }
public int MoveAngleY { get; set; }
public static void Initialize()
{
m_Facets = [Map.Felucca, Map.Trammel];
/* Static weather:
*
* Format:
* AddWeather( temperature, chanceOfPrecipitation, chanceOfExtremeTemperature, <area ...> );
*/
// ice island
AddWeather(
-15,
100,
5,
new Rectangle2D(3850, 160, 390, 320),
new Rectangle2D(3900, 480, 380, 180),
new Rectangle2D(4160, 660, 150, 110)
);
// covetous entrance, around vesper and minoc
AddWeather(+15, 50, 5, new Rectangle2D(2425, 725, 250, 250));
// despise entrance, north of britain
AddWeather(+15, 50, 5, new Rectangle2D(1245, 1045, 250, 250));
/* Dynamic weather:
*
* Format:
* AddDynamicWeather( temperature, chanceOfPrecipitation, chanceOfExtremeTemperature, moveSpeed, width, height, bounds );
*/
for (var i = 0; i < 15; ++i)
{
Facet = facet;
Area = area;
Temperature = temperature;
ChanceOfPrecipitation = chanceOfPrecipitation;
ChanceOfExtremeTemperature = chanceOfExtremeTemperature;
AddDynamicWeather(+15, 100, 5, 8, 400, 400, new Rectangle2D(0, 0, 5120, 4096));
}
}
var list = GetWeatherList(facet);
list?.Add(this);
Timer.DelayCall(
TimeSpan.FromSeconds((0.2 + Utility.RandomDouble() * 0.8) * interval.TotalSeconds),
interval,
OnTick
);
public static List<Weather> GetWeatherList(Map facet)
{
if (facet == null)
{
return null;
}
public Map Facet { get; }
public Rectangle2D[] Area { get; set; }
public int Temperature { get; set; }
public int ChanceOfPrecipitation { get; set; }
public int ChanceOfExtremeTemperature { get; set; }
// For dynamic weather:
public Rectangle2D Bounds { get; set; }
public int MoveSpeed { get; set; }
public int MoveAngleX { get; set; }
public int MoveAngleY { get; set; }
public static void Initialize()
if (!m_WeatherByFacet.TryGetValue(facet, out var list))
{
m_Facets = new[] { Map.Felucca, Map.Trammel };
/* Static weather:
*
* Format:
* AddWeather( temperature, chanceOfPercipitation, chanceOfExtremeTemperature, <area ...> );
*/
// ice island
AddWeather(
-15,
100,
5,
new Rectangle2D(3850, 160, 390, 320),
new Rectangle2D(3900, 480, 380, 180),
new Rectangle2D(4160, 660, 150, 110)
);
// covetous entrance, around vesper and minoc
AddWeather(+15, 50, 5, new Rectangle2D(2425, 725, 250, 250));
// despise entrance, north of britain
AddWeather(+15, 50, 5, new Rectangle2D(1245, 1045, 250, 250));
/* Dynamic weather:
*
* Format:
* AddDynamicWeather( temperature, chanceOfPercipitation, chanceOfExtremeTemperature, moveSpeed, width, height, bounds );
*/
for (var i = 0; i < 15; ++i)
{
AddDynamicWeather(+15, 100, 5, 8, 400, 400, new Rectangle2D(0, 0, 5120, 4096));
}
m_WeatherByFacet[facet] = list = [];
}
public static List<Weather> GetWeatherList(Map facet)
return list;
}
public static void AddDynamicWeather(
int temperature, int chanceOfPrecipitation, int chanceOfExtremeTemperature, int moveSpeed, int width, int height,
Rectangle2D bounds
)
{
for (var i = 0; i < m_Facets.Length; ++i)
{
if (facet == null)
{
return null;
}
if (!m_WeatherByFacet.TryGetValue(facet, out var list))
{
m_WeatherByFacet[facet] = list = new List<Weather>();
}
return list;
}
public static void AddDynamicWeather(
int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, int moveSpeed, int width, int height,
Rectangle2D bounds
)
{
for (var i = 0; i < m_Facets.Length; ++i)
{
var area = new Rectangle2D();
var isValid = false;
for (var j = 0; j < 10; ++j)
{
area = new Rectangle2D(
bounds.X + Utility.Random(bounds.Width - width),
bounds.Y + Utility.Random(bounds.Height - height),
width,
height
);
if (!CheckWeatherConflict(m_Facets[i], null, area))
{
isValid = true;
}
if (isValid)
{
break;
}
}
if (!isValid)
{
continue;
}
new Weather(
m_Facets[i],
new[] { area },
temperature,
chanceOfPercipitation,
chanceOfExtremeTemperature,
TimeSpan.FromSeconds(30.0)
)
{ Bounds = bounds, MoveSpeed = moveSpeed };
}
}
public static void AddWeather(
int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, params Rectangle2D[] area
)
{
for (var i = 0; i < m_Facets.Length; ++i)
{
new Weather(
m_Facets[i],
area,
temperature,
chanceOfPercipitation,
chanceOfExtremeTemperature,
TimeSpan.FromSeconds(30.0)
);
}
}
public static bool CheckWeatherConflict(Map facet, Weather exclude, Rectangle2D area)
{
var list = GetWeatherList(facet);
if (list == null)
{
return false;
}
for (var i = 0; i < list.Count; ++i)
{
var w = list[i];
if (w != exclude && w.IntersectsWith(area))
{
return true;
}
}
return false;
}
public static bool CheckIntersection(Rectangle2D r1, Rectangle2D r2) => r1.X < r2.X + r2.Width &&
r2.X < r1.X + r1.Width &&
r1.Y < r2.Y + r2.Height &&
r2.Y < r1.Y + r1.Height;
public static bool CheckContains(Rectangle2D big, Rectangle2D small) =>
small.X >= big.X && small.Y >= big.Y && small.X + small.Width <= big.X + big.Width
&& small.Y + small.Height <= big.Y + big.Height;
public virtual bool IntersectsWith(Rectangle2D area)
{
for (var i = 0; i < Area.Length; ++i)
{
if (CheckIntersection(area, Area[i]))
{
return true;
}
}
return false;
}
public virtual void Reposition()
{
if (Area.Length == 0)
{
return;
}
var width = Area[0].Width;
var height = Area[0].Height;
var area = new Rectangle2D();
var isValid = false;
for (var j = 0; j < 10; ++j)
{
area = new Rectangle2D(
Bounds.X + Utility.Random(Bounds.Width - width),
Bounds.Y + Utility.Random(Bounds.Height - height),
bounds.X + Utility.Random(bounds.Width - width),
bounds.Y + Utility.Random(bounds.Height - height),
width,
height
);
if (!CheckWeatherConflict(Facet, this, area))
if (!CheckWeatherConflict(m_Facets[i], null, area))
{
isValid = true;
}
@ -252,181 +142,271 @@ namespace Server.Misc
if (!isValid)
{
return;
continue;
}
Area[0] = area;
new Weather(
m_Facets[i],
[area],
temperature,
chanceOfPrecipitation,
chanceOfExtremeTemperature,
TimeSpan.FromSeconds(30.0)
)
{ Bounds = bounds, MoveSpeed = moveSpeed };
}
}
public static void AddWeather(
int temperature, int chanceOfPrecipitation, int chanceOfExtremeTemperature, params Rectangle2D[] area
)
{
for (var i = 0; i < m_Facets.Length; ++i)
{
new Weather(
m_Facets[i],
area,
temperature,
chanceOfPrecipitation,
chanceOfExtremeTemperature,
TimeSpan.FromSeconds(30.0)
);
}
}
public static bool CheckWeatherConflict(Map facet, Weather exclude, Rectangle2D area)
{
var list = GetWeatherList(facet);
if (list == null)
{
return false;
}
public virtual void RecalculateMovementAngle()
for (var i = 0; i < list.Count; ++i)
{
var angle = Utility.RandomDouble() * Math.PI * 2.0;
var w = list[i];
var cos = Math.Cos(angle);
var sin = Math.Sin(angle);
MoveAngleX = (int)(100 * cos);
MoveAngleY = (int)(100 * sin);
}
public virtual void MoveForward()
{
if (Area.Length == 0)
if (w != exclude && w.IntersectsWith(area))
{
return;
return true;
}
}
return false;
}
public static bool CheckIntersection(Rectangle2D r1, Rectangle2D r2) => r1.X < r2.X + r2.Width &&
r2.X < r1.X + r1.Width &&
r1.Y < r2.Y + r2.Height &&
r2.Y < r1.Y + r1.Height;
public static bool CheckContains(Rectangle2D big, Rectangle2D small) =>
small.X >= big.X && small.Y >= big.Y && small.X + small.Width <= big.X + big.Width
&& small.Y + small.Height <= big.Y + big.Height;
public virtual bool IntersectsWith(Rectangle2D area)
{
for (var i = 0; i < Area.Length; ++i)
{
if (CheckIntersection(area, Area[i]))
{
return true;
}
}
return false;
}
public virtual void Reposition()
{
if (Area.Length == 0)
{
return;
}
var width = Area[0].Width;
var height = Area[0].Height;
var area = new Rectangle2D();
var isValid = false;
for (var j = 0; j < 10; ++j)
{
area = new Rectangle2D(
Bounds.X + Utility.Random(Bounds.Width - width),
Bounds.Y + Utility.Random(Bounds.Height - height),
width,
height
);
if (!CheckWeatherConflict(Facet, this, area))
{
isValid = true;
}
for (var i = 0; i < 5; ++i) // try 5 times to find a valid spot
if (isValid)
{
var xOffset = MoveSpeed * MoveAngleX / 100;
var yOffset = MoveSpeed * MoveAngleY / 100;
break;
}
}
var oldArea = Area[0];
var newArea = new Rectangle2D(oldArea.X + xOffset, oldArea.Y + yOffset, oldArea.Width, oldArea.Height);
if (!isValid)
{
return;
}
if (!CheckWeatherConflict(Facet, this, newArea) && CheckContains(Bounds, newArea))
{
Area[0] = newArea;
break;
}
Area[0] = area;
}
public virtual void RecalculateMovementAngle()
{
var angle = Utility.RandomDouble() * Math.PI * 2.0;
var cos = Math.Cos(angle);
var sin = Math.Sin(angle);
MoveAngleX = (int)(100 * cos);
MoveAngleY = (int)(100 * sin);
}
public virtual void MoveForward()
{
if (Area.Length == 0)
{
return;
}
for (var i = 0; i < 5; ++i) // try 5 times to find a valid spot
{
var xOffset = MoveSpeed * MoveAngleX / 100;
var yOffset = MoveSpeed * MoveAngleY / 100;
var oldArea = Area[0];
var newArea = new Rectangle2D(oldArea.X + xOffset, oldArea.Y + yOffset, oldArea.Width, oldArea.Height);
if (!CheckWeatherConflict(Facet, this, newArea) && CheckContains(Bounds, newArea))
{
Area[0] = newArea;
break;
}
RecalculateMovementAngle();
}
}
public virtual void OnTick()
{
if (m_Stage == 0)
{
m_Active = ChanceOfPrecipitation > Utility.Random(100);
m_ExtremeTemperature = ChanceOfExtremeTemperature > Utility.Random(100);
if (MoveSpeed > 0)
{
Reposition();
RecalculateMovementAngle();
}
}
public virtual void OnTick()
if (m_Active)
{
if (m_Stage == 0)
if (m_Stage > 0 && MoveSpeed > 0)
{
m_Active = ChanceOfPrecipitation > Utility.Random(100);
m_ExtremeTemperature = ChanceOfExtremeTemperature > Utility.Random(100);
if (MoveSpeed > 0)
{
Reposition();
RecalculateMovementAngle();
}
MoveForward();
}
if (m_Active)
int type, density;
var temperature = Temperature;
if (m_ExtremeTemperature)
{
if (m_Stage > 0 && MoveSpeed > 0)
{
MoveForward();
}
int type, density;
var temperature = Temperature;
if (m_ExtremeTemperature)
{
temperature *= -1;
}
if (m_Stage < 15)
{
density = m_Stage * 5;
}
else
{
density = Math.Clamp(150 - m_Stage * 5, 10, 70);
}
if (density == 0)
{
type = 0xFE;
}
else if (temperature > 0)
{
type = 0;
}
else
{
type = 2;
}
foreach (var ns in NetState.Instances)
{
var mob = ns.Mobile;
if (mob == null || mob.Map != Facet)
{
continue;
}
var contains = Area.Length == 0;
for (var j = 0; !contains && j < Area.Length; ++j)
{
contains = Area[j].Contains(mob.Location);
}
if (!contains)
{
continue;
}
ns.SendWeather((byte)type, (byte)density, (byte)temperature);
}
temperature *= -1;
}
m_Stage++;
m_Stage %= 30;
}
}
public class WeatherMap : MapItem
{
[Constructible]
public WeatherMap()
{
SetDisplay(0, 0, 5119, 4095, 400, 400);
}
public WeatherMap(Serial serial) : base(serial)
{
}
public override string DefaultName => "weather map";
public override void OnDoubleClick(Mobile from)
{
var facet = from.Map;
if (facet == null)
if (m_Stage < 15)
{
return;
density = m_Stage * 5;
}
else
{
density = Math.Clamp(150 - m_Stage * 5, 10, 70);
}
var list = Weather.GetWeatherList(facet);
ClearPins();
for (var i = 0; i < list.Count; ++i)
if (density == 0)
{
var w = list[i];
type = 0xFE;
}
else if (temperature > 0)
{
type = 0;
}
else
{
type = 2;
}
for (var j = 0; j < w.Area.Length; ++j)
foreach (var ns in NetState.Instances)
{
var mob = ns.Mobile;
if (mob == null || mob.Map != Facet)
{
AddWorldPin(w.Area[j].X + w.Area[j].Width / 2, w.Area[j].Y + w.Area[j].Height / 2);
continue;
}
var contains = Area.Length == 0;
for (var j = 0; !contains && j < Area.Length; ++j)
{
contains = Area[j].Contains(mob.Location);
}
if (!contains)
{
continue;
}
ns.SendWeather((byte)type, (byte)density, (byte)temperature);
}
base.OnDoubleClick(from);
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
m_Stage++;
m_Stage %= 30;
}
}
[SerializationGenerator(0)]
public partial class WeatherMap : MapItem
{
[Constructible]
public WeatherMap() => SetDisplay(0, 0, 5119, 4095, 400, 400);
public override string DefaultName => "weather map";
public override void OnDoubleClick(Mobile from)
{
var facet = from.Map;
if (facet == null)
{
return;
}
var list = Weather.GetWeatherList(facet);
ClearPins();
for (var i = 0; i < list.Count; ++i)
{
var w = list[i];
for (var j = 0; j < w.Area.Length; ++j)
{
AddWorldPin(w.Area[j].X + w.Area[j].Width / 2, w.Area[j].Y + w.Area[j].Height / 2);
}
}
base.OnDoubleClick(from);
}
}

View file

@ -15,10 +15,12 @@
using System;
using System.Runtime.CompilerServices;
using ModernUO.Serialization;
namespace Server.Mobiles;
internal sealed class TransferItem : Item
[SerializationGenerator(0, false)]
internal sealed partial class TransferItem : Item
{
private readonly BaseCreature _creature;
@ -32,22 +34,11 @@ internal sealed class TransferItem : Item
Hue = creature.Hue & 0x0FFF;
}
public TransferItem(Serial serial) : base(serial)
{
}
public static bool IsInCombat(BaseCreature creature) => creature?.Aggressors.Count > 0 || creature?.Aggressed.Count > 0;
public override void Serialize(IGenericWriter writer)
[AfterDeserialization(false)]
private void AfterDeserialization()
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
reader.ReadInt(); // version
Delete();
}

View file

@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
using ModernUO.Serialization;
using Server.Items;
namespace Server.Mobiles
{
public class GenericBuyInfo : IBuyItemInfo
public partial class GenericBuyInfo : IBuyItemInfo
{
private int m_Amount;
private IEntity m_DisplayEntity;
@ -164,33 +165,32 @@ namespace Server.Mobiles
return m_DisplayEntity;
}
private class DisplayCache : Container
[SerializationGenerator(0, false)]
private partial class DisplayCache : Container
{
private static DisplayCache m_Cache;
private List<Mobile> m_Mobiles;
private static DisplayCache _cache;
[SerializableField(0)]
private List<Mobile> _mobiles;
private Dictionary<Type, IEntity> m_Table;
private DisplayCache() : base(0)
{
m_Table = new Dictionary<Type, IEntity>();
m_Mobiles = new List<Mobile>();
}
public DisplayCache(Serial serial) : base(serial)
{
_mobiles = new List<Mobile>();
}
public static DisplayCache Cache
{
get
{
if (m_Cache?.Deleted != false)
if (_cache?.Deleted != false)
{
m_Cache = new DisplayCache();
_cache = new DisplayCache();
}
return m_Cache;
return _cache;
}
}
@ -213,20 +213,18 @@ namespace Server.Mobiles
}
else if (obj is Mobile mobile)
{
m_Mobiles.Add(mobile);
_mobiles.Add(mobile);
}
}
public override void OnAfterDelete()
private void ClearContents()
{
base.OnAfterDelete();
for (var i = 0; i < m_Mobiles.Count; ++i)
for (var i = 0; i < _mobiles.Count; ++i)
{
m_Mobiles[i].Delete();
_mobiles[i].Delete();
}
m_Mobiles.Clear();
_mobiles.Clear();
for (var i = Items.Count - 1; i >= 0; --i)
{
@ -235,44 +233,36 @@ namespace Server.Mobiles
Items[i].Delete();
}
}
}
if (m_Cache == this)
public override void OnAfterDelete()
{
base.OnAfterDelete();
ClearContents();
if (_cache == this)
{
m_Cache = null;
_cache = null;
}
}
public override void Serialize(IGenericWriter writer)
[AfterDeserialization]
private void AfterDeserialization()
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(m_Mobiles);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
List<IEntity> entities = [..Items];
entities.AddRange(reader.ReadEntityList<Mobile>());
m_Mobiles = new List<Mobile>(); // This cannot be null in case it is referenced before disposing
m_Table = new Dictionary<Type, IEntity>();
if (_cache == this && Items.Count <= 0 && _mobiles.Count <= 0)
{
return;
}
Timer.StartTimer(() =>
{
foreach (var entity in entities)
{
entity.Delete();
}
ClearContents();
if (m_Cache == null)
if (_cache == null)
{
m_Cache = this;
_cache = this;
m_Table = [];
}
else
{

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using ModernUO.CodeGeneratedEvents;
using ModernUO.Serialization;
using Server.Accounting;
using Server.Collections;
using Server.ContextMenus;
@ -17,7 +18,7 @@ using Server.Targeting;
namespace Server.Multis
{
public abstract class BaseHouse : BaseMulti
public abstract partial class BaseHouse : BaseMulti
{
public static bool DecayEnabled { get; set; }
@ -3725,37 +3726,34 @@ namespace Server.Multis
}
}
private class TransferItem : Item
[SerializationGenerator(0)]
private partial class TransferItem : Item
{
private readonly BaseHouse m_House;
private readonly BaseHouse _house;
public TransferItem(BaseHouse house) : base(0x14F0)
{
m_House = house;
_house = house;
Hue = 0x480;
Movable = false;
}
public TransferItem(Serial serial) : base(serial)
{
}
public override string DefaultName => "a house transfer contract";
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
var houseName = m_House == null ? "an unnamed house" : m_House.Sign.GetName();
var owner = m_House?.Owner?.Name ?? "nobody";
var houseName = _house == null ? "an unnamed house" : _house.Sign.GetName();
var owner = _house?.Owner?.Name ?? "nobody";
int xLong = 0, yLat = 0, xMins = 0, yMins = 0;
bool xEast = false, ySouth = false;
var valid = m_House != null && Sextant.Format(
m_House.Location,
m_House.Map,
var valid = _house != null && Sextant.Format(
_house.Location,
_house.Map,
ref xLong,
ref yLat,
ref xMins,
@ -3777,20 +3775,10 @@ namespace Server.Multis
}
}
public override void Serialize(IGenericWriter writer)
[AfterDeserialization(false)]
private void AfterDeserialization()
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
Timer.DelayCall(Delete);
Delete();
}
public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted)
@ -3805,7 +3793,7 @@ namespace Server.Multis
return true;
}
if (Deleted || m_House?.Deleted != false || !m_House.IsOwner(from) || !from.CheckAlive() ||
if (Deleted || _house?.Deleted != false || !_house.IsOwner(from) || !from.CheckAlive() ||
!to.CheckAlive())
{
return false;
@ -3817,7 +3805,7 @@ namespace Server.Multis
return false;
}
return m_House.CheckTransferPosition(from, to);
return _house.CheckTransferPosition(from, to);
}
public override void OnSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted)
@ -3829,7 +3817,7 @@ namespace Server.Multis
Delete();
if (m_House?.Deleted != false || !m_House.IsOwner(from) || !from.CheckAlive() || !to.CheckAlive())
if (_house?.Deleted != false || !_house.IsOwner(from) || !from.CheckAlive() || !to.CheckAlive())
{
return;
}
@ -3847,13 +3835,13 @@ namespace Server.Multis
*/
to.SendLocalizedMessage(501339);
m_House.RemoveKeys(from);
m_House.Owner = to;
m_House.Bans.Clear();
m_House.Friends.Clear();
m_House.CoOwners.Clear();
m_House.ChangeLocks(to);
m_House.LastTraded = Core.Now;
_house.RemoveKeys(from);
_house.Owner = to;
_house.Bans.Clear();
_house.Friends.Clear();
_house.CoOwners.Clear();
_house.ChangeLocks(to);
_house.LastTraded = Core.Now;
}
}