Jeux Tarifs Pro Infrastructure Guides Blog Partenariat À propos

Bibliothèque de scripts RedM : 15 scripts Lua gratuits prêts à copier

Une collection de scripts RedM gratuits et commentés pour Red Dead Redemption 2 : téléportation, chevaux, soins, repères sur la carte, heure et météo synchronisées, annonces, liste blanche, journaux Discord, anti-AFK, primes et scripts VORP.

3 min de lecture Mis à jour le 21 octobre 2026

Des scripts RedM complets, commentés et prêts à l'emploi. Ils fonctionnent sans framework, sauf ceux marqués VORP. Chacun tient dans une seule ressource.

Installer un script de cette page
  1. Créez un dossier dans resources/[scripts]/, par exemple eso-cheval.
  2. Créez dedans les fichiers indiqués avec le gestionnaire de fichiers du panel ou en SFTP.
  3. Ajoutez ensure eso-cheval au server.cfg.
  4. Redémarrez le serveur depuis txAdmin.
Commandes d'administration

Les commandes marquées « admin » utilisent RegisterCommand(..., true). Donnez les droits avec add_ace group.admin command allow et add_principal identifier.fivem:VOTRE_ID group.admin dans le server.cfg.

Le manifeste commun

fxmanifest.lua
fx_version 'cerulean'
game 'rdr3'
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'
lua54 'yes'

author 'EsoterHost'
version '1.0.0'

shared_script 'config.lua'   -- si le script a un config.lua
client_script 'client.lua'
server_script 'server.lua'
Ne traduisez pas rdr3_warning

La phrase doit rester exactement identique, en anglais, sinon la ressource ne démarre pas.

Fonctions utilitaires

Plusieurs scripts utilisent ces deux fonctions d'affichage. Ajoutez-les en haut de client.lua quand un script les appelle.

client.lua (utilitaires)
local function texteEcran(texte, x, y, taille)
  SetTextScale(taille or 0.4, taille or 0.4)
  SetTextColor(255, 255, 255, 230)
  SetTextCentre(true)
  SetTextDropshadow(1, 0, 0, 0, 255)
  DisplayText(CreateVarString(10, 'LITERAL_STRING', texte), x, y)
end

local function texte3D(coords, texte)
  local visible, x, y = GetScreenCoordFromWorldCoord(coords.x, coords.y, coords.z)
  if visible then texteEcran(texte, x, y, 0.35) end
end

1. Téléportation : /tp et /tpm (admin)

client.lua
local function teleporter(x, y, z)
  local ped = PlayerPedId()
  DoScreenFadeOut(300)
  while not IsScreenFadedOut() do Wait(0) end
  SetEntityCoords(ped, x, y, z, false, false, false, false)

  -- Si aucune hauteur n'est donnée, on cherche le sol
  if z == 0.0 then
    for hauteur = 0, 800, 25 do
      SetEntityCoords(ped, x, y, hauteur + 0.0, false, false, false, false)
      Wait(30)
      local ok, sol = GetGroundZFor_3dCoord(x, y, hauteur + 0.0, false)
      if ok then SetEntityCoords(ped, x, y, sol + 1.0, false, false, false, false) break end
    end
  end
  DoScreenFadeIn(300)
end

RegisterCommand('tp', function(_, args)
  local x, y, z = tonumber(args[1]), tonumber(args[2]), tonumber(args[3])
  if not x or not y then
    return TriggerEvent('chat:addMessage', { args = { 'TP', 'Utilisation : /tp x y [z]' } })
  end
  teleporter(x, y, z or 0.0)
end, true)

RegisterCommand('tpm', function()
  -- GET_WAYPOINT_COORDS (le point de passage posé sur la carte)
  local c = GetWaypointCoords()
  if c.x == 0.0 and c.y == 0.0 then
    return TriggerEvent('chat:addMessage', { args = { 'TP', 'Posez un point de passage sur la carte' } })
  end
  teleporter(c.x, c.y, 0.0)
end, true)

2. Faire apparaître un cheval : /cheval (admin)

