-
Notifications
You must be signed in to change notification settings - Fork 98
Lua Scripting
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
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
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 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.
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)
The following return types exist:
ReturnType = {
None,
Boolean,
Integer,
String,
Float,
Vector3
}
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.
You can reload all your scripts in-game by simply turning the mod off and on again with the CTRL + L
shortcut.
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)
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.
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)
Some natives require pointers as arguments. You can use Holder
s 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).
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