Tactical Action · Features

Game Modes: Campaign, Co-op, PvP & Horde

A focused page within the Tactical Action Features documentation. The full map and every sibling page live in the Features hub.

8sections11 minread1diagram

On this page

This is the answer to "what do I actually press play on?" V4 advertises a sprawling catalogue — an eleven-row campaign table that runs from a 16-mission Raven-Shield breach to a couch-co-op Contra run, a cross-cell co-op ladder, a 5v5 ranked attack/defense, a 6v6 suite, a 100-player drop, and a six-cell horde mode — but the product only holds together if every one of those surfaces bottoms out in the same orchestration seam instead of forking the engine per genre. They do. A "mode" in V4 is a thin data record plus a load plan, registered in one game-instance subsystem, and the four families this page covers — single-player campaigns, drop-in co-op, competitive PvP, and wave-based horde — are differentiated not by separate runtimes but by the per-plugin component that runs after the registry hands off. This page tours those four families on the player's side of the menu: what each is, what you do in it, and which parts are shipped, compiled, tested C++ versus content that is named-but-uncooked. The engine-side treatment of the registry, discovery pipeline, and live-service backbone is the architecture companion, ../architecture/game-modes-live-service.md; the training, replay, signature-event, and AI-Director surfaces these modes feed get their own page, ./modes-training-replay-signature-and-ai-director.md. For the full scope this slots into, start at the hub: ../V4_features.md.

What ships, honestly#

The mode machinery is real, compiled, and tested, and so is the per-family domain logic. UV4ModeSubsystem (V4/ue/Source/V4Modes/Private/V4ModeSubsystem.cpp, 245 lines) implements registration, a four-result transition, a deterministic weighted quick-play lottery, and a fail-closed local-multiplayer admission gate as ordinary C++ that runs headless under automation; V4ModesTests/ModeSpec.cpp pins it with 89 assertions. Each mode family then layers its own shipped plugin: the R6 5v5 match machine (R6ModernSpec.cpp, 103 assertions), the CoD 6v6 rule catalog and match component (CoDMultiplayerSpec.cpp, 83), the 12-mission CoD campaign catalog (CoDCampaignSpec.cpp, 62), the Shadow War crossover progression (ShadowWarSpec.cpp, 29), the 18-mission Spec Ops co-op model (SpecOpsCoopSpec.cpp, 61), and the six-variant horde wave director (HordeDefenseSpec.cpp, 33). These are not stat-sheet placeholders; they carry real arithmetic — performance-pressure curves, party-size difficulty scaling, best-of-N round resolution, mode-specific scoring gates — that a test would fail on if hardcoded.

Three honest qualifications, in the spirit of the architecture companion. First, the content is uncooked. V4 represents every level and asset as a JSON descriptor (*.uasset.v4asset.json / *.umap.v4asset.json), so a horde wave director is real code while the wave's enemy meshes and the campaign's MetaHuman principals are described, not baked; the soft map paths each catalog builds (/V4Mode_SpecOps_Coop/Maps/L_SpecOps_07.L_SpecOps_07, …) resolve to nothing at runtime today. Second, the catalogue is wider than the shipped plugins. The eleven-row campaign table in the features monolith is design scope; on disk, the two campaign families with fully-shipped C++ mission catalogs are the CoD campaign and the Shadow War crossover — the Raven-Shield, Commandos, Desperados, Wukong, Conquest, Civ, and Contra campaigns live under their own V4Mode_* plugins with their own automation specs and are inventoried on the per-cell pages. Third, network authority is one layer down. The PvP match components below are server-friendly state machines; the dedicated-server client-server netcode, lag compensation, Glicko-2 matchmaking, and host migration they assume sit in V4Netcode and the Rust online-services crate, covered in ./shared-cross-cell-engine.md.

How any mode boots#

