# BPC_MeleeSystem — Melee Weapon Component

## Blueprint Spec — UE 5.5–5.7

---

### Parent Class
`ActorComponent`

### Dependencies
- [`BPC_DamageReceptionSystem`](BPC_DamageReceptionSystem.md)
- [`BPC_CombatFeedbackComponent`](54_BPC_CombatFeedbackComponent.md)
- [`I_Damageable`](../01-core/03_I_InterfaceLibrary.md)
- [`DA_WeaponData`](../14-data-assets/)
- Owner Character Animation Blueprint

### Purpose
Melee weapon specialization. Handles swing detection, hitbox overlap checking during windup / active frames, and combo chain sequencing. Supports light attacks, heavy attacks, charge attacks, and block/parry.

### Variables

| Name | Type | Description |
|------|------|-------------|
| `ComboSection` | FName | Active montage section for combo |
| `ComboStep` | Int | Current combo step index |
| `bCanCombo` | Bool | True during window after hit or end of swing |
| `ComboWindowDuration` | Float | Seconds to chain next attack |
| `SwingMontage` | UAnimMontage | Full melee animation set |
| `HitDetectionCollision` | UCapsuleComponent | Overlap collision for hit detection |
| `bHitRegistered` | Bool | Prevents multi-hit on same swing |
| `HitActors` | Array<AActor> | Already hit this swing |
| `SwingPhase` | ESwingPhase | Windup / Active / Recovery / Idle |
| `ChargeDuration` | Float | Hold time for charged heavy attack |
| `bIsBlocking` | Bool | Currently blocking stance |
| `ParryWindow` | Float | Active parry frames in seconds |
| `bParryActive` | Bool | Within parry active window |
| `StaggerDuration` | Float | Hit reaction stun (self or target) |

### Enums

| Enum | Values | Description |
|------|--------|-------------|
| `ESwingPhase` | Idle, WindUp, Active, Recovery, ParryWindow | Attack animation phase |
| `EAttackType` | LightAttack, HeavyAttack, ChargeAttack, SprintAttack, ParryRiposte | Swing variant |

### Functions

| Name | Inputs | Outputs | Description |
|------|--------|---------|-------------|
| `StartSwing` | AttackType: EAttackType | — | Play montage section, set SwingPhase |
| `OnSwingWindup` | — | — | Begin hit detection |
| `OnSwingActive` | — | — | Enable HitDetectionCollision overlap |
| `OnSwingHit` | HitResult: FHitResult | — | Single hit registration |
| `OnSwingRecovery` | — | — | Disable hit collision, check combo window |
| `OnSwingComplete` | — | — | Return to Idle |
| `StartBlock` | — | — | Play blocking animation |
| `EndBlock` | — | — | Release block stance |
| `ParryCheck` | IncomingAttack | Bool | If parry window active → counter |
| `GetComboStep` | — | Int | Return current combo index |
| `ResetCombo` | — | — | Clear combo step counter |

### Blueprint Flow

```
[Combo Chain Logic]
  LightAttackInput →
    If SwingPhase == Idle:
        ComboStep = 0
        StartSwing(LightAttack)
    ElseIf SwingPhase == Active || SwingPhase == Recovery:
        If bCanCombo && ComboStep < MaxComboLength:
            ComboStep++
            StartSwing(LightAttack) — next section of montage

[OnSwingActive — called by Animation Notify]
  └─► HitDetectionCollision.SetCollisionEnabled(QueryOnly)
  └─► On overlap → OnSwingHit

[OnSwingHit]
  └─► If HitActor already in HitActors → return
  └─► Add HitActor to HitActors
  └─► If HitActor implements I_Damageable:
         BPC_DamageReceptionSystem.ApplyMeleeDamage(
             Damage = WeaponData.Damage * AttackTypeMultiplier,
             HitActor,
             HitLocation,
             ImpulseDirection
         )
  └─► BPC_CombatFeedbackComponent.PlayHitFX(HitResult)
  └─► ApplyStagger(HitActor)

[OnSwingRecovery — called by Animation Notify]
  └─► HitDetectionCollision.SetCollisionEnabled(NoCollision)
  └─► HitActors.Empty
  └─► Set bCanCombo = true
  └─► Start timer for ComboWindowDuration
  └─► If no combo input received → OnSwingComplete

[OnSwingComplete]
  └─► SwingPhase = Idle
  └─► bCanCombo = false
  └─► ComboStep = 0

[StartBlock]
  └─► bIsBlocking = true
  └─► Play block montage loop section
  └─► Owner movement speed reduced

[ParryCheck]
  └─► If bParryActive && incoming swing phase == Active:
         Play parry riposte animation
         Stagger incoming attacker
         Return true
  └─► Return false
```

### Communications With

| Target | Method | Why |
|--------|--------|-----|
| [`BPC_DamageReceptionSystem`](BPC_DamageReceptionSystem.md) | Get Component | Apply melee damage and stagger |
| [`BPC_CombatFeedbackComponent`](54_BPC_CombatFeedbackComponent.md) | Get Component | Swing whoosh, hit impact, block sparks |
| Owner Animation Blueprint | Direct | Query SwingPhase for animation state |
| Owner Character Movement | Direct | Reduce speed during block |
| Owner Character Input | Direct | Light / Heavy / Block input mapping |
| [`I_Damageable`](../01-core/03_I_InterfaceLibrary.md) | Interface | Damage application on hit actors |

