feat(hs): web-applicable update plugin for the Heykel Savasi event
AddHeykelSavasiEventUpdateSeason6 (version 100): adds map 92 + terrain, statue/guard monsters, red/blue base gates, event NPC 560 in Lorencia, and the mini-game definition to an EXISTING config via the admin Updates page (no DB wipe). Reuses HeykelSavasiMap/HeykelSavasiInitializer; idempotent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,124 @@
|
|||||||
|
// <copyright file="AddHeykelSavasiEventUpdateSeason6.cs" company="MUnique">
|
||||||
|
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the Heykel Savasi 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.
|
||||||
|
/// </summary>
|
||||||
|
[PlugIn]
|
||||||
|
[Display(Name = PlugInName, Description = PlugInDescription)]
|
||||||
|
[Guid("F2A7C4D9-3E1B-4A86-9C0D-5B7E2A1F8D42")]
|
||||||
|
public class AddHeykelSavasiEventUpdateSeason6 : UpdatePlugInBase
|
||||||
|
{
|
||||||
|
internal const string PlugInName = "Add Heykel Savasi event (map 92)";
|
||||||
|
|
||||||
|
internal const string PlugInDescription = "Adds the Heykel Savasi 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.";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override UpdateVersion Version => UpdateVersion.AddHeykelSavasiEventSeason6;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string Name => PlugInName;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string Description => PlugInDescription;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool IsMandatory => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override DateTime CreatedAt => new(2026, 07, 21, 12, 0, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration)
|
||||||
|
{
|
||||||
|
// Idempotency guard: skip if the Heykel Savasi 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<GameServerConfiguration>().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<ExitGate>();
|
||||||
|
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<ExitGate>();
|
||||||
|
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<MonsterDefinition>();
|
||||||
|
gameConfiguration.Monsters.Add(npc);
|
||||||
|
npc.Number = 560;
|
||||||
|
npc.Designation = "Heykel Savasi Gorevlisi";
|
||||||
|
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<MonsterSpawnArea>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -504,4 +504,9 @@ public enum UpdateVersion
|
|||||||
/// The version of the <see cref="AddWarriorWingsUpdateSeason6"/> (Warrior Wings/Cape 12/242-247).
|
/// The version of the <see cref="AddWarriorWingsUpdateSeason6"/> (Warrior Wings/Cape 12/242-247).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
AddWarriorWingsSeason6 = 99,
|
AddWarriorWingsSeason6 = 99,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The version of the <see cref="AddHeykelSavasiEventUpdateSeason6"/> (Heykel Savasi team event: map 92, NPC 560, mini game definition).
|
||||||
|
/// </summary>
|
||||||
|
AddHeykelSavasiEventSeason6 = 100,
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user