# Combat Systems, Defensive Options & Game Feel

```mermaid
flowchart LR
  Input[Player input frame] --> Ruleset[Ruleset legality and motion grammar]
  Ruleset --> Ability[Offense defense tag or assist ability]
  Ability --> Authority[Deterministic cost timing target and hit validation]
  Authority --> State[Confirmed combat state]
  State --> Feel[Hitstop shake slow motion tint audio and VFX]
  State --> Replay[Rollback replay and frame-data evidence]
  Authority --> Refusal[Illegal late unavailable or interrupted feedback]
```

The model separates authoritative combat from game-feel presentation. A cue may
predict or dramatize an effect, but only confirmed deterministic state advances
damage, meter, position, round, or replay truth.

This is the product-side view of the moment-to-moment fight: what a player
actually does with the sticks and buttons, what defensive vocabulary the game
hands them, and why a hit _feels_ like Mortal Kombat in one match and like
Street Fighter 6 in the next. The companion architecture page,
[../architecture/combat-system-gas-frame-data-and-determinism.md](../architecture/combat-system-gas-frame-data-and-determinism.md),
explains _how_ the engine stays frame-deterministic enough to roll back and
re-simulate; this page stays on the player's side of the screen and inventories
the offensive systems, the defensive options library, and the game-feel layer as
**features**, while pointing at the exact C++ and balance data that back each
one.

The throughline is V2's whole reason for existing: **per-ruleset feel from one
shared combat core.** A single fighter actor can be re-skinned into a 2D
motion-input duelist, a Tekken juggle machine, a Soul Calibur weapon master, an
MMA grappler, or a WWE worker — not by swapping engines, but by changing which
attributes a move touches, which defensive options the ruleset enables, and
which hitstop/shake curve plays on impact. Almost all of this is real, tested
Unreal C++ under `V2/ue/Source/V2Combat` and `V2/ue/Source/V2Gameplay`, tuned by
CSVs under `V2/balance/feel/` and `V2/balance/data/`. For the full mode
taxonomy, roster, and the rest of the scope this slots into, start at the
feature hub: [../V2_features.md](../V2_features.md).

## What ships, honestly

The combat **logic** is substantive and broadly tested. The offensive and
defensive resolution lives in `UV2CombatResolver`
(`V2Combat/Public/V2CombatResolver.h`, an 823-line `UBlueprintFunctionLibrary`)
plus a family of stateful `UActorComponent`s — `UV2ComboCounterComponent`,
`UV2JuggleStateComponent`, `UV2BlockstringStateComponent` — and the real
per-call math sits in `V2Combat/Private/V2CombatTypes.cpp`, which is **~24,300
lines** of domain logic (the matching header is ~15,800). Game feel is a real,
CSV-driven catalog. The suite under `V2/ue/Source/V2Tests` carries **407**
`*.spec.cpp` automation specs, including an 8,300-line
`Automation/Combat.Module.spec.cpp` that exercises the resolver evaluators and
combat components directly, plus dedicated `Combat/GameFeelTuning.spec.cpp` and
`Gameplay/CameraShake.spec.cpp` suites.

Three honest qualifications. **First**, the resolver's evaluators are _pure
deterministic functions_ — each public `Evaluate*` call forwards to a
`Request.Evaluate()` that checks windows and returns a result with a fail-loud
reason tag. They compute the right answer; wiring them into live abilities,
input, and animation is the GAS + sim-world job covered in the architecture
companion. **Second**, the defensive options are **opt-in per ruleset**: every
config struct (`FV2CombatParryRulesetConfig`, …) defaults to `bEnabled = false`,
so the library _exists_ in full but which family a given ruleset turns on is
data, not a guarantee that all of them are live at once. **Third**,
`V2/balance/data/frame-data.csv` is a **4-move sample** that demonstrates the
column schema, not a shipped frame database — the authoritative per-move numbers
live in `UV2MoveFrameData` data assets. And as the architecture page flags, the
editor-time _validator_ that would forbid a designer from shipping a move with
no property data is planned, not enforced. There are no `.uasset` binaries in
the repo; this is a logic-and-data skeleton.

## Offensive systems — the layered attack vocabulary

V2 combat is **layered**, and the layers activate per ruleset. A player in an MK
match never touches the 8-way-run weapon layer; a Soul Calibur player never sees
the Drive gauge. One actor carries all of them; the ruleset decides which are
armed.

### The universal spine every move shares

Underneath every layer is a move contract. Each move is a `UV2MoveFrameData`
asset (`V2Combat/Public/V2MoveFrameData.h`, ~1,300 lines) wrapping a small
honest `FV2FrameData` of `StartupFrames` / `ActiveFrames` / `RecoveryFrames` /
`OnHitAdvantage` / `OnBlockAdvantage` plus juggle scaling. The sample
`frame-data.csv` shows the shape a designer reads — e.g. `Heavy Launcher` at 18
startup / 3 active / 29 recovery, **+38 on hit, −14 on block, 92 damage** — the
classic "huge reward, deeply punishable" launcher profile, versus a
`Cross-Up Kick` at 11/4/17, −3 on block (barely minus, a safe pressure tool).
That on-block number is the entire mind-game economy of a fighting game
expressed as one integer.

Every move also carries an **attack-property bitmask**,
`EV2CombatAttackProperty`, with exactly the eight bits the genre needs — `Low`,
`Mid`, `High`, `Overhead`, `Crossup`, `AntiAir`, `OTG`, `Unblockable` — so the
defender's block check, the crossup/anti-air logic, and the training-mode
overlays all read the same source of truth. Hits resolve through a deterministic
sweep (`UV2CombatResolver::ResolveFixedFrameSweep`) and a trade resolver
(`ResolveTradeEvents`) whose `EV2CombatTradeResolutionKind` distinguishes a
clean `SimultaneousDamage` trade from a `CounterHitPriority` win or a
`GuardImpactClash` — the difference between "you both got hit," "you got
counter-hit for extra damage," and "your weapons rang off each other."

### Strikes, juggles, and the combo economy

The headline offensive feature is the **combo**, and V2 models it as an economy,
not a fixed string. `UV2ComboCounterComponent` tracks the live hit count and,
crucially, **starter proration**: `RegisterProratedCollisionEvent` scales the
whole combo by the move that started it (`EV2CombatStarterProrationProfile`), so
a light-starter combo deals less than the same route off a launcher — the reason
a "confirm" matters more than raw button mashing. It also knows the difference
between techable and untechable hits and resets the counter for the right reason
(`EV2ComboCounterResetReason`: `Tech`, `WakeUp`, `BlockedHit`,
`DamageScalingReset`).

The juggle layer — Tekken culture — lives in `UV2JuggleStateComponent`. It
registers a launcher, caps the air string (`MaxJuggleHits` default **12**), and
applies **per-ruleset juggle damage scaling** (`EvaluateJuggleDamageScale`,
keyed on `EV2ShaktiRulesetId`), so the same number of air hits bleeds value
differently in Tekken than in MK. It owns the **tornado/screw** state
(`RegisterTornado`, one use by default), **wall splat** (single by default, up
to **3** in rulesets that allow multi-wall-splat via
`DoesRulesetAllowMultiWallSplat`), and **stage transitions** that move the fight
to a new floor. Tekken's launcher kinematics are real numbers on the move asset
— `TekkenLaunchImpulse = (160, 0, 520)`, a 12-hit juggle cap, 0.92 starter
scaling.

Pressure that _doesn't_ combo is the blockstring, modelled by
`UV2BlockstringStateComponent`: it accumulates blockstun, tracks the gap between
blocked hits, and reports `IsTrueBlockstring()` — i.e. whether the defender is
genuinely locked down or has a frame to escape. That single boolean is what
separates "respect this string" from "mash a reversal here."

### Supers, finishers, and counter-hit drama

The spectacle layer is real too.
`UV2CombatResolver::BuildDefaultSuperMoveGrammar` seeds the cinematic super
catalog — **SF Critical Art (Level 3)**, **MK X-Ray**, **MK Fatal Blow**,
**Tekken Rage Art**, **SC Critical Edge** — each entry naming its cinematic
sequence and slow-mo cue, and `EvaluateSuperMoveActivation` gates activation on
the meter rules. These pair with the 21 typed GAS ability subclasses on the
gameplay side (the nine `UV2_Ability_*` ruleset super variants — including the
MK Fatal Blow's real "only under 30% health" gate) detailed in the architecture
companion. Counter-hit and "big moment" emphasis are first-class evaluators:
`EvaluateCounterHit`, MK's `EvaluateKrushingBlow` (a hidden-condition alt-hit
with its own cinematic freeze), `EvaluateWakeupAction` for okizeme, and
`EvaluateComebackState` for the low-HP rally. Tekken's full kit — Heat
activation and Heat moves, Rage activation/Rage Art, Ki Charge, Power Crush
armor, and stance switching — each has a dedicated resolver entry. Beyond
striking, the same resolver carries the **grapple/MMA/wrestling** offensive
surfaces (takedowns, ground-position transitions, ground-and-pound, submissions,
pins, kickouts, object usage, and stipulation logic) and the **Def Jam**
environmental finishers, Blazin' meter, and crowd momentum — each a real
`Evaluate*` function, not a placeholder.

## The defensive options library

V2's standout system is that it doesn't ship _one_ defense; it ships the genre's
**entire defensive vocabulary** as a toggleable library, so each match plays in
the defensive grammar of the family it's emulating. Every option is a real
evaluator on `UV2CombatResolver` whose request struct enforces a timing window
and returns a fail-loud reason tag — these are not stubs, they compute
correctness and honestly reject bad input.

### One resolver, many defenses

| Defensive option (lineage)               | Resolver entry                    | What the player gets                                                                      |
| ---------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------- |
| **Parry** (3rd Strike)                   | `EvaluateParry`                   | Time the block on the hit-frame: no chip, attacker stunned, defender gains frames + meter |
| **Just Defend** (KOF / Garou)            | `EvaluateJustDefend`              | Perfect-frame block for 0 chip                                                            |
| **Instant Block** (Tekken)               | `EvaluateInstantBlock`            | Release-and-repress guard on first contact → reduced blockstun                            |
| **Faultless Defense** (Guilty Gear)      | `EvaluateFaultlessDefense`        | Meter-cost air/ground guard with extra pushback and chip mitigation                       |
| **Push Block / Advancing Guard** (MvC)   | `EvaluatePushBlock`               | Shove the attacker out of pressure at meter cost                                          |
| **Burst** (Guilty Gear)                  | `EvaluateBurst`                   | One-shot (or burst-meter) panic button out of a combo                                     |
| **Counter Assault / Alpha Counter**      | `EvaluateCounterAssault`          | Special out of blockstun to reverse the turn                                              |
| **Guard Cancel** (KOF)                   | `EvaluateGuardCancel`             | Cancel block into a roll/blowback at meter cost                                           |
| **Negative Penalty** (KOF)               | `EvaluateNegativePenalty`         | Anti-turtle inactivity penalty                                                            |
| **Hold / Strike / Throw triangle** (DOA) | `EvaluateHoldStrikeThrow`         | RPS reversal layer (also drives WWE clinch)                                               |
| **Super-armor / invuln frames**          | `EvaluateSuperDefenseFrames`      | Armored or invincible windows on reversals                                                |
| **Guard Impact** (Soul Calibur)          | `EvaluateSoulCaliburGuardImpact`  | `Repel` / `Deflect` / `Resist` weapon deflection                                          |
| **Reversal Edge** (SCVI)                 | `EvaluateSoulCaliburReversalEdge` | Cinematic RPS clash at meter cost                                                         |