client.lua
RegisterCommand('cheval', function(_, args)
  local modele = args[1] or 'A_C_Horse_Arabian_White'
  local hash = joaat(modele)
  if not IsModelValid(hash) then
    return TriggerEvent('chat:addMessage', { args = { 'Écurie', 'Modèle inconnu : ' .. modele } })
  end

  RequestModel(hash)
  local limite = GetGameTimer() + 5000
  while not HasModelLoaded(hash) and GetGameTimer() < limite do Wait(10) end
  if not HasModelLoaded(hash) then return end

  local ped = PlayerPedId()
  local pos = GetOffsetFromEntityInWorldCoords(ped, 0.0, 3.0, 0.0)
  local cheval = CreatePed(hash, pos.x, pos.y, pos.z, GetEntityHeading(ped), true, true, false, false)
  Citizen.InvokeNative(0x283978A15512B2FE, cheval, true)       -- _SET_RANDOM_OUTFIT_VARIATION
  Citizen.InvokeNative(0x028F76B6E78246EB, ped, cheval, -1)     -- _SET_PED_ONTO_MOUNT
  SetModelAsNoLongerNeeded(hash)
end, true)
ModèleCheval
A_C_Horse_Arabian_WhiteArabe blanc
A_C_Horse_Turkoman_GoldTurkmène doré
A_C_Horse_Thoroughbred_DappleGreyPur-sang gris pommelé
A_C_Horse_MissouriFoxTrotter_SilverDapplePintoMissouri Fox Trotter
A_C_Horse_Mustang_GoldenDunMustang isabelle
A_C_Horse_Shire_DarkBayShire bai foncé (trait)

3. Soigner et réanimer : /heal et /revive (admin)

client.lua
RegisterCommand('heal', function()
  local ped = PlayerPedId()
  SetEntityHealth(ped, GetEntityMaxHealth(ped))
end, true)

RegisterCommand('revive', function()
  local ped = PlayerPedId()
  local c = GetEntityCoords(ped)
  NetworkResurrectLocalPlayer(c.x, c.y, c.z, GetEntityHeading(ped), true, false)
  SetEntityHealth(PlayerPedId(), GetEntityMaxHealth(PlayerPedId()))
  ClearPedTasksImmediately(PlayerPedId())
end, true)
Avec VORP

VORP gère la mort et la réanimation lui-même. Sur un serveur VORP, utilisez ses commandes d'administration plutôt que /revive.

4. Repères sur la carte

config.lua
Config = {}

Config.Reperes = {
  { nom = 'Saloon de Valentine', coords = vector3(-313.0, 805.0, 118.98), sprite = 'blip_saloon' },
  { nom = 'Bureau du shérif', coords = vector3(-278.0, 805.4, 119.38), sprite = 'blip_ambient_sheriff' },
  { nom = 'Magasin général', coords = vector3(-324.3, 803.9, 117.88), sprite = 'blip_shop_store' },
  { nom = 'Écurie', coords = vector3(-365.2, 791.9, 116.18), sprite = 'blip_shop_horse' },
}
client.lua
local reperes = {}

