Summary
Implement the core Castle Siege win condition: the crown capture system. Three players from the same attacking side must simultaneously occupy the crown and both switches for a configured duration to capture the castle.
Prerequisites
Requirements
1. CheckMiddleWinner() — In GameLogic/CastleSiege/CastleSiegeCrownMechanics.cs (new file)
Called every tick (every second) during Start state.
Logic:
- Get
CrownUser, SwitchUsers[0], SwitchUsers[1] from CastleSiegeContext.
- All three must be:
- Non-null.
- Alive (
IsAlive).
- In a guild (
GuildStatus != null).
- On an attacking side (not
None, not Defense).
- On the same attacking side.
- If conditions are not met:
- If the crown user changed or left, send
CrownAccessState.Fail to the previous user.
- Do not reset accumulated time (capped at
CrownHoldTimeSeconds - 1 on fail).
- Return.
- Increment
CrownAccumulatedTime by the tick interval (1 second).
- Send
CrownAccessState.Attempt to the crown user with the current accumulated time.
- If
CrownAccumulatedTime >= Configuration.CrownHoldTimeSeconds:
- Send
CrownAccessState.Success to the crown user.
- Call
ChangeWinnerGuild().
2. ChangeWinnerGuild() — In the same file
Called when a capture succeeds.
Logic:
- Set
MiddleOwnerGuildId to the crown user's guild ID.
- Swap sides:
- The capturing guild's side becomes
Defense.
- The previous
Defense side becomes the capturing guild's old attack side.
- Call
SetPlayerJoinSideAsync(killLifeStones: true) to:
- Re-assign all players to their new sides.
- Kill all Life Stones.
- Respawn all non-defense players to the attack respawn area.
- Lock the crown (
IsCrownAvailable = false).
- Reset
CrownAccumulatedTime to zero.
- Clear
CrownUser and both SwitchUsers.
- Broadcast
CastleSiegeOwnershipChangeNotification to all players on the CS map.
3. SendSwitchInfo() — In GameLogic/CastleSiege/CastleSiegeSwitchMechanics.cs (new file)
Called every second during Start state.
Logic:
- For each switch (0 and 1):
- Send
CastleSiegeSwitchInfo packet to all players on the CS map with:
- Switch ID, state (empty/occupied), occupant's join side, guild name, character name.
- Determine crown availability:
- If both switch users are non-null and on the same attacking side →
IsCrownAvailable = true.
- Otherwise →
IsCrownAvailable = false.
- Send
CastleSiegeCrownStateUpdate to all players with the current lock/unlock state.
4. Crown Access State Broadcasting
When the crown user's state changes, send CrownAccessState packet:
| Value |
Name |
When |
| 0 |
Attempt |
Player is actively pressing, accumulating time |
| 1 |
Success |
Capture completed |
| 2 |
Fail |
Player was interrupted (killed, left, switch broken) |
The packet includes the accumulated time in milliseconds.
5. CheckResult() — Called when Start timer expires
In CastleSiegePlugIn.OnEnterStateAsync(End):
- If
MiddleOwnerGuildId has a value → that guild is the new castle owner.
- If
MiddleOwnerGuildId is null → the existing castle owner retains ownership.
- If ownership changed:
- Update
CastleSiegeData.OwnerGuildId, IsOccupied = true.
- Reset tax rates to 0, tribute money to 0 (Phase 10).
- Save to database.
- Broadcast ownership result.
6. View Interfaces & Remote Views
ICastleSiegeCrownStatePlugIn — sends crown lock/unlock state.
ICastleSiegeCrownAccessStatePlugIn — sends crown access state (attempt/success/fail) to the crown user.
ICastleSiegeSwitchInfoPlugIn — sends switch occupant info.
ICastleSiegeOwnershipChangePlugIn — sends ownership change notification.
Files to Create
| File |
Description |
GameLogic/CastleSiege/CastleSiegeCrownMechanics.cs |
CheckMiddleWinner, ChangeWinnerGuild, CheckResult |
GameLogic/CastleSiege/CastleSiegeSwitchMechanics.cs |
SendSwitchInfo, crown availability |
GameLogic/Views/CastleSiege/ICastleSiegeCrownStatePlugIn.cs |
View interface |
GameLogic/Views/CastleSiege/ICastleSiegeCrownAccessStatePlugIn.cs |
View interface |
GameLogic/Views/CastleSiege/ICastleSiegeSwitchInfoPlugIn.cs |
View interface |
GameLogic/Views/CastleSiege/ICastleSiegeOwnershipChangePlugIn.cs |
View interface |
GameServer/RemoteView/CastleSiege/CastleSiegeCrownStatePlugIn.cs |
Remote view |
GameServer/RemoteView/CastleSiege/CastleSiegeCrownAccessStatePlugIn.cs |
Remote view |
GameServer/RemoteView/CastleSiege/CastleSiegeSwitchInfoPlugIn.cs |
Remote view |
GameServer/RemoteView/CastleSiege/CastleSiegeOwnershipChangePlugIn.cs |
Remote view |
Acceptance Criteria
Summary
Implement the core Castle Siege win condition: the crown capture system. Three players from the same attacking side must simultaneously occupy the crown and both switches for a configured duration to capture the castle.
Prerequisites
CastleSiegeCrown,CastleSiegeSwitchNPC classes and their intelligence.SetPlayerJoinSideAsync.CastleSiegeContextandStartstate tick handlers.Requirements
1.
CheckMiddleWinner()— InGameLogic/CastleSiege/CastleSiegeCrownMechanics.cs(new file)Called every tick (every second) during
Startstate.Logic:
CrownUser,SwitchUsers[0],SwitchUsers[1]fromCastleSiegeContext.IsAlive).GuildStatus != null).None, notDefense).CrownAccessState.Failto the previous user.CrownHoldTimeSeconds - 1on fail).CrownAccumulatedTimeby the tick interval (1 second).CrownAccessState.Attemptto the crown user with the current accumulated time.CrownAccumulatedTime >= Configuration.CrownHoldTimeSeconds:CrownAccessState.Successto the crown user.ChangeWinnerGuild().2.
ChangeWinnerGuild()— In the same fileCalled when a capture succeeds.
Logic:
MiddleOwnerGuildIdto the crown user's guild ID.Defense.Defenseside becomes the capturing guild's old attack side.SetPlayerJoinSideAsync(killLifeStones: true)to:IsCrownAvailable = false).CrownAccumulatedTimeto zero.CrownUserand bothSwitchUsers.CastleSiegeOwnershipChangeNotificationto all players on the CS map.3.
SendSwitchInfo()— InGameLogic/CastleSiege/CastleSiegeSwitchMechanics.cs(new file)Called every second during
Startstate.Logic:
CastleSiegeSwitchInfopacket to all players on the CS map with:IsCrownAvailable = true.IsCrownAvailable = false.CastleSiegeCrownStateUpdateto all players with the current lock/unlock state.4. Crown Access State Broadcasting
When the crown user's state changes, send
CrownAccessStatepacket:AttemptSuccessFailThe packet includes the accumulated time in milliseconds.
5.
CheckResult()— Called whenStarttimer expiresIn
CastleSiegePlugIn.OnEnterStateAsync(End):MiddleOwnerGuildIdhas a value → that guild is the new castle owner.MiddleOwnerGuildIdis null → the existing castle owner retains ownership.CastleSiegeData.OwnerGuildId,IsOccupied = true.6. View Interfaces & Remote Views
ICastleSiegeCrownStatePlugIn— sends crown lock/unlock state.ICastleSiegeCrownAccessStatePlugIn— sends crown access state (attempt/success/fail) to the crown user.ICastleSiegeSwitchInfoPlugIn— sends switch occupant info.ICastleSiegeOwnershipChangePlugIn— sends ownership change notification.Files to Create
GameLogic/CastleSiege/CastleSiegeCrownMechanics.csGameLogic/CastleSiege/CastleSiegeSwitchMechanics.csGameLogic/Views/CastleSiege/ICastleSiegeCrownStatePlugIn.csGameLogic/Views/CastleSiege/ICastleSiegeCrownAccessStatePlugIn.csGameLogic/Views/CastleSiege/ICastleSiegeSwitchInfoPlugIn.csGameLogic/Views/CastleSiege/ICastleSiegeOwnershipChangePlugIn.csGameServer/RemoteView/CastleSiege/CastleSiegeCrownStatePlugIn.csGameServer/RemoteView/CastleSiege/CastleSiegeCrownAccessStatePlugIn.csGameServer/RemoteView/CastleSiege/CastleSiegeSwitchInfoPlugIn.csGameServer/RemoteView/CastleSiege/CastleSiegeOwnershipChangePlugIn.csAcceptance Criteria
CrownHoldTimeSeconds.CrownHoldTimeSeconds - 1on failure (not reset to 0).