Skip to content

Combat Moves Server Setup ​

The resource is client-side, so a server's job here is to set sensible defaults, decide what players may change, and use the convars for the things that must not be negotiable.

Hard limits: convars ​

Put these in server.cfg. The client re-reads all four at the start of every slide, so a setr change applies on the player's next slide with no restart or reconnect. They clamp what the slide actually does, whatever config.lua and the menu say — the menu rows still appear and still toggle, the clamp bites when the slide runs.

cfg
setr combat_slide_allow_timescale "false"   # recommended
setr combat_slide_allow_deadeye   "true"
setr combat_slide_allow_infinite  "false"
setr combat_slide_max_duration    "2000"
ConvarDefaultWhat it does
combat_slide_allow_timescaletruefalse blocks the slide's bullet time
combat_slide_allow_deadeyetruefalse blocks automatic Dead Eye on a slide
combat_slide_allow_infinitetruefalse blocks unlimited-length slides
combat_slide_max_duration10000ceiling in ms on a finite slide's length

combat_slide_max_duration only bounds finite slides. When Config.InfiniteSlide is on and combat_slide_allow_infinite is still true, the slide ends at Config.MaxInfiniteDuration instead, which is client-side and editable — so set combat_slide_allow_infinite to false if you want the convar to be the real ceiling.

Set combat_slide_allow_timescale to false on a populated server

Bullet time changes time scale for the whole client, which means the player using it sees the world slowed while everyone else sees them moving normally. It already ships off in config.lua — the convar is what stops a player turning it back on from the menu. The convar covers the slide only: the dive has its own bullet time, Config.Dive.enableBulletTimeDuringDive, which also ships false but has no convar behind it, so leave that one off in config.lua.

These four are the only values a player cannot reach. Everything else is advisory.

Deciding what players can change ​

Config.Menu gates the panel at four levels, coarse to fine.

Hiding something only removes it from the panel

The feature carries on running on whatever config.lua says. To switch a feature off, use its own enabled flag.

lua
Config.Menu = {
    enabled = true,            -- the whole menu

    pages = {                  -- a page, and its tab
        slide  = true,
        roll   = true,
        tricks = true,
        dive   = true,
    },

    sections = {               -- a heading inside a page, and its rows
        ['slide.behaviour']   = true,
        ['slide.combat']      = true,
        ['slide.camera']      = true,
        ['roll.try-it']       = true,
        ['tricks.tricks']     = true,
        ['tricks.more']       = true,
        ['dive.diving']       = true,
        ['dive.crawling']     = true,
        ['dive.prone-camera'] = true,
        ['dive.dive-camera']  = true,
        ['dive.stealth']      = true,
        ['dive.fix']          = true,
        ['menu.menu']         = true,
        ['menu.pages']        = true,
        ['menu.session']      = true,
    },

    options = {                -- one row; absent means shown
        -- ['slide.behaviour.mud-decal'] = false,
    },
}

Find ids with cs_menuids, never by hand

cs_menuids

It prints every id the menu can switch with its current state, read off the pages as they are really built — so what it prints is exactly what config.lua will match. cs_menuids dive filters on a substring anywhere in the id, not a prefix, so root-list ids such as menu.dive-crawl-gun come through too; cs_menuids off lists only what is hidden.

Ids are page.section.row, lower case with dashes for spaces. A row above the first heading has no section part. Full behaviour on The menu.

Common setups ​

Read-only panel. Players can look but not change anything useful:

lua
Config.Menu.sections = {
    ['slide.behaviour'] = false,
    ['slide.combat']    = false,
    ['slide.camera']    = false,
    ['dive.diving']     = false,
    ['dive.crawling']   = false,
}

No menu at all.

lua
Config.Menu.enabled = false

The key is ignored, /combatmoves prints a notice once, and the OpenMenu export returns false. Every feature still works on your values.

Lock the page set. The root list has a live Pages section that lets a player turn pages back on. Hide it and config.lua becomes the only way:

lua
Config.Menu.sections['menu.pages'] = false

Set your pages deliberately first — with that section hidden, nothing in game can turn one on again.

Turning features off entirely ​

Hiding a page does not disable it. These do:

lua
Config.Roll.enabled      = false
Config.GunTricks.enabled = false
Config.Dive.enabled      = false

The slide has no single flag — trigger combat_slide:setEnabled with false, or call the SetEnabled export. Both write the one flag the slide's input loop reads.

Config.SlideKey = nil does not disable the slide

client/input.lua resolves the key once at load, cannot resolve nil, prints unknown key "nil" - falling back to C and binds C instead — so the slide carries on, on a key you did not pick. Config.MenuKey has nothing to do with the slide either: it is only the key that opens the panel, and setting it to nil leaves /combatmoves as the way in.

