fix: Overhauls champion titles & codegen champion system (#1430)
## MAJOR CHANGE Added a champion title system to facilitate the existing champion titles. This should make it easier to extend or create other related game content. Champion titles will be saved in a folder called _ChampionTitles_. ### Motivation The motivation to refactor was two-folder, but mostly related to performance in two ways. First, every player had a ChampionTitleInfo object with an array of ChamptionTitleInfo. We want to eliminate the need for this information unless a player actually uses it. This should save a considerable amount of memory. Second, to facilitate the atrophy mechanic, the champion titles would run atrophy post-world save, adding to the time that the server is frozen. Eliminating this post-world save side effect unlocks our ability to further optimize the world save process since there are no direct side effects. ### Bugs fixed - [X] Fixed titles getting cut off on the paperdoll - [X] Fixed champion title not displaying overhead (OPL) ### Screenshots <img width="216" alt="image" src="https://github.com/modernuo/ModernUO/assets/3953314/8916f895-8d68-4fb0-892e-108a0c43be90">
This commit is contained in:
parent
4dddc8d3f1
commit
51ecee6caa
44 changed files with 3028 additions and 2785 deletions
|
|
@ -40,9 +40,6 @@ public abstract class BaseGuild : ISerializable
|
|||
public abstract GuildType Type { get; set; }
|
||||
public abstract bool Disbanded { get; }
|
||||
|
||||
public abstract bool ShouldExecuteAfterSerialize { get; }
|
||||
public abstract void AfterSerialize();
|
||||
|
||||
public abstract void Delete();
|
||||
|
||||
public bool Deleted => Disbanded;
|
||||
|
|
|
|||
|
|
@ -112,10 +112,4 @@ public class Entity : IEntity
|
|||
public void Serialize(IGenericWriter writer)
|
||||
{
|
||||
}
|
||||
|
||||
public bool ShouldExecuteAfterSerialize => false;
|
||||
|
||||
public void AfterSerialize()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1041,12 +1041,6 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
|
|||
}
|
||||
}
|
||||
|
||||
public virtual bool ShouldExecuteAfterSerialize => false;
|
||||
|
||||
public virtual void AfterSerialize()
|
||||
{
|
||||
}
|
||||
|
||||
public void MoveToWorld(WorldLocation worldLocation)
|
||||
{
|
||||
MoveToWorld(worldLocation.Location, worldLocation.Map);
|
||||
|
|
|
|||
|
|
@ -126,8 +126,6 @@ public static class Core
|
|||
private static long _tickCount;
|
||||
|
||||
// Don't access this from other threads than the game thread.
|
||||
// Persistence accesses this via AfterSerialize or Serialize in other threads, but the value is set and won't change
|
||||
// since the game loop is frozen at that moment.
|
||||
private static DateTime _now;
|
||||
|
||||
// For Unix Stopwatch.Frequency is normalized to 1ns
|
||||
|
|
|
|||
|
|
@ -2380,12 +2380,6 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
|
|||
writer.Write((byte)m_IntLock);
|
||||
}
|
||||
|
||||
public virtual bool ShouldExecuteAfterSerialize => false;
|
||||
|
||||
public virtual void AfterSerialize()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Deleted { get; private set; }
|
||||
|
||||
public virtual void Delete()
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ public static class GenericPersistence
|
|||
string name,
|
||||
Action<IGenericWriter> serializer,
|
||||
Action<IGenericReader> deserializer,
|
||||
Action afterSerialize = null,
|
||||
int priority = Persistence.DefaultPriority
|
||||
)
|
||||
{
|
||||
|
|
@ -49,6 +48,6 @@ public static class GenericPersistence
|
|||
void Deserialize(string savePath, Dictionary<ulong, string> typesDb) =>
|
||||
AdhocPersistence.Deserialize(Path.Combine(savePath, name, $"{name}.bin"), deserializer);
|
||||
|
||||
Persistence.Register(name, Serialize, WriteSnapshot, Deserialize, afterSerialize, priority);
|
||||
Persistence.Register(name, Serialize, WriteSnapshot, Deserialize, priority);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,12 +34,6 @@ public interface ISerializable
|
|||
void Deserialize(IGenericReader reader);
|
||||
void Serialize(IGenericWriter writer);
|
||||
|
||||
// Determines if AfterSerialize should execute. This is checked on a worker thread.
|
||||
bool ShouldExecuteAfterSerialize { get; }
|
||||
|
||||
// Executes after serialization if ShouldExecuteAfterSerialize is true. This is run on the game thread synchronously.
|
||||
void AfterSerialize();
|
||||
|
||||
bool Deleted { get; }
|
||||
void Delete();
|
||||
|
||||
|
|
@ -60,13 +54,6 @@ public interface ISerializable
|
|||
{
|
||||
SaveBuffer ??= new BufferWriter(true, types);
|
||||
|
||||
// Queue for post serialization if this entity has it enabled
|
||||
// This will run AfterSerialize in the main game thread after the world is done saving
|
||||
if (ShouldExecuteAfterSerialize)
|
||||
{
|
||||
World.EnqueueAfterSerialization(this);
|
||||
}
|
||||
|
||||
// Clean, don't bother serializing
|
||||
if (SavePosition > -1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ public static class Persistence
|
|||
Action serializer,
|
||||
Action<string> snapshotWriter,
|
||||
Action<string, Dictionary<ulong, string>> deserializer,
|
||||
Action afterSerialize = null,
|
||||
int priority = DefaultPriority
|
||||
)
|
||||
{
|
||||
|
|
@ -42,7 +41,6 @@ public static class Persistence
|
|||
Name = name,
|
||||
Priority = priority,
|
||||
Serialize = serializer,
|
||||
AfterSerialize = afterSerialize,
|
||||
WriteSnapshot = snapshotWriter,
|
||||
Deserialize = deserializer
|
||||
}
|
||||
|
|
@ -91,12 +89,6 @@ public static class Persistence
|
|||
public static void Serialize()
|
||||
{
|
||||
Parallel.ForEach(_registry, entry => entry.Serialize());
|
||||
|
||||
// Synchronously run the AfterSerialize on the main game thread
|
||||
foreach (var entry in _registry)
|
||||
{
|
||||
entry.AfterSerialize?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteSnapshot(string path, ConcurrentQueue<Type> types)
|
||||
|
|
@ -141,7 +133,6 @@ public static class Persistence
|
|||
|
||||
// Serializes to memory buffers and run in parallel
|
||||
public Action Serialize { get; init; }
|
||||
public Action AfterSerialize { get; init; }
|
||||
public Action<string> WriteSnapshot { get; init; }
|
||||
public Action<string, Dictionary<ulong, string>> Deserialize { get; init; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ public static class World
|
|||
private static Dictionary<Serial, IEntity> _pendingAdd = new();
|
||||
private static Dictionary<Serial, IEntity> _pendingDelete = new();
|
||||
private static ConcurrentQueue<Item> _decayQueue = new();
|
||||
private static ConcurrentQueue<ISerializable> _afterSerializeEntities = new();
|
||||
|
||||
private static string _tempSavePath; // Path to the temporary folder for the save
|
||||
private static bool _enableSaveStats;
|
||||
|
|
@ -166,7 +165,7 @@ public static class World
|
|||
_enableSaveStats = ServerConfiguration.GetOrUpdateSetting("world.enableSaveStats", false);
|
||||
|
||||
// Mobiles & Items
|
||||
Persistence.Register("Mobiles & Items", SaveEntities, WriteEntities, LoadEntities, AfterSerialize, 1);
|
||||
Persistence.Register("Mobiles & Items", SaveEntities, WriteEntities, LoadEntities, 1);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
|
@ -187,9 +186,6 @@ public static class World
|
|||
_decayQueue.Enqueue(item);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void EnqueueAfterSerialization(ISerializable entity) => _afterSerializeEntities.Enqueue(entity);
|
||||
|
||||
public static void Broadcast(int hue, bool ascii, string text)
|
||||
{
|
||||
var length = OutgoingMessagePackets.GetMaxMessageLength(text);
|
||||
|
|
@ -519,14 +515,6 @@ public static class World
|
|||
*/
|
||||
public static ConcurrentQueue<Type> SerializedTypes { get; } = new();
|
||||
|
||||
private static void AfterSerialize()
|
||||
{
|
||||
while (_afterSerializeEntities.TryDequeue(out var entity))
|
||||
{
|
||||
entity.AfterSerialize();
|
||||
}
|
||||
}
|
||||
|
||||
private static void SaveEntities()
|
||||
{
|
||||
_serializationStart = DateTime.UtcNow;
|
||||
|
|
|
|||
|
|
@ -333,12 +333,6 @@ namespace Server.Accounting
|
|||
}
|
||||
}
|
||||
|
||||
public bool ShouldExecuteAfterSerialize => false;
|
||||
|
||||
public void AfterSerialize()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the account, all characters of the account, and all houses of those characters
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -13,56 +13,31 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using ModernUO.Serialization;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
namespace Server.Engines.CannedEvil;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class ChampionAltar : PentagramAddon
|
||||
{
|
||||
public class ChampionAltar : PentagramAddon
|
||||
[SerializableField(0, setter: "private")]
|
||||
private ChampionSpawn _spawn;
|
||||
|
||||
public ChampionAltar(ChampionSpawn spawn) => _spawn = spawn;
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
public ChampionSpawn Spawn { get; private set; }
|
||||
base.OnAfterDelete();
|
||||
Spawn?.Delete();
|
||||
}
|
||||
|
||||
public ChampionAltar(ChampionSpawn spawn) => Spawn = spawn;
|
||||
|
||||
public override void OnAfterDelete()
|
||||
[AfterDeserialization(false)]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
if (Spawn == null)
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
Spawn?.Delete();
|
||||
}
|
||||
|
||||
public ChampionAltar(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(Spawn);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Spawn = reader.ReadEntity<ChampionSpawn>();
|
||||
|
||||
if (Spawn == null)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,95 +13,70 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using ModernUO.Serialization;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
namespace Server.Engines.CannedEvil;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class ChampionPlatform : BaseAddon
|
||||
{
|
||||
public class ChampionPlatform : BaseAddon
|
||||
[SerializableField(0, setter: "private")]
|
||||
private ChampionSpawn _spawn;
|
||||
|
||||
public ChampionPlatform(ChampionSpawn spawn)
|
||||
{
|
||||
public ChampionSpawn Spawn { get; private set; }
|
||||
_spawn = spawn;
|
||||
|
||||
public ChampionPlatform(ChampionSpawn spawn)
|
||||
for (var x = -2; x <= 2; ++x)
|
||||
{
|
||||
Spawn = spawn;
|
||||
|
||||
for (var x = -2; x <= 2; ++x)
|
||||
for (var y = -2; y <= 2; ++y)
|
||||
{
|
||||
for (var y = -2; y <= 2; ++y)
|
||||
{
|
||||
AddComponent(0x750, x, y, -5);
|
||||
}
|
||||
AddComponent(0x750, x, y, -5);
|
||||
}
|
||||
}
|
||||
|
||||
for (var x = -1; x <= 1; ++x)
|
||||
for (var x = -1; x <= 1; ++x)
|
||||
{
|
||||
for (var y = -1; y <= 1; ++y)
|
||||
{
|
||||
for (var y = -1; y <= 1; ++y)
|
||||
{
|
||||
AddComponent(0x750, x, y, 0);
|
||||
}
|
||||
AddComponent(0x750, x, y, 0);
|
||||
}
|
||||
|
||||
for (var i = -1; i <= 1; ++i)
|
||||
{
|
||||
AddComponent(0x751, i, 2, 0);
|
||||
AddComponent(0x752, 2, i, 0);
|
||||
|
||||
AddComponent(0x753, i, -2, 0);
|
||||
AddComponent(0x754, -2, i, 0);
|
||||
}
|
||||
|
||||
AddComponent(0x759, -2, -2, 0);
|
||||
AddComponent(0x75A, 2, 2, 0);
|
||||
AddComponent(0x75B, -2, 2, 0);
|
||||
AddComponent(0x75C, 2, -2, 0);
|
||||
}
|
||||
|
||||
public void AddComponent(int id, int x, int y, int z)
|
||||
for (var i = -1; i <= 1; ++i)
|
||||
{
|
||||
AddonComponent ac = new AddonComponent(id) { Hue = 0x497 };
|
||||
AddComponent(ac, x, y, z);
|
||||
AddComponent(0x751, i, 2, 0);
|
||||
AddComponent(0x752, 2, i, 0);
|
||||
|
||||
AddComponent(0x753, i, -2, 0);
|
||||
AddComponent(0x754, -2, i, 0);
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
AddComponent(0x759, -2, -2, 0);
|
||||
AddComponent(0x75A, 2, 2, 0);
|
||||
AddComponent(0x75B, -2, 2, 0);
|
||||
AddComponent(0x75C, 2, -2, 0);
|
||||
}
|
||||
|
||||
public void AddComponent(int id, int x, int y, int z)
|
||||
{
|
||||
AddonComponent ac = new AddonComponent(id) { Hue = 0x497 };
|
||||
AddComponent(ac, x, y, z);
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
Spawn?.Delete();
|
||||
}
|
||||
|
||||
[AfterDeserialization(false)]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
if (Spawn == null)
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
Spawn?.Delete();
|
||||
}
|
||||
|
||||
public ChampionPlatform(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(Spawn);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Spawn = reader.ReadEntity<ChampionSpawn>();
|
||||
|
||||
if (Spawn == null)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,86 +13,41 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using ModernUO.Serialization;
|
||||
using Server.Engines.CannedEvil;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(2, false)]
|
||||
public partial class ChampionSkull : Item
|
||||
{
|
||||
public class ChampionSkull : Item
|
||||
[InvalidateProperties]
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private ChampionSkullType _type;
|
||||
|
||||
public override int LabelNumber => 1049479 + (int)_type;
|
||||
|
||||
[Constructible]
|
||||
public ChampionSkull(ChampionSkullType type) : base(0x1AE1)
|
||||
{
|
||||
private ChampionSkullType m_Type;
|
||||
_type = type;
|
||||
LootType = LootType.Cursed;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public ChampionSkullType Type
|
||||
// TODO: All hue values
|
||||
Hue = type switch
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
m_Type = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
ChampionSkullType.Power => 0x159,
|
||||
ChampionSkullType.Venom => 0x172,
|
||||
ChampionSkullType.Greed => 0x1EE,
|
||||
ChampionSkullType.Death => 0x025,
|
||||
ChampionSkullType.Pain => 0x035,
|
||||
_ => Hue
|
||||
};
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1049479 + (int)m_Type;
|
||||
|
||||
[Constructible]
|
||||
public ChampionSkull(ChampionSkullType type) : base(0x1AE1)
|
||||
{
|
||||
m_Type = type;
|
||||
LootType = LootType.Cursed;
|
||||
|
||||
// TODO: All hue values
|
||||
Hue = type switch
|
||||
{
|
||||
ChampionSkullType.Power => 0x159,
|
||||
ChampionSkullType.Venom => 0x172,
|
||||
ChampionSkullType.Greed => 0x1EE,
|
||||
ChampionSkullType.Death => 0x025,
|
||||
ChampionSkullType.Pain => 0x035,
|
||||
_ => Hue
|
||||
};
|
||||
}
|
||||
|
||||
public ChampionSkull(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1); // version
|
||||
|
||||
writer.Write((int)m_Type);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
case 0:
|
||||
{
|
||||
m_Type = (ChampionSkullType)reader.ReadInt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
if (LootType != LootType.Cursed)
|
||||
{
|
||||
LootType = LootType.Cursed;
|
||||
}
|
||||
|
||||
if (Insured)
|
||||
{
|
||||
Insured = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void Deserialize(IGenericReader reader, int version)
|
||||
{
|
||||
_type = (ChampionSkullType)reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,194 +13,156 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using ModernUO.Serialization;
|
||||
using Server.Items;
|
||||
using Server.Targeting;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
namespace Server.Engines.CannedEvil;
|
||||
|
||||
[SerializationGenerator(1, false)]
|
||||
public partial class ChampionSkullBrazier : AddonComponent
|
||||
{
|
||||
public class ChampionSkullBrazier : AddonComponent
|
||||
[InvalidateProperties]
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private ChampionSkullType _type;
|
||||
|
||||
[InvalidateProperties]
|
||||
[SerializableField(1)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private ChampionSkullPlatform _platform;
|
||||
|
||||
[SerializableProperty(2)]
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Item Skull
|
||||
{
|
||||
private ChampionSkullType m_Type;
|
||||
private Item m_Skull;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public ChampionSkullPlatform Platform { get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public ChampionSkullType Type
|
||||
get => _skull;
|
||||
set
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
m_Type = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
_skull = value;
|
||||
this.MarkDirty();
|
||||
_platform?.Validate();
|
||||
}
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1049489 + (int)_type;
|
||||
|
||||
public ChampionSkullBrazier(ChampionSkullPlatform platform, ChampionSkullType type) : base(0x19BB)
|
||||
{
|
||||
Hue = 0x455;
|
||||
Light = LightType.Circle300;
|
||||
|
||||
_platform = platform;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
_platform?.Validate();
|
||||
BeginSacrifice(from);
|
||||
}
|
||||
|
||||
public void BeginSacrifice(Mobile from)
|
||||
{
|
||||
if (Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Item Skull
|
||||
if (_skull is { Deleted: true })
|
||||
{
|
||||
get => m_Skull;
|
||||
set
|
||||
{
|
||||
m_Skull = value;
|
||||
Platform?.Validate();
|
||||
}
|
||||
Skull = null;
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1049489 + (int)m_Type;
|
||||
|
||||
public ChampionSkullBrazier(ChampionSkullPlatform platform, ChampionSkullType type) : base(0x19BB)
|
||||
if (from.Map != Map || !from.InRange(GetWorldLocation(), 3))
|
||||
{
|
||||
Hue = 0x455;
|
||||
Light = LightType.Circle300;
|
||||
from.SendLocalizedMessage(500446); // That is too far away.
|
||||
}
|
||||
else if (!Harrower.CanSpawn)
|
||||
{
|
||||
from.SendMessage("The harrower has already been spawned.");
|
||||
}
|
||||
else if (_skull == null)
|
||||
{
|
||||
from.SendLocalizedMessage(1049485); // What would you like to sacrifice?
|
||||
from.Target = new SacrificeTarget(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendLocalizedMessageTo(from, 1049487); // I already have my champions awakening skull!
|
||||
}
|
||||
}
|
||||
|
||||
Platform = platform;
|
||||
m_Type = type;
|
||||
public void EndSacrifice(Mobile from, ChampionSkull skull)
|
||||
{
|
||||
if (Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public ChampionSkullBrazier(Serial serial) : base(serial)
|
||||
if (_skull is { Deleted: true })
|
||||
{
|
||||
Skull = null;
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
if (from.Map != Map || !from.InRange(GetWorldLocation(), 3))
|
||||
{
|
||||
Platform?.Validate();
|
||||
|
||||
BeginSacrifice(from);
|
||||
from.SendLocalizedMessage(500446); // That is too far away.
|
||||
}
|
||||
|
||||
public void BeginSacrifice(Mobile from)
|
||||
else if (!Harrower.CanSpawn)
|
||||
{
|
||||
if (Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Skull is { Deleted: true })
|
||||
{
|
||||
Skull = null;
|
||||
}
|
||||
|
||||
if (from.Map != Map || !from.InRange(GetWorldLocation(), 3))
|
||||
{
|
||||
from.SendLocalizedMessage(500446); // That is too far away.
|
||||
}
|
||||
else if (!Harrower.CanSpawn)
|
||||
{
|
||||
from.SendMessage("The harrower has already been spawned.");
|
||||
}
|
||||
else if (m_Skull == null)
|
||||
{
|
||||
from.SendLocalizedMessage(1049485); // What would you like to sacrifice?
|
||||
from.Target = new SacrificeTarget(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendLocalizedMessageTo(from, 1049487); // I already have my champions awakening skull!
|
||||
}
|
||||
from.SendMessage("The harrower has already been spawned.");
|
||||
}
|
||||
|
||||
public void EndSacrifice(Mobile from, ChampionSkull skull)
|
||||
else if (skull == null)
|
||||
{
|
||||
if (Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Skull is { Deleted: true })
|
||||
{
|
||||
Skull = null;
|
||||
}
|
||||
|
||||
if (from.Map != Map || !from.InRange(GetWorldLocation(), 3))
|
||||
{
|
||||
from.SendLocalizedMessage(500446); // That is too far away.
|
||||
}
|
||||
else if (!Harrower.CanSpawn)
|
||||
{
|
||||
from.SendMessage("The harrower has already been spawned.");
|
||||
}
|
||||
else if (skull == null)
|
||||
{
|
||||
SendLocalizedMessageTo(from, 1049488); // That is not my champions awakening skull!
|
||||
}
|
||||
else if (m_Skull != null)
|
||||
{
|
||||
SendLocalizedMessageTo(from, 1049487); // I already have my champions awakening skull!
|
||||
}
|
||||
else if (!skull.IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1049486); // You can only sacrifice items that are in your backpack!
|
||||
}
|
||||
else if (skull.Type == Type)
|
||||
{
|
||||
skull.Movable = false;
|
||||
skull.MoveToWorld(GetWorldTop(), Map);
|
||||
|
||||
Skull = skull;
|
||||
}
|
||||
else
|
||||
{
|
||||
SendLocalizedMessageTo(from, 1049488); // That is not my champions awakening skull!
|
||||
}
|
||||
SendLocalizedMessageTo(from, 1049488); // That is not my champions awakening skull!
|
||||
}
|
||||
|
||||
private class SacrificeTarget : Target
|
||||
else if (_skull != null)
|
||||
{
|
||||
private readonly ChampionSkullBrazier m_Brazier;
|
||||
|
||||
public SacrificeTarget(ChampionSkullBrazier brazier) : base(12, false, TargetFlags.None) =>
|
||||
m_Brazier = brazier;
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted) =>
|
||||
m_Brazier.EndSacrifice(from, targeted as ChampionSkull);
|
||||
SendLocalizedMessageTo(from, 1049487); // I already have my champions awakening skull!
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
else if (!skull.IsChildOf(from.Backpack))
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write((int)m_Type);
|
||||
writer.Write(Platform);
|
||||
writer.Write(m_Skull);
|
||||
from.SendLocalizedMessage(1049486); // You can only sacrifice items that are in your backpack!
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
else if (skull.Type == Type)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
skull.Movable = false;
|
||||
skull.MoveToWorld(GetWorldTop(), Map);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
Skull = skull;
|
||||
}
|
||||
else
|
||||
{
|
||||
SendLocalizedMessageTo(from, 1049488); // That is not my champions awakening skull!
|
||||
}
|
||||
}
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Type = (ChampionSkullType)reader.ReadInt();
|
||||
Platform = reader.ReadEntity<ChampionSkullPlatform>();
|
||||
m_Skull = reader.ReadEntity<Item>();
|
||||
private class SacrificeTarget : Target
|
||||
{
|
||||
private readonly ChampionSkullBrazier _brazier;
|
||||
|
||||
if (Platform == null)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
public SacrificeTarget(ChampionSkullBrazier brazier) : base(12, false, TargetFlags.None) =>
|
||||
_brazier = brazier;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
protected override void OnTarget(Mobile from, object targeted) =>
|
||||
_brazier.EndSacrifice(from, targeted as ChampionSkull);
|
||||
}
|
||||
|
||||
if (Hue == 0x497)
|
||||
{
|
||||
Hue = 0x455;
|
||||
}
|
||||
private void Deserialize(IGenericReader reader, int version)
|
||||
{
|
||||
_type = (ChampionSkullType)reader.ReadInt();
|
||||
_platform = reader.ReadEntity<ChampionSkullPlatform>();
|
||||
_skull = reader.ReadEntity<Item>();
|
||||
}
|
||||
|
||||
if (Light != LightType.Circle300)
|
||||
{
|
||||
Light = LightType.Circle300;
|
||||
}
|
||||
[AfterDeserialization(false)]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
if (_platform == null)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,127 +13,104 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using ModernUO.Serialization;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
namespace Server.Engines.CannedEvil;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class ChampionSkullPlatform : BaseAddon
|
||||
{
|
||||
public class ChampionSkullPlatform : BaseAddon
|
||||
[SerializableField(0)]
|
||||
private ChampionSkullBrazier _power;
|
||||
|
||||
[SerializableField(1)]
|
||||
private ChampionSkullBrazier _enlightenment;
|
||||
|
||||
[SerializableField(2)]
|
||||
private ChampionSkullBrazier _venom;
|
||||
|
||||
[SerializableField(3)]
|
||||
private ChampionSkullBrazier _pain;
|
||||
|
||||
[SerializableField(4)]
|
||||
private ChampionSkullBrazier _greed;
|
||||
|
||||
[SerializableField(5)]
|
||||
private ChampionSkullBrazier _death;
|
||||
|
||||
[Constructible]
|
||||
public ChampionSkullPlatform()
|
||||
{
|
||||
private ChampionSkullBrazier m_Power, m_Enlightenment, m_Venom, m_Pain, m_Greed, m_Death;
|
||||
AddComponent(new AddonComponent(0x71A), -1, -1, -1);
|
||||
AddComponent(new AddonComponent(0x709), 0, -1, -1);
|
||||
AddComponent(new AddonComponent(0x709), 1, -1, -1);
|
||||
AddComponent(new AddonComponent(0x709), -1, 0, -1);
|
||||
AddComponent(new AddonComponent(0x709), 0, 0, -1);
|
||||
AddComponent(new AddonComponent(0x709), 1, 0, -1);
|
||||
AddComponent(new AddonComponent(0x709), -1, 1, -1);
|
||||
AddComponent(new AddonComponent(0x709), 0, 1, -1);
|
||||
AddComponent(new AddonComponent(0x71B), 1, 1, -1);
|
||||
|
||||
[Constructible]
|
||||
public ChampionSkullPlatform()
|
||||
AddComponent(new AddonComponent(0x50F), 0, -1, 4);
|
||||
AddComponent(_power = new ChampionSkullBrazier(this, ChampionSkullType.Power), 0, -1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 1, -1, 4);
|
||||
AddComponent(_enlightenment = new ChampionSkullBrazier(this, ChampionSkullType.Enlightenment), 1, -1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), -1, 0, 4);
|
||||
AddComponent(_venom = new ChampionSkullBrazier(this, ChampionSkullType.Venom), -1, 0, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 1, 0, 4);
|
||||
AddComponent(_pain = new ChampionSkullBrazier(this, ChampionSkullType.Pain), 1, 0, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), -1, 1, 4);
|
||||
AddComponent(_greed = new ChampionSkullBrazier(this, ChampionSkullType.Greed), -1, 1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 0, 1, 4);
|
||||
AddComponent(_death = new ChampionSkullBrazier(this, ChampionSkullType.Death), 0, 1, 5);
|
||||
|
||||
AddonComponent comp = new LocalizedAddonComponent(0x20D2, 1049495) { Hue = 0x482 };
|
||||
AddComponent(comp, 0, 0, 5);
|
||||
|
||||
comp = new LocalizedAddonComponent(0x0BCF, 1049496) { Hue = 0x482 };
|
||||
AddComponent(comp, 0, 2, -7);
|
||||
|
||||
comp = new LocalizedAddonComponent(0x0BD0, 1049497) { Hue = 0x482 };
|
||||
AddComponent(comp, 2, 0, -7);
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (Validate(_power) && Validate(_enlightenment) && Validate(_venom) && Validate(_pain) &&
|
||||
Validate(_greed) && Validate(_death))
|
||||
{
|
||||
AddComponent(new AddonComponent(0x71A), -1, -1, -1);
|
||||
AddComponent(new AddonComponent(0x709), 0, -1, -1);
|
||||
AddComponent(new AddonComponent(0x709), 1, -1, -1);
|
||||
AddComponent(new AddonComponent(0x709), -1, 0, -1);
|
||||
AddComponent(new AddonComponent(0x709), 0, 0, -1);
|
||||
AddComponent(new AddonComponent(0x709), 1, 0, -1);
|
||||
AddComponent(new AddonComponent(0x709), -1, 1, -1);
|
||||
AddComponent(new AddonComponent(0x709), 0, 1, -1);
|
||||
AddComponent(new AddonComponent(0x71B), 1, 1, -1);
|
||||
Mobile harrower = Harrower.Spawn(new Point3D(X, Y, Z + 6), Map);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 0, -1, 4);
|
||||
AddComponent(m_Power = new ChampionSkullBrazier(this, ChampionSkullType.Power), 0, -1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 1, -1, 4);
|
||||
AddComponent(m_Enlightenment = new ChampionSkullBrazier(this, ChampionSkullType.Enlightenment), 1, -1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), -1, 0, 4);
|
||||
AddComponent(m_Venom = new ChampionSkullBrazier(this, ChampionSkullType.Venom), -1, 0, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 1, 0, 4);
|
||||
AddComponent(m_Pain = new ChampionSkullBrazier(this, ChampionSkullType.Pain), 1, 0, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), -1, 1, 4);
|
||||
AddComponent(m_Greed = new ChampionSkullBrazier(this, ChampionSkullType.Greed), -1, 1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 0, 1, 4);
|
||||
AddComponent(m_Death = new ChampionSkullBrazier(this, ChampionSkullType.Death), 0, 1, 5);
|
||||
|
||||
AddonComponent comp = new LocalizedAddonComponent(0x20D2, 1049495) { Hue = 0x482 };
|
||||
AddComponent(comp, 0, 0, 5);
|
||||
|
||||
comp = new LocalizedAddonComponent(0x0BCF, 1049496) { Hue = 0x482 };
|
||||
AddComponent(comp, 0, 2, -7);
|
||||
|
||||
comp = new LocalizedAddonComponent(0x0BD0, 1049497) { Hue = 0x482 };
|
||||
AddComponent(comp, 2, 0, -7);
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (Validate(m_Power) && Validate(m_Enlightenment) && Validate(m_Venom) && Validate(m_Pain) &&
|
||||
Validate(m_Greed) && Validate(m_Death))
|
||||
if (harrower == null)
|
||||
{
|
||||
Mobile harrower = Harrower.Spawn(new Point3D(X, Y, Z + 6), Map);
|
||||
|
||||
if (harrower == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Clear(m_Power);
|
||||
Clear(m_Enlightenment);
|
||||
Clear(m_Venom);
|
||||
Clear(m_Pain);
|
||||
Clear(m_Greed);
|
||||
Clear(m_Death);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear(ChampionSkullBrazier brazier)
|
||||
{
|
||||
if (brazier != null)
|
||||
{
|
||||
Effects.SendBoltEffect(brazier);
|
||||
|
||||
brazier.Skull?.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Validate(ChampionSkullBrazier brazier) => brazier is { Skull: { Deleted: false } };
|
||||
|
||||
public ChampionSkullPlatform(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Power);
|
||||
writer.Write(m_Enlightenment);
|
||||
writer.Write(m_Venom);
|
||||
writer.Write(m_Pain);
|
||||
writer.Write(m_Greed);
|
||||
writer.Write(m_Death);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Power = reader.ReadEntity<ChampionSkullBrazier>();
|
||||
m_Enlightenment = reader.ReadEntity<ChampionSkullBrazier>();
|
||||
m_Venom = reader.ReadEntity<ChampionSkullBrazier>();
|
||||
m_Pain = reader.ReadEntity<ChampionSkullBrazier>();
|
||||
m_Greed = reader.ReadEntity<ChampionSkullBrazier>();
|
||||
m_Death = reader.ReadEntity<ChampionSkullBrazier>();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
Clear(_power);
|
||||
Clear(_enlightenment);
|
||||
Clear(_venom);
|
||||
Clear(_pain);
|
||||
Clear(_greed);
|
||||
Clear(_death);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Clear(ChampionSkullBrazier brazier)
|
||||
{
|
||||
if (brazier != null)
|
||||
{
|
||||
Effects.SendBoltEffect(brazier);
|
||||
|
||||
brazier.Skull?.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Validate(ChampionSkullBrazier brazier) => brazier is { Skull: { Deleted: false } };
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
150
Projects/UOContent/Engines/CannedEvil/ChampionSpawnInfo.cs
Normal file
150
Projects/UOContent/Engines/CannedEvil/ChampionSpawnInfo.cs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.CannedEvil;
|
||||
|
||||
public enum ChampionSpawnType
|
||||
{
|
||||
Abyss,
|
||||
Arachnid,
|
||||
ColdBlood,
|
||||
ForestLord,
|
||||
VerminHorde,
|
||||
UnholyTerror,
|
||||
SleepingDragon,
|
||||
Glade,
|
||||
Corrupt,
|
||||
// Unliving,
|
||||
// Pit,
|
||||
// DragonTurtle,
|
||||
// Khaldun
|
||||
}
|
||||
|
||||
public class ChampionSpawnInfo
|
||||
{
|
||||
public ChampionSpawnType Type { get; }
|
||||
|
||||
public Type Champion { get; }
|
||||
|
||||
public Type[][] SpawnTypes { get; }
|
||||
|
||||
public TextDefinition[] LevelNames { get; }
|
||||
|
||||
public ChampionSpawnInfo(ChampionSpawnType type, Type champion, TextDefinition[] levelNames, Type[][] spawnTypes)
|
||||
{
|
||||
Type = type;
|
||||
Champion = champion;
|
||||
LevelNames = levelNames;
|
||||
SpawnTypes = spawnTypes;
|
||||
}
|
||||
|
||||
// After updating this table, make sure to update ChampionTitleContext.
|
||||
public static ChampionSpawnInfo[] Table { get; } = {
|
||||
new(ChampionSpawnType.Abyss, typeof(Semidar), new TextDefinition[]{ 1113118, 1113107, 1113096 }, new[]
|
||||
{
|
||||
new[]{ typeof(GreaterMongbat), typeof(Imp) }, // Level 1
|
||||
new[]{ typeof(Gargoyle), typeof(Harpy) }, // Level 2
|
||||
new[]{ typeof(FireGargoyle), typeof(StoneGargoyle) }, // Level 3
|
||||
new[]{ typeof(Daemon), typeof(Succubus) } // Level 4
|
||||
}),
|
||||
new(ChampionSpawnType.Arachnid, typeof(Mephitis), new TextDefinition[]{ 1113117, 1113106, 1113095 }, new[]
|
||||
{
|
||||
new[]{ typeof(Scorpion), typeof(GiantSpider) }, // Level 1
|
||||
new[]{ typeof(TerathanDrone), typeof(TerathanWarrior) }, // Level 2
|
||||
new[]{ typeof(DreadSpider), typeof(TerathanMatriarch) }, // Level 3
|
||||
new[]{ typeof(PoisonElemental), typeof(TerathanAvenger) } // Level 4
|
||||
}),
|
||||
new(ChampionSpawnType.ColdBlood, typeof(Rikktor), new TextDefinition[]{ 1113115, 1113104, 1113093 }, new[]
|
||||
{
|
||||
new[]{ typeof(Lizardman), typeof(GiantSerpent) }, // Level 1
|
||||
new[]{ typeof(LavaLizard), typeof(OphidianWarrior) }, // Level 2
|
||||
new[]{ typeof(Drake), typeof(OphidianArchmage) }, // Level 3
|
||||
new[]{ typeof(Dragon), typeof(OphidianKnight) } // Level 4
|
||||
}),
|
||||
new(ChampionSpawnType.ForestLord, typeof(LordOaks), new TextDefinition[]{ 1113116, 1113105, 1113094 }, new[]
|
||||
{
|
||||
new[]{ typeof(Pixie), typeof(ShadowWisp) }, // Level 1
|
||||
new[]{ typeof(Kirin), typeof(Wisp) }, // Level 2
|
||||
new[]{ typeof(Centaur), typeof(Unicorn) }, // Level 3
|
||||
new[]{ typeof(EtherealWarrior), typeof(SerpentineDragon) } // Level 4
|
||||
}),
|
||||
new(ChampionSpawnType.VerminHorde, typeof(Barracoon), new TextDefinition[]{ 1113119, 1113108, 1113097 }, new[]
|
||||
{
|
||||
new[]{ typeof(GiantRat), typeof(Slime) }, // Level 1
|
||||
new[]{ typeof(DireWolf), typeof(Ratman) }, // Level 2
|
||||
new[]{ typeof(HellHound), typeof(RatmanMage) }, // Level 3
|
||||
new[]{ typeof(RatmanArcher), typeof(SilverSerpent) } // Level 4
|
||||
}),
|
||||
new(ChampionSpawnType.UnholyTerror, typeof(Neira), new TextDefinition[]{ 1113120, 1113109, 1113098 }, new[]
|
||||
{
|
||||
Core.AOS ? // Level 1
|
||||
new[]{ typeof(Bogle), typeof(Ghoul), typeof(Shade), typeof(Spectre), typeof(Wraith) }
|
||||
: new[]{ typeof(Ghoul), typeof(Shade), typeof(Spectre), typeof(Wraith) },
|
||||
|
||||
new[]{ typeof(BoneMagi), typeof(Mummy), typeof(SkeletalMage) }, // Level 2
|
||||
new[]{ typeof(BoneKnight), typeof(Lich), typeof(SkeletalKnight) }, // Level 3
|
||||
new[]{ typeof(LichLord), typeof(RottingCorpse) } // Level 4
|
||||
}),
|
||||
new(ChampionSpawnType.SleepingDragon, typeof(Serado), new TextDefinition[]{ 1113121, 1113110, 1113099 }, new[]
|
||||
{
|
||||
new[]{ typeof(DeathwatchBeetleHatchling), typeof(Lizardman) }, // Level 1
|
||||
new[]{ typeof(DeathwatchBeetle), typeof(Kappa) }, // Level 2
|
||||
new[]{ typeof(LesserHiryu), typeof(RevenantLion) }, // Level 3
|
||||
new[]{ typeof(Hiryu), typeof(Oni) } // Level 4
|
||||
}),
|
||||
new(ChampionSpawnType.Glade, typeof(Twaulo), new TextDefinition[]{ 1113123, 1113112, 1113101 }, new[]
|
||||
{
|
||||
new[]{ typeof(Pixie), typeof(ShadowWisp) }, // Level 1
|
||||
new[]{ typeof(Centaur), typeof(MLDryad) }, // Level 2
|
||||
new[]{ typeof(Satyr), typeof(CuSidhe) }, // Level 3
|
||||
new[]{ typeof(FeralTreefellow), typeof(RagingGrizzlyBear) } // Level 4
|
||||
}),
|
||||
new(ChampionSpawnType.Corrupt, typeof(Ilhenir), new TextDefinition[]{ 1113122, 1113111, 1113100 }, new[]
|
||||
{
|
||||
new[]{ typeof(PlagueSpawn), typeof(Bogling) }, // Level 1
|
||||
new[]{ typeof(PlagueBeast), typeof(BogThing) }, // Level 2
|
||||
new[]{ typeof(PlagueBeastLord), typeof(InterredGrizzle) }, // Level 3
|
||||
new[]{ typeof(FetidEssence), typeof(PestilentBandage) } // Level 4
|
||||
}),
|
||||
// new(ChampionSpawnType.Unliving, typeof(PrimevalLich), new TextDefinition[]{ 1113124, 1113113, 1113102 }, new[]
|
||||
// {
|
||||
// new[]{ typeof(GoreFiend), typeof(VampireBat) },
|
||||
// new[]{ typeof(FleshGolem), typeof(DarkWisp) },
|
||||
// new[]{ typeof(UndeadGargoyle), typeof(Wight) },
|
||||
// new[]{ typeof(SkeletalDrake), typeof(DreamWraith) }
|
||||
// }),
|
||||
// new(ChampionSpawnType.Pit, typeof(AbyssalInfernal), new TextDefinition[]{ 1113125, 1113114, 1113103 }, new[]
|
||||
// {
|
||||
// new[]{ typeof(HordeMinion), typeof(ChaosDaemon) },
|
||||
// new[]{ typeof(StoneHarpy), typeof(ArcaneDaemon) },
|
||||
// new[]{ typeof(PitFiend), typeof(Moloch) },
|
||||
// new[]{ typeof(ArchDaemon), typeof(AbyssalAbomination) }
|
||||
// }),
|
||||
// new(ChampionSpawnType.Valley, typeof(DragonTurtle), new TextDefinition[]{ "Explorer", "Huntsman", "Msafiri" }, new[]
|
||||
// {
|
||||
// new[]{ typeof(MyrmidexDrone), typeof(MyrmidexLarvae) },
|
||||
// new[]{ typeof(SilverbackGorilla), typeof(WildTiger) },
|
||||
// new[]{ typeof(GreaterPhoenix ), typeof(Infernus) },
|
||||
// new[]{ typeof(Dimetrosaur), typeof(Allosaurus) }
|
||||
// }),
|
||||
// new(ChampionSpawnType.Khaldun, typeof(KhalAnkur), new TextDefinition[]{ "Banisher", "Enforcer", "Eradicator" }, new[]
|
||||
// {
|
||||
// new[]{ typeof(SkelementalKnight), typeof(KhaldunBlood) },
|
||||
// new[]{ typeof(SkelementalMage), typeof(Viscera) },
|
||||
// new[]{ typeof(CultistAmbusher), typeof(ShadowFiend) },
|
||||
// new[]{ typeof(KhalAnkurWarriors) }
|
||||
// })
|
||||
};
|
||||
|
||||
public static ChampionSpawnInfo GetInfo(ChampionSpawnType type)
|
||||
{
|
||||
var v = (int)type;
|
||||
|
||||
if (v < 0 || v >= Table.Length)
|
||||
{
|
||||
v = 0;
|
||||
}
|
||||
|
||||
return Table[v];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2022 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: ChampionSpawnType.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
{
|
||||
public enum ChampionSpawnType
|
||||
{
|
||||
Abyss,
|
||||
Arachnid,
|
||||
ColdBlood,
|
||||
ForestLord,
|
||||
VerminHorde,
|
||||
UnholyTerror,
|
||||
SleepingDragon,
|
||||
Glade,
|
||||
Pestilence,
|
||||
Graveyard
|
||||
}
|
||||
|
||||
public class ChampionSpawnInfo
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public Type Champion { get; }
|
||||
|
||||
public Type[][] SpawnTypes { get; }
|
||||
|
||||
public string[] LevelNames { get; }
|
||||
|
||||
public ChampionSpawnInfo(string name, Type champion, string[] levelNames, Type[][] spawnTypes)
|
||||
{
|
||||
Name = name;
|
||||
Champion = champion;
|
||||
LevelNames = levelNames;
|
||||
SpawnTypes = spawnTypes;
|
||||
}
|
||||
|
||||
public static ChampionSpawnInfo[] Table { get; } = {
|
||||
new("Abyss", typeof(Semidar), new[]{ "Foe", "Assassin", "Conqueror" }, new[]
|
||||
{
|
||||
new[]{ typeof(GreaterMongbat), typeof(Imp) }, // Level 1
|
||||
new[]{ typeof(Gargoyle), typeof(Harpy) }, // Level 2
|
||||
new[]{ typeof(FireGargoyle), typeof(StoneGargoyle) }, // Level 3
|
||||
new[]{ typeof(Daemon), typeof(Succubus) } // Level 4
|
||||
}),
|
||||
new("Arachnid", typeof(Mephitis), new[]{ "Bane", "Killer", "Vanquisher" }, new[]
|
||||
{
|
||||
new[]{ typeof(Scorpion), typeof(GiantSpider) }, // Level 1
|
||||
new[]{ typeof(TerathanDrone), typeof(TerathanWarrior) }, // Level 2
|
||||
new[]{ typeof(DreadSpider), typeof(TerathanMatriarch) }, // Level 3
|
||||
new[]{ typeof(PoisonElemental), typeof(TerathanAvenger) } // Level 4
|
||||
}),
|
||||
new("Cold Blood", typeof(Rikktor), new[]{ "Blight", "Slayer", "Destroyer" }, new[]
|
||||
{
|
||||
new[]{ typeof(Lizardman), typeof(GiantSerpent) }, // Level 1
|
||||
new[]{ typeof(LavaLizard), typeof(OphidianWarrior) }, // Level 2
|
||||
new[]{ typeof(Drake), typeof(OphidianArchmage) }, // Level 3
|
||||
new[]{ typeof(Dragon), typeof(OphidianKnight) } // Level 4
|
||||
}),
|
||||
new("Forest Lord", typeof(LordOaks), new[]{ "Enemy", "Curse", "Slaughterer" }, new[]
|
||||
{
|
||||
new[]{ typeof(Pixie), typeof(ShadowWisp) }, // Level 1
|
||||
new[]{ typeof(Kirin), typeof(Wisp) }, // Level 2
|
||||
new[]{ typeof(Centaur), typeof(Unicorn) }, // Level 3
|
||||
new[]{ typeof(EtherealWarrior), typeof(SerpentineDragon) } // Level 4
|
||||
}),
|
||||
new("Vermin Horde", typeof(Barracoon), new[]{ "Adversary", "Subjugator", "Eradicator" }, new[]
|
||||
{
|
||||
new[]{ typeof(GiantRat), typeof(Slime) }, // Level 1
|
||||
new[]{ typeof(DireWolf), typeof(Ratman) }, // Level 2
|
||||
new[]{ typeof(HellHound), typeof(RatmanMage) }, // Level 3
|
||||
new[]{ typeof(RatmanArcher), typeof(SilverSerpent) } // Level 4
|
||||
}),
|
||||
new("Unholy Terror", typeof(Neira), new[]{ "Scourge", "Punisher", "Nemesis" }, new[]
|
||||
{
|
||||
Core.AOS ? // Level 1
|
||||
new[]{ typeof(Bogle), typeof(Ghoul), typeof(Shade), typeof(Spectre), typeof(Wraith) }
|
||||
: new[]{ typeof(Ghoul), typeof(Shade), typeof(Spectre), typeof(Wraith) },
|
||||
|
||||
new[]{ typeof(BoneMagi), typeof(Mummy), typeof(SkeletalMage) }, // Level 2
|
||||
new[]{ typeof(BoneKnight), typeof(Lich), typeof(SkeletalKnight) }, // Level 3
|
||||
new[]{ typeof(LichLord), typeof(RottingCorpse) } // Level 4
|
||||
}),
|
||||
new("Sleeping Dragon", typeof(Serado), new[]{ "Rival", "Challenger", "Antagonist" } , new[]
|
||||
{
|
||||
new[]{ typeof(DeathwatchBeetleHatchling), typeof(Lizardman) }, // Level 1
|
||||
new[]{ typeof(DeathwatchBeetle), typeof(Kappa) }, // Level 2
|
||||
new[]{ typeof(LesserHiryu), typeof(RevenantLion) }, // Level 3
|
||||
new[]{ typeof(Hiryu), typeof(Oni) } // Level 4
|
||||
}),
|
||||
new("Glade", typeof(Twaulo), new[]{ "Banisher", "Enforcer", "Eradicator" } , new[]
|
||||
{
|
||||
new[]{ typeof(Pixie), typeof(ShadowWisp) }, // Level 1
|
||||
new[]{ typeof(Centaur), typeof(MLDryad) }, // Level 2
|
||||
new[]{ typeof(Satyr), typeof(CuSidhe) }, // Level 3
|
||||
new[]{ typeof(FeralTreefellow), typeof(RagingGrizzlyBear) } // Level 4
|
||||
}),
|
||||
new("The Corrupt", typeof(Ilhenir), new[]{ "Cleanser", "Expunger", "Depurator" } , new[]
|
||||
{
|
||||
new[]{ typeof(PlagueSpawn), typeof(Bogling) }, // Level 1
|
||||
new[]{ typeof(PlagueBeast), typeof(BogThing) }, // Level 2
|
||||
new[]{ typeof(PlagueBeastLord), typeof(InterredGrizzle) }, // Level 3
|
||||
new[]{ typeof(FetidEssence), typeof(PestilentBandage) } // Level 4
|
||||
}),
|
||||
};
|
||||
|
||||
public static ChampionSpawnInfo GetInfo(ChampionSpawnType type)
|
||||
{
|
||||
var v = (int)type;
|
||||
|
||||
if (v < 0 || v >= Table.Length)
|
||||
{
|
||||
v = 0;
|
||||
}
|
||||
|
||||
return Table[v];
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Projects/UOContent/Engines/CannedEvil/ChampionTitle.cs
Normal file
30
Projects/UOContent/Engines/CannedEvil/ChampionTitle.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Engines.CannedEvil;
|
||||
|
||||
[SerializationGenerator(0)]
|
||||
public partial class ChampionTitle
|
||||
{
|
||||
[EncodedInt]
|
||||
[SerializableField(0)]
|
||||
private int _value;
|
||||
|
||||
// TODO: Change to delta time
|
||||
[SerializableField(1)]
|
||||
private DateTime _lastDecay;
|
||||
|
||||
public bool Atrophy(int value)
|
||||
{
|
||||
var before = Value;
|
||||
|
||||
Value -= Math.Min(value, before);
|
||||
|
||||
if (before != Value)
|
||||
{
|
||||
LastDecay = Core.Now;
|
||||
}
|
||||
|
||||
return Value > 0;
|
||||
}
|
||||
}
|
||||
379
Projects/UOContent/Engines/CannedEvil/ChampionTitleContext.cs
Normal file
379
Projects/UOContent/Engines/CannedEvil/ChampionTitleContext.cs
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.CannedEvil;
|
||||
|
||||
[PropertyObject]
|
||||
[SerializationGenerator(1)]
|
||||
public partial class ChampionTitleContext
|
||||
{
|
||||
private const int LossAmount = 90;
|
||||
private static readonly TimeSpan LossDelay = TimeSpan.FromDays(1.0);
|
||||
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private int _harrower;
|
||||
|
||||
private PlayerMobile _player;
|
||||
|
||||
public PlayerMobile Player => _player;
|
||||
|
||||
public ChampionTitleContext(PlayerMobile player) => _player = player;
|
||||
|
||||
// Visible to PublicMobile for migrations
|
||||
internal void Deserialize(IGenericReader reader, int version)
|
||||
{
|
||||
_harrower = reader.ReadEncodedInt();
|
||||
|
||||
var length = reader.ReadEncodedInt();
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the list/enum for ChampionSpawnInfo changes, then this has to change for migrations
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
var type = (ChampionSpawnType)i;
|
||||
ref var title = ref GetTitleValueRef(type);
|
||||
|
||||
if (Unsafe.IsNullRef(ref title))
|
||||
{
|
||||
throw new NotImplementedException($"Cannot find ChampionSpawnType value {type}.");
|
||||
}
|
||||
|
||||
title = new ChampionTitle();
|
||||
title.Deserialize(reader);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializableField(1)]
|
||||
private ChampionTitle _abyss;
|
||||
|
||||
[SerializableFieldSaveFlag(1)]
|
||||
private bool ShouldSerializeAbyss() => _abyss != null;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int AbyssValue
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.Abyss)?.Value ?? 0;
|
||||
set => SetValue(ChampionSpawnType.Abyss, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime AbyssLastDecay
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.Abyss)?.LastDecay ?? DateTime.MinValue;
|
||||
set => SetLastDecay(ChampionSpawnType.Abyss, value);
|
||||
}
|
||||
|
||||
[SerializableField(2)]
|
||||
private ChampionTitle _arachnid;
|
||||
|
||||
[SerializableFieldSaveFlag(2)]
|
||||
private bool ShouldSerializeArachnid() => _arachnid != null;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ArachnidValue
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.Arachnid)?.Value ?? 0;
|
||||
set => SetValue(ChampionSpawnType.Arachnid, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime ArachnidLastDecay
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.Arachnid)?.LastDecay ?? DateTime.MinValue;
|
||||
set => SetLastDecay(ChampionSpawnType.Arachnid, value);
|
||||
}
|
||||
|
||||
[SerializableField(3)]
|
||||
private ChampionTitle _coldBlood;
|
||||
|
||||
[SerializableFieldSaveFlag(3)]
|
||||
private bool ShouldSerializeColdBlood() => _coldBlood != null;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ColdBloodValue
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.ColdBlood)?.Value ?? 0;
|
||||
set => SetValue(ChampionSpawnType.ColdBlood, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime ColdBloodLastDecay
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.ColdBlood)?.LastDecay ?? DateTime.MinValue;
|
||||
set => SetLastDecay(ChampionSpawnType.ColdBlood, value);
|
||||
}
|
||||
|
||||
[SerializableField(4)]
|
||||
private ChampionTitle _forestLord;
|
||||
|
||||
[SerializableFieldSaveFlag(4)]
|
||||
private bool ShouldSerializeForestLord() => _forestLord != null;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ForestLordValue
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.ForestLord)?.Value ?? 0;
|
||||
set => SetValue(ChampionSpawnType.ForestLord, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime ForestLordLastDecay
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.ForestLord)?.LastDecay ?? DateTime.MinValue;
|
||||
set => SetLastDecay(ChampionSpawnType.ForestLord, value);
|
||||
}
|
||||
|
||||
[SerializableField(5)]
|
||||
private ChampionTitle _verminHorde;
|
||||
|
||||
[SerializableFieldSaveFlag(5)]
|
||||
private bool ShouldSerializeVerminHorde() => _verminHorde != null;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int VerminHordeValue
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.VerminHorde)?.Value ?? 0;
|
||||
set => SetValue(ChampionSpawnType.VerminHorde, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime VerminHordeLastDecay
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.VerminHorde)?.LastDecay ?? DateTime.MinValue;
|
||||
set => SetLastDecay(ChampionSpawnType.VerminHorde, value);
|
||||
}
|
||||
|
||||
[SerializableField(6)]
|
||||
private ChampionTitle _unholyTerror;
|
||||
|
||||
[SerializableFieldSaveFlag(6)]
|
||||
private bool ShouldSerializeUnholyTerror() => _unholyTerror != null;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int UnholyTerrorValue
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.UnholyTerror)?.Value ?? 0;
|
||||
set => SetValue(ChampionSpawnType.UnholyTerror, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime UnholyTerrorLastDecay
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.UnholyTerror)?.LastDecay ?? DateTime.MinValue;
|
||||
set => SetLastDecay(ChampionSpawnType.UnholyTerror, value);
|
||||
}
|
||||
|
||||
[SerializableField(7)]
|
||||
private ChampionTitle _sleepingDragon;
|
||||
|
||||
[SerializableFieldSaveFlag(7)]
|
||||
private bool ShouldSerializeSleepingDragon() => _sleepingDragon != null;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int SleepingDragonValue
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.SleepingDragon)?.Value ?? 0;
|
||||
set => SetValue(ChampionSpawnType.SleepingDragon, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime SleepingDragonLastDecay
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.SleepingDragon)?.LastDecay ?? DateTime.MinValue;
|
||||
set => SetLastDecay(ChampionSpawnType.SleepingDragon, value);
|
||||
}
|
||||
|
||||
[SerializableField(8)]
|
||||
private ChampionTitle _corrupt;
|
||||
|
||||
[SerializableFieldSaveFlag(8)]
|
||||
private bool ShouldSerializeCorrupt() => _corrupt != null;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int CorruptValue
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.Corrupt)?.Value ?? 0;
|
||||
set => SetValue(ChampionSpawnType.Corrupt, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime CorruptLastDecay
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.Corrupt)?.LastDecay ?? DateTime.MinValue;
|
||||
set => SetLastDecay(ChampionSpawnType.Corrupt, value);
|
||||
}
|
||||
|
||||
[SerializableField(9)]
|
||||
private ChampionTitle _glade;
|
||||
|
||||
[SerializableFieldSaveFlag(9)]
|
||||
private bool ShouldSerializeGlade() => _glade != null;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int GladeValue
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.Glade)?.Value ?? 0;
|
||||
set => SetValue(ChampionSpawnType.Glade, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime GladeLastDecay
|
||||
{
|
||||
get => GetTitle(ChampionSpawnType.Glade)?.LastDecay ?? DateTime.MinValue;
|
||||
set => SetLastDecay(ChampionSpawnType.Glade, value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ChampionTitle GetTitle(ChampionSpawnType type) => GetTitleValueRef(type);
|
||||
|
||||
// Get a pointer to the title so we can manipulate it internally such as nullifying it.
|
||||
// Using this technique instead of an array decouples the context from changes to ChampionSpawnInfo.Table indexes
|
||||
private ref ChampionTitle GetTitleValueRef(ChampionSpawnType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ChampionSpawnType.Abyss:
|
||||
{
|
||||
return ref _abyss;
|
||||
}
|
||||
case ChampionSpawnType.Arachnid:
|
||||
{
|
||||
return ref _arachnid;
|
||||
}
|
||||
case ChampionSpawnType.ColdBlood:
|
||||
{
|
||||
return ref _coldBlood;
|
||||
}
|
||||
case ChampionSpawnType.ForestLord:
|
||||
{
|
||||
return ref _forestLord;
|
||||
}
|
||||
case ChampionSpawnType.VerminHorde:
|
||||
{
|
||||
return ref _verminHorde;
|
||||
}
|
||||
case ChampionSpawnType.UnholyTerror:
|
||||
{
|
||||
return ref _unholyTerror;
|
||||
}
|
||||
case ChampionSpawnType.SleepingDragon:
|
||||
{
|
||||
return ref _sleepingDragon;
|
||||
}
|
||||
case ChampionSpawnType.Glade:
|
||||
{
|
||||
return ref _glade;
|
||||
}
|
||||
case ChampionSpawnType.Corrupt:
|
||||
{
|
||||
return ref _corrupt;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return ref Unsafe.NullRef<ChampionTitle>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ChampionTitle TryGetOrCreateTitle(ChampionSpawnType type)
|
||||
{
|
||||
ref var title = ref GetTitleValueRef(type);
|
||||
if (Unsafe.IsNullRef(ref title))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return title ??= new ChampionTitle();
|
||||
}
|
||||
|
||||
public void SetValue(ChampionSpawnType type, int value)
|
||||
{
|
||||
ref var title = ref GetTitleValueRef(type);
|
||||
if (Unsafe.IsNullRef(ref title))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (title != null)
|
||||
{
|
||||
if (value <= 0)
|
||||
{
|
||||
title = null;
|
||||
|
||||
_player.InvalidateProperties();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
title = new ChampionTitle();
|
||||
}
|
||||
|
||||
title.Value = value;
|
||||
title.LastDecay = Core.Now;
|
||||
_player.InvalidateProperties();
|
||||
}
|
||||
|
||||
public void SetLastDecay(ChampionSpawnType type, DateTime value)
|
||||
{
|
||||
var title = TryGetOrCreateTitle(type);
|
||||
if (title != null)
|
||||
{
|
||||
title.LastDecay = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Award(ChampionSpawnType type, int value)
|
||||
{
|
||||
var title = TryGetOrCreateTitle(type);
|
||||
if (title == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
title.Value += value;
|
||||
if (title.LastDecay == DateTime.MinValue)
|
||||
{
|
||||
title.LastDecay = Core.Now;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckAtrophy()
|
||||
{
|
||||
var valuesUsed = _harrower > 0;
|
||||
|
||||
for (var i = 0; i < ChampionSpawnInfo.Table.Length; i++)
|
||||
{
|
||||
ref var title = ref GetTitleValueRef(ChampionSpawnInfo.Table[i].Type);
|
||||
if (Unsafe.IsNullRef(ref title))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var decay = title.LastDecay;
|
||||
if (decay > DateTime.MinValue && decay + LossDelay < Core.Now)
|
||||
{
|
||||
// Use bitwise-or to force-execute the Atrophy function
|
||||
var isUsed = title.Atrophy(LossAmount);
|
||||
|
||||
if (!isUsed)
|
||||
{
|
||||
title = null;
|
||||
}
|
||||
|
||||
valuesUsed |= isUsed;
|
||||
}
|
||||
}
|
||||
|
||||
return valuesUsed;
|
||||
}
|
||||
|
||||
public override string ToString() => "...";
|
||||
}
|
||||
172
Projects/UOContent/Engines/CannedEvil/ChampionTitleSystem.cs
Normal file
172
Projects/UOContent/Engines/CannedEvil/ChampionTitleSystem.cs
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Server.Collections;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.CannedEvil;
|
||||
|
||||
public static class ChampionTitleSystem
|
||||
{
|
||||
// All of the players with murders
|
||||
private static readonly Dictionary<PlayerMobile, ChampionTitleContext> _championTitleContexts = new();
|
||||
|
||||
private static readonly Timer _championTitleTimer = new ChampionTitleTimer();
|
||||
|
||||
public static void Configure()
|
||||
{
|
||||
GenericPersistence.Register("ChampionTitles", Serialize, Deserialize);
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
EventSink.PlayerDeleted += OnPlayerDeleted;
|
||||
|
||||
_championTitleTimer.Start();
|
||||
}
|
||||
|
||||
private static void OnPlayerDeleted(Mobile m)
|
||||
{
|
||||
if (m is PlayerMobile pm)
|
||||
{
|
||||
_championTitleContexts.Remove(pm);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Deserialize(IGenericReader reader)
|
||||
{
|
||||
var version = reader.ReadEncodedInt();
|
||||
|
||||
var count = reader.ReadEncodedInt();
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var context = new ChampionTitleContext(reader.ReadEntity<PlayerMobile>());
|
||||
context.Deserialize(reader);
|
||||
|
||||
_championTitleContexts.Add(context.Player, context);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Serialize(IGenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
writer.WriteEncodedInt(_championTitleContexts.Count);
|
||||
foreach (var (m, context) in _championTitleContexts)
|
||||
{
|
||||
writer.Write(m);
|
||||
context.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetChampionTitleContext(this PlayerMobile player, out ChampionTitleContext context) =>
|
||||
_championTitleContexts.TryGetValue(player, out context);
|
||||
|
||||
public static ChampionTitleContext GetOrCreateChampionTitleContext(this PlayerMobile player)
|
||||
{
|
||||
ref var context = ref CollectionsMarshal.GetValueRefOrAddDefault(_championTitleContexts, player, out var exists);
|
||||
if (!exists)
|
||||
{
|
||||
context = new ChampionTitleContext(player);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
// Called when killing a harrower. Will give a minimum of 1 point.
|
||||
public static void AwardHarrowerTitle(PlayerMobile pm)
|
||||
{
|
||||
var context = pm.GetOrCreateChampionTitleContext();
|
||||
|
||||
var count = 1;
|
||||
for (var i = 0; i < ChampionSpawnInfo.Table.Length; i++)
|
||||
{
|
||||
var title = context.GetTitle(ChampionSpawnInfo.Table[i].Type);
|
||||
if (title?.Value > 900)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
context.Harrower = Math.Max(count, context.Harrower); // Harrower titles never decay.
|
||||
}
|
||||
|
||||
public static int GetChampionTitleLabel(this PlayerMobile player)
|
||||
{
|
||||
if (!player.GetChampionTitleContext(out var context))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (context.Harrower > 0)
|
||||
{
|
||||
return 1113082 + Math.Min(context.Harrower, 10);
|
||||
}
|
||||
|
||||
var highestValue = 0;
|
||||
var highestType = 0;
|
||||
|
||||
for (var i = 0; i < ChampionSpawnInfo.Table.Length; i++)
|
||||
{
|
||||
var t = context.GetTitle(ChampionSpawnInfo.Table[i].Type);
|
||||
if (t == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var v = t.Value;
|
||||
|
||||
if (v > highestValue)
|
||||
{
|
||||
highestValue = v;
|
||||
highestType = i;
|
||||
}
|
||||
}
|
||||
|
||||
var offset = highestValue switch
|
||||
{
|
||||
> 800 => 3,
|
||||
> 300 => highestValue / 300,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
if (offset > 0)
|
||||
{
|
||||
var champInfo = ChampionSpawnInfo.Table[highestType];
|
||||
var championLevelName = champInfo.LevelNames[Math.Min(offset, champInfo.LevelNames.Length) - 1];
|
||||
return championLevelName.Number;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private class ChampionTitleTimer : Timer
|
||||
{
|
||||
public ChampionTitleTimer() : base(TimeSpan.FromMinutes(5.0), TimeSpan.FromMinutes(5.0))
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (_championTitleContexts.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var queue = PooledRefQueue<Mobile>.Create();
|
||||
|
||||
foreach (var context in _championTitleContexts.Values)
|
||||
{
|
||||
if (!context.CheckAtrophy())
|
||||
{
|
||||
queue.Enqueue(context.Player);
|
||||
}
|
||||
}
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
_championTitleContexts.Remove((PlayerMobile)queue.Dequeue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,42 +13,30 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Engines.CannedEvil;
|
||||
|
||||
[SerializationGenerator(0)]
|
||||
public partial class DungeonChampionSpawn : ChampionSpawn
|
||||
{
|
||||
public class DungeonChampionSpawn : ChampionSpawn
|
||||
[Constructible]
|
||||
public DungeonChampionSpawn()
|
||||
{
|
||||
[Constructible]
|
||||
public DungeonChampionSpawn()
|
||||
{
|
||||
CannedEvilTimer.AddSpawn(this);
|
||||
}
|
||||
CannedEvilTimer.AddSpawn(this);
|
||||
}
|
||||
|
||||
public DungeonChampionSpawn(Serial serial) : base(serial)
|
||||
{
|
||||
CannedEvilTimer.AddSpawn(this);
|
||||
}
|
||||
public DungeonChampionSpawn(Serial serial)
|
||||
{
|
||||
CannedEvilTimer.AddSpawn(this);
|
||||
}
|
||||
|
||||
public override bool ProximitySpawn => true;
|
||||
public override bool AlwaysActive => false;
|
||||
public override bool ProximitySpawn => true;
|
||||
public override bool AlwaysActive => false;
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); //version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
CannedEvilTimer.RemoveSpawn(this);
|
||||
}
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
CannedEvilTimer.RemoveSpawn(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,60 +1,32 @@
|
|||
namespace Server.Items
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class HarrowerGate : Moongate
|
||||
{
|
||||
public class HarrowerGate : Moongate
|
||||
[SerializableField(0)]
|
||||
private Mobile _harrower;
|
||||
|
||||
public HarrowerGate(Mobile harrower, Point3D loc, Map map, Point3D targLoc, Map targMap) : base(targLoc, targMap)
|
||||
{
|
||||
private Mobile m_Harrower;
|
||||
_harrower = harrower;
|
||||
|
||||
public HarrowerGate(Mobile harrower, Point3D loc, Map map, Point3D targLoc, Map targMap) : base(targLoc, targMap)
|
||||
Dispellable = false;
|
||||
ItemID = 0x1FD4;
|
||||
Light = LightType.Circle300;
|
||||
|
||||
MoveToWorld(loc, map);
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1049498; // dark moongate
|
||||
|
||||
[AfterDeserialization(false)]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
if (_harrower == null)
|
||||
{
|
||||
m_Harrower = harrower;
|
||||
|
||||
Dispellable = false;
|
||||
ItemID = 0x1FD4;
|
||||
Light = LightType.Circle300;
|
||||
|
||||
MoveToWorld(loc, map);
|
||||
}
|
||||
|
||||
public HarrowerGate(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1049498; // dark moongate
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Harrower);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Harrower = reader.ReadEntity<Mobile>();
|
||||
|
||||
if (m_Harrower == null)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Light != LightType.Circle300)
|
||||
{
|
||||
Light = LightType.Circle300;
|
||||
}
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,43 +13,31 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Engines.CannedEvil;
|
||||
|
||||
[SerializationGenerator(0)]
|
||||
public partial class LLChampionSpawn : ChampionSpawn
|
||||
{
|
||||
public class LLChampionSpawn : ChampionSpawn
|
||||
public override bool HasStarRoomGate => false;
|
||||
|
||||
[Constructible]
|
||||
public LLChampionSpawn()
|
||||
{
|
||||
public override bool HasStarRoomGate => false;
|
||||
CannedEvilTimer.AddSpawn(this);
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public LLChampionSpawn()
|
||||
{
|
||||
CannedEvilTimer.AddSpawn(this);
|
||||
}
|
||||
public LLChampionSpawn(Serial serial)
|
||||
{
|
||||
CannedEvilTimer.AddSpawn(this);
|
||||
}
|
||||
|
||||
public LLChampionSpawn(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
public override bool AlwaysActive => false;
|
||||
|
||||
public override bool AlwaysActive => false;
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); //version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
CannedEvilTimer.AddSpawn(this);
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
CannedEvilTimer.RemoveSpawn(this);
|
||||
}
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
CannedEvilTimer.RemoveSpawn(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,98 +1,68 @@
|
|||
using System;
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(1, false)]
|
||||
public partial class StarRoomGate : Moongate
|
||||
{
|
||||
public class StarRoomGate : Moongate
|
||||
private static TimeSpan GateDuration = TimeSpan.FromMinutes(2.0);
|
||||
|
||||
[SerializableField(0)]
|
||||
private bool _decays;
|
||||
|
||||
[DeltaDateTime]
|
||||
[SerializableField(1)]
|
||||
private DateTime _decayTime;
|
||||
|
||||
private Timer _timer;
|
||||
|
||||
[Constructible]
|
||||
public StarRoomGate(Point3D loc, Map map, bool decays) : this(decays)
|
||||
{
|
||||
private bool m_Decays;
|
||||
private DateTime m_DecayTime;
|
||||
private Timer m_Timer;
|
||||
MoveToWorld(loc, map);
|
||||
Effects.PlaySound(loc, map, 0x20E);
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public StarRoomGate(Point3D loc, Map map, bool decays) : this(decays)
|
||||
[Constructible]
|
||||
public StarRoomGate(bool decays = false) : base(new Point3D(5143, 1774, 0), Map.Felucca)
|
||||
{
|
||||
Dispellable = false;
|
||||
ItemID = 0x1FD4;
|
||||
|
||||
if (decays)
|
||||
{
|
||||
MoveToWorld(loc, map);
|
||||
Effects.PlaySound(loc, map, 0x20E);
|
||||
_decays = true;
|
||||
_decayTime = Core.Now + GateDuration;
|
||||
|
||||
_timer = Timer.DelayCall(GateDuration, Delete);
|
||||
}
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public StarRoomGate(bool decays = false) : base(new Point3D(5143, 1774, 0), Map.Felucca)
|
||||
public override int LabelNumber => 1049498; // dark moongate
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
_timer?.Stop();
|
||||
base.OnAfterDelete();
|
||||
}
|
||||
|
||||
private void Deserialize(IGenericReader reader, int version)
|
||||
{
|
||||
_decays = reader.ReadBool();
|
||||
|
||||
if (_decays)
|
||||
{
|
||||
Dispellable = false;
|
||||
ItemID = 0x1FD4;
|
||||
|
||||
if (decays)
|
||||
{
|
||||
m_Decays = true;
|
||||
m_DecayTime = Core.Now + TimeSpan.FromMinutes(2.0);
|
||||
|
||||
m_Timer = new InternalTimer(this, m_DecayTime);
|
||||
m_Timer.Start();
|
||||
}
|
||||
_decayTime = reader.ReadDeltaTime();
|
||||
}
|
||||
}
|
||||
|
||||
public StarRoomGate(Serial serial) : base(serial)
|
||||
[AfterDeserialization]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
if (_decays)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1049498; // dark moongate
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
m_Timer?.Stop();
|
||||
|
||||
base.OnAfterDelete();
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Decays);
|
||||
|
||||
if (m_Decays)
|
||||
{
|
||||
writer.WriteDeltaTime(m_DecayTime);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Decays = reader.ReadBool();
|
||||
|
||||
if (m_Decays)
|
||||
{
|
||||
m_DecayTime = reader.ReadDeltaTime();
|
||||
|
||||
m_Timer = new InternalTimer(this, m_DecayTime);
|
||||
m_Timer.Start();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private readonly Item m_Item;
|
||||
|
||||
public InternalTimer(Item item, DateTime end) : base(end - Core.Now) => m_Item = item;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Item.Delete();
|
||||
}
|
||||
_timer = Timer.DelayCall(_decayTime - Core.Now, Delete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ public static class ValorVirtue
|
|||
}
|
||||
else if (idol.Spawn.Active)
|
||||
{
|
||||
if (idol.Spawn.Champion != null) // TODO: Message?
|
||||
if (idol.Spawn.Champion != null)
|
||||
{
|
||||
return;
|
||||
from.SendLocalizedMessage(1112470); // You may not use Valor on this Champion Idol. The Champion has already spawned.
|
||||
}
|
||||
|
||||
int needed, consumed;
|
||||
|
|
|
|||
11
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionAltar.v0.json
generated
Normal file
11
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionAltar.v0.json
generated
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Engines.CannedEvil.ChampionAltar",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Spawn",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSpawn",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
11
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionPlatform.v0.json
generated
Normal file
11
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionPlatform.v0.json
generated
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Engines.CannedEvil.ChampionPlatform",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Spawn",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSpawn",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
21
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionSkullBrazier.v1.json
generated
Normal file
21
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionSkullBrazier.v1.json
generated
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"version": 1,
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullBrazier",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Type",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullType",
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Platform",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullPlatform",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Skull",
|
||||
"type": "Server.Item",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
36
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionSkullPlatform.v0.json
generated
Normal file
36
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionSkullPlatform.v0.json
generated
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullPlatform",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Power",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullBrazier",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Enlightenment",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullBrazier",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Venom",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullBrazier",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Pain",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullBrazier",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Greed",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullBrazier",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Death",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullBrazier",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
186
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionSpawn.v10.json
generated
Normal file
186
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionSpawn.v10.json
generated
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
{
|
||||
"version": 10,
|
||||
"type": "Server.Engines.CannedEvil.ChampionSpawn",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Level",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ActivatedByProximity",
|
||||
"type": "bool",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NextProximityTime",
|
||||
"type": "System.DateTime",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeltaTime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MaxLevel",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ActivatedByValor",
|
||||
"type": "bool",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DamageEntries",
|
||||
"type": "System.Collections.Generic.Dictionary\u003CServer.Mobile, int\u003E",
|
||||
"rule": "DictionaryMigrationRule",
|
||||
"ruleArguments": [
|
||||
"Server.Mobile",
|
||||
"SerializableInterfaceMigrationRule",
|
||||
"0",
|
||||
"int",
|
||||
"PrimitiveTypeMigrationRule",
|
||||
"1",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ConfinedRoaming",
|
||||
"type": "bool",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Idol",
|
||||
"type": "Server.Engines.CannedEvil.IdolOfTheChampion",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "HasBeenAdvanced",
|
||||
"type": "bool",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SpawnArea",
|
||||
"type": "Server.Rectangle2D",
|
||||
"rule": "PrimitiveUOTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"Rect2D"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "RandomizeType",
|
||||
"type": "bool",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Kills",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Active",
|
||||
"type": "bool",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Type",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSpawnType",
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Creatures",
|
||||
"type": "System.Collections.Generic.List\u003CServer.Mobile\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"Server.Mobile",
|
||||
"SerializableInterfaceMigrationRule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "RedSkulls",
|
||||
"type": "System.Collections.Generic.List\u003CServer.Item\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"Server.Item",
|
||||
"SerializableInterfaceMigrationRule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "WhiteSkulls",
|
||||
"type": "System.Collections.Generic.List\u003CServer.Item\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"Server.Item",
|
||||
"SerializableInterfaceMigrationRule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Platform",
|
||||
"type": "Server.Engines.CannedEvil.ChampionPlatform",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Altar",
|
||||
"type": "Server.Engines.CannedEvil.ChampionAltar",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "ExpireDelay",
|
||||
"type": "System.TimeSpan",
|
||||
"rule": "PrimitiveTypeMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "ExpireTime",
|
||||
"type": "System.DateTime",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeltaTime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Champion",
|
||||
"type": "Server.Mobile",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "RestartDelay",
|
||||
"type": "System.TimeSpan",
|
||||
"rule": "PrimitiveTypeMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "RestartTime",
|
||||
"type": "System.DateTime",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeltaTime"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
22
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionTitle.v0.json
generated
Normal file
22
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionTitle.v0.json
generated
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitle",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Value",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"EncodedInt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "LastDecay",
|
||||
"type": "System.DateTime",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
95
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionTitleContext.v1.json
generated
Normal file
95
Projects/UOContent/Migrations/Server.Engines.CannedEvil.ChampionTitleContext.v1.json
generated
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
{
|
||||
"version": 1,
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitleContext",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Harrower",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Abyss",
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitle",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Arachnid",
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitle",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ColdBlood",
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitle",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ForestLord",
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitle",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "VerminHorde",
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitle",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "UnholyTerror",
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitle",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SleepingDragon",
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitle",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Corrupt",
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitle",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Glade",
|
||||
"type": "Server.Engines.CannedEvil.ChampionTitle",
|
||||
"usesSaveFlag": true,
|
||||
"rule": "RawSerializableMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
4
Projects/UOContent/Migrations/Server.Engines.CannedEvil.DungeonChampionSpawn.v0.json
generated
Normal file
4
Projects/UOContent/Migrations/Server.Engines.CannedEvil.DungeonChampionSpawn.v0.json
generated
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Engines.CannedEvil.DungeonChampionSpawn"
|
||||
}
|
||||
11
Projects/UOContent/Migrations/Server.Engines.CannedEvil.IdolOfTheChampion.v0.json
generated
Normal file
11
Projects/UOContent/Migrations/Server.Engines.CannedEvil.IdolOfTheChampion.v0.json
generated
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Engines.CannedEvil.IdolOfTheChampion",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Spawn",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSpawn",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
4
Projects/UOContent/Migrations/Server.Engines.CannedEvil.LLChampionSpawn.v0.json
generated
Normal file
4
Projects/UOContent/Migrations/Server.Engines.CannedEvil.LLChampionSpawn.v0.json
generated
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Engines.CannedEvil.LLChampionSpawn"
|
||||
}
|
||||
11
Projects/UOContent/Migrations/Server.Items.ChampionSkull.v2.json
generated
Normal file
11
Projects/UOContent/Migrations/Server.Items.ChampionSkull.v2.json
generated
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 2,
|
||||
"type": "Server.Items.ChampionSkull",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Type",
|
||||
"type": "Server.Engines.CannedEvil.ChampionSkullType",
|
||||
"rule": "EnumMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
11
Projects/UOContent/Migrations/Server.Items.HarrowerGate.v0.json
generated
Normal file
11
Projects/UOContent/Migrations/Server.Items.HarrowerGate.v0.json
generated
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.HarrowerGate",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Harrower",
|
||||
"type": "Server.Mobile",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
22
Projects/UOContent/Migrations/Server.Items.StarRoomGate.v1.json
generated
Normal file
22
Projects/UOContent/Migrations/Server.Items.StarRoomGate.v1.json
generated
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"version": 1,
|
||||
"type": "Server.Items.StarRoomGate",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Decays",
|
||||
"type": "bool",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DecayTime",
|
||||
"type": "System.DateTime",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
"DeltaTime"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1207,12 +1207,6 @@ namespace Server.Guilds
|
|||
writer.Write(Website);
|
||||
}
|
||||
|
||||
public override bool ShouldExecuteAfterSerialize => false;
|
||||
|
||||
public override void AfterSerialize()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
World.RemoveGuild(this);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using Server.Buffers;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Mobiles;
|
||||
|
||||
|
|
@ -13,12 +14,6 @@ namespace Server.Misc
|
|||
public const int MinKarma = -15000;
|
||||
public const int MaxKarma = 15000;
|
||||
|
||||
public static string[] HarrowerTitles =
|
||||
{
|
||||
"Spite", "Opponent", "Hunter", "Venom", "Executioner",
|
||||
"Annihilator", "Champion", "Assailant", "Purifier", "Nullifier"
|
||||
};
|
||||
|
||||
private static readonly string[,] m_Levels =
|
||||
{
|
||||
{ "Neophyte", "Neophyte", "Neophyte" },
|
||||
|
|
@ -39,85 +34,85 @@ namespace Server.Misc
|
|||
1249,
|
||||
new[]
|
||||
{
|
||||
new KarmaEntry(-10000, "The Outcast {0}"),
|
||||
new KarmaEntry(-5000, "The Despicable {0}"),
|
||||
new KarmaEntry(-2500, "The Scoundrel {0}"),
|
||||
new KarmaEntry(-1250, "The Unsavory {0}"),
|
||||
new KarmaEntry(-625, "The Rude {0}"),
|
||||
new KarmaEntry(624, "{0}"),
|
||||
new KarmaEntry(1249, "The Fair {0}"),
|
||||
new KarmaEntry(2499, "The Kind {0}"),
|
||||
new KarmaEntry(4999, "The Good {0}"),
|
||||
new KarmaEntry(9999, "The Honest {0}"),
|
||||
new KarmaEntry(10000, "The Trustworthy {0}")
|
||||
new KarmaEntry(-10000, "The Outcast "),
|
||||
new KarmaEntry(-5000, "The Despicable "),
|
||||
new KarmaEntry(-2500, "The Scoundrel "),
|
||||
new KarmaEntry(-1250, "The Unsavory "),
|
||||
new KarmaEntry(-625, "The Rude "),
|
||||
new KarmaEntry(624, ""),
|
||||
new KarmaEntry(1249, "The Fair "),
|
||||
new KarmaEntry(2499, "The Kind "),
|
||||
new KarmaEntry(4999, "The Good "),
|
||||
new KarmaEntry(9999, "The Honest "),
|
||||
new KarmaEntry(10000, "The Trustworthy ")
|
||||
}
|
||||
),
|
||||
new(
|
||||
2499,
|
||||
new[]
|
||||
{
|
||||
new KarmaEntry(-10000, "The Wretched {0}"),
|
||||
new KarmaEntry(-5000, "The Dastardly {0}"),
|
||||
new KarmaEntry(-2500, "The Malicious {0}"),
|
||||
new KarmaEntry(-1250, "The Dishonorable {0}"),
|
||||
new KarmaEntry(-625, "The Disreputable {0}"),
|
||||
new KarmaEntry(624, "The Notable {0}"),
|
||||
new KarmaEntry(1249, "The Upstanding {0}"),
|
||||
new KarmaEntry(2499, "The Respectable {0}"),
|
||||
new KarmaEntry(4999, "The Honorable {0}"),
|
||||
new KarmaEntry(9999, "The Commendable {0}"),
|
||||
new KarmaEntry(10000, "The Estimable {0}")
|
||||
new KarmaEntry(-10000, "The Wretched "),
|
||||
new KarmaEntry(-5000, "The Dastardly "),
|
||||
new KarmaEntry(-2500, "The Malicious "),
|
||||
new KarmaEntry(-1250, "The Dishonorable "),
|
||||
new KarmaEntry(-625, "The Disreputable "),
|
||||
new KarmaEntry(624, "The Notable "),
|
||||
new KarmaEntry(1249, "The Upstanding "),
|
||||
new KarmaEntry(2499, "The Respectable "),
|
||||
new KarmaEntry(4999, "The Honorable "),
|
||||
new KarmaEntry(9999, "The Commendable "),
|
||||
new KarmaEntry(10000, "The Estimable ")
|
||||
}
|
||||
),
|
||||
new(
|
||||
4999,
|
||||
new[]
|
||||
{
|
||||
new KarmaEntry(-10000, "The Nefarious {0}"),
|
||||
new KarmaEntry(-5000, "The Wicked {0}"),
|
||||
new KarmaEntry(-2500, "The Vile {0}"),
|
||||
new KarmaEntry(-1250, "The Ignoble {0}"),
|
||||
new KarmaEntry(-625, "The Notorious {0}"),
|
||||
new KarmaEntry(624, "The Prominent {0}"),
|
||||
new KarmaEntry(1249, "The Reputable {0}"),
|
||||
new KarmaEntry(2499, "The Proper {0}"),
|
||||
new KarmaEntry(4999, "The Admirable {0}"),
|
||||
new KarmaEntry(9999, "The Famed {0}"),
|
||||
new KarmaEntry(10000, "The Great {0}")
|
||||
new KarmaEntry(-10000, "The Nefarious "),
|
||||
new KarmaEntry(-5000, "The Wicked "),
|
||||
new KarmaEntry(-2500, "The Vile "),
|
||||
new KarmaEntry(-1250, "The Ignoble "),
|
||||
new KarmaEntry(-625, "The Notorious "),
|
||||
new KarmaEntry(624, "The Prominent "),
|
||||
new KarmaEntry(1249, "The Reputable "),
|
||||
new KarmaEntry(2499, "The Proper "),
|
||||
new KarmaEntry(4999, "The Admirable "),
|
||||
new KarmaEntry(9999, "The Famed "),
|
||||
new KarmaEntry(10000, "The Great ")
|
||||
}
|
||||
),
|
||||
new(
|
||||
9999,
|
||||
new[]
|
||||
{
|
||||
new KarmaEntry(-10000, "The Dread {0}"),
|
||||
new KarmaEntry(-5000, "The Evil {0}"),
|
||||
new KarmaEntry(-2500, "The Villainous {0}"),
|
||||
new KarmaEntry(-1250, "The Sinister {0}"),
|
||||
new KarmaEntry(-625, "The Infamous {0}"),
|
||||
new KarmaEntry(624, "The Renowned {0}"),
|
||||
new KarmaEntry(1249, "The Distinguished {0}"),
|
||||
new KarmaEntry(2499, "The Eminent {0}"),
|
||||
new KarmaEntry(4999, "The Noble {0}"),
|
||||
new KarmaEntry(9999, "The Illustrious {0}"),
|
||||
new KarmaEntry(10000, "The Glorious {0}")
|
||||
new KarmaEntry(-10000, "The Dread "),
|
||||
new KarmaEntry(-5000, "The Evil "),
|
||||
new KarmaEntry(-2500, "The Villainous "),
|
||||
new KarmaEntry(-1250, "The Sinister "),
|
||||
new KarmaEntry(-625, "The Infamous "),
|
||||
new KarmaEntry(624, "The Renowned "),
|
||||
new KarmaEntry(1249, "The Distinguished "),
|
||||
new KarmaEntry(2499, "The Eminent "),
|
||||
new KarmaEntry(4999, "The Noble "),
|
||||
new KarmaEntry(9999, "The Illustrious "),
|
||||
new KarmaEntry(10000, "The Glorious ")
|
||||
}
|
||||
),
|
||||
new(
|
||||
10000,
|
||||
new[]
|
||||
{
|
||||
new KarmaEntry(-10000, "The Dread {1} {0}"),
|
||||
new KarmaEntry(-5000, "The Evil {1} {0}"),
|
||||
new KarmaEntry(-2500, "The Dark {1} {0}"),
|
||||
new KarmaEntry(-1250, "The Sinister {1} {0}"),
|
||||
new KarmaEntry(-625, "The Dishonored {1} {0}"),
|
||||
new KarmaEntry(624, "{1} {0}"),
|
||||
new KarmaEntry(1249, "The Distinguished {1} {0}"),
|
||||
new KarmaEntry(2499, "The Eminent {1} {0}"),
|
||||
new KarmaEntry(4999, "The Noble {1} {0}"),
|
||||
new KarmaEntry(9999, "The Illustrious {1} {0}"),
|
||||
new KarmaEntry(10000, "The Glorious {1} {0}")
|
||||
new KarmaEntry(-10000, "The Dread "),
|
||||
new KarmaEntry(-5000, "The Evil "),
|
||||
new KarmaEntry(-2500, "The Dark "),
|
||||
new KarmaEntry(-1250, "The Sinister "),
|
||||
new KarmaEntry(-625, "The Dishonored "),
|
||||
new KarmaEntry(624, ""),
|
||||
new KarmaEntry(1249, "The Distinguished "),
|
||||
new KarmaEntry(2499, "The Eminent "),
|
||||
new KarmaEntry(4999, "The Noble "),
|
||||
new KarmaEntry(9999, "The Illustrious "),
|
||||
new KarmaEntry(10000, "The Glorious ")
|
||||
}
|
||||
)
|
||||
};
|
||||
|
|
@ -274,7 +269,7 @@ namespace Server.Misc
|
|||
|
||||
public static string ComputeTitle(Mobile beholder, Mobile beheld)
|
||||
{
|
||||
var title = new StringBuilder();
|
||||
using var title = ValueStringBuilder.Create();
|
||||
|
||||
var fame = beheld.Fame;
|
||||
var karma = beheld.Karma;
|
||||
|
|
@ -297,7 +292,21 @@ namespace Server.Misc
|
|||
|
||||
if (karma <= ke.m_Karma || j == karmaEntries.Length - 1)
|
||||
{
|
||||
title.AppendFormat(ke.m_Title, beheld.Name, beheld.Female ? "Lady" : "Lord");
|
||||
if (karma >= 10000)
|
||||
{
|
||||
if (beheld.Female)
|
||||
{
|
||||
title.Append($"{ke.m_Title}Lady {beheld.Name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
title.Append($"{ke.m_Title}Lord {beheld.Name}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
title.Append($"{ke.m_Title}{beheld.Name}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -313,40 +322,14 @@ namespace Server.Misc
|
|||
|
||||
if (beheld is PlayerMobile mobile && mobile.DisplayChampionTitle)
|
||||
{
|
||||
var info = mobile.ChampionTitles;
|
||||
|
||||
if (info.Harrower > 0)
|
||||
var titleLabel = mobile.GetChampionTitleLabel();
|
||||
if (titleLabel > 0)
|
||||
{
|
||||
title.Append($": {HarrowerTitles[Math.Min(HarrowerTitles.Length, info.Harrower) - 1]} of Evil");
|
||||
}
|
||||
else
|
||||
{
|
||||
int highestValue = 0, highestType = 0;
|
||||
for (var i = 0; i < ChampionSpawnInfo.Table.Length; i++)
|
||||
{
|
||||
var v = info.GetValue(i);
|
||||
// Should this be translated to the receivers language? Prefix titles aren't?
|
||||
title.Append($": {Localization.GetText(titleLabel)}");
|
||||
|
||||
if (v > highestValue)
|
||||
{
|
||||
highestValue = v;
|
||||
highestType = i;
|
||||
}
|
||||
}
|
||||
|
||||
var offset = highestValue switch
|
||||
{
|
||||
> 800 => 3,
|
||||
> 300 => highestValue / 300,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
if (offset > 0)
|
||||
{
|
||||
var champInfo = ChampionSpawnInfo.GetInfo((ChampionSpawnType)highestType);
|
||||
title.Append(
|
||||
$": {champInfo.LevelNames[Math.Min(offset, champInfo.LevelNames.Length) - 1]} of the {champInfo.Name}"
|
||||
);
|
||||
}
|
||||
// Do not display the skills title
|
||||
return title.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,339 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Server.Engines.CannedEvil;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[PropertyObject]
|
||||
public class ChampionTitleInfo
|
||||
{
|
||||
private const int LossAmount = 90;
|
||||
private static TimeSpan LossDelay = TimeSpan.FromDays(1.0);
|
||||
|
||||
private TitleInfo[] m_Values;
|
||||
|
||||
public ChampionTitleInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public ChampionTitleInfo(IGenericReader reader)
|
||||
{
|
||||
var version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Harrower = reader.ReadEncodedInt();
|
||||
|
||||
var length = reader.ReadEncodedInt();
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
m_Values = new TitleInfo[length];
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
m_Values[i] = new TitleInfo(reader);
|
||||
}
|
||||
|
||||
if (m_Values.Length != ChampionSpawnInfo.Table.Length)
|
||||
{
|
||||
var oldValues = m_Values;
|
||||
m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length];
|
||||
|
||||
for (var i = 0; i < m_Values.Length && i < oldValues.Length; i++)
|
||||
{
|
||||
m_Values[i] = oldValues[i];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Pestilence
|
||||
{
|
||||
get => GetValue(ChampionSpawnType.Pestilence);
|
||||
set => SetValue(ChampionSpawnType.Pestilence, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Abyss
|
||||
{
|
||||
get => GetValue(ChampionSpawnType.Abyss);
|
||||
set => SetValue(ChampionSpawnType.Abyss, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Arachnid
|
||||
{
|
||||
get => GetValue(ChampionSpawnType.Arachnid);
|
||||
set => SetValue(ChampionSpawnType.Arachnid, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ColdBlood
|
||||
{
|
||||
get => GetValue(ChampionSpawnType.ColdBlood);
|
||||
set => SetValue(ChampionSpawnType.ColdBlood, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ForestLord
|
||||
{
|
||||
get => GetValue(ChampionSpawnType.ForestLord);
|
||||
set => SetValue(ChampionSpawnType.ForestLord, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int SleepingDragon
|
||||
{
|
||||
get => GetValue(ChampionSpawnType.SleepingDragon);
|
||||
set => SetValue(ChampionSpawnType.SleepingDragon, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int UnholyTerror
|
||||
{
|
||||
get => GetValue(ChampionSpawnType.UnholyTerror);
|
||||
set => SetValue(ChampionSpawnType.UnholyTerror, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int VerminHorde
|
||||
{
|
||||
get => GetValue(ChampionSpawnType.VerminHorde);
|
||||
set => SetValue(ChampionSpawnType.VerminHorde, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Harrower { get; set; }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int GetValue(ChampionSpawnType type) => GetValue((int)type);
|
||||
|
||||
public int GetValue(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_Values?.Length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_Values?[index]?.Value ?? 0;
|
||||
}
|
||||
|
||||
public DateTime GetLastDecay(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_Values?.Length)
|
||||
{
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
|
||||
return m_Values?[index]?.LastDecay ?? DateTime.MinValue;
|
||||
}
|
||||
|
||||
public void SetValue(ChampionSpawnType type, int value)
|
||||
{
|
||||
var index = (int)type;
|
||||
if (index < 0 || index >= ChampionSpawnInfo.Table.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length];
|
||||
var title = m_Values[index];
|
||||
if (title == null)
|
||||
{
|
||||
if (value > 0)
|
||||
{
|
||||
m_Values[index] = new TitleInfo(value, Core.Now);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
title.Value = Math.Max(value, 0);
|
||||
title.LastDecay = title.Value == 0 ? DateTime.MinValue : Core.Now;
|
||||
}
|
||||
|
||||
public void Award(ChampionSpawnType type, int value)
|
||||
{
|
||||
var index = (int)type;
|
||||
if (value <= 0 || index < 0 || index >= ChampionSpawnInfo.Table.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length];
|
||||
var title = m_Values[index];
|
||||
if (title == null)
|
||||
{
|
||||
m_Values[index] = new TitleInfo(value, Core.Now);
|
||||
return;
|
||||
}
|
||||
|
||||
title.Value += value;
|
||||
if (title.LastDecay == DateTime.MinValue)
|
||||
{
|
||||
title.LastDecay = Core.Now;
|
||||
}
|
||||
}
|
||||
|
||||
public void Atrophy(int index, int value)
|
||||
{
|
||||
if (value <= 0 || index < 0 || index >= ChampionSpawnInfo.Table.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var title = m_Values?[index];
|
||||
if (title == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var before = title.Value;
|
||||
|
||||
title.Value -= Math.Min(value, title.Value);
|
||||
|
||||
if (before != title.Value)
|
||||
{
|
||||
title.LastDecay = Core.Now;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => "...";
|
||||
|
||||
public static void Serialize(IGenericWriter writer, ChampionTitleInfo titles)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
writer.WriteEncodedInt(titles.Harrower);
|
||||
|
||||
var length = titles.m_Values?.Length ?? 0;
|
||||
writer.WriteEncodedInt(length);
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
titles.m_Values![i] ??= new TitleInfo();
|
||||
|
||||
TitleInfo.Serialize(writer, titles.m_Values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ShouldAtrophy(PlayerMobile pm)
|
||||
{
|
||||
var t = pm.ChampionTitles;
|
||||
if (t?.m_Values == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < t.m_Values.Length; i++)
|
||||
{
|
||||
var decay = t.GetLastDecay(i);
|
||||
if (decay > DateTime.MinValue && decay + LossDelay < Core.Now)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void CheckAtrophy(PlayerMobile pm)
|
||||
{
|
||||
var t = pm.ChampionTitles;
|
||||
if (t?.m_Values == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < t.m_Values.Length; i++)
|
||||
{
|
||||
var decay = t.GetLastDecay(i);
|
||||
if (decay > DateTime.MinValue && decay + LossDelay < Core.Now)
|
||||
{
|
||||
t.Atrophy(i, LossAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when killing a harrower. Will give a minimum of 1 point.
|
||||
public static void AwardHarrowerTitle(PlayerMobile pm)
|
||||
{
|
||||
var t = pm.ChampionTitles;
|
||||
if (t == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.m_Values == null)
|
||||
{
|
||||
if (t.Harrower == 0)
|
||||
{
|
||||
t.Harrower = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
t.m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length];
|
||||
|
||||
var count = 1;
|
||||
for (var i = 0; i < t.m_Values.Length; i++)
|
||||
{
|
||||
if (t.m_Values[i].Value > 900)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
t.Harrower = Math.Max(count, t.Harrower); // Harrower titles never decay.
|
||||
}
|
||||
|
||||
private class TitleInfo
|
||||
{
|
||||
public TitleInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public TitleInfo(int value, DateTime lastDecay)
|
||||
{
|
||||
Value = value;
|
||||
LastDecay = lastDecay;
|
||||
}
|
||||
|
||||
public TitleInfo(IGenericReader reader)
|
||||
{
|
||||
var version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Value = reader.ReadEncodedInt();
|
||||
LastDecay = reader.ReadDateTime();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Value { get; set; }
|
||||
|
||||
public DateTime LastDecay { get; set; }
|
||||
|
||||
public static void Serialize(IGenericWriter writer, TitleInfo info)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
writer.WriteEncodedInt(info.Value);
|
||||
writer.Write(info.LastDecay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ using Server.Accounting;
|
|||
using Server.Collections;
|
||||
using Server.ContextMenus;
|
||||
using Server.Engines.BulkOrders;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Engines.ConPVP;
|
||||
using Server.Engines.Craft;
|
||||
using Server.Engines.Help;
|
||||
|
|
@ -206,8 +207,6 @@ namespace Server.Mobiles
|
|||
|
||||
m_GameTime = TimeSpan.Zero;
|
||||
m_GuildRank = RankDefinition.Lowest;
|
||||
|
||||
ChampionTitles = new ChampionTitleInfo();
|
||||
}
|
||||
|
||||
public PlayerMobile(Serial s) : base(s)
|
||||
|
|
@ -693,8 +692,8 @@ namespace Server.Mobiles
|
|||
set => SetFlag(PlayerFlag.DisplayChampionTitle, value);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public ChampionTitleInfo ChampionTitles { get; private set; }
|
||||
[CommandProperty(AccessLevel.GameMaster, canModify: true)]
|
||||
public ChampionTitleContext ChampionTitles => this.GetOrCreateChampionTitleContext();
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ShortTermMurders
|
||||
|
|
@ -1859,21 +1858,13 @@ namespace Server.Mobiles
|
|||
{
|
||||
if (AutoRenewInsurance)
|
||||
{
|
||||
list.Add(
|
||||
new CallbackEntry(
|
||||
6202,
|
||||
CancelRenewInventoryInsurance
|
||||
)
|
||||
); // Cancel Renewing Inventory Insurance
|
||||
// Cancel Renewing Inventory Insurance
|
||||
list.Add(new CallbackEntry(6202, CancelRenewInventoryInsurance));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(
|
||||
new CallbackEntry(
|
||||
6200,
|
||||
AutoRenewInventoryInsurance
|
||||
)
|
||||
); // Auto Renew Inventory Insurance
|
||||
// Auto Renew Inventory Insurance
|
||||
list.Add(new CallbackEntry(6200, AutoRenewInventoryInsurance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2855,6 +2846,7 @@ namespace Server.Mobiles
|
|||
|
||||
switch (version)
|
||||
{
|
||||
case 33: // Removes champion title
|
||||
case 32: // Removes virtue properties
|
||||
case 31: // Removed Short/Long Term Elapse
|
||||
case 30:
|
||||
|
|
@ -2928,7 +2920,11 @@ namespace Server.Mobiles
|
|||
}
|
||||
case 23:
|
||||
{
|
||||
ChampionTitles = new ChampionTitleInfo(reader);
|
||||
if (version < 33)
|
||||
{
|
||||
ChampionTitles.Deserialize(reader);
|
||||
}
|
||||
|
||||
goto case 22;
|
||||
}
|
||||
case 22:
|
||||
|
|
@ -3165,8 +3161,6 @@ namespace Server.Mobiles
|
|||
LastOnline = ((Account)Account).LastLogin;
|
||||
}
|
||||
|
||||
ChampionTitles ??= new ChampionTitleInfo();
|
||||
|
||||
if (AccessLevel > AccessLevel.Player)
|
||||
{
|
||||
IgnoreMobiles = true;
|
||||
|
|
@ -3184,8 +3178,6 @@ namespace Server.Mobiles
|
|||
}
|
||||
}
|
||||
|
||||
CheckAtrophies();
|
||||
|
||||
if (Hidden) // Hiding is the only buff where it has an effect that's serialized.
|
||||
{
|
||||
AddBuff(new BuffInfo(BuffIcon.HidingAndOrStealth, 1075655));
|
||||
|
|
@ -3196,7 +3188,7 @@ namespace Server.Mobiles
|
|||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(32); // version
|
||||
writer.Write(33); // version
|
||||
|
||||
if (Stabled == null)
|
||||
{
|
||||
|
|
@ -3251,8 +3243,6 @@ namespace Server.Mobiles
|
|||
}
|
||||
}
|
||||
|
||||
ChampionTitleInfo.Serialize(writer, ChampionTitles);
|
||||
|
||||
writer.WriteEncodedInt(ToTItemsTurnedIn);
|
||||
writer.Write(ToTTotalMonsterFame); // This ain't going to be a small #.
|
||||
|
||||
|
|
@ -3317,22 +3307,6 @@ namespace Server.Mobiles
|
|||
writer.Write(GameTime);
|
||||
}
|
||||
|
||||
// Do we need to run an after serialize?
|
||||
public override bool ShouldExecuteAfterSerialize => ShouldAtrophy();
|
||||
|
||||
public override void AfterSerialize()
|
||||
{
|
||||
base.AfterSerialize();
|
||||
CheckAtrophies();
|
||||
}
|
||||
|
||||
public bool ShouldAtrophy() => ChampionTitleInfo.ShouldAtrophy(this);
|
||||
|
||||
public void CheckAtrophies()
|
||||
{
|
||||
ChampionTitleInfo.CheckAtrophy(this);
|
||||
}
|
||||
|
||||
public override bool CanSee(Mobile m)
|
||||
{
|
||||
if (m is CharacterStatue statue)
|
||||
|
|
@ -3439,6 +3413,17 @@ namespace Server.Mobiles
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Add the Titles Menu for later Eras:
|
||||
// https://uo.com/wiki/ultima-online-wiki/player/skill-titles-order/
|
||||
if (DisplayChampionTitle)
|
||||
{
|
||||
var titleLabel = this.GetChampionTitleLabel();
|
||||
if (titleLabel > 0)
|
||||
{
|
||||
list.Add(titleLabel);
|
||||
}
|
||||
}
|
||||
|
||||
if (Core.ML && AllFollowers != null)
|
||||
{
|
||||
foreach (var follower in AllFollowers)
|
||||
|
|
@ -4457,6 +4442,7 @@ namespace Server.Mobiles
|
|||
}
|
||||
|
||||
DisplayChampionTitle = !DisplayChampionTitle;
|
||||
InvalidateProperties();
|
||||
}
|
||||
|
||||
public virtual bool HasRecipe(Recipe r) => r != null && HasRecipe(r.ID);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Engines.Virtues;
|
||||
using Server.Items;
|
||||
using Server.Spells;
|
||||
|
|
@ -325,7 +326,7 @@ namespace Server.Mobiles
|
|||
|
||||
if (ds.m_HasRight && ds.m_Mobile is PlayerMobile mobile)
|
||||
{
|
||||
ChampionTitleInfo.AwardHarrowerTitle(mobile);
|
||||
ChampionTitleSystem.AwardHarrowerTitle(mobile);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue