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

111 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.
```csharp
[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: Implement**`CastleSiegeContext`'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).