# Rulesets, Tag-Team & Kameo Assists

```mermaid
classDiagram
  class RulesetDefinition {
    movementFamily
    defensePolicy
    meterPolicy
  }
  class TeamFormat {
    rosterSlots
    switchPolicy
    sharedResources
  }
  class KameoDefinition {
    assistMoves
    cooldown
    restrictions
  }
  class CombatantState {
    activeFighter
    benchState
    assistState
  }
  RulesetDefinition --> CombatantState : governs
  TeamFormat --> CombatantState : structures
  KameoDefinition --> CombatantState : extends
```

Ruleset feel, team structure, and assist behavior compose through explicit data
instead of conditionals scattered through the shared combat core. Each
combination still requires deterministic and balance validation.

V2's headline promise is not "blend every fighting game into one soup" but
**per-ruleset feel**: when a match runs the MK ruleset it must hit like Mortal
Kombat, when it runs the Tekken ruleset it must move like Tekken, and the engine
underneath has to honour both from one shared roster, one shared move grammar,
and one deterministic simulation. That is a harder bar than a roster crossover —
it means the _same_ fighter actor is re-skinned, frame by frame, into whichever
family the match selected, by which combat layers turn on, which defensive
options are legal, which super gates apply, how impacts freeze the screen, and
what the decisive moment looks like. This page covers the three features that
deliver that promise at the edges of moment-to-moment combat: the **per-ruleset
feel** system and how it is tuned, the **tag-team** formats and mechanics, and
the MK1-style **Kameo** assist partner. It is the feature-side companion to the
"Combat & Game Feel" group; the section hub is
[../V2_features.md](../V2_features.md).

## What ships, honestly

The three features sit at very different points on the implemented-versus-spec
spectrum, and this page labels each one where it actually is.

- **Per-ruleset feel is real and tested.** The ruleset identity
  (`EV2ShaktiRulesetId`, eight families), the combat layers that activate per
  ruleset (`GetNativeCombatLayerMaskForRuleset`, a real bitmask switch), the
  defensive options legal per ruleset (`GetNativeDefenseOptionMaskForRuleset`),
  the nine ruleset super abilities, the per-ruleset match-flow nodes, the
  per-ruleset HUD overlay, and the per-ruleset game-feel profiles + balance CSVs
  are all substantive Unreal C++ and on-disk data, exercised by the automation
  suite.
- **Tag-team is split.** The named mechanics — Snapback, DHC, X-Factor/Pandora,
  Cross Assault, Baroque/Duo cancel — are **not** GAS ability subclasses. They
  are a validated **data-contract catalog** (`FV2TagTeamMechanicsCatalog`) in
  the `V2Modes` module, plus a real runtime _seam_ on the ability system: a
  replicated tag-out/tag-in animation handshake and a replicated assist
  cooldown. Treat "each mechanic is its own ability" as aspirational; the
  catalog that describes them, and the handshake/cooldown plumbing they will
  ride, are what exists today.
- **Kameo is authored data behind a launch gate.** The Kameo partner system is a
  validated configuration inside the Create-a-Moveset editor catalog, with a
  default-builder and a contract test — but there is **no dedicated runtime
  Kameo summon / health-depletion component**; it shares the assist-call seam
  conceptually and is tracked as the launch readiness gate
  `Gate.MK1KameoSystem`.

The deterministic-combat and rollback internals these features lean on are
documented in
[../architecture/combat-system-gas-frame-data-and-determinism.md](../architecture/combat-system-gas-frame-data-and-determinism.md)
and
[../architecture/rollback-netcode-and-tag-team.md](../architecture/rollback-netcode-and-tag-team.md);
this page stays on the feature surface and only dips into the C++ where a claim
needs backing.

## Per-ruleset feel: one engine, eight families

### The ruleset identity and the layers that turn on

A match's family is a single enum. `EV2ShaktiRulesetId`
(`V2/ue/Source/V2Combat/Public/V2CombatTypes.h:211`) names **eight** rulesets —
`MK, SF, KOF, Tekken, WWE, UFC, SC, DJ` — and the authored gameplay-tag table
(`V2/ue/Config/Tags/V2.GameplayTags.ini`) carries the matching `Rules.Mode.*`
roots (`MK`, `SF`, `Tekken`, `WWE`, `UFC`, `SoulCalibur`, `DefJam`, plus
`TagTeam`). KOF is honestly a second-class citizen at the tag level — it has no
`Rules.Mode.KOF` tag and instead surfaces through the combat-layer and tag-team
mechanics — which matches the source's "seven first-class rulesets plus
crossover" framing.

The actual per-ruleset feel is encoded in **which combat layers activate**.
`EV2CombatRulesetLayer` (`V2CombatRulesetData.h`) is a 16-value bitflag set —
`Block, Juggle, DefenseOptions, ComboScaling, TekkenMovement, TekkenHeat, TekkenRage, TekkenPowerCrush, TekkenStance, WakeupOptions, KrushingBlow, FastCancel, ModeCancel, RingOut, Submission, EnvironmentFinisher`
— and `UV2CombatRulesetData::GetNativeCombatLayerMaskForRuleset`
(`V2CombatRulesetData.cpp`) is a literal `switch` that returns the active mask
per family over a `CommonStrikingMask` of
`Block | Juggle | DefenseOptions | ComboScaling | WakeupOptions`:

| Ruleset      | Layers added to the common striking base                                                       | Notably dropped         |
| ------------ | ---------------------------------------------------------------------------------------------- | ----------------------- |
| **MK**       | `KrushingBlow`, `ModeCancel`, `EnvironmentFinisher`                                            | —                       |
| **SF / KOF** | `FastCancel`, `ModeCancel`                                                                     | —                       |
| **Tekken**   | `TekkenMovement`, `TekkenHeat`, `TekkenRage`, `TekkenPowerCrush`, `TekkenStance`, `FastCancel` | —                       |
| **WWE**      | `Submission`, `EnvironmentFinisher` (base = Block/DefenseOptions/ComboScaling/WakeupOptions)   | **`Juggle`**            |
| **UFC**      | `Submission` (base only)                                                                       | **`Juggle`**, finishers |
| **SC**       | `RingOut`, `ModeCancel`                                                                        | —                       |
| **DJ**       | `Juggle`, `FastCancel`, `EnvironmentFinisher`                                                  | **`WakeupOptions`**     |

That table _is_ the feel difference, in code. Wrestling and MMA drop `Juggle`
because real grappling has no air-juggle culture and add `Submission`; Tekken
turns on its entire signature family; Soul Calibur adds `RingOut`; Def Jam keeps
environmental finishers but drops formal wake-up option-selects. A designer can
union extra layers on top via an `OverrideLayerMask`, and
`FV2CombatRulesetSelectionResult` reports `NativeLayerMask`,
`OverrideLayerMask`, `ActiveLayerMask`, and an accept/reject `ReasonTag`;
`IsLayerActive(Layer)` answers per layer. The `V2.Combat.Module` automation spec
(`V2/ue/Source/V2Tests/Automation/Combat.Module.spec.cpp:213`) drives
`GetResolvedCombatLayerMask()` and asserts the per-ruleset layers (e.g.
`TekkenHeat`, `RingOut`, `Submission`) are present or absent as designed, and
that disabling `bRingOutEnabled` removes the `RingOut` layer.

### The defensive grammar shifts per family

Each family also plays in a different defensive language.
`GetNativeDefenseOptionMaskForRuleset` maps the ruleset to its legal options
from the broader defensive library:

| Ruleset    | Native defensive options                                               |
| ---------- | ---------------------------------------------------------------------- |
| **SF**     | `Parry` (3rd-Strike-style)                                             |
| **KOF**    | `JustDefend`, `GuardCancel`, `NegativePenalty`                         |
| **Tekken** | `InstantBlock`                                                         |
| **WWE**    | `HoldStrikeThrowTriangle` (DOA-style RPS reversal)                     |
| **SC**     | `HoldStrikeThrowTriangle` **only** when Reversal-Heavy mode is enabled |
| others     | none native (the library stays off)                                    |

So a Street Fighter match grants the parry, a King of Fighters match grants
just-defend plus guard-cancel plus the anti-turtle negative penalty, and a
Tekken match grants the instant-block timing — each from one shared library,
gated by the ruleset. The full defensive vocabulary and the game-feel layer are
detailed in
[./combat-systems-defense-and-game-feel.md](./combat-systems-defense-and-game-feel.md).

### Per-ruleset supers and finisher gates

Where most fighting games have one super button, V2's super is a typed family.
`UV2_Ability_Super`
(`V2/ue/Source/V2Gameplay/Public/Abilities/V2_AbilityClasses.h:174`) carries two
real config blocks — `ConfigureSuperMeterProfile(...)` and
`ConfigureMKStaminaProfile(...)` — and **nine** concrete ruleset variants
descend from it, each configured in its constructor (`V2_AbilityClasses.cpp`):

| Super variant     | Configured behaviour                                                             |
| ----------------- | -------------------------------------------------------------------------------- |
| `SFDriveImpact`   | `SuperBarCost = 0` — spends the Drive gauge, not the super bar                   |
| `SFCriticalArtL1` | 1-bar                                                                            |
| `SFCriticalArtL2` | 2-bar, **12-frame invincible reversal**                                          |
| `SFCriticalArtL3` | 3-bar, cinematic preset `Seq.SF.CriticalArt.Level3`                              |
| `TekkenRageArt`   | Tekken-tagged (`Rules.Mode.Tekken`), server-initiated, 52-frame recovery window  |
| `MKXRay`          | MK stamina cost 2.0, **requires full X-Ray meter**                               |
| `MKFatalBlow`     | `ConfigureMKStaminaProfile(2.0, false, true, 0.30)` — **only under 30 % health** |
| `SCCriticalEdge`  | 1-bar, 12-frame invincible, cinematic `Seq.SC.CriticalEdge`                      |
| `DJBlazin`        | Blazin'-meter super                                                              |

The MK Fatal Blow's "only when you're under 30 % health" rule is a real
`FatalBlowHealthThresholdPct = 0.30f` gate, not a comment — exactly the kind of
ruleset-specific constant that distinguishes real feel from a renamed CRUD
struct. Notice the asymmetry: **WWE and UFC have no super subclass at all.**
Their decisive moment is not a meter-burn super but a match-flow interlude — a
pin or a scorecard — which is the next layer.

### Per-ruleset match flow and KO conditions

The match-state machine injects per-mode nodes rather than baking modes into the
phase enum. `EV2MatchModeStateNodeType`
(`V2/ue/Source/V2Gameplay/Public/Match/V2_MatchState.h:18`) enumerates the
per-ruleset interludes — `MKFinisherWindow`, `WWEPin`, `WWESubmission`,
`UFCRoundEndScorecard`, `SCRingOutTermination`, `DJEnvironmentFinisherPrompt`,
`SFKOReplay`, `TekkenRageActivationLockout` — each a `FV2MatchModeStateNode`
with a duration and a `bBlocksFighterInput` flag, so the engine honestly stops
accepting fighter input during a WWE pin mini-game or a UFC scorecard. The
decisive condition itself is `EV2MatchRulesetKOBehavior` (`TraditionalRounds`,
`LastManStanding`, `FlashKO`, `TechnicalKnockout`, `SubmissionOnly`,
`RingOutLoss`), and `EV2MatchRulesetStipulationType` carries the WWE/SC
stipulation grammar (`DQOnWeapon`, `NoDisqualification`, `SubmissionOnly`,
`TableMatch`, `CageMatch`, `RingOut`, `EnvironmentalFinishers`). The phase
machine and its rollback-safe snapshot are covered in
[../architecture/combat-system-gas-frame-data-and-determinism.md](../architecture/combat-system-gas-frame-data-and-determinism.md).

### How the feel is tuned — the data in `V2/balance/feel`

The numbers that make each ruleset _hit_ differently are deliberately data, not
hard-coded C++. `V2/balance/feel/hitstop_curves.csv` carries a `ruleset_id`
column and one row per family/tier — `MK.Small` freezes the attacker 3 frames
and defender 4; `MK.Heavy` jumps to 8/10 with a 6-frame `sakkin`; `SF6.Heavy`
stays conservative at 6/7; `Tekken.Heavy` sits at 7/8; `SC.WeaponClash` at 7/9;
`UFC.KO` realistic at 4/6; `WWE.Explosion` broadcast-loud at 9/11 — and every
row sets `rollback_budget_excluded = true` so hitstop never blows the
resimulation budget. `slowmo_freeze_curves.csv` is likewise per-ruleset
(`SC.ReversalEdge` 18 frames, `MK.MidComboLauncher` 10, `WWE.BroadcastKO` 54,
`UFC.RealisticFlashKO` 30), and `camera_shake_curves.csv` scales from `Small`
(0.20, reduced-motion 0.12) up to `Fatality` (1.20, 0.35). The per-ruleset
camera-shake _personality_ is `EV2GameFeelRulesetProfileKind`
(`MK, SF6, Tekken, SoulCalibur, UFC, WWE`); `GameFeelTuning.spec.cpp` asserts
`HasRequiredRulesetProfiles()` and that each profile (MK, SF6, UFC, WWE) is
discoverable, and that the catalog's tunability paths point at the canonical
`V2/balance/feel/*.csv`.

Two more pieces complete the per-ruleset surface. Individual moves resolve
differently per family — `UV2MoveFrameData` exposes
`CanTekkenLaunch(EV2ShaktiRulesetId)`, `ResolveTekkenHeatMove(...)`, and
`GetResolvedChipDamageOnBlock(EV2ShaktiRulesetId)`, all keyed on the ruleset
(`MoveDataAsset.spec.cpp`). And the HUD follows: `UV2RulesetHUDOverlayWidget`
(`V2/ue/Source/V2UI/Public/V2RulesetHUDOverlayWidget.h`) configures from a
`FV2RulesetHUDOverlaySpec`, exposes `GetRulesetId()` and `HasMeterKind(...)`,
and swaps the on-screen meters (Drive bars, stun, rage, Heat) to match the
active family. Presentation and HUD detail live in
[./roster-presentation-and-stages.md](./roster-presentation-and-stages.md).

## Tag-team: formats, mechanics, and the honest seam

### Data catalog vs. runtime GAS

The monolith says Snapback/DHC/X-Factor/Cross Assault "are abilities in
`V2Gameplay` with their own GAS subclass." **They are not.** A search of
`V2Gameplay` finds no `UGameplayAbility` subclass for any of them; the names
resolve to a deterministic data-contract catalog, `FV2TagTeamMechanicsCatalog`
(`V2/ue/Source/V2Modes/Public/V2ModeTypes.h:4514`), validated by
`V2.Modes.TagTeamMechanics.AssetContract`
(`V2/ue/Source/V2Tests/Private/Modes/TagTeamMechanics.spec.cpp`).

What _is_ real runtime GAS is the seam the mechanics will ride. The ability
system component carries a replicated **tag animation handshake**,
`FV2TagTeamAnimationHandshake`
(`V2/ue/Source/V2Gameplay/Public/V2AbilitySystemComponent.h:21`), a
server-authoritative state machine over `EV2TagTeamAnimationHandshakePhase`
(`None → TagOutRequested → TagOutMontageStarted → TagInMontageStarted → Completed`,
or `Rejected`) with default montages `AM_V2_TagOut` / `AM_V2_TagIn`; and a
replicated **assist cooldown**, `FV2AssistCallCooldown`, with
`CooldownFrames = 360`. There is also a concrete `UV2_Ability_AssistCall`
ability (`V2_AbilityClasses.h:158`, `DefaultCooldownFrames = 360`). And the
whole thing rides the _same_ rollback session as 1v1 — just with more fighters
per snapshot — per
[../architecture/rollback-netcode-and-tag-team.md](../architecture/rollback-netcode-and-tag-team.md).

### Three formats

`EV2TagTeamFormatKind` is `TwoVsTwo`, `ThreeVsThree`, `Trinity`, each a
`FV2TagTeamFormatSpec`:

