Files
AdamuSw/docs/superpowers/plans/2026-07-15-cs-p3-siege-battle.md

7.5 KiB
Raw Blame History

CS P3 — Kuşatma Savaşı — Uygulama Planı

For agentic workers: REQUIRED SUB-SKILL: superpowers:subagent-driven-development or superpowers:executing-plans. Steps use checkbox (- [ ]) tracking.

Goal: Castle Siege'i oynanabilir yapmak. İlk increment: Siege fazı başlayınca kayıtlı guild üyelerini CS haritasına (Valley of Loren) al, orada PvP aç, bir Taht ele geçirme noktası koy; kuşatma bitince tahtı tutan guild kazanır ve kale sahibi olur. Kapılar/kristaller/tam S6 protokolü sonraki increment'ler.

Architecture: P1 state machine'in Siege fazına giriş/çıkışına kanca takılır (CastleSiegeContext faz-değişim event'i zaten var: PhaseChanged). Siege başlayınca CastleSiegeEventPlugIn (server-side, GameContext erişimli) kayıtlı oyuncuları warp'lar + PvP açar; Taht bir NPC (talk → guild'i "occupier" yapar); Settlement'ta occupier = kazanan → context.SetOwner. Reuse: player.WarpToAsync(ExitGate), Map.Definition.BattleZone (PvP), IPlayerTalkToNpcPlugIn (Taht), P1 CastleSiegeContext.

Tech Stack: .NET 10, OpenMU GameLogic/PlugIns, NUnit.

Global Constraints

  • Depo: d:/OpenMU/MU Client_Mobile 1.04d - Season 6E3/AdamuSw (bash tırnak içinde).
  • Additive-first; core dokunuşu // ADAMU-CUSTOM.
  • Lokal derleme -p:ci=true. Commit yazarı Acentech Dev <acentech_dev@affinitybox.com>.
  • CS map = Valley of Loren (WorldIndex 30) — implementation'da Persistence/Initialization'dan tam numarayı + entrance gate'i doğrula.
  • Zaman/rastgele state machine mantığında enjekte (P1 deseni).

Investigation notları (implementation başında doğrula)

  • Warp: player.WarpToAsync(ExitGate gate) (Player.cs:1088). CS map entrance gate'i gerekir — Initialization'da Valley of Loren spawn/exit gate'ini bul veya oluştur.
  • PvP: kill izni GameContext.PvpEnabled || Map.Definition.BattleZone != null || CurrentMiniGame.AllowPlayerKilling (Player.cs:725). CS map'e Siege sırasında PvP açmak için: ya map Definition'a BattleZone ekle, ya da CS'ye özel bir AllowPlayerKilling context (MiniGame benzeri). Karar (impl): BattleZone en temiz — Valley of Loren Definition'a BattleZone tanımı (Initialization).
  • Taht NPC: yeni bir NPC number (S6 CS'de "Crown/Throne switch"). IPlayerTalkToNpcPlugIn ile ele geçirme (remote-NPC/Guardsman deseni).
  • CastleSiegeContext'e occupier alanı + kazanan mantığı eklenir (P1'de OwnerGuildName string; occupier de string guild adı).

Task 1: State machine — occupier + settlement kazananı

Files:

  • Modify: src/GameLogic/CastleSiege/CastleSiegeContext.cs
  • Test: tests/MUnique.OpenMU.Tests/CastleSiege/CastleSiegeContextTest.cs

