Tactical Action · Features

The Shared Cross-Cell Engine

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

9sections10 minread2diagrams

On this page

V4 sells an impossible-sounding promise: one game that has to feel like six. A breach-and-clear in the tactical cell, a Commandos patrol-dodge in the real-time-tactics cell, a Wukong parry in the action-RPG cell, and a StarCraft build order in the RTS cell are supposed to read as different genres to the player — and yet ship in one Unreal Engine 5.5 executable, share one roster, and hold together under one narrative. The thing that makes "one game" literally true underneath the marketing is the shared cross-cell engine: a small set of foundation modules that every cell is built on, plus a single, disciplined mechanism by which a cell specializes them. The bet is that the expensive, correctness-critical machinery — the ability spine, the AI brain, the roster, the animation rig, the difficulty controller — is written once and reused, while each cell contributes only its narrow slice: one stat block, one verb family, one animation dataset, one tuning table. This page is the inventory of that shared spine on the player's side of the screen, grounded in the actual Unreal C++ that backs it. For the full mode taxonomy, the roster, and the scope this slots into, start at the hub: ../V4_features.md.

What ships, honestly#

The shared core is real, compiled, and tested. The foundation module V4/ue/Source/V4Core carries the cell enum, the unified operator roster, the cross-cell gadget and takedown catalogues, the save spine, localization, and dev cheats — and its V4Core.Build.cs links only engine modules (Core, CoreUObject, Engine, InputCore, RenderCore, Slate, SlateCore) with zero V4* dependencies, exactly what a foundation should be. Above it, V4Gameplay carries the GAS spine, V4Animation the shared rig, and the V4Perception → V4Crowd → V4Schedules chain the unified AI brain — each depending on V4Core and nothing sideways. Every claim below is pinned by automation under V4/ue/Source/V4Tests: OperatorRosterSpec, TakedownLibrarySpec, GadgetLibrarySpec, AIDirectorSpec, the V4PerceptionTests (StimulusSpec, DecaySpec), SaveGameSpec, AnimBPCompileSpec, plus the GAS trio (AttributeSetSpec, AbilityClassSpec, AbilitySpec).

Two honest qualifications carry through the whole page. First, the logic and data skeleton is in-tree C++, but the content is not cooked: per the architecture companion, a tree-wide search finds 0 binary .uasset and a single .umap against 891 .v4asset.json descriptors. So the roster's rivalry graph, the takedown catalogue, and the motion-matching dataset specs are real code, while the meshes, mocap clips, voice libraries, and animation assets they soft-path to are described, not baked. Second, this layer is a conventional, replicated, server-authoritative stack — it is not rollback-deterministic, and the abilities and effects are UCLASS C++ types, not authored Blueprint assets (zero .uasset ability/effect binaries). Network authority itself is a separate concern, living one tier down in V4Netcode. What follows is the shared engine on its own terms.

The spine: one pawn, one cell enum, six stat blocks#

The whole architecture turns on one tiny enum. EV4RulesetCell (V4Core/Public/V4CellState.h) is None, Tactical, Stealth, Tactics, ActionRPG, RTS, Arcade — seven values, the join key for the entire engine. Attribute sets, abilities, effects, animation datasets, AI-director tunings, and the save snapshot all carry it, and a one-line FV4CellStateChanged delegate broadcasts transitions.

Every controllable character — operator, hero, unit, arcade pilot — is the same AV4Pawn_Operator owning the same UV4AbilitySystemComponent. The pawn's InitializeForCell is the entire cell-switching mechanism: it NewObjects the one attribute set for the requested cell, hands it to the ASC, and records the cell. Because the active attribute set is a single overwritten pointer, a pawn is either a Tactical operator or an ARPG hero, never both — mutual exclusion enforced by construction. Six concrete stat blocks descend from one abstract base (UV4AttributeSetBase): UV4Attr_Tactical (Health, Armor, Ammo, Suppression), UV4Attr_Stealth (Detection, Noise, DisguiseClass), UV4Attr_Tactics (ActionPoints, Vision), UV4Attr_ARPG (Stamina, Posture, Will, Mana), UV4Attr_RTS (UnitHealth, UnitArmor, UnitAttack, UnitRange), and UV4Attr_Arcade (Lives, ScoreMultiplier). Abilities are cell-gated: UV4GameplayAbilityBase checks RequiredCell against the ASC's active cell in CanActivateAbility, so a Tactical GA_Fire simply cannot fire on a pawn mounted as a Wukong hero. The full anatomy — 32 ability verbs, 23 effect classes, the armor-mitigation and decay-on-apply tricks — is the architecture companion's job; read ../architecture/gas-layout.md. The point here is that this is the shared mechanism, and "adding a seventh cell" costs exactly one enum value, one stat block, one verb module, and one tuning arm, with no change to the base.