Every family below routes through the same three calls. A mode is one FV4ModeDefinition (V4Modes/Public/V4ModeTypes.h:17) — five fields: ModeId, localized DisplayName, a GameFeaturePluginURL, a soft EntryMap, and the ActivationAssets streamed on entry. RegisterMode stores it by id (rejecting an empty id); TransitionToMode (V4ModeSubsystem.cpp:44) is the switch, returning EV4ModeTransitionResult::UnknownMode for an unregistered id, AlreadyActive when you re-select the current mode, and otherwise Succeeded after setting CurrentModeId and broadcasting OnModeTransitionCompleted so HUD and telemetry follow without polling. Quick-play is a deterministic weighted lotterySelectQuickPlayMode (:193) sums the Weight of every enabled, registered entry, takes Roll = FMath::Abs(Seed) % TotalWeight, and walks the playlist subtracting weights until Roll lands in a band, so the same seed yields the same mode for the whole community. The diagram shows how the four families diverge only after the transition:

flowchart TD Menu[Player picks a mode or quick-play seed] --> Reg["UV4ModeSubsystem::TransitionToMode(ModeId)"] Reg --> Res{EV4ModeTransitionResult} Res -->|UnknownMode / AlreadyActive| Stop[delegate broadcast, no state change] Res -->|Succeeded| Cur[CurrentModeId set + OnModeTransitionCompleted] Cur --> Campaign["Campaign — UV4CoDCampaignMissionCatalog / UV4ShadowWarProgression"] Cur --> Coop["Co-op — UV4SpecOpsOnlineCoopModel + UV4LocalMultiplayerPolicyLibrary gate"] Cur --> PvP["PvP — UV4R6ModernMatchComponent / UV4CoDMPMatchComponent"] Cur --> Horde["Horde — UV4HordeWavePacingDirector"] Campaign -->|cross-cell handoff re-enters the registry| Reg

Campaign modes#

Campaigns are V4's single-player spine. The flagship shipped catalog is the CoD cinematic campaign: UV4CoDCampaignMissionCatalog::BuildLaunchMissions() (V4CoDCampaignMissionCatalog.cpp:64) returns exactly 12 missions — Helo Insertion, Spectre Watch, Black Tide, Dune Run, Dam Break, Iron Valley, Glassfall, Red Sand, Whiteout Chase, Lights Out, Line Control, Skyhook — each carrying a soft map asset, a 90-second opener LevelSequence, an AI squad (SquadMemberIds = {Price, Wraith, Hale}), and a mandatory set-piece. The set-piece archetype drives a real flag: MakeSetpiece (:26) marks bVehicleSegment true for the Helicopter, AC-130 gunship, Tank, Dune-Buggy, and Snowmobile types, so the four-plus advertised vehicle missions are data, not prose. ValidateLaunchCampaign (:82) is a genuine gate: it rejects a campaign without 12 missions, an opener outside the 60–120-second window, fewer than two branch moments or three squad members, any branch flagged bMajorStoryBranch (CoD-lineage campaigns allow only light-dialogue and optional-objective branches), or a missing entry from the 12 required set-piece archetypes. The five difficulty tiers (Recruit, Regular, Hardened, Veteran, Realism) come from GetDifficultyTiers, the from-menu mission-select with per-mission difficulty tracking from BuildMissionReplayMenu (mission 1 plus any completed mission is unlocked), and the 30-minute pre-rendered cinematic pool with Movie-Render-Queue cook hook from BuildCinematicBudget.

The Shadow War crossover is the unifying arc, and it is the one campaign that exercises the mode registry as a gameplay verb. It is a six-mission story in which the same operators recur across cells — a Hitman-cell assassination sets up a CoD-cell battle that sets up an RTS-cell invasion — and the cell transitions are real. UV4ShadowWarProgression::ExecuteHandoff (V4ShadowWarCampaign.cpp:476) does not narrate a handoff; it records the save point, calls Modes->TransitionToMode(Handoff->FromModeId) then TransitionToMode(Handoff->ToModeId) on the live UV4ModeSubsystem, carries the handoff's narrative flags into the save, and sets bNarrativeStateCarried only after confirming every carried flag is present in Save.NarrativeStateFlags. The arc is JSON-loaded (LoadCampaignMissions over DT_ShadowWar_Missions.json) and ValidateCampaign enforces the §141 contract — every mission spans ≥2 cells whose mode ids resolve against the discovered roster, handoffs connect consecutive legs with save points, shared operators come from the unified §42 roster and recur across the whole arc, and bridge cinematics consume none of the pre-rendered pool. A JSON save round-trip (ExportSave/ImportSave) and sequential unlock gating complete the shell.

Co-op modes#

Co-op spans online drop-in missions and local couch/LAN play, and both halves are shipped C++. The online surface is Spec Ops: UV4SpecOpsMissionCatalog::BuildLaunchMissions() (V4SpecOpsCoopSystems.cpp:177) builds exactly 18 cross-cell missions, each 1–4-player and each carrying at least two CrossCellLoadouts whose cells are validated to be listed as supported — so an Embassy Breakpoint flows Tactical → Stealth and a Citadel All-Cell mission spans four cells. The difficulty model is the feature doc's headline numbers, computed not transcribed: UV4SpecOpsDifficultyModel::BuildDifficultyProfile (:262) sets EnemyScalar = 1.0 + (PlayerCount-1) × 0.45, yielding exactly 1.0× / 1.45× / 1.90× / 2.35× for 1–4 players, alongside ReviveTokenCount = max(0, 5 - players) and a friendly-fire scale that loosens with party size. The post-launch online model UV4SpecOpsOnlineCoopModel is dense: Marathon chains the full 18-mission ladder into one timed host-authoritative run (BuildMarathonRunConfig pulls all 18 mission ids; AdvanceMarathonRun only completes after the last mission while preserving elapsed time; the leaderboard score is difficultyFloor × 100000 − timePenalty); Endurance is endless with deliberately diminishing supply (BuildEnduranceWaveState shrinks the ammo pool by ResourceScalar = clamp(1 - (wave-1)×0.08, 0.1, 1.0) and drops a heal flask every two waves); a six-card modifier deck (Vampiric Heal, Speed Demons, Iron Armour, Inverted Vision Cones, Low Visibility, Scarce Munitions) feeds a deterministic SelectModifierStackAtMissionStart that combines enemy and reward scalars per weekly featured contract; the matchmaking queue matches on shared region and intersecting preferred cells with skill averaging (UV4SpecOpsMatchmakingQueue::FindMatch); and the Temple Breach crossover puts a Tactical-FPS player and a Wukong player in the same room with asymmetric objectives. BuildDropInPolicy pins the seam honestly: host-authoritative, drop-in and drop-out enabled, host migration disabled for the mission.

Local co-op rides the UV4LocalMultiplayerPolicyLibrary policy gate. The five shipped split-screen policies (BuildLaunchPolicies, V4LocalMultiplayer.cpp:81) cover Tactical Co-op, Wukong Two-Tail, Contra Co-op (screen-edge tethering on), RTS Team (deterministic lockstep at 25 Hz), and the 1–4-player Spec Ops experience, plus an RTST hot-seat policy (single-keyboard alternation) and an 8-player LAN skirmish (backend-free deterministic lockstep, broadcast port 7777). Admission is a real fail-closed predicate: CanStartLocalMultiplayerSession (V4ModeSubsystem.cpp:112) rejects an unknown experience, an unsupported player count, the wrong platform class, or — the honest seam between couch and cloud — a backend-required session when the backend is unavailable, so a LAN skirmish that needs matchmaking refuses to start offline rather than fake a connection. ValidateLaunchPolicies independently asserts each of those invariants (screen-edge tethering for Contra, single-keyboard for hot-seat, backend-free lockstep for LAN).

PvP modes#

Competitive PvP ships as per-mode match state machines that a dedicated server drives. The R6-style 5v5 is UV4R6ModernMatchComponent (V4R6ModernMatchComponent.cpp): two rosters (Attackers/Defenders) capped at five operators each, a ConfigureMatch that sets RankedBestOf9 to 9 rounds / 5 to win (or CasualBestOf7 to 7 / 4), a 60-second setup phase, and a real phase machine Setup → Action → RoundEnd → MatchEnd advanced by AdvancePhase. CompleteObjective resolves the round per objective type — Bomb plant and Hostage extraction award the attackers immediately, SecureArea accrues clamped progress until 1.0 — and RecordRoundWin flips the match to MatchEnd the instant a team reaches RoundsToWin or the round count hits MaxRounds. The attacker and defender gadget vocabulary is a 16-value EV4R6GadgetType enum (hard/soft breach, drone, EMP, smoke, flash, frag, claymore, heartbeat scanner; reinforced wall, barbed wire, deployable shield, bulletproof camera, proximity alarm, trap mine, jammer), with structural destruction carried by a separate V4R6ModernDestructionComponent.

The CoD-style 6v6 suite is data-driven through UV4CoDMPModeCatalog::BuildModeRules() (V4CoDMPModeCatalog.cpp:35), which builds exactly 10 rulesets and sets the mode-specific flags from the type — Team Deathmatch to 75, Domination to 200, Hardpoint to 250 with bRotatingObjective, Search & Destroy as a one-life best-of-11, Kill Confirmed to 65 with bRequiresDogTags, plus Free-for-All, Gun Game (bFinalKnifeRequired), Prop Hunt, One in the Chamber, and Sticks and Stones (bBankruptcyMechanic). UV4CoDMPMatchComponent then enforces those flags: RecordKill (V4CoDMPMatchComponent.cpp:25) refuses a kill that lacks a confirmed dog tag in Kill Confirmed, and gates the winning kill on a final-knife in Gun Game, while AdvanceTime resolves a time-limit win by comparing team scores. The 100-player Battle Royale (V4Mode_Tactical_CoDWarzone, the largest mode spec in the suite at 127 assertions) — drop, shrinking circles, Gulag, buy stations, loadout drops, and the Resurgence/Plunder variants — is inventoried with the rest of the loud tactical surface on ./cell-tactical-fps.md. All PvP modes inherit the same ranked ladders, MMR, and replay capture described in the architecture companion's live-service section.

Horde defense#

Horde is one shared wave director with a per-cell verb set. UV4HordeVariantCatalog::BuildLaunchVariants() (V4HordeDefenseSystems.cpp:49) defines exactly six launch variants, one per cell: Tactical Last Stand, Shadow Evade (bEvadeOnly — the waves hunt you), Tactics Stronghold, Wukong Trial Swarm, RTS Tower Hold (bUsesTowerDefense), and Contra Barrage (bSideScrolling2D); ValidateLaunchContent asserts all six cells and all six variant kinds are covered. A single post-launch cross-cell variant, Fireteam Stronghold (BuildPostLaunchVariants), lets a Tactical-FPS fireteam defend an RTST-cell base. The pacing is real domain math, not a difficulty slider: UV4HordeWavePacingDirector::BuildWavePlan (:244) multiplies a base spawn rate by WaveScalar = 1 + (wave-1)×0.12, a PlayerScalar = 1 + (players-1)×0.18, a per-variant spawn modifier (evade 0.65×, tower 1.20×, side-scroll 1.35×), and a clamped performance-pressure term — V4PerformancePressure (:40) reads recent objective success, survival time, and damage taken into a [0.75, 1.35] band so a coordinated party gets pushed and a struggling one gets relief, the same adaptive discipline the AI Director uses elsewhere. Elite count scales as clamp(wave/3 + …, 0, 12), and BuildWaveSchedule rolls a full session's curve. The feature spec's "every 5th wave is a boss wave," the inter-wave build/buy intermission, and the per-cell leaderboards are the design layer this director's numbers feed.

Where this connects#

The mode registry is the orchestration layer almost everything in this page hangs off, and it is also the seam to the rest of V4. The shared GAS spine, perception model, netcode authority, and the registry/discovery internals all four families ride are in ./shared-cross-cell-engine.md; the training ranges, replay theater, per-cell signature modes (R6 Anniversary, CoD Zombies, Hitman Elusive Targets, Wukong Mirror Veneration), and the PvE-only AI Director that tunes these modes are on ./modes-training-replay-signature-and-ai-director.md. The genre-by-genre engine view — where each campaign's cell, each PvP cell's gunplay or RTS economy, and each horde variant's verb set actually live — is split across the per-cell pages (./cell-tactical-fps.md and its siblings). For the engine-side registry, the GameFeature discovery pipeline, the live-service subsystem, and the Rust online-services backbone that ranked PvP, co-op matchmaking, and replay storage read from, read the architecture companion, ../architecture/game-modes-live-service.md.