Armes et outils en Lua
Écrire des armes entièrement en Lua (les SWEP de Garry's Mod), jeter et ramasser des armes au sol, créer des outils de toolgun (les STOOL) avec leur panneau de réglages, et contrôler le toolgun, le physgun et la touche E avec des hooks.
weapon.json). Une arme Lua décrit son comportement en code, et peut reprendre le modèle et les animations d'une arme du jeu ou d'une arme de l'éditeur avec SWEP.Base.Armes en Lua (SWEP)
Où les écrire
| Où | Fichier |
|---|---|
| Gamemode | weapons/<classe>.lua |
| Addon | lua/weapons/<classe>.lua |
| N'importe quel fichier partagé | weapons.Register(SWEP, "classe") |
Ces fichiers sont chargés côté serveur et côté client : le serveur fait les dégâts, le client donne le retour immédiat (son, traçantes, animation, chargeur affiché). Pendant le chargement, la table globale SWEP est prête (avec SWEP.Primary = {} et SWEP.Secondary = {}) ; la classe est le nom du fichier sans .lua, en minuscules. Nom de classe : lettres minuscules, chiffres et _, 48 caractères au plus, et pas le nom d'une arme du jeu (physgun, toolgun, crowbar, pistol, shotgun, rifle). 256 classes au plus.
Pour donner l'arme : ply:Give("classe") (serveur). Avec SWEP.Spawnable = true, elle apparaît aussi dans l'onglet Armes du menu de spawn.
Champs de SWEP
| Champ | Défaut | Rôle |
|---|---|---|
PrintName | la classe | Nom affiché (sélecteur, HUD, menu). |
Category | "Armes Lua" | Catégorie dans l'onglet Armes du menu de spawn. |
Slot | 3 | Emplacement, compté à partir de 0 comme dans GMod : Slot = 0 → touche 1… 5 → touche 6. |
SlotPos | 0 | Ordre dans l'emplacement (plus petit d'abord, puis par nom). |
Spawnable | false | true : dans le menu de spawn ; sinon seulement par ply:Give. |
AdminOnly | false | Depuis le menu de spawn, réservée aux admins (et à l'hôte). |
Base | — | Une autre classe Lua (héritage des champs et fonctions), ou une arme du jeu ("pistol", "shotgun", "rifle", "crowbar", "physgun", "toolgun"), ou l'id d'une arme de l'éditeur ("addon:<clé>/weapons/<fichier>.json"). Une arme du jeu donne le modèle, les animations (1re et 3e personne) et les valeurs par défaut de Primary (dégâts, cadence, dispersion, chargeur, son, rechargement). |
Model | — | Un prop tenu en main à la place d'une arme ("builtin:…" ou "addon:<clé>/models/…glb") : pas d'animation, mouvements simples (recul, balancement, rechargement). WorldModel est accepté s'il commence par builtin: ou addon:. |
ViewModel | — | Modèle de la vue 1re personne, id d'un modèle d'addon ou du jeu ("addon:<clé>/models/v_arme.glb", "builtin:…" ; les chemins models/…mdl de GMod sont ignorés). Il remplace la vue de la base (sauf si Base est une arme de l'éditeur et que Model est vide : la vue de l'éditeur reste) : voir Modèle de vue personnalisé. Un id inconnu affiche une erreur. |
UseHands, ViewModelFlip | false | Avec ViewModel : ajoute la main du jeu au modèle (pour un modèle sans bras) ; retourne le modèle en miroir (arme à gauche). |
ModelScale, ModelOffset, ModelAngle | 1, Vector(0, 0, 0) | Échelle du prop (0,01 à 20), décalage dans la main (mètres, ±2 ; la poignée est à l'origine, le canon vers −Z), rotation (degrés). |
ModelColor | Color(255, 255, 255) | Teinte du modèle : multiplie la couleur de ses matériaux, comme ent:SetColor sur un prop (alpha < 255 = transparent). Appliquée au modèle tenu en main en 3e personne, à la vue 1re personne d'un prop (Model), du physgun, du toolgun, et à l'arme jetée au sol. Pas sur la vue animée 1re personne d'une arme du jeu (bras compris) ni d'une arme de l'éditeur. Héritée par Base comme les autres champs. |
Icon | — | Image du sélecteur et du HUD (image de materials/ ou "physicore/…png") ; sinon le modèle est rendu. |
Instructions, Purpose | — | Aide affichée en bas du HUD quand l'arme est en main. |
DrawCrosshair | true | false cache le viseur du jeu. |
ReloadTime | base, ou 1,5 | Durée de DefaultReload (secondes). |
Primary.ClipSize | −1 | Taille du chargeur (−1 = pas de chargeur). |
Primary.DefaultClip | ClipSize | Munitions données avec l'arme : le chargeur est rempli, le reste va dans la réserve du type Ammo. Redonner l'arme ajoute DefaultClip à la réserve. |
Primary.Ammo | "none" | Type de munitions (réserve partagée avec ply:GiveAmmo(n, type) et ply:GetAmmo(type)). "none" = réserve illimitée pour recharger. |
Primary.Automatic | false | Tir continu en maintenant le clic. |
Primary.Damage, NumShots (ou NumberofShots), Cone (ou Spread, en degrés), Delay, Sound, Recoil (degrés), Range (m), Force, TakeAmmo, DrySound | base | Utilisés par la fonction PrimaryAttack par défaut. |
Secondary.* | Pareil pour le clic droit (ClipSize, DefaultClip, Ammo, Automatic). |
Fonctions appelées par le jeu
| Fonction | Côté | Quand |
|---|---|---|
SWEP:Initialize() | les deux | Création de l'objet arme du joueur (première utilisation). |
SWEP:PrimaryAttack() | les deux | Clic gauche (répété si Primary.Automatic), en respectant SetNextPrimaryFire. Par défaut : CanPrimaryAttack → ShootBullet(Primary.Damage, Primary.NumShots, Primary.Cone) → ShootEffects → EmitSound(Primary.Sound) → TakePrimaryAmmo(1) → ViewPunch(Primary.Recoil) → SetNextPrimaryFire(CurTime() + Primary.Delay). |
SWEP:SecondaryAttack() | les deux | Clic droit (rien par défaut). |
SWEP:Reload() | les deux | Touche R (par défaut self:DefaultReload()). |
SWEP:Deploy() / SWEP:Holster() | les deux | L'arme est prise en main / rangée. Côté client, Holster qui renvoie false garde l'arme en main (sauf changement imposé par le serveur ou arme retirée). |
SWEP:Think() | les deux | Chaque image physique tant que l'arme est en main (serveur : pour chaque joueur ; client : le joueur local). |
SWEP:Equip(owner) | serveur | L'arme vient d'être donnée. |
SWEP:OnDrop() | serveur | L'arme est jetée (ply:DropWeapon). |
SWEP:OnRemove() | les deux | Le joueur n'a plus l'arme. |
SWEP:DrawHUD() | client | Chaque image après HUDPaint, si l'arme est en main (draw.*, surface.*). |
SWEP:GetViewModelPosition(pos, ang), SWEP:CalcViewModelView(…), SWEP:PreDrawViewModel(…), SWEP:PostDrawViewModel(…), SWEP:ViewModelDrawn(…) | client | Chaque image de la vue 1re personne du propriétaire : voir Modèle de vue personnalisé. |
SWEP:DrawWorldModel(flags) | client | Chaque image où le modèle en main est visible (autres joueurs, 3e personne) : voir plus bas. |
Côté client, PrimaryAttack, SecondaryAttack et Reload ne tournent que chez le propriétaire (prédiction) ; les autres joueurs voient le tir grâce au serveur.
Méthodes de l'arme (self)
| Méthode | Description |
|---|---|
self:GetOwner() / self.Owner | Le joueur. |
self:GetClass(), self:GetPrintName(), self:GetSlot() | Classe, nom, emplacement. |
self:IsValid(), self:IsActive() | Le joueur a toujours l'arme ; elle est en main. |
self:Clip1() / self:Clip2() | Balles dans le chargeur (−1 sans chargeur). Compté par le serveur ; le client affiche sa prédiction. |
self:SetClip1(n) / self:SetClip2(n) | Change le chargeur. |
self:GetMaxClip1() / GetMaxClip2() | Primary.ClipSize / Secondary.ClipSize. |
self:Ammo1() / self:Ammo2() | Réserve du type Primary.Ammo / Secondary.Ammo (0 si "none"). |
self:TakePrimaryAmmo(n) / TakeSecondaryAmmo(n) | Retire n balles du chargeur (de la réserve s'il n'y a pas de chargeur). |
self:CanPrimaryAttack() / CanSecondaryAttack() | false pendant un rechargement, ou chargeur vide (joue Primary.DrySound, par défaut le clic à vide, et bloque 0,25 s). |
self:SetNextPrimaryFire(t) / SetNextSecondaryFire(t) | Heure (CurTime()) avant laquelle le clic est ignoré (60 s plus tard au plus). Aussi GetNextPrimaryFire(), GetNextSecondaryFire(). |
self:ShootBullet(dégâts, nombre, dispersion, portée, poussée) | Tir réel : nombre balles (1 à 32) dans un cône de dispersion degrés (0 à 45), portée en mètres (200 par défaut, 2000 au plus), poussée sur les props (dégâts × 1,5 par défaut). Le serveur trace depuis sa vue du joueur avec la même dispersion que le client, applique les dégâts (tête × 2, réglage « Dégâts entre joueurs », hooks PlayerShouldTakeDamage, ScalePlayerDamage, EntityTakeDamage pour les props) et montre traçantes et impacts aux autres. |
self:FireBullets({Damage, Num, Spread, Distance, Force}) | Variante GMod ; Spread en degrés, ou un Vector(x, y, 0) comme dans GMod (converti). ShootBullet passe par elle. Avant le tir, le hook EntityFireBullets peut l'annuler ou changer la table. |
self:ShootEffects() | Éclair du canon, animation de tir (1re et 3e personne), recul de l'arme. |
self:EmitSound(chemin, niveau, hauteur, volume) | Son sur le joueur. Pendant un tir du joueur, le serveur l'envoie à tous sauf lui (il l'a déjà joué). |
self:SendWeaponAnim(clip, durée) | Animation de la vue 1re personne : "fire", "reload", "draw", "idle", "attack", "attack_hit", "inspect"…, ou les constantes ACT_VM_PRIMARYATTACK ("fire"), ACT_VM_SECONDARYATTACK, ACT_VM_RELOAD, ACT_VM_DRAW, ACT_VM_IDLE, ACT_VM_HOLSTER, ACT_VM_MISSCENTER ("attack"), ACT_VM_HITCENTER ("attack_hit"). "fire", "attack", "reload" et "draw" sont aussi joués en 3e personne. |
self:DefaultReload(), self:IsReloading() | Recharge depuis la réserve en SWEP.ReloadTime secondes (renvoie true si le rechargement commence) ; rechargement en cours ? |
self:ViewPunch(degrés) | Recul de la vue du propriétaire. |
self:SetHoldType(type) | Gardé dans self.HoldType (la pose vient de la base). |
self:SetModelColor(couleur) | Serveur : change la teinte de cette arme du joueur pendant la partie (remplace SWEP.ModelColor) ; envoyée à tous les joueurs, y compris ceux qui arrivent après. Reste valable si l'arme est redonnée ; Color(255, 255, 255) rend les couleurs d'origine. Sans effet côté client. |
self:GetModelColor() | Teinte actuelle : celle de SetModelColor, sinon SWEP.ModelColor (blanc par défaut). |
Bibliothèque weapons
| Fonction | Description |
|---|---|
weapons.Register(SWEP, classe) | Déclare une arme Lua (à faire des deux côtés). |
weapons.GetStored(classe) | La table SWEP, ou nil. |
weapons.Get(classe) | La table SWEP, ou les réglages d'une arme de l'éditeur. |
weapons.IsLua(classe) | true pour une arme Lua. |
weapons.GetSWEPList() | Toutes les tables SWEP. |
weapons.GetList() | Armes des addons, plus les armes Lua Spawnable (kind = "lua"). |
Exemple : pistolet laser
-- gamemodes/mon_mode/weapons/laser_pistol.lua (ou lua/weapons/laser_pistol.lua dans un addon)
SWEP.PrintName = "Pistolet laser"
SWEP.Category = "Armes de test"
SWEP.Slot = 1 -- touche 2
SWEP.Spawnable = true
SWEP.Base = "pistol" -- modèle, animations et sons du pistolet du jeu
SWEP.Instructions = "Clic G : tirer · Clic D : rafale de 3 · R : recharger"
SWEP.Primary.ClipSize = 20
SWEP.Primary.DefaultClip = 60 -- 20 dans le chargeur, 40 en réserve
SWEP.Primary.Ammo = "laser"
SWEP.Primary.Automatic = false
SWEP.Primary.Damage = 18
SWEP.Primary.Delay = 0.2
SWEP.ReloadTime = 1.4
function SWEP:PrimaryAttack()
if not self:CanPrimaryAttack() then return end
self:ShootBullet(18, 1, 0.3, 300) -- dégâts, balles, dispersion (°), portée (m)
self:ShootEffects()
self:EmitSound("physicore/weapons/pistol_fire.wav", 75, 140)
self:TakePrimaryAmmo(1)
self:ViewPunch(0.6)
self:SetNextPrimaryFire(CurTime() + 0.2)
end
function SWEP:SecondaryAttack()
if self:Clip1() < 3 then return end
self:ShootBullet(14, 3, 2.5)
self:ShootEffects()
self:EmitSound("physicore/weapons/pistol_fire.wav", 75, 90)
self:TakePrimaryAmmo(3)
self:SetNextPrimaryFire(CurTime() + 0.6)
self:SetNextSecondaryFire(CurTime() + 0.6)
end
if CLIENT then
function SWEP:DrawHUD()
draw.SimpleText("Laser : " .. self:Clip1(), "Default", ScrW() / 2, ScrH() / 2 + 40, Color(255, 80, 80), 1, 1)
end
end
Pour le donner : ply:Give("laser_pistol") ; des munitions en plus : ply:GiveAmmo(40, "laser").
Exemple : un prop comme arme
SWEP.PrintName = "Planche à claques"
SWEP.Slot = 2
SWEP.Spawnable = true
SWEP.Model = "builtin:plank"
SWEP.ModelScale = 0.35
SWEP.ModelAngle = Vector(0, 90, 0) -- la planche dans l'axe de la vue
SWEP.ModelOffset = Vector(0, 0, -0.2)
SWEP.ModelColor = Color(255, 120, 120) -- planche teintée de rouge
SWEP.Primary.ClipSize = -1
SWEP.Primary.Ammo = "none"
SWEP.DrawCrosshair = false
function SWEP:PrimaryAttack()
self:SendWeaponAnim(ACT_VM_MISSCENTER) -- mouvement de frappe
self:ShootBullet(35, 1, 0, 2, 400) -- portée 2 m, grosse poussée
self:EmitSound("physicore/weapons/crowbar_swing.wav")
self:SetNextPrimaryFire(CurTime() + 0.6)
end
Exemple : héritage
-- weapons/laser_rifle.lua : reprend tout du pistolet laser, en automatique.
SWEP.Base = "laser_pistol"
SWEP.PrintName = "Fusil laser"
SWEP.Slot = 3
SWEP.Primary.Automatic = true
SWEP.Primary.ClipSize = 40
Modèle de vue personnalisé
SWEP.ViewModel donne à l'arme sa propre vue 1re personne : un modèle d'un addon ("addon:<clé>/models/v_arme.glb", importé comme un prop) ou du jeu ("builtin:…"). Il est placé dans le repère de la caméra : son origine est l'œil du joueur, l'avant vers −Z, comme les modèles de vue des armes du jeu (modélise-le bras compris, tel qu'il doit apparaître à l'écran). Il suit le balancement et la marche du jeu. Le modèle en main pour les autres joueurs reste Model / WorldModel, ou celui de la base, et la pose en 3e personne suit la base.
SWEP.UseHands = trueajoute la main du jeu au modèle (pour un modèle d'arme seule).SWEP.ViewModelFlip = trueretourne le modèle en miroir (arme dans la main gauche).- Animations : si le modèle a un
AnimationPlayer(les actions d'un.glbexporté de Blender), ses clips jouent comme ceux des armes du jeu :"idle"en boucle au repos,"draw"à la sortie, etself:SendWeaponAnim(clip, durée)joue un clip du même nom ("fire"prend"attack"s'il n'y a pas de"fire";durée> 0 cale la vitesse du clip). Après chaque clip, le modèle revient à"idle".ShootEffects()joue"fire",DefaultReload()joue"reload"calé surSWEP.ReloadTime. Un clip absent ne fait rien ; un modèle sansAnimationPlayerreste fixe. - Un nœud
Muzzledans le modèle donne le départ des traçantes, un nœudFlashest montré à chaque tir (éclair du canon), comme pour les armes du jeu.
Fonctions client, appelées à chaque image de la vue 1re personne du propriétaire (pour toute arme Lua dont la vue vient d'une arme du jeu, d'un prop ou de ViewModel ; pas quand la base est une arme de l'éditeur sans Model) :
| Fonction | Rôle |
|---|---|
SWEP:GetViewModelPosition(pos, ang) | Reçoit la position et les angles dans le monde du modèle de vue (après balancement et marche) ; renvoyer pos, ang le déplace. Ne rien renvoyer le laisse en place |
SWEP:CalcViewModelView(vm, ancienPos, ancienAng, pos, ang) | Pareil, appelée après la précédente (les deux paires valent la même position) ; renvoyer pos, ang |
Hook CalcViewModelView(wep, vm, ancienPos, ancienAng, pos, ang) | Pareil pour toutes les armes Lua, en dernier |
SWEP:PreDrawViewModel(vm, wep, ply), hook PreDrawViewModel(vm, ply, wep) | Renvoyer true cache le modèle de vue pour cette image |
SWEP:PostDrawViewModel(vm, wep, ply), SWEP:ViewModelDrawn(vm), hook PostDrawViewModel(vm, ply, wep) | Après, quand le modèle est montré (pour dessiner par-dessus avec le dessin 3D, par exemple) |
SWEP:DrawWorldModel(flags) | Chaque image où le modèle en main d'un joueur est visible (chez chaque joueur qui le voit). Si la classe la définit, le modèle n'est montré que si elle appelle self:DrawModel() ; sans elle, il est toujours montré |
vm vaut toujours nil : il n'y a pas d'entité de modèle de vue. SWEP.ViewModelFOV n'est pas géré.
-- weapons/fusil_scifi.lua : modèle de vue d'un addon, abaissé quand on court, caché en visant.
SWEP.PrintName = "Fusil SF"
SWEP.Base = "rifle" -- tir, chargeur et pose en 3e personne du fusil du jeu
SWEP.Spawnable = true
SWEP.ViewModel = "addon:mon_pack/models/v_fusil_sf.glb" -- clips draw, idle, fire, reload
SWEP.WorldModel = "addon:mon_pack/models/w_fusil_sf.glb"
if CLIENT then
function SWEP:GetViewModelPosition(pos, ang)
local ply = self:GetOwner()
if ply:KeyDown(IN_SPEED) and ply:GetVelocity():Length() > 4 then
return pos - ang:Up() * 0.06, ang + Vector(-12, 8, 0)
end
end
function SWEP:PreDrawViewModel(vm, wep, ply)
return ply:KeyDown(IN_ATTACK2) -- lunette : on cache le modèle
end
function SWEP:DrawWorldModel(flags)
if not self:GetOwner():GetNWBool("cache_arme") then self:DrawModel() end
end
end
Hook EntityFireBullets
EntityFireBullets(tireur, balle) est appelé à chaque FireBullets (donc à chaque ShootBullet), côté serveur et côté client (chez le tireur, pour sa prédiction). balle est la table du tir : Damage, Num, Spread, Distance, Force (les champs absents prennent leur valeur par défaut). Renvoyer false annule le tir ; on peut modifier la table (renvoyer true, comme dans GMod) pour changer le tir. Seules les armes Lua passent par ce hook.
-- shared.lua : dégâts doublés pour l'équipe 2, pas de tir dans la zone de départ.
hook.Add("EntityFireBullets", "regles_tir", function(tireur, balle)
if tireur:GetPos():Distance(Vector(0, 0, 0)) < 10 then return false end
if tireur:Team() == 2 then
balle.Damage = (balle.Damage or 10) * 2
return true
end
end)
SWEP.ViewModel ; la pose en 3e personne suit la base, et ViewModelFOV n'est pas géré. Une classe déclarée seulement côté serveur fait des dégâts, mais sans effets immédiats chez le tireur ni icône dans son sélecteur : déclare les armes dans un fichier partagé. Le serveur accepte au plus 30 actions d'arme par seconde et par joueur.Armes au sol et sélection
| Méthode | Côté | Description |
|---|---|---|
ply:Give(id) | serveur | Marche aussi pour une classe Lua (avec Primary.DefaultClip). |
ply:SelectWeapon(id) | serveur / client | Serveur : le joueur prend l'arme (sans le hook PlayerSwitchWeapon). Client : seulement pour LocalPlayer(), en passant par le hook. |
ply:DropWeapon(id) | serveur | L'arme (par défaut celle en main) tombe devant le joueur avec ses munitions (chargeur, et réserve propre pour les armes du jeu). Renvoie true si elle a été jetée. |
ply:GetWeapon(classe) | partagé | L'objet arme Lua si le joueur l'a, sinon nil. |
ply:GetActiveWeaponTable() | partagé | L'objet arme Lua en main, sinon nil (ply:GetActiveWeapon() renvoie toujours l'id en texte). |
ply:GetClip(id) | partagé | Chargeur d'une arme (du jeu, de l'éditeur ou Lua). |
Une arme au sol se ramasse en marchant dessus ou en la visant avec E. Si le joueur a déjà l'arme, il ne prend que les munitions (l'arme reste au sol s'il n'y en a pas). Celui qui l'a jetée ne la ramasse pas en marchant pendant 1,5 s. 64 armes au sol au plus (les plus anciennes disparaissent). Elle ne bloque pas les joueurs.
-- init.lua : on lâche son arme à la mort ; les armes lourdes sont interdites aux civils.
local TEAM_CIVIL = 1 -- numéro d'équipe déclaré avec team.SetUp
hook.Add("PlayerDeath", "lacher_arme", function(victime)
local id = victime:GetActiveWeapon()
if id ~= "" and id ~= "physgun" and id ~= "toolgun" then victime:DropWeapon(id) end
end)
hook.Add("PlayerCanPickupWeapon", "civils", function(ply, id)
if ply:Team() == TEAM_CIVIL and (id == "rifle" or id == "shotgun") then return false end
end)
concommand.Add("jeter", function(ply) ply:DropWeapon() end)
-- shared.lua : pas de changement d'arme pendant qu'on vise avec le clic droit.
hook.Add("PlayerSwitchWeapon", "pas_en_visant", function(ply, ancienne, nouvelle)
if ply:IsKeyDown(MOUSE_RIGHT) then return true end
end)
Outils de toolgun (TOOL)
Où les écrire
| Où | Fichier |
|---|---|
| Gamemode | stools/<nom>.lua |
| Addon | lua/weapons/gmod_tool/stools/<nom>.lua |
| N'importe quel fichier partagé | tool.Register(TOOL, "nom") |
Chargé côté serveur et côté client. La table globale TOOL est prête (TOOL.ClientConVar = {}) ; le nom de l'outil est le nom du fichier en minuscules (minuscules, chiffres et _, pas le nom d'un outil du jeu). L'outil apparaît dans la liste des outils du menu de spawn.
Champs de TOOL
| Champ | Rôle |
|---|---|
TOOL.Name | Nom dans la liste des outils et sur l'écran du toolgun. |
TOOL.Category | Catégorie de la liste ("Lua" par défaut) ; peut être une catégorie du jeu ("Construction", "Édition"…). |
TOOL.Desc (ou Help, ou Information en texte) | Aide affichée en bas du HUD et dans le menu. |
TOOL.ClientConVar = { cle = défaut } | Réglages du joueur. Un nombre (ou le texte d'un nombre, comme "255" dans GMod) donne un champ numérique, un booléen une case à cocher, une Color un sélecteur de couleur, un autre texte un champ texte. Gardés sur l'ordinateur du joueur. 64 au plus. |
function TOOL.BuildCPanel(panel) | Client, fonction statique (avec un point) : construit le panneau de réglages du menu de spawn à la place des champs automatiques. |
Fonctions appelées par le jeu
| Fonction | Quand |
|---|---|
TOOL:LeftClick(trace) | Clic gauche. Renvoyer true montre le tir du toolgun (traçante). |
TOOL:RightClick(trace) | Clic droit. |
TOOL:Reload(trace) | Touche R. |
TOOL:Think() | Chaque image physique tant que l'outil est en main. |
TOOL:Deploy() / TOOL:Holster() | Le toolgun est sorti sur cet outil / l'outil est quitté. |
Ces fonctions tournent des deux côtés : côté client pour le retour immédiat, mais les modifications du monde se font côté serveur (if CLIENT then return true end). trace contient Hit, HitPos, HitNormal, HitWorld, HitNonWorld, Entity (prop touché ou nil), StartPos (les yeux), Normal (direction) et Fraction.
Méthodes de l'outil (self)
| Méthode | Description |
|---|---|
self:GetOwner() / self.Owner | Le joueur. |
self:GetMode() | Nom de l'outil. |
self:GetClientInfo(cle) | Réglage du joueur en texte (booléen "1" / "0", couleur "r g b a"). Côté serveur : les valeurs envoyées avec le dernier clic (ou quand le joueur change un réglage), vérifiées. |
self:GetClientNumber(cle, défaut), self:GetClientBool(cle) | Réglage en nombre, en booléen. |
self:GetStage() / self:SetStage(n) | Étape libre, pour les outils en plusieurs clics. |
Panneau de réglages
Méthode de panel | Description |
|---|---|
Help(texte), ControlHelp(texte), Header(texte) | Textes. |
NumSlider(texte, convar, min, max, décimales) | Champ numérique lié à un réglage. convar = "<outil>_<cle>" (style GMod) ou "<cle>". |
CheckBox(texte, convar), TextEntry(texte, convar) | Case à cocher, champ texte. |
ComboBox(texte, convar, options) | Liste : { "a", "b" } ou { ["Libellé"] = valeur }. |
ColorPicker(texte, convar) | Couleur (réglage Color), ou ColorPicker(texte, "x_r", "x_g", "x_b", "x_a") pour 3 ou 4 réglages de 0 à 255. |
Button(texte, fonction) | Bouton qui appelle la fonction (client). |
AddItem(panneau) | Ajoute un panneau créé avec vgui.Create. |
AddControl(type, params) | Style GMod : "Header" / "Label" (Description / Text), "Slider" (Label, Command, Min, Max, Type = "Integer"), "CheckBox", "TextBox", "Color" (Red, Green, Blue, Alpha). |
ClearControls() | Vide le panneau. |
Un réglage absent de ClientConVar affiche une erreur Lua. 200 contrôles au plus. Bibliothèque : tool.Register(TOOL, nom), tool.Get(nom) (la table TOOL), tool.GetList() (noms triés).
Exemple : peinture rouge
-- gamemodes/mon_mode/stools/rouge.lua (ou lua/weapons/gmod_tool/stools/rouge.lua)
TOOL.Name = "Peinture rouge"
TOOL.Category = "Édition"
TOOL.Desc = "Clic G : peindre en rouge · Clic D : couleur d'origine · R : intensité actuelle"
TOOL.ClientConVar = { intensite = "255", transparent = false }
function TOOL:LeftClick(trace)
local ent = trace.Entity
if not IsValid(ent) then return false end
if CLIENT then return true end -- le client montre juste le tir
local r = math.Clamp(self:GetClientNumber("intensite", 255), 0, 255)
local a = self:GetClientBool("transparent") and 120 or 255
ent:SetColor(Color(r, 0, 0, a))
return true
end
function TOOL:RightClick(trace)
if not IsValid(trace.Entity) then return false end
if SERVER then trace.Entity:SetColor(Color(255, 255, 255)) end
return true
end
function TOOL:Reload(trace)
if CLIENT then return false end
self:GetOwner():ChatPrint("Intensité actuelle : " .. self:GetClientInfo("intensite"))
return false
end
function TOOL.BuildCPanel(panel)
panel:Help("Peint les props en rouge.")
panel:NumSlider("Intensité du rouge", "rouge_intensite", 0, 255, 0)
panel:CheckBox("Semi-transparent", "rouge_transparent")
end
Toolgun, physgun et touche E
| Hook | Côté | Description |
|---|---|---|
CanTool(ply, trace, outil) | serveur et client | Avant chaque action du toolgun (outils du jeu et outils Lua ; clic, clic droit, R). false refuse. outil : id de l'outil ("remover", "color", "weld"…, ou le nom d'un outil Lua). Pour une contrainte, appelé pour chacun des deux props. Côté client, l'action n'est même pas envoyée. |
PhysgunPickup(ply, ent) | serveur | false : le physgun ne peut pas l'attraper. |
PhysgunDrop(ply, ent) | serveur | Le joueur lâche un prop du physgun. |
OnPhysgunFreeze(ply, ent) | serveur | Clic droit en tenant un prop : false le lâche sans le figer. |
CanPlayerUnfreeze(ply, ent) | serveur | R au physgun sur un prop figé : false le garde figé. |
PlayerUse(ply, ent) | serveur | E sur n'importe quel prop à portée (4 m du bord du prop, plus pour un véhicule) : false bloque l'usage (monter dans un véhicule, ENT:Use, bouton d'un gadget, ramasser une arme au sol). 8 usages par seconde au plus. |
-- Protection des props : seul le propriétaire (ou un admin) peut les modifier.
hook.Add("CanTool", "proprio", function(ply, trace, outil)
local ent = trace and trace.Entity
if IsValid(ent) and ent:GetOwner() ~= ply and not ply:IsAdmin() then
if SERVER then ply:ChatPrint("Ce prop n'est pas à toi.") end
return false
end
end)
-- Seule la police peut monter dans les voitures de police.
local TEAM_POLICE = 2
hook.Add("PlayerUse", "voitures_police", function(ply, ent)
if ent:IsVehicle() and ent:GetNWBool("police") and ply:Team() ~= TEAM_POLICE then return false end
end)
Voir aussi la liste complète des hooks.