The unified roster: one operator, seven faces#

V4 ships one canonical roster that surfaces differently in each cell, and the roster is not a spreadsheet — it is built and validated in C++. UV4OperatorRosterCatalog::BuildCanonicalRoster (V4Core/Private/V4OperatorRoster.cpp) hand-constructs 34 operators: 12 Tactical Special-Forces (Cobra, Rook, Vega…), 8 RTST specialists, 6 Wukong heroes (Sunward, Lian, Oxheart…), and 8 RTS hero units (Sovereign, Broodmother, Arch-Templar…). Each operator carries seven FV4OperatorCellRepresentation entries — one per EV4OperatorMeshRole (TacticalFirstPerson, TacticalThirdPerson, StealthThirdPerson, TacticsTopDown, ARPGThirdPerson, RTSUnit, ArcadeSprite) — so the same operator has a first-person tactical rig, a top-down tactics silhouette, an over-shoulder ARPG body, an RTS unit mesh, and a 2D arcade sprite, each a distinct soft-pathed asset. The eight RTST specialists are a shared pool that projects onto 6 Commandos and 6 Desperados roster slots, with exactly 4 operators (Glass, Fuse, Masque, Tinker) crossing both via faction reskins.

What makes this real rather than a data dump is ValidateCanonicalRoster, a linter that fails the build of the roster unless every contract holds: 34 operators total; the 12/8/6/6/8 group counts; the 6/6 Commandos/Desperados projection with exactly 4 overlaps; a 1500-word backstory, a signature line, sketch art, theme-music attribution, and both a mocap and a voice credit per operator; 1–3 reciprocal rivals each; a passed sensitivity review with ≥4 checklist items; all seven mesh roles present; and a rivalry graph that resolves to exactly 31 unique pairs. OperatorRosterSpec asserts every one of those numbers, plus 34 per-operator NIL interviews and reciprocal-rivalry symmetry — a test that would collapse instantly against a placeholder list. Honestly labeled: the definitions, validation, and rivalry graph are production C++; the meshes, mocap intros, and ~120-line voice libraries they reference are FSoftObjectPaths, not baked assets.

The cross-cell content libraries: gadgets and takedowns#

Two V4Core catalogues give every cell a shared vocabulary of verbs while letting each cell opt in. UV4GadgetLibraryCatalog authors 60 launch gadgets across five domains — TacticalFPS (18), StealthSplinterCell (12), HitmanPacification (8), RTSTSpecialist (14), and WukongCharm (8) — each tagged with one of 14 gadget classes (Breach, Recon, Smoke, Flash, Trap, Fortification, Distraction, Charm…) and a real balance profile (FV4GadgetBalanceProfile: Charges, CooldownSeconds, DurationSeconds, RadiusMeters, NoiseMeters, PickCost, CounterplayWindowSeconds). It also emits a balance ledger with one row per gadget so nerfs and buffs are auditable post-launch; GadgetLibrarySpec pins the 60 total, the per-domain counts, and the one-row-per-gadget ledger invariant.

UV4TakedownLibraryCatalog does the same for melee stealth: 9 launch takedowns (SneakChoke, Garrote, StabAndCover, SlitThroat, PillowHood, Syringe, Brick, Drown, PushOffLedge) and 3 sound profiles (Silent, Quiet, Loud). Each takedown carries an FV4TakedownAnimationPair (attacker + victim clips, sync marker, motion-warping flag), a list of compatible cell ids, GAS ability mappings, and rule predicates (bRequiresRearArc, bRequiresSeatedTarget, bRequiresLiquid, bRequiresLedge). TakedownLibrarySpec asserts the 9 takedowns, the 3 profiles, and specifics like the Garrote's 2.5 s silent execution — and that the stealth takedown maps to GA_StealthTakedown on the Stealth cell while the tactics takedown maps to GA_TacticsTakedown on the Tactics cell, which is the cross-cell sharing made concrete: one library, two cells, two abilities.

One AI brain: perception, crowd, and schedules#

The single loudest "one engine across every genre" claim is the AI. A Hitman crowd, a Commandos patrol, a Splinter Cell mercenary, and a tactical-FPS guard all read stimuli through the same V4Perception model. UV4PerceptionComponent subclasses Unreal's UAIPerceptionComponent and adds a batched-stimulus pipeline (SubmitV4Stimuli/FlushV4Stimuli accumulate and flush at a 10 Hz EvaluatorTickRateHz), faction recognition that resolves a disguise against accepted-disguise tags (RecognizeFaction, CanTreatAsAlly), and alert propagation: PropagateAlertToAllies within a 400-unit radius and PropagateGunfireToAllies within 2500, each crediting AlertSuspicionAmount = 35. The brain itself is UV4SuspicionStateMachine, a Calm → Curious → Alert → Hostile machine with thresholds 25 / 60 / 90, a DecayRatePerSecond of 12.5, a 5-point hysteresis margin so states don't flicker on the boundary, and a real CalculateDetectionTimeSeconds(Distance, MaxDistance, BaseTime, bEnforcer) that makes nearer and Enforcer-class observers detect faster. StimulusSpec and DecaySpec drive the math directly.

stateDiagram-v2 [*] --> Calm Calm --> Curious: suspicion > 25 Curious --> Alert: > 60 Alert --> Hostile: > 90 Hostile --> Alert: decay − hysteresis Alert --> Curious: decay 12.5 / s Curious --> Calm: decay below 25

The chain extends upward. V4Crowd (UV4CrowdSubsystem) drives dense civilian populations — HandlePanicMassSignal propagates panic through the crowd and AssignFleeTargetsForPanic routes agents to the nearest exit, the Hitman panic-spread and AoE-village behaviour built on the same perception substrate (PanicSpec, PerfSpec). V4Schedules (UV4ScheduleComponent, UV4ScheduleAsset) sits on top of that, looping each named NPC through a node sequence (waypoint + task + duration) so a target's daily routine is a schedule the player can intersect (LoopSpec). Crowd builds on perception; schedules build on crowd — the dependency arrow is the design promise.

The shared animation pipeline#

V4Animation is the shared rig every humanoid cell drives. The UV4AnimationPipelineManifest is a validated UDataAsset describing the pipeline as data: per-cell FV4MotionMatchingDatasetSpec entries (each with PoseHistoryFrames = 8, a 600 ms trajectory horizon, and weighted stance / velocity / acceleration / facing match costs), FV4IKRigSpec and FV4RetargeterSpec entries for skeleton retargeting, and an FV4MetaHumanPipelineSpec for facial mocap and lip-sync configuration. The runtime seam is UV4MotionWarpingHandler, a component wrapping Unreal's UMotionWarpingComponent: ApplyWarpAlignment and CalculateAlignedTransform align a montage to a runtime target for three shared contexts — EV4MotionWarpContext::{Breach, Throw, Finisher} — which is precisely why a tactical door-breach, a grenade throw, and a Wukong finisher can all snap to the correct world transform from one handler. Chooser tables (FV4HitReactionChooserRow, FV4WakeupChooserRow) select hit reactions by damage band and wakeups by down-time, shared across cells. AnimBPCompileSpec validates the manifest and the AnimBP slot/state-machine contracts. Honestly labeled: the manifest and warping math are real C++; the motion-matching databases, MetaHumans, and montages they name are soft-pathed content, not in-tree binaries.

The AI Director: one adaptive-difficulty controller, six tunings#

UV4AIDirectorSubsystem (V4Gameplay) is one adaptive-difficulty brain that serves every PvE cell. ComputePressure folds a performance window into a single 0–1 score with fixed, summed-to-one weights0.42 × damage-taken + 0.25 × death-rate + 0.20 × detection-events + 0.13 × inverse-objective-progress — and ResolveDifficultyStep nudges difficulty up or down only when pressure leaves a deadband around a 0.55 target. From there a per-cell step applier translates the step into genre-appropriate tuning: Tactical adjusts AI aim-accuracy, reaction-time, and grenade frequency; RTST adjusts patrol density and vision-cone half-angle; Wukong adjusts boss damage and the parry window (clamped to a floor of 6 frames); the RTS campaign adjusts AI economy bonus and wave interval; Contra adjusts spawn and bullet-pattern density. A FV4AIDirectorRubberBandProfile rejects any adjustment that would be perceptible (a single-frame parry delta cap, a 120 ms reaction cap, a 45 s minimum interval). The standout is a compile-time safety guarantee: a static_assert(V4AIDirectorPvPHooksCompileDisabled()) over a constexpr policy table makes the build fail if any PvP mode were ever wired to the director — the engine cannot ship rubber-banding into ranked play. AIDirectorSpec exercises the pressure formula, the per-cell steps, and the PvP-disable. Honestly labeled: the director computes and emits tuning structs; whether a given cell's AI consumes every scalar is that cell's responsibility.

How a cell specializes the engine#

Put together, the engine is a deliberate split between one shared mechanism and six narrow specializations. A cell ships as a GameFeatures plugin (activated at runtime by V4Modes' UV4ModeSubsystem and V4GameFeatureAction_ActivateModeAssets), and to specialize the shared engine it supplies exactly five things: one EV4RulesetCell value, one attribute set, one UGA_* verb family with its RequiredCell gate, one slice of effect classes, and one per-cell tuning arm in the AI director — while reusing the operator pawn, the ASC, the roster, the perception brain, the animation rig, the gadget and takedown catalogues, and the save snapshot unchanged.

flowchart TB Op["AV4Pawn_Operator + UV4AbilitySystemComponent<br/><sub>ActiveCell : EV4RulesetCell (the join key)</sub>"] subgraph SHARED["Shared cross-cell engine (write once)"] Roster["V4Core · Operator Roster<br/><sub>34 ops · 7 mesh roles · 31 rivalries</sub>"] Libs["V4Core · Gadget + Takedown libraries<br/><sub>60 gadgets · 9 takedowns · balance ledger</sub>"] Perc["V4Perception → V4Crowd → V4Schedules<br/><sub>suspicion 25/60/90 · panic · routines</sub>"] Anim["V4Animation<br/><sub>motion-match · warp · chooser</sub>"] Dir["V4Gameplay · AI Director<br/><sub>pressure 0.42/0.25/0.20/0.13 · PvP-locked</sub>"] Save["V4Core · Save snapshot<br/><sub>schema-versioned · cell-aware</sub>"] end Op --> SHARED SHARED --> Tac["Tactical<br/><sub>Attr_Tactical · 8 verbs</sub>"] SHARED --> Ste["Stealth<br/><sub>Attr_Stealth · 7 verbs</sub>"] SHARED --> Tcs["Tactics<br/><sub>Attr_Tactics · 4 verbs</sub>"] SHARED --> Arp["ActionRPG<br/><sub>Attr_ARPG · 6 verbs</sub>"] SHARED --> Rts["RTS<br/><sub>Attr_RTS · 4 verbs</sub>"] SHARED --> Arc["Arcade<br/><sub>Attr_Arcade · 3 verbs</sub>"]

The cell-aware save spine closes the loop honestly: UV4SaveGameSubsystem persists a schema-versioned UV4CoreSaveGame snapshot carrying the ActiveCell and slot id (SaveGameSpec), so progression is cell-tagged at the engine seam. The richer Operator-XP and Account-XP tracks the features catalogue describes are a broader persistence/online concern, layered above this snapshot — named here so the boundary is clear, not over-claimed. Everything else on this page is the shared core a designer leans on the moment they stand up a seventh cell: write the slice, inherit the spine.