| Format      | Fighters/team | Defining flags                                             |
| ----------- | ------------- | ---------------------------------------------------------- |
| **2v2**     | 2             | one active fighter/side, `bSwitchableMidComboViaTagButton` |
| **3v3**     | 3             | `bAssistCallEnabled`                                       |
| **Trinity** | 3             | `bAnchorAssistOncePerMatch` (Tekken-Tag-2-style anchor)    |

The test asserts each format is discoverable with the right `FightersPerTeam`,
that 2v2 switches mid-combo and keeps one active fighter per side, and that
Trinity carries the once-per-match anchor assist.

### The seven mechanics

`EV2TagTeamMechanicKind` carries seven entries, each a `FV2TagTeamMechanicSpec`
of typed boolean intent plus `MeterCost` / `CooldownFrames`:

| Mechanic              | Spec intent (flags asserted by the test)                         |
| --------------------- | ---------------------------------------------------------------- |
| **TagCancel**         | `bDesignerCuratedLauncherAnimation`, `bComboExtender`            |
| **Snapback**          | `bForcedOpponentTagOut`, `bSnappedOutFighterRecoversHpOffscreen` |
| **DelayedHyperCombo** | `bPartnerSuperCancel`, `MeterCost > 0`                           |
| **AssistCall**        | `bSingleMoveAssistWithCooldown`, `CooldownFrames == 360`         |
| **CrossAssault**      | `bCrossAssaultTwoFightersControlledByOnePlayer`, `MeterCost > 0` |
| **XFactorPandora**    | `bTemporaryPowerUpTradesHpForDamageSpeed`                        |
| **BaroqueDuoCancel**  | `bPartnerCallCost`, `bComboExtender`                             |

These are spec flags, not abilities — but they are _checked_ spec: the assist
cooldown is asserted to be exactly 360 frames, DHC and Cross Assault are
asserted to cost meter, and Snapback is asserted to both force the opponent out
and recover the snapped-out fighter's HP off-screen.

### Team HP, sim, authoring, and queues

The rest of the catalog is equally concrete. `FV2TagTeamTeamHpSpec` gives
per-fighter bars, partner HP on the HUD, **off-screen regen at `0.35 %/s`**
(`OffscreenRegenPercentPerSecond = 0.35f`), and team-KO **only when the entire
roster is at zero HP**. `FV2TagTeamNetSimSpec` pins `SimulationHz = 60` with **2
active sim fighters per side**, deterministic tag transitions, frame-accurate
tag animation, and a replay encoder that records tag actions.
`FV2TagTeamAuthoringSpec` points at real CSVs on disk:
`V2/balance/tag/tag_cancel_dhc_matrix.csv` (per-fighter pairing rows with
`cross_ip_restriction` and `cinematic_restriction` columns — e.g.
`Fighter.NyxRiver` × `Fighter.BishopCrowe` is `CrossIPRestricted`) and
`V2/balance/tag/team_theme_music.csv` (per-team loop/stinger cues with
`kof_style` / `mvc_style` flags). Three online queues round it out —
`RankedTagTeam` (4 players, role-preference balancing), `TagCoop`, and
`CrewBattle` (best-of-five single-elimination, 6 players). The registry
round-trip is verified too: `UV2ModeRegistrySubsystem` accepts the catalog and
`CaptureRegistrySnapshot` reports **3 formats / 7 mechanics / 3 queues** plus
per-area readiness flags.

## Kameo assists: an MK1-style partner, authored as data

V2 ships a Kameo option distinct from full Tag — a second fighter who stays
off-screen except during assist animations. In code it is authored configuration
inside the Create-a-Moveset editor catalog
(`V2/ue/Source/V2Combat/Public/V2MovesetData.h`), three nested structs:

- `FV2KameoAssistActionDefinition` — `ActionId`, `ButtonSlotId`,
  `DirectionalModifierId`, `MoveId`, `CooldownFrames`, `MeterCost`, with
  `IsValidAction()`.
- `FV2KameoFighterDefinition` — `KameoFighterId`, an array of assist actions,
  `HealthMax = 100`, and **`HealthRefillPerSecond = 8.0`** (the
  refills-while-un-summoned rule), with `IsValidKameoFighter()`.
- `FV2KameoSystemConfig` — `bPerRulesetToggle`, `bSingleSummonPartner`,
  `bDistinctFromFullTag`, `LaunchRulesetId = "Ruleset.MK"`,
  `bCrossOverRulesetsOptIn`, `bRankedKameoAndNoKameoQueues`, and the fighter
  list, with `IsValidConfig()`.

The default builder (`V2MovesetData.cpp:777`) constructs an `Asha` Kameo by
looping **3 button slots (`Kameo1/2/3`) × 4 directional modifiers
(`Neutral/Forward/Back/Down`) = 12 assist actions**, each with a 240-frame
cooldown and 0.5 meter cost. (Worth flagging the nuance honestly: the source
prose says "3 button-mapped Kameo assists," and there are indeed 3 button slots
— but with directional modifiers the catalog enumerates twelve distinct assist
actions, and the contract test
`V2/ue/Source/V2Tests/Private/Combat/MovesetDataAsset.spec.cpp:238` asserts
`AssistActions.Num() >= 12`, that `LaunchRulesetId == "Ruleset.MK"`, that the
system is `bDistinctFromFullTag`, and that the ranked Kameo/no-Kameo queue split
is on.) The `"Ruleset.MK"` id is a legacy gameplay-tag name that
`DefaultEngine.ini` redirects to `Rules.Mode.MK`.

The honest caveat: this is **authored data plus validation, not a runtime
system**. A grep for `kameo` across `V2/ue/Source` finds it only in the moveset
data asset, the test harness, and the contract spec — there is no runtime
component that summons the partner, drains its health when it is hit during an
assist, or refills it on a timer. Those behaviours are _described_ by the config
(`HealthMax`, `HealthRefillPerSecond`, the per-action cooldown/meter cost) and
would reuse the same assist-call seam the ASC already exposes
(`FV2AssistCallCooldown`, `UV2_Ability_AssistCall`), but the Kameo-specific
runtime is not built; the feature is tracked as the launch readiness gate
`Gate.MK1KameoSystem` in `V2/balance/launch/launch-readiness.json`. So Kameo
today is a fully-specified, test-backed _contract_ — enabled in the MK ruleset
at launch, opt-in for crossover rulesets, with its own ranked queue split —
awaiting the runtime that consumes it.

## How it connects

Per-ruleset feel is the configuration layer over the deterministic combat core:
the layer mask, defensive options, super gates, and game-feel catalog all read
from `V2Combat` / `V2Gameplay` and are proven by the combat automation suite
([../architecture/combat-system-gas-frame-data-and-determinism.md](../architecture/combat-system-gas-frame-data-and-determinism.md)).
Tag-team rides the rollback session and its multi-fighter snapshot, and its
named mechanics are a `V2Modes` catalog rather than abilities
([../architecture/rollback-netcode-and-tag-team.md](../architecture/rollback-netcode-and-tag-team.md)).
The defensive grammar and game-feel tuning continue in
[./combat-systems-defense-and-game-feel.md](./combat-systems-defense-and-game-feel.md);
the per-ruleset HUD overlay, team theme music, and stage rules surface in
[./roster-presentation-and-stages.md](./roster-presentation-and-stages.md). The
section hub is [../V2_features.md](../V2_features.md).

## Related

- [Combat Systems, Defense & Game Feel](./combat-systems-defense-and-game-feel.md)
  — the layered combat, defensive vocabulary, and hitstop/shake/slow-mo this
  page configures per ruleset
- [Roster, Presentation & Stages](./roster-presentation-and-stages.md) — the
  per-ruleset HUD overlay, team theme music, and stage/ring-out rules
- [Combat System: GAS, Frame Data & Determinism](../architecture/combat-system-gas-frame-data-and-determinism.md)
  — the ruleset-aware move contract, super abilities, and match-state machine in
  C++
- [Rollback Netcode, Client-Server & Tag-Team Sim](../architecture/rollback-netcode-and-tag-team.md)
  — the tag-team mechanics catalog correction and the multi-fighter rollback it
  rides
- The section hub: [../V2_features.md](../V2_features.md)
