feat(CS-P3): REAL castle gates (NPC 277) at 6 client gate positions -> client closes+blocks them; breakable via HP template; inner guardian statues (283)
Some checks failed
.NET Core / build (push) Has been cancelled
Some checks failed
.NET Core / build (push) Has been cancelled
This commit is contained in:
@@ -25,17 +25,23 @@ using MUnique.OpenMU.PlugIns;
|
|||||||
public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustomConfiguration<CastleSiegeConfiguration>, ISupportDefaultCustomConfiguration
|
public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustomConfiguration<CastleSiegeConfiguration>, ISupportDefaultCustomConfiguration
|
||||||
{
|
{
|
||||||
private const ushort ValleyOfLorenMapNumber = 30;
|
private const ushort ValleyOfLorenMapNumber = 30;
|
||||||
private const short CastleGateNumber = 131; // reuse BloodCastle "Castle Gate" destructible definition
|
private const short CastleGateNumber = 277; // client MONSTER_CASTLE_GATE1 -> renders a real gate + blocks terrain until broken
|
||||||
private const short GuardianStatueNumber = 132; // reuse BloodCastle "Statue of Saint" destructible definition
|
private const short GateTemplateNumber = 131; // BloodCastle "Castle Gate" destructible (has HP) — HP template for 277
|
||||||
|
private const short GuardianStatueNumber = 283; // "Guardian Statue" — inner castle defense
|
||||||
|
private const short StatueTemplateNumber = 132; // BloodCastle "Statue of Saint" destructible (has HP) — HP template for 283
|
||||||
private const int SwitchHoldRange = 3;
|
private const int SwitchHoldRange = 3;
|
||||||
|
|
||||||
// Castle defenses spawned at siege start — destructibles the attackers must break: (number, x, y).
|
// Castle defenses spawned at siege start — destructibles the attackers must break: (number, x, y).
|
||||||
// Positions are in the throne-room area (near the crown ~176,212 and the switches ~167-184,194-195),
|
// Gates are at the 6 REAL castle gate positions (client g_byGateLocation) so the client renders them
|
||||||
// where players can actually reach and hit them (the earlier statue spot 170/182,206 was confirmed reachable).
|
// closed and blocks the terrain until broken. Guardian statues stand inside near the throne.
|
||||||
private static readonly (short Number, byte X, byte Y)[] DefenseSpawns =
|
private static readonly (short Number, byte X, byte Y)[] DefenseSpawns =
|
||||||
{
|
{
|
||||||
(CastleGateNumber, 168, 200),
|
(CastleGateNumber, 67, 114),
|
||||||
(CastleGateNumber, 184, 200),
|
(CastleGateNumber, 93, 114),
|
||||||
|
(CastleGateNumber, 119, 114),
|
||||||
|
(CastleGateNumber, 81, 161),
|
||||||
|
(CastleGateNumber, 107, 161),
|
||||||
|
(CastleGateNumber, 93, 204),
|
||||||
(GuardianStatueNumber, 170, 208),
|
(GuardianStatueNumber, 170, 208),
|
||||||
(GuardianStatueNumber, 182, 208),
|
(GuardianStatueNumber, 182, 208),
|
||||||
};
|
};
|
||||||
@@ -127,6 +133,23 @@ public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustom
|
|||||||
=> gameContext.ForEachPlayerAsync(player =>
|
=> gameContext.ForEachPlayerAsync(player =>
|
||||||
player.InvokeViewPlugInAsync<IShowMessagePlugIn>(p => p.ShowMessageAsync(message, MessageType.GoldenCenter)).AsTask());
|
player.InvokeViewPlugInAsync<IShowMessagePlugIn>(p => p.ShowMessageAsync(message, MessageType.GoldenCenter)).AsTask());
|
||||||
|
|
||||||
|
private static void EnsureDestructible(MonsterDefinition target, MonsterDefinition? template)
|
||||||
|
{
|
||||||
|
if (target.ObjectKind == NpcObjectKind.Destructible)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target.ObjectKind = NpcObjectKind.Destructible;
|
||||||
|
if (template is not null && target.Attributes.Count == 0)
|
||||||
|
{
|
||||||
|
foreach (var attribute in template.Attributes)
|
||||||
|
{
|
||||||
|
target.Attributes.Add(attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task SpawnCastleDefensesAsync(IGameContext gameContext, CastleSiegeContext context)
|
private static async Task SpawnCastleDefensesAsync(IGameContext gameContext, CastleSiegeContext context)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -154,6 +177,12 @@ public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustom
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The stock CS gate (277) / statue (283) definitions have no HP and aren't destructible;
|
||||||
|
// make them breakable by borrowing the HP/attributes of a working destructible (131/132).
|
||||||
|
var template = gameContext.Configuration.Monsters.FirstOrDefault(
|
||||||
|
m => m.Number == (spawn.Number == CastleGateNumber ? GateTemplateNumber : StatueTemplateNumber));
|
||||||
|
EnsureDestructible(definition, template);
|
||||||
|
|
||||||
var spawnArea = new MonsterSpawnArea
|
var spawnArea = new MonsterSpawnArea
|
||||||
{
|
{
|
||||||
MonsterDefinition = definition,
|
MonsterDefinition = definition,
|
||||||
|
|||||||
Reference in New Issue
Block a user