To stop a feature loading at all, remove its file from client_scripts in fxmanifest.lua and set the matching Config.Menu.pages key to false. The menu does not notice a missing file — its tab list is static, so the tab stays. The Tricks and Dive pages call the feature's exports while building their rows, so they fail as soon as a player opens the tab: openPage catches it, prints [combat_moves] menu page failed: ... and closes the whole menu rather than dropping the one page. The Slide and Roll pages build without touching any export, so they open normally and only fail when a row is actually used.

Keep four files whatever you remove

client/natives.lua, client/keys.lua, client/input.lua and client/menu.lua. input.lua is the only definition of CS.Input, which slide.lua calls; menu.lua is what cs_menuids reads.

That is the minimum, not a guarantee — the four feature files also call each other's exports, unguarded. roll.lua calls IsSliding(); guntricks.lua calls IsSliding() and IsRolling(); dive.lua calls all three. Remove slide.lua and rolling, spinning and diving all break. Only dive.lua can be dropped without taking a sibling with it.

Things worth tuning ​

SettingDefaultWhy you might change it
Config.MinSpeed2.5raise it so only a full sprint can slide
Config.RequireSprintfalsetrue requires an actual sprint, not a jog
Config.Cooldown750raise it to stop slide-spamming in a fight
Config.StaminaDrainRate2.0make sliding cost something
Config.Roll.cooldown900the equivalent for rolls
Config.Dive.cooldown800and for dives
Config.Dive.enableIFramesDuringDivetrueinvincibility while airborne — consider turning this off for PvP
Config.Dive.minStaminaToDive10.0gates diving on stamina
Config.GunTricks.requirePistoltruefalse lets anything be spun
Config.GunTricks.key'N'push-to-talk — change it on a voice server
Config.MenuMousetruefalse makes the menu keyboard-only and leaves mouse look alone
Config.Debugtruemust be false in production

enableIFramesDuringDive is the one to think hardest about

It makes the player bullet, fire and melee proof for the length of a dive. That is good for cinematic play and exploitable in serious PvP. The dive already costs 9 stamina and needs at least 10 to start, which is the only other brake on it.

Before you go live ​

  • [ ] Config.Debug = false — it ships true, and prints a report to every player's console after every move
  • [ ] setr combat_slide_allow_timescale "false" in server.cfg
  • [ ] Decide on Config.Dive.enableIFramesDuringDive
  • [ ] Change Config.GunTricks.key off N if you run voice chat
  • [ ] Decide what Config.Menu exposes, then consider hiding menu.pages
  • [ ] Cooldowns set for your server's pace
  • [ ] Test the menu opens and closes cleanly, and that /unstuck works

Performance ​

The resource is client-side only. There is no server tick, no database query and no network traffic beyond the normal replication of a character's animations.

Each feature runs an idle loop that waits on an input and does nothing else. The per-frame work — camera, controls, animation state — only happens while a move is actually in progress, which is at most a second or two at a time. When nobody is sliding, rolling, spinning or prone, the resource costs effectively nothing.

Turning Config.Debug off removes the per-move console reports. The two diagnostic threads only exist while a player is running cs_watch or cs_dive, and stop with cs_watch off / cs_dive off.

Running alongside other resources ​

It touches no framework, so it coexists with VORP, RSG Core, RedEM:RP, QBR and standalone setups without configuration.

What could conflict:

  • Anything that calls ClearPedTasks on the local player every frame will interrupt a move mid-animation.
  • Anything that takes over the camera will fight the slide and dive cameras. Set Config.CustomCamera = false and Config.Dive.enableProneCamera = false / enableDiveCamera = false to hand the camera back.
  • Anything that disables control groups every frame may swallow the inputs.

If a move half-plays and snaps back, suspect one of those first. cs_watch shows live control and ped state, which usually identifies the culprit in a few seconds.

Security notes ​

The resource is client-side, which means a player with a modified client can set any value in their own copy of config.lua. That is true of every client-side resource. What it does and does not mean here:

  • They can only affect their own character. The moves are played as animation tasks on their own ped. There is no event another client acts on, because there is no server script and no net events the resource sends.
  • The four convars are read from the server, freshly on every slide, so allow_timescale, allow_deadeye, allow_infinite and max_duration are genuinely not under the player's control. max_duration only bounds a finite slide, so pair it with allow_infinite set to false.
  • Everything else is advisory. Cooldowns, stamina costs, invincibility during a dive — assume a determined player can remove those limits for themselves, and set Config.Dive.enableIFramesDuringDive = false on principle if your server is competitive PvP.

There are four net events the resource listens on (combat_slide:setEnabled and its three siblings) so your own scripts can enable and disable features. They only ever turn things on or off for the client that receives them.

The cs_* commands are always registered

Config.Debug gates console printing, not command registration — so the 28 diagnostic commands exist on every client whether it is on or off. They are client-side and only act on the player running them: the worst a player can do with them is change their own animation flags or camera values, which they could already do by editing their own config.lua. The useful consequence is that /unstuck works in production. See Debug commands.

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