The `EvaluateParry` implementation is representative of the whole library: it
clamps the parry window (default **6** frames), computes the input-lead frames
against the incoming hit, and only on a `IsInputWithinParryWindow()` success
returns `bParried = true`, `bNegatesChipDamage = true`, the attacker's stun
(default **18** frames), the defender's frame advantage (default **+12**), and a
meter reward (default **10**) — otherwise it returns one of a dozen precise
rejection tags (`Parry.Rejected.NotInWindow`, `…RulesetDisabled`, …). Instant
Block similarly verifies the release-then-repress ordering happened _on first
contact_ before granting reduced blockstun; Burst checks one-shot availability
or burst-meter cost before it fires. The standard block path is split into its
own trio — `EvaluateBlock`, `EvaluateBlockChipDamage`, `EvaluateBlockPushback` —
so chip (which, per the architecture page, converts to SF6-style recoverable
white health) and pushback are tunable independently of the block decision.

### Throws, techs, and per-ruleset toggling

The throw game is a defensive surface too: `EvaluateThrowAttempt`,
`EvaluateThrowTech`, `EvaluateCounterThrow`, and `EvaluateCrouchTech` give the
defender the genre's full anti-grab toolkit. SF6's Drive system rounds out the
defensive menu on the gameplay side — `EV2DriveGaugeAction` carries
`DriveImpact`, `DriveParry`, `DriveRush`, `ODSpecial`, and `DriveReversal` with
real per-action costs (`DriveReversalCost = 2.0`), and the punishing **Burnout**
state is modelled by `FV2DriveBurnoutStateResult` (doubled
`BurnoutChipDamageScalar`).

What ties the library to the "per-ruleset feel" promise is that
`UV2CombatRulesetData` carries a **config struct for every option** —
`ParryConfig`, `JustDefendConfig`, `InstantBlockConfig`,
`FaultlessDefenseConfig`, `PushBlockConfig`, `BurstConfig`,
`CounterAssaultConfig`, `GuardCancelConfig`, `NegativePenaltyConfig`,
`HoldStrikeThrowConfig` — each with its own enable flag, window timings, costs,
and per-fighter overrides (`FV2CombatParryFighterWindow`). A ruleset enables
exactly the defenses that belong to its lineage; the rest stay dormant. Which
rulesets light up which options, and how that meshes with tag-team assists and
the Kameo partner system, is covered in
[./rulesets-tag-and-kameo.md](./rulesets-tag-and-kameo.md).

## Game feel — hitstop, shake, slow-mo, tint

A correct hit that feels limp is a failed feature. V2 centralizes game feel into
one tunable catalog — `UV2CombatRulesetData::BuildDefaultGameFeelCatalog()`
returns an `FV2GameFeelCatalog` (id `GameFeel.Catalog.V2`) — so every ruleset
can hit differently from one shared system, and every value is a CSV a designer
edits without a recompile.

### Hitstop and hitlag — the "weight" of a hit

