//
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//
namespace MUnique.OpenMU.Persistence.Initialization.Updates;
using System.Runtime.InteropServices;
using MUnique.OpenMU.DataModel.Configuration;
using MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Events;
using MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Maps;
using MUnique.OpenMU.PlugIns;
///
/// Adds the TvT Event team event data to an existing configuration: the imported LoL arena map
/// (server number 92 / client World93) with its terrain, the statue (561) and guard (580) monster
/// definitions, the red/blue base spawn gates, the event NPC (560) placed in Lorencia, and the
/// mini-game definition. The event logic (context, packet handlers, chat commands, buffs) ships in
/// the game-logic assemblies and needs no configuration update.
///
[PlugIn]
[Display(Name = PlugInName, Description = PlugInDescription)]
[Guid("F2A7C4D9-3E1B-4A86-9C0D-5B7E2A1F8D42")]
public class AddHeykelSavasiEventUpdateSeason6 : UpdatePlugInBase
{
internal const string PlugInName = "Add TvT Event event (map 92)";
internal const string PlugInDescription = "Adds the TvT Event team-vs-team event: the LoL arena map (server 92 / World93) with terrain, statue+guard monsters, red/blue base spawn gates, the event NPC (560) in Lorencia, and the mini-game definition.";
///
public override UpdateVersion Version => UpdateVersion.AddHeykelSavasiEventSeason6;
///
public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id;
///
public override string Name => PlugInName;
///
public override string Description => PlugInDescription;
///
public override bool IsMandatory => true;
///
public override DateTime CreatedAt => new(2026, 07, 21, 12, 0, 0, DateTimeKind.Utc);
///
protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration)
{
// Idempotency guard: skip if the TvT Event map (92) already exists.
if (gameConfiguration.Maps.Any(m => m.Number == HeykelSavasiMap.Number))
{
return;
}
// 1. Map (No 92) + terrain (Terrain93.att) + statue (561) / guard (580) monster definitions.
var mapInitializer = new HeykelSavasiMap(context, gameConfiguration);
mapInitializer.Initialize();
mapInitializer.SetSafezoneMap();
var map = gameConfiguration.Maps.First(m => m.Number == HeykelSavasiMap.Number);
// 2. Host the map on every game server configuration (fresh seeds do this automatically,
// but existing databases need it added explicitly).
var serverConfigs = await context.GetAsync().ConfigureAwait(false);
foreach (var serverConfig in serverConfigs)
{
if (serverConfig.Maps.All(m => m.Number != HeykelSavasiMap.Number))
{
serverConfig.Maps.Add(map);
}
}
// 3. Red/Blue base spawn gates. The X1/Y1 anchors MUST match HeykelSavasiContext.GetTeamSpawnGate
// (Red = 42,10 top tip of the arena diamond; Blue = 42,92 bottom tip).
var redBase = context.CreateNew();
map.ExitGates.Add(redBase);
redBase.Map = map;
redBase.X1 = 42;
redBase.Y1 = 10;
redBase.X2 = 42;
redBase.Y2 = 10;
redBase.Direction = Direction.South;
redBase.IsSpawnGate = true;
var blueBase = context.CreateNew();
map.ExitGates.Add(blueBase);
blueBase.Map = map;
blueBase.X1 = 42;
blueBase.Y1 = 92;
blueBase.X2 = 42;
blueBase.Y2 = 92;
blueBase.Direction = Direction.North;
blueBase.IsSpawnGate = true;
// 4. Event NPC (560) placed in Lorencia.
if (gameConfiguration.Monsters.All(m => m.Number != 560))
{
var npc = context.CreateNew();
gameConfiguration.Monsters.Add(npc);
npc.Number = 560;
npc.Designation = "TvT Guard";
npc.NpcWindow = NpcWindow.Undefined;
npc.ObjectKind = NpcObjectKind.PassiveNpc;
npc.SetGuid(npc.Number);
var lorencia = gameConfiguration.Maps.First(m => m.Number == Lorencia.Number);
var spawn = context.CreateNew();
lorencia.MonsterSpawns.Add(spawn);
spawn.GameMap = lorencia;
spawn.MonsterDefinition = npc;
spawn.Quantity = 1;
spawn.X1 = 140;
spawn.X2 = 140;
spawn.Y1 = 120;
spawn.Y2 = 120;
spawn.Direction = Direction.SouthEast;
spawn.SpawnTrigger = SpawnTrigger.Automatic;
}
// 5. Mini-game definition (its Entrance references a spawn gate on the map -> after step 3).
new HeykelSavasiInitializer(context, gameConfiguration).Initialize();
}
}