WELCOME TO INFOCHEATS.NET

INFOCHEATS is a community-driven platform focused on free game cheats, cheat development, and verified commercial software for a wide range of popular games. We provide a large collection of free cheats shared by the community. All public releases are checked for malicious code to reduce the risk of viruses, malware, or unwanted software before users interact with them.

Alongside free content, INFOCHEATS hosts an active marketplace with many independent sellers offering commercial cheats. Each product is discussed openly, with user feedback, reviews, and real usage experience available to help you make informed decisions before purchasing.

Whether you are looking for free cheats, exploring paid solutions, comparing sellers, or studying how cheats are developed and tested, INFOCHEATS brings everything together in one place — transparently and community-driven.

Source [Script] Hell Let Loose — Logitech G HUB Recoil Control System (RCS) with Weapon Presets

byte_corvus

Newbie
Newbie

byte_corvus

Newbie
Newbie
Status
Offline
Joined
Mar 3, 2026
Messages
170
Reaction score
7
Been seeing a lot of people struggling with the recoil patterns in Hell Let Loose lately. Since I’ve been running similar logic for other shooters, I pulled this Logitech G HUB LUA script from a private group. It is essentially a ported RCS (Recoil Control System) from older sources, but it works surprisingly well if you dial in your specific DPI and in-game sensitivity.

Tech Overview:
This is a standard LUA-based external script. It hooks into the mouse driver events to compensate for recoil by calculating the movement relative to the weapon’s preset value. Since it is strictly external and relies on G HUB’s scripting engine, it is significantly safer than memory-altering internals, though you should always be cautious about how much you push the randomization settings.

Technical Nuances:
  1. RCS Mechanism: It utilizes a loop that moves the mouse based on the defined value (vertical) and horizontal variables.
  2. Randomization: I have kept the random noise settings (randomLevelX/Y) low to maintain accuracy, but you can crank these if you want to avoid "robotic" linear movement patterns.
  3. Logic: The script includes a weapon/operator cycle system. You can switch between AXIS and ALIES, and cycle through primaries and secondaries using the mouse buttons configured in the script header.

Code:
--[[
HLL - RCS (Recoil Control System)
Version: 1488 (English, variables & comments translated and clarified)
Author: heinrich himmler (converted and documented by ChatGPT)
 
Quick documentation (brief):
- Purpose: lightweight, configurable RCS script for Logitech G HUB (Lua).
- Requirements: Logitech G HUB, DPI/sens recommended in header.
 
Controls (default):
- Toggle RCS on/off: CapsLock
- Switch side (AXISUSSR/ALIES): Right Ctrl + ScrollButton (middle mouse button by default)
- Next operator: Mouse button 7
- Previous operator: Mouse button 8
- Switch primary weapon: Ctrl + ScrollButton
- Switch secondary weapon / cycle secondaries: Alt + ScrollButton
- Fire with RCS active: Left mouse button (ADS required if configured)
 
License & modification: This script is provided as-is. You are free to modify, adapt and redistribute your own versions. Keep responsible use in mind.
 
NOTE: The documentation below and inline comments explain the code and available commands. Use the menu (Log output) to confirm current operator/weapon and RCS status.
]]
 
-- Enable primary mouse events for G HUB
EnablePrimaryMouseButtonEvents(true)
 
-- ====== CONFIGURATION ======
local toggleLock = "capslock"        -- lock key used to toggle RCS on/off
local requireADS = true                -- require aiming down sights (mouse button 3) for RCS to run
 
-- ====== BUTTONS (customize per your mouse) ======
local nextButton = 7                  -- next operator
local prevButton = 8                  -- previous operator
local scrollButton = 3                -- scroll click (used with modifiers)
 
