// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // namespace MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Events; using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.DataModel.Entities; using MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Maps; /// /// Initializes the Castle Siege configuration and persistent state. /// internal sealed class CastleSiegeInitializer : InitializerBase { private const short GateMonsterNumber = 277; private const short StatueMonsterNumber = 283; /// /// Initializes a new instance of the class. /// /// The context. /// The game configuration. public CastleSiegeInitializer(IContext context, GameConfiguration gameConfiguration) : base(context, gameConfiguration) { } /// public override void Initialize() { var configuration = this.InitializeConfiguration(); this.InitializeData(configuration); } /// /// Initializes the Castle Siege configuration, if it does not exist yet. /// /// The Castle Siege configuration. internal CastleSiegeConfiguration InitializeConfiguration() { if (this.GameConfiguration.CastleSiegeConfiguration is { } existingConfiguration) { return existingConfiguration; } var configuration = this.Context.CreateNew(); configuration.Enabled = true; configuration.CrownHoldTimeSeconds = 60; // The client's crown registration panel counts down from 60s. configuration.RegisterMinLevel = 200; configuration.RegisterMinMembers = 20; configuration.ParticipantRewardMinSeconds = 60; configuration.MaxAttackingGuilds = 3; configuration.GuildScoreCastleSiege = 0; configuration.GuildScoreCastleSiegeMembers = 0; configuration.GateBuyPrice = 9_500_000; configuration.StatueBuyPrice = 4_500_000; configuration.CastleSiegeMapDefinition = this.GameConfiguration.Maps.Single(map => map.Number == ValleyOfLoren.Number); configuration.LandOfTrialsMapDefinition = this.GameConfiguration.Maps.Single(map => map.Number == LandOfTrials.Number); // AdaMu deliberately leaves StateSchedule empty. Upstream drives the cycle from a fixed weekly // schedule; AdaMu drives it from CastleSiegeEventPlugIn (manual /cs commands, AdminPanel durations // and the optional auto-open times in the plugin configuration). Nothing reads StateSchedule here. this.InitializeNpcDefinitions(configuration); this.InitializeUpgradeDefinitions(configuration); this.InitializeMachineZones(configuration); configuration.DefenseRespawnArea = this.CreateZone(74, 144, 115, 154); configuration.AttackRespawnArea = this.CreateZone(35, 11, 144, 48); this.GameConfiguration.CastleSiegeConfiguration = configuration; return configuration; } /// /// Initializes the persistent Castle Siege state. /// /// The Castle Siege configuration. /// The persistent Castle Siege state. internal CastleSiegeData InitializeData(CastleSiegeConfiguration configuration) { var data = this.Context.CreateNew(); data.OwnerGuildId = null; data.IsOccupied = false; data.TaxChaos = 0; data.TaxStore = 0; data.TaxHunt = 0; data.IsHuntZoneEnabled = false; data.TributeMoney = 0; var gateHitPoints = configuration.GateLifeUpgrades.Single(upgrade => upgrade.Level == 0).Value; var statueHitPoints = configuration.StatueLifeUpgrades.Single(upgrade => upgrade.Level == 0).Value; foreach (var npcDefinition in configuration.NpcDefinitions.Where(definition => definition.IsPersistedToDatabase)) { var npcState = this.Context.CreateNew(); npcState.MonsterNumber = npcDefinition.MonsterDefinition!.Number; npcState.InstanceId = npcDefinition.InstanceId; npcState.DefenseLevel = 0; npcState.RegenLevel = 0; npcState.LifeLevel = 0; npcState.CurrentHp = npcState.MonsterNumber switch { GateMonsterNumber => gateHitPoints, StatueMonsterNumber => statueHitPoints, _ => throw new InvalidOperationException($"The persisted Castle Siege NPC monster number {npcState.MonsterNumber} is unsupported."), }; data.NpcStates.Add(npcState); } return data; } private void InitializeNpcDefinitions(CastleSiegeConfiguration configuration) { this.AddNpc(configuration, 216, 1, false, CastleSiegeJoinSide.Attack1, 176, 212, Direction.SouthWest); this.AddNpc(configuration, 217, 1, false, CastleSiegeJoinSide.Attack1, 167, 194, Direction.NorthWest); this.AddNpc(configuration, 218, 1, false, CastleSiegeJoinSide.Attack1, 184, 195, Direction.NorthWest); this.AddNpc(configuration, 219, 1, false, CastleSiegeJoinSide.Defense, 93, 208, Direction.SouthWest); this.AddNpc(configuration, 219, 2, false, CastleSiegeJoinSide.Defense, 81, 165, Direction.SouthWest); this.AddNpc(configuration, 219, 3, false, CastleSiegeJoinSide.Defense, 107, 165, Direction.SouthWest); this.AddNpc(configuration, 219, 4, false, CastleSiegeJoinSide.Defense, 67, 118, Direction.SouthWest); this.AddNpc(configuration, 219, 5, false, CastleSiegeJoinSide.Defense, 93, 118, Direction.SouthWest); this.AddNpc(configuration, 219, 6, false, CastleSiegeJoinSide.Defense, 119, 118, Direction.SouthWest); this.AddNpc(configuration, 221, 1, false, CastleSiegeJoinSide.Attack1, 63, 19, Direction.NorthEast); this.AddNpc(configuration, 221, 2, false, CastleSiegeJoinSide.Attack1, 119, 19, Direction.NorthEast); this.AddNpc(configuration, 222, 1, false, CastleSiegeJoinSide.Defense, 80, 188, Direction.SouthWest); this.AddNpc(configuration, 222, 2, false, CastleSiegeJoinSide.Defense, 105, 188, Direction.SouthWest); this.AddNpc(configuration, GateMonsterNumber, 1, true, CastleSiegeJoinSide.Defense, 93, 204, Direction.SouthWest); this.AddNpc(configuration, GateMonsterNumber, 2, true, CastleSiegeJoinSide.Defense, 81, 161, Direction.SouthWest); this.AddNpc(configuration, GateMonsterNumber, 3, true, CastleSiegeJoinSide.Defense, 107, 161, Direction.SouthWest); this.AddNpc(configuration, GateMonsterNumber, 4, true, CastleSiegeJoinSide.Defense, 67, 114, Direction.SouthWest); this.AddNpc(configuration, GateMonsterNumber, 5, true, CastleSiegeJoinSide.Defense, 93, 114, Direction.SouthWest); this.AddNpc(configuration, GateMonsterNumber, 6, true, CastleSiegeJoinSide.Defense, 119, 114, Direction.SouthWest); this.AddNpc(configuration, StatueMonsterNumber, 1, true, CastleSiegeJoinSide.Defense, 94, 227, Direction.SouthWest); this.AddNpc(configuration, StatueMonsterNumber, 2, true, CastleSiegeJoinSide.Defense, 94, 182, Direction.SouthWest); this.AddNpc(configuration, StatueMonsterNumber, 3, true, CastleSiegeJoinSide.Defense, 82, 130, Direction.SouthWest); this.AddNpc(configuration, StatueMonsterNumber, 4, true, CastleSiegeJoinSide.Defense, 107, 130, Direction.SouthWest); } private void InitializeUpgradeDefinitions(CastleSiegeConfiguration configuration) { this.AddUpgrade(configuration.GateDefenseUpgrades, 0, 0, 0, 100); this.AddUpgrade(configuration.GateDefenseUpgrades, 1, 2, 3_000_000, 180); this.AddUpgrade(configuration.GateDefenseUpgrades, 2, 3, 3_000_000, 300); this.AddUpgrade(configuration.GateDefenseUpgrades, 3, 4, 3_000_000, 520); this.AddUpgrade(configuration.StatueDefenseUpgrades, 0, 0, 0, 80); this.AddUpgrade(configuration.StatueDefenseUpgrades, 1, 3, 3_000_000, 180); this.AddUpgrade(configuration.StatueDefenseUpgrades, 2, 5, 3_000_000, 340); this.AddUpgrade(configuration.StatueDefenseUpgrades, 3, 7, 3_000_000, 550); this.AddUpgrade(configuration.GateLifeUpgrades, 0, 0, 0, 1_900_000); this.AddUpgrade(configuration.GateLifeUpgrades, 1, 2, 1_000_000, 2_500_000); this.AddUpgrade(configuration.GateLifeUpgrades, 2, 3, 1_000_000, 3_500_000); this.AddUpgrade(configuration.GateLifeUpgrades, 3, 4, 1_000_000, 5_200_000); this.AddUpgrade(configuration.StatueLifeUpgrades, 0, 0, 0, 1_500_000); this.AddUpgrade(configuration.StatueLifeUpgrades, 1, 3, 1_000_000, 2_200_000); this.AddUpgrade(configuration.StatueLifeUpgrades, 2, 5, 1_000_000, 3_400_000); this.AddUpgrade(configuration.StatueLifeUpgrades, 3, 7, 1_000_000, 5_000_000); this.AddUpgrade(configuration.StatueRegenUpgrades, 0, 0, 0, 0); this.AddUpgrade(configuration.StatueRegenUpgrades, 1, 3, 5_000_000, 1); this.AddUpgrade(configuration.StatueRegenUpgrades, 2, 5, 5_000_000, 2); this.AddUpgrade(configuration.StatueRegenUpgrades, 3, 7, 5_000_000, 3); } private void InitializeMachineZones(CastleSiegeConfiguration configuration) { configuration.AttackMachineZones.Add(this.CreateZone(62, 103, 72, 112)); configuration.AttackMachineZones.Add(this.CreateZone(88, 104, 124, 111)); configuration.AttackMachineZones.Add(this.CreateZone(116, 105, 124, 112)); configuration.AttackMachineZones.Add(this.CreateZone(73, 86, 105, 103)); configuration.DefenseMachineZones.Add(this.CreateZone(61, 88, 93, 108)); configuration.DefenseMachineZones.Add(this.CreateZone(92, 89, 127, 111)); configuration.DefenseMachineZones.Add(this.CreateZone(84, 52, 102, 66)); } private void AddNpc( CastleSiegeConfiguration configuration, short monsterNumber, byte instanceId, bool isPersisted, CastleSiegeJoinSide defaultSide, byte spawnX, byte spawnY, Direction direction) { var definition = this.Context.CreateNew(); definition.MonsterDefinition = this.GameConfiguration.Monsters.Single(monster => monster.Number == monsterNumber); definition.InstanceId = instanceId; definition.IsPersistedToDatabase = isPersisted; definition.DefaultSide = defaultSide; definition.SpawnX = spawnX; definition.SpawnY = spawnY; definition.Direction = direction; configuration.NpcDefinitions.Add(definition); } private void AddUpgrade( ICollection target, byte level, int jewelCount, int zen, int value) { var upgrade = this.Context.CreateNew(); upgrade.Level = level; upgrade.RequiredJewelOfGuardianCount = jewelCount; upgrade.RequiredZen = zen; upgrade.Value = value; target.Add(upgrade); } private CastleSiegeZoneDefinition CreateZone(byte x1, byte y1, byte x2, byte y2) { var zone = this.Context.CreateNew(); zone.X1 = x1; zone.Y1 = y1; zone.X2 = x2; zone.Y2 = y2; return zone; } }