Hitstop is the brief freeze on impact that sells force. The catalog's
`HitstopPolicy` splits attacker and defender hitstop, adds a defender-only
hitlag window, a counter-hit bonus (**2–3** frames), a configurable block
hitstop (default **4**), and a crush/punish bonus — all authored per ruleset and
per damage tier in `V2/balance/feel/hitstop_curves.csv`. The shipped rows make
the identity differences concrete: `MK.Heavy` freezes **8 attacker / 10 defender
/ 8 hitlag** with a 6-frame Sakkin, `MK.Launcher` goes to **9 / 12 / 9**, while
`SF6.Heavy` stays conservative at **6 / 7 / 5** and `SC.WeaponClash` rings at
**7 / 9 / 6** — MK's "juicy and heavy," SF6's "crisp and quick," Soul Calibur's
"steel-on-steel." Two columns matter for netplay: every row sets
`rollback_budget_excluded = true` and `resim_cosmetic_suppressed = true`, which
is why a heavy hit's freeze never blows the rollback budget and never
re-triggers during re-simulation (the architecture page traces this through the
sim world's `if (HitstopFrames > 0) --HitstopFrames; else ++AnimationFrame;`).

### Camera shake, slow-mo, freeze, and tint

`V2/balance/feel/camera_shake_curves.csv` defines **9** shake curves scaling
from `Small` (base **0.20**, reduced-motion ceiling **0.12**) through `Heavy`,
`BoneShatter`, `WeaponClash`, and `Explosion` up to `KO` (**1.00 / 0.35**) and
`Fatality` (**1.20 / 0.35**) — and `GameFeelTuning.spec.cpp` asserts the
ordering _must_ hold (Fatality stronger than KO) and that every reduced-motion
ceiling sits below its base intensity, so the accessibility clamp can never be
louder than the default. At runtime `UV2CameraShakeLibrary` folds Perlin /
spring / directional-impact patterns into one evaluation clamped to a 50-unit /
10-degree maximum.

`slowmo_freeze_curves.csv` tunes the dramatic pauses: a round-clinching **KO
slow-mo at 48 frames** with a camera ride, a **finisher freeze-frame at 18
frames** with zoom and tint, Soul Calibur's Reversal-Edge clash at 18, MK's
mid-combo launcher emphasis at 10, and ruleset-specific KO treatments (WWE
broadcast KO at **54**, UFC's realistic flash KO at **30**) — every row exposing
an `accessibility_opt_out`. Screen-state tints (counter-hit flash, low-HP
vignette, comeback aura, and power-state tints for Devil / Soul Charge / Heat /
Blazin' / Burnout) and the photo-mode tone curves round out the visual layer.

### Tunability and accessibility

The catalog's `FV2GameFeelTunabilitySpec` points at the exact CSV paths
(`V2/balance/feel/hitstop_curves.csv`, `…/camera_shake_curves.csv`,
`…/slowmo_freeze_curves.csv`, `…/photo_mode_tone_curves.csv`) and names an
editor utility widget (`EUW_GameFeelMovePreview`) for previewing feel per move —
and the spec adversarially rejects a catalog whose tunability path _doesn't_
point at the canonical balance CSVs. Because the reduced-motion ceilings are the
same data the accessibility surfaces read, "tone down screen shake" is not a
separate code path; it's a clamp baked into the shared feel system. The full
accessibility surface is in the UI/HUD/accessibility feature page set.

## Control schemes and the accessibility ramp

The same combat core serves both the execution purist and the newcomer. V2 ships
**Classic** (full motion-input fidelity), **Modern** (assisted single-button
specials, ranked-eligible), **Dynamic** (fully assisted, ranked-locked), and
**Easy** combo/Fatality options. The balance tradeoff is real data, not a
slogan: `V2/balance/data/modern-vs-classic-balance.csv` pins Modern's default
damage scalar at **0.80** against Classic's **1.00**, and already records a
per-fighter tuning exception — `Fighter.King` Modern bumped to **0.82** because
simplified grappler routes underperform Classic beyond the launch parity band.
That's the control-scheme balance loop expressed as a tracked, designer-owned
tuning row.

## How it connects

Combat is the hub the rest of V2 reads. The frame data, attack properties, and
input-buffer windows feed the animation and motion-matching layer; the
deterministic hit resolution and the tag-team/assist handshakes feed netplay;
the combo, juggle, and blockstring components plus the golden-replay corpus feed
the training, trials, and replay surfaces in
[./mode-catalog-training-and-replay.md](./mode-catalog-training-and-replay.md);
and the per-ruleset feel definitions, defensive toggles, tag mechanics, and
Kameo partner system are inventoried in
[./rulesets-tag-and-kameo.md](./rulesets-tag-and-kameo.md). For the engine-side
treatment of every system named here — the GAS authority/sim-world split, the
attribute sets, the gameplay-effect appliers, the determinism guardrails, and
the state-hash desync signal — read the architecture companion,
[../architecture/combat-system-gas-frame-data-and-determinism.md](../architecture/combat-system-gas-frame-data-and-determinism.md).

## Related

- The feature hub: [../V2_features.md](../V2_features.md)
- [Rulesets, Tag & Kameo](./rulesets-tag-and-kameo.md) — per-ruleset feel,
  tag-team/assist mechanics, and the MK1-style Kameo partner option
- [Mode Catalog, Training & Replay](./mode-catalog-training-and-replay.md) —
  where these systems are practiced, recorded, and played back
- Architecture companion:
  [../architecture/combat-system-gas-frame-data-and-determinism.md](../architecture/combat-system-gas-frame-data-and-determinism.md)
  — GAS, frame data, game feel, and determinism on the engine side