### Reuse Notes
- Uses animation notifies for phase transitions (Notify_Windup, Notify_Active, Notify_Recovery, Notify_CanCombo, Notify_ParryWindow).
- Combo system uses montage section names "Combo_1", "Combo_2", etc.
- Hit collision is a simple box or capsule that exists only during Active phase.
- Block reduces incoming damage via DamageReception; parry reflects stagger.
- Renamed from `BP_MeleeWeapon` to `BPC_MeleeSystem` per Master naming convention.
- Cross-references updated: `BPC_DamageHandlerComponent` → `BPC_DamageReceptionSystem`.

---

## Manual Implementation Guide

### Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_MeleeSystem`
2. Attach to `BP_WeaponBase` subclass: `BP_MeleeWeapon`
3. Add `HitDetectionCollision` (Capsule or Box component) to weapon — disabled by default

### Variable Init (BeginPlay)
```
Event BeginPlay
  ├─ Set SwingPhase = Idle
  ├─ Set ComboStep = 0
  ├─ Set bCanCombo = false
  ├─ Set bIsBlocking = false
  ├─ Disable HitDetectionCollision (NoCollision)
  ├─ Get Owner Weapon → Read DA_WeaponData for: ComboWindowDuration, ChargeDuration, ParryWindow, StaggerDuration
  └─ Get Owner → Find BPC_DamageReceptionSystem → Cache
```

### Function Implementations

#### `StartSwing(AttackType: EAttackType)` → `void`

```
[Function: StartSwing]
  Step 1: Branch on SwingPhase != Idle AND SwingPhase != Recovery → Return (can't chain now)
  Step 2: Set SwingPhase = WindUp
  Step 3: Build montage section name:
    If this is combo: "Combo_" + ComboStep
    If AttackType == HeavyAttack: prefix "Heavy_"
    If AttackType == ChargeAttack: "Charge_"
  Step 4: Play Montage (SwingMontage, Section = built section name)
  Step 5: Set bHitRegistered = false, Clear HitActors array
  Step 6: Fire OnSwingStarted(AttackType, ComboStep)
```

**Nodes:** `Switch on EAttackType`, `Build String`, `Play Montage` (with Starting Section), `Clear Array`

#### `OnSwingActive()` → `void` *(Called by Animation Notify: "Notify_Active")*

```
  Step 1: Set SwingPhase = Active
  Step 2: HitDetectionCollision.SetCollisionEnabled(QueryOnly)
  Step 3: Set bHitRegistered = false
```

#### `OnSwingHit(HitResult)` → `void` *(Called by HitDetectionCollision OnComponentBeginOverlap)*

```
  Step 1: Get Hit Actor from Overlap → Cast to Actor
  Step 2: ForEach HitActors → if match found → Return (already hit this actor this swing)
  Step 3: Add HitActor to HitActors
  Step 4: If HitActor implements I_Damageable:
    Get BPC_DamageReceptionSystem → Call ApplyMeleeDamage:
      BaseDamage = WeaponData.Damage
      Multiplier: Light=1.0, Heavy=1.8, Charge=2.5, Sprint=1.5
      HitLocation = HitResult.ImpactPoint
      Apply impulse in swing direction
  Step 5: Get BPC_CombatFeedbackComponent → Call PlayHitFX(HitResult)
  Step 6: Apply Stagger to HitActor
```

#### `OnSwingRecovery()` → `void` *(Animation Notify: "Notify_Recovery")*

```
  Step 1: Set SwingPhase = Recovery
  Step 2: HitDetectionCollision.SetCollisionEnabled(NoCollision)
  Step 3: Clear HitActors
  Step 4: Set bCanCombo = true
  Step 5: Start Timer (ComboWindowDuration) → On timer: if no combo received → OnSwingComplete()
```

#### `OnSwingComplete()` → `void`

```
  Step 1: Set SwingPhase = Idle
  Step 2: Set bCanCombo = false
  Step 3: Set ComboStep = 0
  Step 4: Fire OnSwingFinished
```

#### `StartBlock()` → `void`

```
  Step 1: Set bIsBlocking = true
  Step 2: Play block montage loop section
  Step 3: Get Owner Character → Get CharacterMovement → Set MaxWalkSpeed *= 0.5
  Step 4: Set ParryWindow timer: bParryActive = true for ParryWindow seconds
    On timer end → bParryActive = false
```

#### `EndBlock()` → `void`

```
  Step 1: Set bIsBlocking = false
  Step 2: Stop block montage
  Step 3: Restore MaxWalkSpeed
```

### Build Checklist
- [ ] Create BPC_MeleeSystem, add to BP_MeleeWeapon
- [ ] Add HitDetectionCollision component (Capsule/Box, NoCollision by default)
- [ ] Create SwingMontage with sections: Combo_1, Combo_2, Combo_3, Heavy_1, Charge_1
- [ ] Place Animation Notifies: Notify_Active, Notify_Recovery, Notify_CanCombo, Notify_ParryWindow
- [ ] Implement phase state machine: Idle→WindUp→Active→Recovery→(combo)→Idle
- [ ] Bind HitDetectionCollision.OnComponentBeginOverlap → OnSwingHit
- [ ] Implement combo system with bCanCombo window timer
- [ ] Implement block/parry with damage reduction and stagger reflection