feat(CS): authentic Crown-hold throne capture (S6 protocol) replacing Sinior-talk
Some checks failed
.NET Core / build (push) Has been cancelled

Break all gates + hold both switches (defenses down) -> the Crown shield drops
(C1 B2 16=0). The guild master then stands on the Crown (176,212) and holds for
CrownHoldDuration (default 60s, client shows a 60s countdown via C1 B2 15) to
capture; capture broadcasts C1 B2 18 + golden text and sets the occupier. Losing a
switch or leaving the crown resets the hold (contestable until the siege timer ends).
Sinior (223) is now informational guidance. +2 tests (14 total).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Acentech Dev
2026-07-15 15:04:10 +03:00
parent 4651ef232c
commit 3dd4881406
7 changed files with 322 additions and 8 deletions

View File

@@ -101,4 +101,82 @@ public class CastleSiegeStatusViewPlugIn : ICastleSiegeStatusViewPlugIn
await connection.SendAsync(WritePacket).ConfigureAwait(false);
}
/// <inheritdoc />
public async ValueTask SetCrownShieldAsync(bool down)
{
var connection = this._player.Connection;
if (connection is null)
{
return;
}
int WritePacket()
{
// C1 0C B2 16 <state> <pad> <dword=0> ; state 0 = shield down, 1 = shield up
var span = connection.Output.GetSpan(12)[..12];
span.Clear();
span[0] = 0xC1;
span[1] = 0x0C;
span[2] = 0xB2;
span[3] = 0x16;
span[4] = (byte)(down ? 0 : 1);
return span.Length;
}
await connection.SendAsync(WritePacket).ConfigureAwait(false);
}
/// <inheritdoc />
public async ValueTask SetCrownRegistAsync(byte state, uint accessMilliseconds)
{
var connection = this._player.Connection;
if (connection is null)
{
return;
}
int WritePacket()
{
// C1 0C B2 15 <state> <pad3> <accessMs:4 LE @offset 8>
var span = connection.Output.GetSpan(12)[..12];
span.Clear();
span[0] = 0xC1;
span[1] = 0x0C;
span[2] = 0xB2;
span[3] = 0x15;
span[4] = state;
System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(8, 4), accessMilliseconds);
return span.Length;
}
await connection.SendAsync(WritePacket).ConfigureAwait(false);
}
/// <inheritdoc />
public async ValueTask AnnounceSealCapturedAsync(string guildName)
{
var connection = this._player.Connection;
if (connection is null)
{
return;
}
int WritePacket()
{
// C1 0D B2 18 <state=1> <guildName[8] utf8>
var span = connection.Output.GetSpan(13)[..13];
span.Clear();
span[0] = 0xC1;
span[1] = 0x0D;
span[2] = 0xB2;
span[3] = 0x18;
span[4] = 1;
var bytes = System.Text.Encoding.UTF8.GetBytes(guildName);
bytes.AsSpan(0, Math.Min(8, bytes.Length)).CopyTo(span.Slice(5, 8));
return span.Length;
}
await connection.SendAsync(WritePacket).ConfigureAwait(false);
}
}