CreateThread(function()
  for _, r in ipairs(Config.Reperes) do
    -- BLIP_ADD_FOR_COORDS, 1664425300 = style de repère standard
    local blip = Citizen.InvokeNative(0x554D9D53F696D002, 1664425300, r.coords.x, r.coords.y, r.coords.z)
    SetBlipSprite(blip, joaat(r.sprite), true)
    SetBlipScale(blip, 0.2)
    Citizen.InvokeNative(0x9CB1A1623062F402, blip, r.nom)       -- _SET_BLIP_NAME
    reperes[#reperes + 1] = blip
  end
end)

-- Retire les repères quand la ressource s'arrête
AddEventHandler('onResourceStop', function(nom)
  if nom ~= GetCurrentResourceName() then return end
  for _, blip in ipairs(reperes) do RemoveBlip(blip) end
end)

5. Heure synchronisée : /heure (admin)

Tous les joueurs voient la même heure, qui avance avec le temps.

server.lua
GlobalState.heure = GlobalState.heure or 9
GlobalState.minute = GlobalState.minute or 0

-- Une minute de jeu toutes les 2 secondes réelles
CreateThread(function()
  while true do
    Wait(2000)
    local m, h = GlobalState.minute + 1, GlobalState.heure
    if m >= 60 then m, h = 0, (h + 1) % 24 end
    GlobalState.minute, GlobalState.heure = m, h
  end
end)

RegisterCommand('heure', function(_, args)
  local h, m = tonumber(args[1]), tonumber(args[2] or 0)
  if h and h >= 0 and h < 24 then GlobalState.heure, GlobalState.minute = h, m or 0 end
end, true)
client.lua
CreateThread(function()
  while true do
    NetworkOverrideClockTime(GlobalState.heure or 9, GlobalState.minute or 0, 0)
    Wait(1000)
  end
end)

6. Météo synchronisée : /meteo (admin)

server.lua
GlobalState.meteo = GlobalState.meteo or 'SUNNY'

local METEOS = {
  SUNNY = true, CLOUDS = true, OVERCAST = true, DRIZZLE = true, RAIN = true,
  THUNDERSTORM = true, FOG = true, MISTY = true, SNOW = true, SNOWLIGHT = true, BLIZZARD = true,
}

RegisterCommand('meteo', function(src, args)
  local m = (args[1] or ''):upper()
  if METEOS[m] then
    GlobalState.meteo = m
  elseif src ~= 0 then
    TriggerClientEvent('chat:addMessage', src, { args = { 'Météo', 'SUNNY, CLOUDS, OVERCAST, DRIZZLE, RAIN, THUNDERSTORM, FOG, MISTY, SNOW, SNOWLIGHT, BLIZZARD' } })
  end
end, true)
client.lua
local actuelle = nil

CreateThread(function()
  while true do
    local cible = GlobalState.meteo or 'SUNNY'
    if cible ~= actuelle then
      -- _SET_WEATHER_TYPE (type, p1, p2, transition, durée, p5)
      Citizen.InvokeNative(0x59174F1AFE095B5A, joaat(cible), true, false, true, 15.0, false)
      actuelle = cible
    end
    Wait(5000)
  end
end)

7. Annonce à tout le serveur : /annonce (admin)

server.lua
RegisterCommand('annonce', function(src, args)
  local message = table.concat(args, ' ')
  if message == '' then return end
  TriggerClientEvent('chat:addMessage', -1, { color = { 200, 60, 40 }, args = { 'Le télégraphe', message } })
  TriggerClientEvent('eso-annonce:afficher', -1, message)
end, true)
client.lua
-- Affiche aussi l'annonce au centre de l'écran pendant 8 secondes
-- (ajoutez la fonction texteEcran des utilitaires en haut du fichier)
RegisterNetEvent('eso-annonce:afficher', function(message)
  local fin = GetGameTimer() + 8000
  CreateThread(function()
    while GetGameTimer() < fin do
      texteEcran('ANNONCE', 0.5, 0.08, 0.5)
      texteEcran(message, 0.5, 0.12, 0.42)
      Wait(0)
    end
  end)
end)

8. Liste blanche par identifiant

Ce script est purement serveur : il fonctionne à l'identique sur FiveM et RedM.

config.lua
Config = {}
Config.Message = "Ce serveur est en liste blanche. Faites votre demande sur notre Discord : discord.gg/votre-code"
Config.Autorises = {
  ['license:0123456789abcdef0123456789abcdef01234567'] = true,
  ['discord:123456789012345678'] = true,
}
server.lua
AddEventHandler('playerConnecting', function(nom, setKickReason, deferrals)
  local src = source
  deferrals.defer()
  Wait(0)
  deferrals.update(('Vérification de la liste blanche pour %s…'):format(nom))
  for _, id in ipairs(GetPlayerIdentifiers(src)) do
    if Config.Autorises[id] then return deferrals.done() end
  end
  deferrals.done(Config.Message)
end)

9. Journal des connexions sur Discord

Créez un webhook dans les paramètres du salon Discord, puis ajoutez au server.cfg :

server.cfg
set eso_logs_webhook "https://discord.com/api/webhooks/xxxx/yyyy"
server.lua
local WEBHOOK = GetConvar('eso_logs_webhook', '')

local function envoyer(titre, description, couleur)
  if WEBHOOK == '' then return end
  PerformHttpRequest(WEBHOOK, function() end, 'POST', json.encode({
    username = 'Journal de la frontière',
    embeds = { { title = titre, description = description, color = couleur, timestamp = os.date('!%Y-%m-%dT%H:%M:%SZ') } },
  }), { ['Content-Type'] = 'application/json' })
end

AddEventHandler('playerJoining', function()
  local src = source
  local ids = {}
  for _, id in ipairs(GetPlayerIdentifiers(src)) do
    if not id:find('^ip:') then ids[#ids + 1] = '`' .. id .. '`' end
  end
  envoyer('Arrivée', ('**%s**\n%s'):format(GetPlayerName(src), table.concat(ids, '\n')), 3066993)
end)

AddEventHandler('playerDropped', function(raison)
  envoyer('Départ', ('**%s**\nRaison : %s'):format(GetPlayerName(source), raison), 15158332)
end)

10. Expulsion des joueurs inactifs (anti-AFK)

client.lua
local LIMITE = 20 * 60
local AVERTISSEMENTS = { 120, 60 }
local derniereAction, dernierePos, averti = GetGameTimer(), vector3(0, 0, 0), {}

CreateThread(function()
  while true do
    Wait(5000)
    local pos = GetEntityCoords(PlayerPedId())
    if #(pos - dernierePos) > 1.0 then
      derniereAction, dernierePos, averti = GetGameTimer(), pos, {}
    end
    local restant = LIMITE - (GetGameTimer() - derniereAction) // 1000
    if restant <= 0 then
      TriggerServerEvent('eso-afk:expulser')
    else
      for _, seuil in ipairs(AVERTISSEMENTS) do
        if restant <= seuil and not averti[seuil] then
          averti[seuil] = true
          TriggerEvent('chat:addMessage', { args = { 'AFK', ('Bougez, sinon vous serez expulsé dans %d secondes'):format(restant) } })
        end
      end
    end
  end
end)
server.lua
RegisterNetEvent('eso-afk:expulser', function()
  if IsPlayerAceAllowed(source, 'afk.ignorer') then return end
  DropPlayer(source, 'Expulsé pour inactivité. Vous pouvez vous reconnecter.')
end)

11. Texte au-dessus du joueur : /me

server.lua
RegisterCommand('me', function(src, args)
  local texte = table.concat(args, ' ')
  if src == 0 or texte == '' or #texte > 120 then return end
  TriggerClientEvent('eso-me:afficher', -1, src, texte)
end, false)
client.lua
-- (ajoutez texteEcran et texte3D des utilitaires en haut du fichier)
RegisterNetEvent('eso-me:afficher', function(serverId, texte)
  local joueur = GetPlayerFromServerId(serverId)
  if joueur == -1 then return end
  local ped = GetPlayerPed(joueur)
  if #(GetEntityCoords(ped) - GetEntityCoords(PlayerPedId())) > 25.0 then return end

  local fin = GetGameTimer() + 6000
  CreateThread(function()
    while GetGameTimer() < fin do
      texte3D(GetEntityCoords(ped) + vector3(0.0, 0.0, 1.0), '* ' .. texte .. ' *')
      Wait(0)
    end
  end)
end)

12. Signalement aux administrateurs : /report

server.lua
local derniers = {}

RegisterCommand('report', function(src, args)
  if src == 0 then return end
  local message = table.concat(args, ' ')
  if message == '' then return end
  if derniers[src] and os.time() - derniers[src] < 60 then
    return TriggerClientEvent('chat:addMessage', src, { args = { 'Report', 'Patientez une minute entre deux signalements' } })
  end
  derniers[src] = os.time()

  for _, id in ipairs(GetPlayers()) do
    if IsPlayerAceAllowed(id, 'report.recevoir') then
      TriggerClientEvent('chat:addMessage', id, { color = { 255, 80, 80 }, args = { ('Report de %s [%s]'):format(GetPlayerName(src), src), message } })
    end
  end
  TriggerClientEvent('chat:addMessage', src, { args = { 'Report', "Message transmis à l'équipe" } })
end, false)

AddEventHandler('playerDropped', function() derniers[source] = nil end)

Donnez le droit de lecture avec add_ace group.admin report.recevoir allow.

13. VORP : salaire automatique

Verse un salaire aux joueurs selon leur métier, toutes les 20 minutes.

config.lua
Config = {}
Config.Intervalle = 20 * 60 * 1000
Config.Salaires = {
  sheriff = 12.0,
  medecin = 10.0,
  forgeron = 6.0,
  chomeur = 1.0,
}
server.lua
local VORPcore = exports.vorp_core:GetCore()

CreateThread(function()
  while true do
    Wait(Config.Intervalle)
    for _, src in ipairs(GetPlayers()) do
      local user = VORPcore.getUser(tonumber(src))
      local perso = user and user.getUsedCharacter
      if perso then
        local paie = Config.Salaires[perso.job] or Config.Salaires.chomeur
        perso.addCurrency(0, paie)
        VORPcore.NotifyRightTip(tonumber(src), ('Paie reçue : %.2f $'):format(paie), 4000)
      end
    end
  end
end)

14. VORP : objet utilisable (gourde de whisky)

objet.sql
INSERT INTO items (item, label, `limit`, can_remove, type, usable, `desc`)
VALUES ('gourde_whisky', 'Gourde de whisky', 3, 1, 'item_standard', 1, 'Redonne un peu de santé');
server.lua
local VORPcore = exports.vorp_core:GetCore()

exports.vorp_inventory:registerUsableItem('gourde_whisky', function(data)
  local src = data.source
  exports.vorp_inventory:closeInventory(src)
  exports.vorp_inventory:subItem(src, 'gourde_whisky', 1)
  TriggerClientEvent('eso-whisky:boire', src)
  VORPcore.NotifyRightTip(src, 'Une gorgée de whisky vous remet sur pied', 3000)
end)
client.lua
RegisterNetEvent('eso-whisky:boire', function()
  local ped = PlayerPedId()
  SetEntityHealth(ped, math.min(GetEntityHealth(ped) + 30, GetEntityMaxHealth(ped)))
end)

15. VORP : avis de recherche et récompense

Un administrateur met une prime sur un joueur. Celui qui le livre au shérif touche la récompense.

server.lua
local VORPcore = exports.vorp_core:GetCore()
local primes = {}             -- [serverId] = montant
local BUREAU = vector3(-278.0, 805.4, 119.38)

RegisterCommand('avis', function(src, args)
  local cible, montant = tonumber(args[1]), tonumber(args[2])
  if not cible or not montant or montant <= 0 or not GetPlayerName(cible) then return end
  primes[cible] = (primes[cible] or 0) + montant
  TriggerClientEvent('chat:addMessage', -1, { color = { 200, 60, 40 }, args = { 'Avis de recherche', ('%s est recherché mort ou vif : %d $'):format(GetPlayerName(cible), primes[cible]) } })
end, true)

-- /livrer [id] : le chasseur de primes livre la cible au bureau du shérif
RegisterCommand('livrer', function(src, args)
  local cible = tonumber(args[1])
  if not cible or not primes[cible] then return end
  local posChasseur = GetEntityCoords(GetPlayerPed(src))
  local posCible = GetEntityCoords(GetPlayerPed(cible))
  if #(posChasseur - BUREAU) > 10.0 or #(posCible - BUREAU) > 10.0 then
    return VORPcore.NotifyRightTip(src, 'Amenez la cible au bureau du shérif', 4000)
  end

  local user = VORPcore.getUser(src)
  if not user then return end
  user.getUsedCharacter.addCurrency(0, primes[cible] + 0.0)
  VORPcore.NotifyRightTip(src, ('Récompense touchée : %d $'):format(primes[cible]), 5000)
  primes[cible] = nil
end, false)

AddEventHandler('playerDropped', function() primes[source] = nil end)

Aller plus loin

Ces scripts sont libres : modifiez-les et utilisez-les sur votre serveur.


EsoterHost n'est ni approuvé, ni sponsorisé, ni affilié à Rockstar Games ou à Cfx.re. RedM et Red Dead Redemption 2 sont des marques de leurs propriétaires.

Ce guide vous a-t-il aidé ? Une question ? Ouvrez un ticket

Vous ne trouvez pas votre réponse ?

Notre équipe répond à vos tickets 7j/7, directement depuis votre espace client.