-- ====== RANDOMIZATION SETTINGS (adjust only if you know what you're doing) ======
local randomLevelX = 0.20
local randomLevelY = 0.10
 
-- ====== FIXED OPERATOR ORDER (do not change programmatically) ======
local operatorOrder = {
    AXISUSSR = {"MP40","GEWEHR-43","STG","MG-34","PPSH","PPSH-DRUM",},
    ALIES = {"BRITISHTOMMY","USTOMMY","M1-CARABINE","M1-GARAND","USLMG","BAR","GREASE",}
}
 
-- ====== OPERATORS (you may add/update following this structure) ======
local operators = {
    AXISUSSR = {
                ["MP40"] = {primaries = {{name = "MP40", value = 1, aggression = 9, horizontal = -0.1}}, secondaries = {}},
                ["GEWEHR-43"] = {primaries = {{name = "PPSH NORMAL MAG", value = 4.5, aggression = 9, horizontal = -0.42}}, secondaries = {{name = "SMG-11", value = 10.0, aggression = 9, horizontal = 0.0}}},
                
                ["STG"] = {primaries = {{name = "MP40", value = 1.22, aggression = 9, horizontal = -0.3}}, secondaries = {}},
                ["MG-34"] = {primaries = {{name = "MG-34", value = 0.2, aggression = 9, horizontal = -0.1}}, secondaries = {{name = "SMG-11", value = 10.0, aggression = 9, horizontal = 0.0}}},
                ["PPSH"] = {primaries = {{name = "PPSH NORMAL MAG", value = 1.55, aggression = 9, horizontal = -0.3}}, secondaries = {{name = "SMG-11", value = 10.0, aggression = 9, horizontal = 0.0}}},
        ["PPSH-DRUM"] = {primaries = {{name = "PPSH", value = 1.8, aggression = 9, horizontal = -0.55}}, secondaries = {{name = "SMG-12", value = 6.5, aggression = 9, horizontal = 0.6}}}
    },  
                
         
    ALIES = {
        ["BRITISHTOMMY"] = {primaries = {{name = "TOMMY GUN", value = 1.1, aggression = 9, horizontal = 0.2}}, secondaries = {{name = "SMG-11", value = 10.0, aggression = 9, horizontal = 0.0}}},
        ["USTOMMY"] = {primaries = {{name = "TOMMY GUN", value = 1.1, aggression = 9, horizontal = 0.2}}, secondaries = {{name = "SMG-11", value = 10.0, aggression = 9, horizontal = 0.0}}},
        ["M1-CARABINE"] = {primaries = {{name = "M1-HITMARKRIFLE", value = 1.8, aggression = 9, horizontal = -0.35}}, secondaries = {{name = "SMG-11", value = 10.0, aggression = 9, horizontal = 0.0}}},
        ["M1-GARAND"] = {primaries = {{name = "M1-GARAND", value = 4.5, aggression = 9, horizontal = -0.42}}, secondaries = {{name = "SMG-11", value = 10.0, aggression = 9, horizontal = 0.0}}},
        ["USLMG"] = {primaries = {{name = "TOMMY GUN", value = 0.2, aggression = 9, horizontal = 0}}, secondaries = {{name = "SMG-11", value = 10.0, aggression = 9, horizontal = 0.0}}},
        ["BAR"] = {primaries = {{name = "TOMMY GUN", value = 1.4, aggression = 9, horizontal = 0}}, secondaries = {{name = "SMG-11", value = 10.0, aggression = 9, horizontal = 0.0}}},
        ["GREASE"] = {primaries = {{name = "GREASE GUN", value = 7.1, aggression = 9, horizontal = 0.0}}, secondaries = {{name = "SMG-12", value = 6.5, aggression = 9, horizontal = 0.0}}}
    }
}
 
-- ====== INTERNAL STATE (do not edit below unless you know what you are doing) ======
local currentSide = "AXISUSSR"
local operatorList = operatorOrder[currentSide]
local currentIndex = 1
local usingSecondary = false
local rcsActive = false
local lastLockState = nil
local memory = { AXISUSSR = {index = 1, secondary = false}, ALIES = {index = 1, secondary = false} }
 
-- Helper: default weapon object (prevents nil access)
local function defaultWeapon()
    return { name = "N/A", value = 0, aggression = 1, horizontal = 0 }
end
 
local function GetCurrentOperator()
    return operatorList[currentIndex]
end
 
local function GetCurrentWeapon()
    local op = GetCurrentOperator()
    local opData = operators[currentSide][op]
    if not opData then return defaultWeapon(), "Primary" end
 
    if not opData.primaryIndex or opData.primaryIndex > #opData.primaries then opData.primaryIndex = 1 end
    if not opData.secondaryIndex or opData.secondaryIndex > #opData.secondaries then opData.secondaryIndex = 1 end
 
    if usingSecondary and #opData.secondaries > 0 then
        return opData.secondaries[opData.secondaryIndex] or defaultWeapon(), "Secondary"
    else
        return opData.primaries[opData.primaryIndex] or defaultWeapon(), "Primary"
    end
end
 
-- Print an organized menu into the G HUB log (OutputLogMessage)
local function PrintMenu()
    ClearLog()
    local op = GetCurrentOperator()
    local weapon, wtype = GetCurrentWeapon()
    local opData = operators[currentSide][op] or { primaries = {}, secondaries = {} }
 
    -- Ensure valid indexes
    if not opData.primaryIndex or opData.primaryIndex < 1 or opData.primaryIndex > #opData.primaries then opData.primaryIndex = 1 end
    if not opData.secondaryIndex or opData.secondaryIndex < 1 or opData.secondaryIndex > #opData.secondaries then opData.secondaryIndex = 1 end
 
    local sideIcon = (currentSide == "AXISUSSR") and "卐" or "✡︎"
 
    local primaryName = "N/A"
    if #opData.primaries > 0 and opData.primaries[opData.primaryIndex] then
        primaryName = opData.primaries[opData.primaryIndex].name
    end
    local primaryMsg = "Primary: " .. primaryName
    if #opData.primaries > 1 then primaryMsg = primaryMsg .. " [" .. tostring(opData.primaryIndex) .. "/" .. tostring(#opData.primaries) .. "]" end
 
    local secondaryMsg = "Secondary: N/A"
    if #opData.secondaries > 0 then
        local sname = opData.secondaries[opData.secondaryIndex] and opData.secondaries[opData.secondaryIndex].name or "N/A"
        secondaryMsg = "Secondary: " .. sname
        if #opData.secondaries > 1 then secondaryMsg = secondaryMsg .. " [" .. tostring(opData.secondaryIndex) .. "/" .. tostring(#opData.secondaries) .. "]" end
    end
 
    local activeWeaponMsg = "N/A"
    if wtype == "Secondary" then
        activeWeaponMsg = (opData.secondaries[opData.secondaryIndex] and opData.secondaries[opData.secondaryIndex].name or "N/A") .. " [Secondary]"
    else
        activeWeaponMsg = (opData.primaries[opData.primaryIndex] and opData.primaries[opData.primaryIndex].name or "N/A") .. " [Primary]"
    end
 
    OutputLogMessage("╔════════════════════════════════════╗\n")
    OutputLogMessage("║   HELL LET LOOSE    |   Version 1488 HH   ║\n")
    OutputLogMessage("╚════════════════════════════════════╝\n")
 
    OutputLogMessage("📌 Status:\n")
    OutputLogMessage(" • Side: %s %s\n", currentSide, sideIcon)
    OutputLogMessage(" • Toggle (%s): %s\n\n", string.upper(toggleLock), rcsActive and "✔️ ON" or "❌ OFF")
 
    OutputLogMessage("🎯 Current Operator:\n")
    OutputLogMessage(" • Name: %s\n", op)
    OutputLogMessage(" • Active Weapon: %s\n\n", activeWeaponMsg)
 
    OutputLogMessage("🔫 Weapons:\n")
    OutputLogMessage(" • %s\n", primaryMsg)
    OutputLogMessage(" • %s\n\n", secondaryMsg)
 
    local v = weapon and weapon.value or 0
    local h = weapon and weapon.horizontal or 0
    local agg = weapon and weapon.aggression or 0
    OutputLogMessage(" • Stats => V: %.2f | H: %.2f | Agg: %d\n", v, h, agg)
    OutputLogMessage("══════════════════════════════════════")
end
 
-- Update toggle state when lock key changes
local function UpdateToggle()
    local state = IsKeyLockOn(toggleLock)
    if state ~= lastLockState then
        rcsActive = state
        lastLockState = state
        PrintMenu()
    end
end
 
-- Switch primary weapon for current operator (cycles primaries)
local function SwitchPrimary()
    local op = GetCurrentOperator()
    local opData = operators[currentSide][op]
    if not opData then return end
    if usingSecondary then
        usingSecondary = false
    elseif #opData.primaries > 1 then
        opData.primaryIndex = (opData.primaryIndex or 1) % #opData.primaries + 1
    end
    memory[currentSide].secondary = usingSecondary
    PrintMenu()
end
 
-- Switch to / cycle secondary weapon for current operator
local function SwitchSecondary()
    local op = GetCurrentOperator()
    local opData = operators[currentSide][op]
    if not opData then return end
 
    if #opData.secondaries > 0 then
        if usingSecondary then
            opData.secondaryIndex = (opData.secondaryIndex or 1) % #opData.secondaries + 1
        else
            usingSecondary = true
            if not opData.secondaryIndex or opData.secondaryIndex > #opData.secondaries then
                opData.secondaryIndex = 1
            end
        end
    else
        usingSecondary = false
    end
 
    memory[currentSide].secondary = usingSecondary
    PrintMenu()
end
 
-- Change operator preset left/right
local function ChangePreset(delta)
    currentIndex = (currentIndex - 1 + delta + #operatorList) % #operatorList + 1
    usingSecondary = false
    memory[currentSide].index = currentIndex
    memory[currentSide].secondary = usingSecondary
    PrintMenu()
end
 
-- Switch side (AXISUSSR/ALIES) and remember indices per side
local function SwitchSide()
    memory[currentSide].index = currentIndex
    memory[currentSide].secondary = usingSecondary
    currentSide = (currentSide == "AXISUSSR") and "ALIES" or "AXISUSSR"
    operatorList = operatorOrder[currentSide]
    currentIndex = memory[currentSide].index or 1
    usingSecondary = memory[currentSide].secondary or false
    PrintMenu()
end
 
-- MAIN EVENT LOOP HANDLER
function OnEvent(event, arg)
    -- always update toggle state on events
    UpdateToggle()
 
    if event == "PROFILE_ACTIVATED" then
        -- seed RNG once when profile is activated to get better randomization
        if math and math.randomseed and GetRunningTime then
            math.randomseed(GetRunningTime())
            math.random(); math.random(); math.random()
        end
 
        lastLockState = IsKeyLockOn(toggleLock)
        rcsActive = lastLockState
        operatorList = operatorOrder[currentSide]
        currentIndex = memory[currentSide].index or 1
        usingSecondary = memory[currentSide].secondary or false
        PrintMenu()
        return
    end
 
    if event == "PROFILE_DEACTIVATED" then
        -- clean state when profile is deactivated
        rcsActive = false
        lastLockState = false
        return
    end
 
    if event == "MOUSE_BUTTON_PRESSED" then
        if arg == prevButton then
            ChangePreset(-1)
            return
        elseif arg == nextButton then
            ChangePreset(1)
            return
        elseif arg == scrollButton then
            -- centralized scroll button with modifiers
            if IsModifierPressed("rctrl") then
                SwitchSide()
                return
            elseif IsModifierPressed("ctrl") and not IsModifierPressed("rctrl") then
                SwitchPrimary()
                return
            elseif IsModifierPressed("alt") then
                SwitchSecondary()
                return
            end
        end
    end
 
    -- Fire behavior when RCS is active and left button is pressed
    if event == "MOUSE_BUTTON_PRESSED" and arg == 1 then
        local weapon, _ = GetCurrentWeapon()
        if not weapon then weapon = defaultWeapon() end
 
        local accumX, accumY = 0, 0
        local canRun = rcsActive and (not requireADS or IsMouseButtonPressed(3))
        if canRun then
            repeat
                UpdateToggle()
                if not rcsActive then break end
                if requireADS and not IsMouseButtonPressed(3) then break end
 
                -- safer random: use math.random integer range
                local rndX = (math.random(-100, 100) / 100) * randomLevelX
                local rndY = (math.random(-100, 100) / 100) * randomLevelY
 
                accumX = accumX + (weapon.horizontal or 0) + rndX
                accumY = accumY + (weapon.value or 0) + rndY
 
                local moveX, fracX = math.modf(accumX)
                local moveY, fracY = math.modf(accumY)
                accumX, accumY = fracX, fracY
 
                if moveX ~= 0 or moveY ~= 0 then
                    -- depending on the game's input mapping you may need to invert Y: MoveMouseRelative(moveX, -moveY)
                    MoveMouseRelative(moveX, moveY)
                end
 
                Sleep(weapon.aggression or 1)
            until not IsMouseButtonPressed(1)
        end
    end
end
 
-- End of translated and cleaned v6.6
-- Documentation: see header block for controls and license note.

Setup Notes:
I am currently running 800 DPI with 40% in-game sensitivity. If you are running anything higher or lower, you will definitely need to tweak the value entries in the weapon tables. The script is setup to trigger only when ADS is active (requireADS = true), which helps a ton with general movement and looting when you aren't trying to beam someone across the map.

Missing Data:
Currently, the Grease Gun and some pistols aren't mapped. You can easily add them by copying a block from another weapon and adjusting the recoil values.

Has anyone played around with the timing in the Sleep(weapon.aggression) loop? I’m curious if reducing the sleep delay makes it more fluid for high-fire-rate weapons or if it just creates jitter. Drop your tweaks below if you’ve optimized the patterns for specific loadouts.

Use at your own risk. Scripts like this are generally fine, but keep your behavior human-like to avoid manual bans from server admins watching spectator cams.
 
Top