Interfaces:

  • Produces: CastleSiegeContext.CaptureThrone(string guildName) (sadece Siege fazında occupier'ı set eder), OccupierGuildName (get), Settlement'ta occupier varsa OwnerGuildName = occupier.

  • Step 1: Test yaz — Siege fazında CaptureThrone("A")OccupierGuildName=="A"; Settlement tick sonrası OwnerGuildName=="A". Ownership fazında CaptureThrone no-op.

[Test]
public async Task ThroneCaptureDuringSiegeBecomesOwnerOnSettlementAsync()
{
    var ctx = new CastleSiegeContext(Config());
    await ctx.ForceStartRegistrationAsync(T0);
    await ctx.ForcePhaseAsync(CastleSiegePhase.Siege, T0);
    ctx.CaptureThrone("Attackers");
    Assert.That(ctx.OccupierGuildName, Is.EqualTo("Attackers"));
    await ctx.TickAsync(T0.AddMinutes(20)); // Siege -> Settlement
    await ctx.TickAsync(T0.AddMinutes(20)); // Settlement -> Ownership (owner atanir)
    Assert.That(ctx.OwnerGuildName, Is.EqualTo("Attackers"));
}
  • Step 2: Çalıştır → fail (CaptureThrone/OccupierGuildName yok).
  • Step 3: ImplementCastleSiegeContext'e:
    • private string? _occupier; + public string? OccupierGuildName => this._occupier;
    • public void CaptureThrone(string g){ if(this.Phase==CastleSiegePhase.Siege) this._occupier = g; }
    • ForceStartRegistrationAsync/ResetAsync'te _occupier=null.
    • Settlement→Ownership geçişinde (TickAsync Settlement case): if(this._occupier is {} occ){ this.SetOwner(occ); } this._occupier=null; (TransitionAsync'ten önce).
  • Step 4: Test geçsin. Step 5: Commit.

Task 2: Siege başlarken warp + PvP; bitince güvenli bölgeye al

Files:

  • Modify: src/GameLogic/PlugIns/PeriodicTasks/CastleSiegeEventPlugIn.cs
  • (Belki) Create: src/GameLogic/CastleSiege/CastleSiegeMapController.cs (warp/PvP yardımcıları)

Interfaces:

  • Consumes: CastleSiegeContext.PhaseChanged (P1), player.WarpToAsync, CS map (Valley of Loren).

  • Produces: Siege fazına girince kayıtlı guild üyeleri CS map'e warp; Ownership'e dönünce map'ten güvenli bölgeye.

  • Step 1: CastleSiegeEventPlugIn.ExecuteTaskAsync içinde faz değişimini yakala (context.Phase önceki-değerle karşılaştır ya da PhaseChanged event'ine abone ol). Siege'e GİRİŞTE: gameContext'teki tüm oyunculardan GuildStatus.GuildId'si kayıtlı guild'lerden biri olanları CS map entrance gate'ine WarpToAsync.

  • Step 2: PvP: CS map Definition'a BattleZone (Initialization'da) — Siege boyunca kill serbest. (Alternatif: CS context'i AllowPlayerKilling=true mini-game gibi kaydet.) Impl'de en az riskli yolu seç, doğrula.

  • Step 3: Siege bitince (Ownership'e dönüş): CS map'teki oyuncuları WarpToSafezoneAsync.

  • Step 4: Derle + smoke. Step 5: Commit.

Not: kayıtlı-guild üye eşleştirmesi için context'te guild ADI tutuyoruz; warp'ta oyuncunun guild adını GuildServer.GetGuildAsync(guildId).Name ile çözüp kayıtlı listeyle karşılaştır (Guardsman handler'daki desen).


Task 3: Taht NPC — ele geçirme

Files:

  • Create: src/GameLogic/CastleSiege/CastleSiegeThroneTalkPlugIn.cs
  • (Initialization) Taht NPC'sini CS map'e yerleştir (number ata).

Interfaces:

  • Consumes: IPlayerTalkToNpcPlugIn, CastleSiegeEventPlugIn.TryGetContext, context.CaptureThrone.

  • Step 1: CastleSiegeThroneTalkPlugIn : IPlayerTalkToNpcPlugIn (Guardsman deseni). Taht NPC number kontrolü → eventArgs.HasBeenHandled=true → Siege fazındaysa + oyuncu kayıtlı guild master/üyesiyse → context.CaptureThrone(guildName) + "Your guild captured the throne!" mesajı.

  • Step 2: Taht NPC'sini CS map'e ekle (Initialization'da MonsterSpawn; number ata, örn. 277 "Castle Gate switch" S6 referansına bak).

  • Step 3: Derle. Step 4: Commit.


Task 4: Uçtan uca test + server image + admin akışı

  • Step 1: Tüm CS testleri geçsin (--filter CastleSiege).
  • Step 2: Image rebuild + container restart.
  • Step 3 (manuel/emülatör): GM ile /csstart → Guardsman'de kayıt → /csphase Siege → oyuncu CS map'e warp olmalı, PvP açık, Taht'a konuş → "captured throne" → /csphase Settlement/csstatus owner = guild. (Not: Taht ele geçirme akışı client↔server canlı doğrulanır.)
  • Step 4: Gitea push.

Sonraki increment'ler (P3 devamı)

  • Kapılar (Destructible, HP, kırılınca terrain açılır — MiniGame terrain-change deseni).
  • Kristaller / Guardian Statue'lar (Destructible; taht'a erişim için yıkılmalı).
  • Kontenjan/giriş kısıtı (Siege'de sadece kayıtlı guild üyeleri map'e girebilir).
  • Tam S6 CS protokolü (server→client CS state/time paketleri → client'ın native kuşatma UI'ı + geri sayım çalışır; client UI'ı hazır).
  • Contention (tek ele geçirme yerine tutma süresi/skor ile kazanan).