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
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue