Skip to content

CS - castle siege #657

@foxrj21

Description

@foxrj21

Understanding Where to Plug This into OpenMU

OpenMU today basically has:

GameLogic: game rules, player actions, etc. (MUnique.OpenMU.GameLogic) munique.github.io

GameMap + AreaOfInterestManager: controls objects on the map, player/NPC observation, etc. munique.github.io

Packet/Network: package structs and handlers (MUnique.OpenMU.Network, GameServer.MessageHandler). munique.github.io

GuildServer and DataModel: guilds, characters, game configuration, persistence (EF Core + PostgreSQL).
GitHub

A concept of plugin points in GameLogic (player entered/exited, object added/removed from the map, etc.).
GitHub

Castle Siege needs to communicate with all of this.

  1. Castle Siege Domain Modeling

The first step is to create the Siege "business model" in the DataModel:

New (or extended) entities

In the MUnique.OpenMU.DataModel project:

Castle

Id

Name (e.g., "Valley of Loren")

OwnerGuild (reference to Guild)

TaxRate (float / int)

LastSiegeEnd (DateTime)

CastleSiegeSchedule

Castle

RegistrationStart, RegistrationEnd

SiegeStart, SiegeEnd

CastleSiegeRegistration

CastleSiegeSchedule

Guild

IsAttacker, IsDefender

SignupOrder / Score (depending on the logic)

CastleSiegeState

Castle

CurrentPhase (enum: None, Registration, Preparation, Siege, Finished)

CurrentOwnerGuild

ControllingGuild (who is currently holding the crown)

ControlTimeSeconds

It may also be worthwhile to extend:

Guild

IsCastleOwner (bool)

OwnedCastle (optional FK)

After that, adjust the Persistence project (EF Core) to map these new entities and include them in the DbContext.

  1. Event Orchestration (Siege State Machine)

Create a service of type “CastleSiegeManager” in the GameLogic/GameServer layer:

public class CastleSiegeManager
{
private readonly IGameContext _gameContext;

private readonly Castle _castle;

private CastleSiegeState _state;

public CastleSiegeManager(IGameContext gameContext, Castle castle) { ... }

public Task TickAsync(CancellationToken ct) { ... } // called periodically

Responsibilities:

Read the schedule (CastleSiegeSchedule) and change the state:

Out of schedule → None

Registration period → Registration

Pre-siege (NPC spawn, gates, announcements) → Preparation

Event time → Siege

Post-event (set owner, apply tax, prizes) → Finished

Interact with the Castle Siege map:

Use the GameMap/AreaOfInterestManager to:

Spawn gates, statues, crown switch, registration NPCs.

Control PVP (map flags/PK allowed).

Register callbacks in plugin points, for example:

ObjectGotKilled → when a gate or statue dies.

GitHub

Control the "crown":

When an attacking guild player uses the crown/switch object:

Validate if they are in the correct area.

Start the "casting" countdown (X seconds).

At the end, mark ControllingGuild = that player's guild.

While ControllingGuild holds, increment ControlTimeSeconds.

If another guild takes the crown, reset or reset according to your desired rule.

End of Siege:

Decide winnerGuild:

Emulating GMO: guild with the most control time / or whoever controls at the end.

Update Castle.OwnerGuild = winnerGuild and save to the DB.

Apply default TaxRate and notify the GuildServer.

  1. Registration Rules and Economy

Registration

Via NPC registration + commands:

Create a PlayerAction of type RegisterCastleSiegeAction in MUnique.OpenMU.GameLogic.PlayerActions.

Create the corresponding PacketHandler for the client's registration request.

Validations:

Guild master only.

Minimum guild level.

Active registration period (CurrentPhase == Registration).

Registrations are persisted in CastleSiegeRegistration.

Castle Fees and Benefits

Economy Integration:

At any point where the server calculates NPC shop prices, you adjust:

FinalPrice = BasePrice * (1 + castle.TaxRate) if it's a city under the castle's influence.

The extra money goes to the GuildBank (if any) or to a guild's "castle funds" field.

This will likely be plugged into some "item sold to NPC" or "buy from NPC" plugin point.

GitHub

  1. Integration with the protocol (packets)

The original client has several Castle Siege-specific packages. In OpenMU you have:

Documentation / package generator at MUnique.OpenMU.Network.Packets.

munique.github.io

Steps:

Map the Castle Siege packages from public documentation (without copying code):

Siege status (owner, time, phase).

Guild registration.

Broadcasts (start/end announcements, gates destroyed, crown taken).

Siege minimap/icon updates.

Create the packet XML structs in the Network.Packets project and regenerate the doc/code according to the standard OpenMU flow.

Create the IPacketHandlerPlugIn for:

CS_REGISTER (guild registration).

CS_COMMAND (enter map, warp, siege teleport).

CS_CROWN_USE (packet when the player uses the crown/switch).

On the GameServer, send the following packets:

Start of phase.

Guild change controlling the crown.

End of Siege and announcement of the winner.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions