Skip to content

Combat Roll ​

LALT plus a movement direction rolls you that way. Eight directions, each a two-phase animation.

Using it ​

Hold a movement direction and press LALT. The direction is read from the movement controls at the moment the roll starts, exactly the way the original picks them.

Direction heldClip pair
Forwardcombatroll_fwd_p1_00 / _p2_00
Forward-rightcombatroll_fwd_p1_45
Forward-leftcombatroll_bwd_p1_-45
Rightcombatroll_fwd_p1_90
Leftcombatroll_bwd_p1_-90
Back-rightcombatroll_bwd_p1_135
Back-leftcombatroll_bwd_p1_-135
Backcombatroll_bwd_p1_180

All eight come out of mech_strafe@generic@roll@base. With no direction held you get the forward roll.

There is a 900 ms cooldown between rolls (Config.Roll.cooldown).

The three trigger modes ​

This is the one place the port had to add something the original did not have.

The original had no key at all

It watched GET_PED_IS_DOING_COMBAT_ROLL and replaced the animation the game was already about to play — and only for John (player_three). On a server where the game never triggers its own combat roll, and where characters are arbitrary models, that does nothing at all. So a key trigger was added, and it is the default.

Config.Roll.triggerBehaviour
'key'the key starts a roll outright — the default
'native'only replace the animation when the game itself starts a combat roll, exactly like the original
'both'either

'native' is there for parity and for servers that have something else driving the game's own roll. On a normal server it will look like the feature is doing nothing.

The original's JOHN_ONLY option is dropped — it is meaningless with arbitrary character models.

Settings ​

Default
Config.Roll.enabledtruethe feature itself
Config.Roll.key'LALT'same names as Config.SlideKey
Config.Roll.suppressWhileHeld{}INPUT_* actions to swallow while held
Config.Roll.cooldown900ms between rolls
Config.Roll.requireAimingfalsethe game's own roll is an aiming move; true restores that
Config.Roll.allowFromStandstilltrueroll without moving first
Config.Roll.faceCameratruesnap to face the camera before rolling
Config.Roll.lockHeadingtruehold that heading for the whole roll
Config.Roll.disablePainAudiotruesilence pain grunts during the roll, as the original does

faceCamera and lockHeading together are what the original does.

When you get the controls back ​

Two phase values decide how the roll ends, and they are the ones to reach for if it feels wrong.

Default
handoverPhase0.84where phase 1 hands over to phase 2
exitPhase0.005where phase 2 hands control back to you
phaseTimeoutMs2000safety cap per phase

The problem exitPhase solves: phase 2's last stretch is the character pushing back up and settling. The heading stays pinned and the roll counts as still running for all of it, so the roll looked finished while the player still had no control — a snag at the end of every roll.

Breaking out early only gives the controls back. The clip is never stopped, so the stand-up still plays out in full.

Tuning it

Measured clip lengths are 700 ms for phase 1 and 767 ms for phase 2. Raise exitPhase if control comes back while you are still visibly tumbling, which reads as a skid. Lower it if control still arrives late.

The menu slider cannot reach the shipped value

Combat Roll → Control back at has a range of 0.50–1.00, but config.lua ships exitPhase = 0.005. Nudging that row once will jump the value to at least 0.50 and bring the end-of-roll snag back with it, and there is no way to get to 0.005 again from the panel. Change it in config.lua and leave that row alone, or hide it:

lua
Config.Menu.options['roll.control-back-at'] = false

Run cs_menuids roll to confirm the id on your build before relying on it.

phaseTimeoutMs is a safety net. Both phases are given a phase target — handoverPhase for phase 1 and exitPhase for phase 2 — but each phase loop also waits on IS_ENTITY_PLAYING_ANIM, so a clip that never reaches its target and whose flags hold the last frame would never report itself finished and the roll would stay "running" forever, blocking every later roll and slide. The cap is generous enough that it never fires on a healthy roll; at the shipped exitPhase = 0.005 phase 2 breaks out on the first frame it reads. With Config.Debug on, the per-phase read-out says cut at <phase> when the cap does fire.

The animation ​

Dictionarymech_strafe@generic@roll@base
Filternoleftarm_filter
ikFlags0x20000A0
Blend in / out8.0 / -8.0
Flags0

Why the flags are 0

This is the one value in the roll that could not be recovered from the decompile with confidence — the caller sets the flags up on the stack and Ghidra lost them. 0 is a plain full-body task, which works. If you want to experiment, cs_rollflags changes them live with no restart and decodes the bits by name.

Combat Moves → Combat Roll, or the Roll tab.

SectionRows
(no heading)Enabled, Trigger, Cooldown, Control back at, Phase 1 handover, Face the camera, Hold heading, Require aiming, From standstill
Try itRoll now

Roll now closes the panel and rolls immediately — hold a direction first to choose which way.

Mutual exclusion ​

The exclusion is one-directional, not mutual. A roll will not start during a slide — canRoll checks IsSliding(). A gun trick will not start during a slide or a roll, and a trick already running is cut if either starts. Diving stands down while any of the three is running.

A slide, though, can start during a roll or a gun trick. canSlide checks neither IsRolling() nor IsSpinning(), and with the shipped Config.MinSpeed = 2.5 and Config.RequireSprint = false a roll's own root motion can satisfy the speed gate. The two then run at once: the roll keeps pinning the heading every frame while lockHeading is on, while the slide drives its own heading, velocity and camera. If you are extending the resource, check explicitly for every move you need to stand down for rather than assuming the three already guard each other. See Developer API.

Turning it off ​

lua
Config.Roll.enabled = false

Or at runtime, per client:

lua
exports.rm_combat_moves:SetRollEnabled(false)
TriggerClientEvent('combat_slide:setRollEnabled', src, false)

Hiding the page in the menu does not disable it — the feature carries on running on whatever config.lua says. See Server setup.

Documentation for RedMorrow. Scripts are licensed per server — redistribution is not permitted.