Combat Moves Debug Commands
Type these in the client console (F8). They are client-side and only act on the player running them.
What Config.Debug actually gates
It gates console printing, not the commands
client/debug.lua is always in client_scripts, and it registers every cs_* command and /unstuck at load — there is no Config.Debug check around any of them. The flag is read by slide.lua, roll.lua, guntricks.lua and dive.lua, and all it does there is decide whether to print.
So:
- Setting
Config.Debug = falsestops the per-move console reports. It does not remove the commands. /unstuckkeeps working in production, which is what you want.- The only two diagnostic threads start when a player runs
cs_watchorcs_dive, and stop withcs_watch off/cs_dive off. Nothing runs in the background becauseConfig.Debugis on.
config.lua ships Config.Debug = true. Set it to false before launch — see Installation.
The one every player needs
/unstuckReleases NUI focus, force-closes the menu, resets gun tricks, stops a slide, clears secondary and primary ped tasks, and sets the trick list back to 'none'.
What /unstuck covers, and the one thing it does not
A stranded trick-list title, a menu that left input grabbed, a slide that will not end, a spin that never started properly — /unstuck clears all of those, and it is safe to give to players.
It does not end a dive. It never calls StopDive, so the dive module stays in its current mode and the crawl and on-back loops re-issue the pose and re-assert the prone camera within a frame of the tasks being cleared. A player stranded prone, crawling, on their back or sitting needs the menu's Dive, Crawl & Gun → Fix → Stand up now row, or the StopDive() export.
General
| Command | What it does |
|---|---|
cs_watch | live read-out of health, cores, ammo and controls; cs_watch off to stop |
cs_menuids [substring|off] | every id Config.Menu can switch, with its state; the filter matches anywhere in the id, not just the start |
cs_watch exists for one specific question — did the gun actually fire? IS_PED_SHOOTING and IS_PED_WEAPON_READY_TO_SHOOT are both unreliable on this RedM build, so the readout watches the ammo column instead. If ammo drops, the gun fired. The command prints its own two-step test when you start it:
Stand still, aim, fire — ammo must drop, which proves the readout works.
Slide while holding aim, then fire.
Slide
| Command | What it does |
|---|---|
cs_anim | probe the two slide dictionaries for 31 candidate clip names; takes no arguments |
cs_play <n> [flags] | play combination n from cs_anim, right now |
cs_stop | clear any test animation |
cs_noanim | does nothing — it writes Config.Anim.disabled, which no code reads |
cs_flags <flags> | change Config.Anim.entryFlags live, decoded by name |
cs_filter <name|auto> | force a bone filter |
cs_move / cs_speed | movement mode and speed |
cs_cam / cs_camtest | tune or cycle the slide camera |
cs_preset / cs_use | whole coherent configurations |
cs_sweep / cs_report | bisect Config.Apply, one subsystem per slide |
How cs_anim knows a clip exists
GET_ANIM_DURATION returns 0.0 for a clip that is not in its dictionary, so it works as a "does this exist" oracle without having to play anything. cs_anim also runs a control test against a deliberately bogus dictionary first — if that reports as loaded, HasAnimDictLoaded cannot be trusted on your build and the rest of the output is meaningless.
It cannot be pointed at a dictionary, and it cannot enumerate one. The two dictionaries are always Config.Anim.entryDict and Config.Anim.exitDict, and the names it tries are a hardcoded list of 31 candidates — a clip whose name is not on that list is never reported, however real it is.
cs_sweep is a cumulative bisection, not a full matrix: 8 fixed rows, one slide each, starting from a slide that does nothing at all and turning one more Config.Apply subsystem back on with every row. For each row it records whether the animation played and whether a shot actually came out, so the first row that breaks usually names the subsystem responsible — with one exception: row 7 switches on stamina and the animation together, so a failure that first appears there could be either. cs_sweep off stops it and restores the action-disable flags.
cs_noanim is inert
It only writes Config.Anim.disabled, and nothing in the resource reads that field — the animation task is gated solely on Config.Apply.anim. To run the control experiment ("does the weapon fire when no animation plays?"), set Config.Apply.anim = false, or use row 1 of cs_sweep.
Roll
| Command | What it does |
|---|---|
cs_rollanim | list clips in the roll dictionary |
cs_rollflags | change roll flags live |
cs_roll | request a roll |
cs_rollkey | print the roll key and trigger, or set the trigger with cs_rollkey trigger <key|native|both> |
cs_rollkey cannot rebind the key. Given a key name it only prints a reminder to set Config.Roll.key in config.lua and restart, because the key is bound at start. Its one live effect is the trigger sub-command.
cs_rollflags is the one that matters, because the roll's flag word is the single value that could not be recovered from the original decompile — it ships as 0 and is meant to be tuned live. See Combat Roll.
Gun tricks
| Command | What it does |
|---|---|
cs_trick / cs_tricks | play or list tricks |
cs_hands <auto|dual|single|left> | force the hand mode |
cs_hud | trick list renderer and position |
cs_prompts | prompt diagnostics |
cs_hud with no arguments prints the current mode and all five position values. It takes either a mode — cs_hud nui|draw|prompt|none — or a field and a value: cs_hud <x|y|line|scale|key> <value>.
Dive
| Command | What it does |
|---|---|
cs_diveanim | load every dive and crawl dictionary and print each clip's real duration |
cs_divetest <class> <dir> | force one dive animation without the movement keys |
cs_dive | live read-out of dive state, stealth, weapon class and submersion |
cs_diveanim prints anything the dictionary does not contain in red. cs_divetest is how you check a single direction and weapon class without having to get the movement keys right. cs_dive off stops the watch.
cs_dive also prints eight IS_WEAPON_* predicates on its second line — pistol, revolver, rifle, repeater, shotgun, bow, two-handed and silent — which is the fastest way to find out why a weapon is landing in the wrong animation class. The other predicates in natives.lua, including sniper, melee and throwable, are not in the readout.
The full list
28 cs_* commands plus unstuck:
unstuck cs_watch cs_menuids
cs_anim cs_play cs_stop cs_noanim cs_flags
cs_filter cs_move cs_speed cs_cam cs_camtest
cs_preset cs_use cs_sweep cs_report
cs_rollanim cs_rollflags cs_roll cs_rollkey
cs_trick cs_tricks cs_hands cs_hud cs_prompts
cs_diveanim cs_divetest cs_divePlus the two menu commands, which are not diagnostics: /combatmoves and /guntricks.
Bisecting a problem
Config.Apply switches every individual thing a slide does to the ped, so a problem can be bisected rather than guessed at:
Config.Apply = {
anim = true, -- TASK_PLAY_ANIM
camera = true, -- the scripted slide camera
velocity = true, -- SET_ENTITY_VELOCITY each frame
heading = true, -- SET_ENTITY_HEADING each frame
controls = true, -- the DISABLE_CONTROL_ACTION list
actionFlags = true, -- _SET_PED_ACTION_DISABLE_FLAG
resetFlags = true, -- SET_PED_RESET_FLAG and keeping the weapon drawn
stamina = true, -- _CHANGE_PED_STAMINA
}With all of them false a slide does nothing but run its timer. Turn one back on at a time, or let cs_sweep do it for you.
Measure, do not guess
Most animation problems in this resource turned out to be a timing or flag value that could be read rather than guessed. cs_diveanim and cs_anim print real clip durations; cs_flags and cs_rollflags decode flag bits by name. Reach for those before changing a number in config.lua.