Skip to content

Lua Scripting

pongo1231 edited this page Aug 27, 2023 · 42 revisions

Starting with mod version 1.9 you are able to write your own effects completely in Lua! Here's how it works:

If you need native definitions (which you very likely do), ensure you have a natives_def.lua inside your chaosmod folder already. If not, go to the scripts folder inside the repository and run the generate_natives.py script. After a few seconds it should generate a natives_def.lua file in the same folder. Move the resulting file into your game's chaosmod folder.

Afterwards create a scripts folder in the same directory. That's where all the Lua scripts will be stored in.

Now create your own Lua script inside that folder.

Autocomplete if you use VS Code: https://github.com/gta-chaos-mod/ChaosModV/blob/master/scripts/generate_vsc_snippets.py

Example

Here's an example of what a script can look like:

EffectInfo = { -- ScriptInfo for mod version < 2.0
    Name = "Party Time",
    EffectId = "misc_partytime", -- ScriptId for mod version < 2.0
    TimedType = "Normal",
    IncompatibleIds = {
        "vehs_rainbow"
    }
}

function OnStart()
    print("Yay party! :D")
end

function OnStop()
    print("Party over :(")

    local playerPed = PLAYER_PED_ID()
    local playerVehicle = GET_VEHICLE_PED_IS_IN(playerPed)

    if playerVehicle then
        SET_ENTITY_AS_MISSION_ENTITY(playerVehicle)
        DELETE_ENTITY(Holder(playerVehicle))
    end
end

function OnTick()
    for _, vehicle in ipairs(GetAllVehicles()) do
        SET_VEHICLE_ENGINE_HEALTH(vehicle, -1.0)
        SET_VEHICLE_CUSTOM_PRIMARY_COLOUR(vehicle, math.random(255), math.random(255), math.random(255))
    end
end

Script Info

Your script will need to contain a ScriptInfo table to be able to register as an effect. The table either must or can contain the following:

EffectInfo = {                            -- Renamed from ScriptInfo since v2.0
    Name = "Party Time",                  -- The name of your effect to display, required
    EffectId = "misc_partytime",          -- An unique id for your effect, required (renamed from ScriptId since v2.0)
    TimedType = "Normal",                 -- The timed type of your effect (defaults to none)
    WeightMultiplier = 5,                 -- Weight multiplier of your effect to make it more / less likely to occur randomly (defaults to 5)
    IsMeta = false,                       -- Whether this effect is a meta effect (defaults to false)
    ExcludeFromVoting = false,            -- Whether this effect should be excluded from voting (defaults to false)
    IsUtility = false,                    -- Whether this effect should only be able to be activated through the debug menu (defaults to false)
    HideRealNameOnStart = false,          -- Whether the effect's name should pop up immediately or only after OnStart (replaced with a fake name until then if available, defaults to false)
    EffectCategory = "None"               -- Effect category to put this effect into, only one effect in a category can run at a time (see https://github.com/gta-chaos-mod/ChaosModV/blob/master/ChaosMod/Effects/EEffectCategory.h#L12= for a list, defaults to none)
    EffectGroup = "_group_weatherchange", -- Effect group to associate this effect with, groups effects together and affects weighting (defaults to none)
    ShortcutKeycode = 0,                  -- Trigger effect if virtual keycode is pressed, see https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes - 0 to disable (defaults to 0)
    ShortcutWithCtrl = false, ShortcutWithShift = false, ShortcutWithAlt = false, -- Modifiers for the shortcut key code, all default to false
    IncompatibleIds = {                   -- A list of incompatible effects listed by their ids (defaults to none)
        "vehs_rainbow"
    }
}

Natives

Natives are the game script functions you can call in your script to do certain actions.

There are several databases of all the natives that have been found online, the FiveM NativeDB being one of them for instance.

Consult the example above to see how to invoke them.

Timed Types

The following timed types exist:

"None"           -- Non-timed effect
"Normal"         -- Normal timed effect
"Short"          -- Short timed effect
"Permanent"      -- Permanent effect
"Custom"         -- Timed effect with custom duration in seconds (also needs CustomTime entry in ScriptInfo)

Return Types

The following return types exist:

ReturnType = {
    None,
    Boolean,
    Integer,
    String,
    Float,
    Vector3
}

Errors

Errors are printed in the chaoslog.txt file.

You can enable a console window for logs by creating a .enableconsole file inside the chaosmod folder.

Hot Reloading

You can reload all your scripts in-game by simply turning the mod off and on again with the CTRL + L shortcut.

Available Functions

Outside of functions provided by the base, math, table, string and bit32 lua libraries and the natives provided by natives_def.lua, the following functions are available:

# Prints a string in the `chaoslog.txt` file
print(string)

# Invokes a native
_invoke(nativeHash, returnType, arguments...)

# Pauses the current fiber for `x` milliseconds
WAIT(ms)

# Calls the WIN32 `GetTickCount64` function
GetTickCount()

# Whether a keyboard key is currently pressed, see https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
IsKeyPressed(keycode)

# Whether a keyboard key has only just been pressed
IsKeyJustPressed(keycode)

# Returns all existing peds on the world
GetAllPeds()
# Returns all existing vehicles on the world
GetAllVehicles()
# Returns all existing props on the world
GetAllProps()

# Requests a model to be loaded into memory and blocks until done so
LoadModel(modelHash)

# Creates a ped and adds it to the mod`s pool for automatic cleanup
CreatePoolPed(pedType, modelHash, x, y, z, heading)

# Creates a vehicle and adds it to the mod`s pool for automatic cleanup
CreatePoolVehicle(modelHash, x, y, z, heading)

# Creates a prop and adds it to the mod`s pool for automatic cleanup
CreatePoolProp(modelHash, x, y, z, dynamic)

# Creates a vehicle on the player's coords with SET_VEHICLE_AS_NO_LONGER_NEEDED applied
CreateTempVehicleOnPlayerPos(modelHash, heading)

# Creates a vehicle for each nearby ped and sets them into it, set distance to <= 0 for unlimited distance
SetSurroundingPedsInVehicles(modelHash, distance)

# Replaces the specified vehicle with a random vehicle, if bAddToPool == false make sure to handle despawning yourself
ReplaceVehicle(vehicle, bAddToPool)

# Creates a vehicle with `SET_VEHICLE_AS_NO_LONGER_NEEDED` already applied
CreateTempVehicle(modelHash, x, y, z, heading)

# Returns every existing weapon in the game
GetAllWeapons()

# Returns every existing ped model in the game
GetAllPedModels()

# Returns every existing vehicle model in the game
GetAllVehicleModels()

# Replaces the lens distortion shader with your own pixel shader source, ensure EffectCategory is set to "Shader" as only one shader replacement can run at a time, see https://github.com/gta-chaos-mod/ChaosModV/blob/master/ChaosMod/Effects/db/Misc/MiscShaderTnPanel.cpp for an example pixel shader
--[[
shaderType can be any of the following:
    EOverrideShaderType.LensDistortion : Overrides screen lens distortion shader
    EOverrideShaderType.Snow           : Overrides snow shader, requires SetSnowState(true)
]]--
OverrideShader(shaderType, shaderSource)

# Reset shaders back to normal
ResetShader()

# Whether there should be snow on the ground
SetSnowState(bool)

# Returns whether vehicle is braking
IsVehicleBraking(vehicle)

# Since v2.0

# Blocks all script threads except this one
EnableScriptThreadBlock()

# Disables the above block
DisableScriptThreadBlock()

# Overrides pitch of all played game sounds
SetAudioPitch(pitch)

# Resets pitch override
ResetAudioPitch()

# Overrides clearness of all played game sounds
SetAudioClearness(clearness)

# Resets clearness override
ResetAudioClearness()

# Offset as Vector3
GetGameplayCamOffsetInWorldCoords(offset)

GetCoordsFromGameplayCam(distance)

IsWeaponShotgun(weaponHash)

# Overrides effect name before OnStart finishes, only available in OnStart
OverrideEffectName(name)

# Overrides effect name with name of another effect id before OnStart finishes, only available in OnStart
OverrideEffectNameById(id)

# Returns the mod version
GetChaosModVersion()

# Returns the current game build 
GetGameBuild()

# Adds a custom label for use with natives which require one (e.g. DISPLAY_HELP_TEXT_THIS_FRAME)
AddCustomLabel(label, text)

# Displays a text on screen as help text for at least durationSecs seconds
DisplayHelpText(text, durationSecs)

# Teleport player (and vehicle they're in) to position, taking ground height into account
TeleportPlayer(x, y, z, noOffset)

Effect Groups

Effects groups are a collection of different effects. During weighting, effects within an effect group will be affected by the weight of the current effect group. Effect groups are meant to group effects with a similar purpose (e.g. spawning a vehicle) together to keep the effect selection as diverse as possible. A list of built-in effect groups can be found here.

It's also possible to register your own effect groups:

EffectGroupInfo = {
    Name = "group_test",   -- Name, should start with `group_` as a convention 
    WeightMultiplier = 1   -- Weight multiplier, Ranges from 1 (lowest) - 65535 (highest), defaults to 1
}

Effect groups may not have a duplicate name; later registrations of an effect group with the same name will be ignored and the weight multiplier of the previous registration will be used. As a recommendation, you should keep the effect group definitions in separate script files for organization purposes.

Meta Modifiers

You can modify some of the behaviors of the mod using Meta Modifiers.

function OnStart()
    MetaModifiers.FlipChaosUI(true)
    MetaModifiers.AdditionalEffectsToDispatch(3)
end

function OnStop()
    MetaModifiers.FlipChaosUI(false)
    MetaModifiers.AdditionalEffectsToDispatch(0)
end

As of writing, the following modifiers are available:

EffectDurationModifier(float)
TimerSpeedModifier(float)
AdditionalEffectsToDispatch(ubyte)
HideChaosUI(bool)
DisableChaos(bool)
FlipChaosUI(bool)

Pointers

Some natives require pointers as arguments. You can use Holders in those cases.

Storing data inside a Holder and accessing it afterwards:

local r, g, b = Holder(), Holder(), Holder()

GET_VEHICLE_CUSTOM_PRIMARY_COLOUR(vehicle, r, g, b)

print(r:AsInteger() .. " " .. g:AsInteger() .. " " .. b:AsInteger())

(You can also use AsBoolean, AsFloat, AsString or AsVector3 depending on the type of the stored data)

Sending data to a native:

DELETE_ENTITY(Holder(vehicle))

Note that the data passed to the Holder won't be modified (e.g. DELETE_ENTITY won't set vehicle to nil in this case).

Vector3

Receiving a Vector3:

local playerCoords = GET_ENTITY_COORDS(playerPed)

print(playerCoords.x .. " " .. playerCoords.y .. " " .. playerCoords.z)

Creating a Vector3:

local vector = Vector3(5.0, 3.0, 1.0)

print(vector.x .. " " .. vector.y .. " " .. vector.z)
-- Will print: 5.0 3.0 1.0