Hooks

Les événements auxquels un addon réagit avec hook.Add, et qu'un gamemode définit avec function GM:Événement(...).

Valeurs de retour

Pour un même événement, les hooks des addons sont appelés les uns après les autres, puis la fonction du gamemode. Dès qu'un hook renvoie une valeur (autre que nil), la suite n'est pas appelée et cette valeur est utilisée par le jeu, comme dans Garry's Mod. Ne renvoie donc rien si tu veux seulement observer l'événement. Les valeurs par défaut viennent du gamemode (Base, Sandbox…).

Pour les hooks qui autorisent ou bloquent quelque chose (CanTool, PlayerSpawnProp, HUDShouldDraw…), seuls true et false comptent : une autre valeur (texte, nombre, table) est ignorée comme si le hook ne renvoyait rien.

Liste des hooks

ÉvénementArgumentsValeur de retour
Initialize——
Thinkdt—
Tick——
PostGamemodeLoaded——
OnReloaded——
ShutDown——
InitPostEntity——
PostCleanupMap——
CheckPasswordsteamID64, ip, mdpServeur, mdpDonné, nomfalse, "raison" refuse, true laisse entrer
PlayerInitialSpawnply—
PlayerAuthedply, steamid, uniqueid—
PlayerSpawnply—
PlayerLoadoutply—
PlayerNoClipplytrue pour autoriser
PlayerGiveWeaponply, armetrue pour accepter
PlayerSetModelply, idfalse refuse le playermodel choisi dans Apparence
PlayerSetBodygroupply, groupe, option (à partir de 0)false refuse ce changement de tenue choisi dans Apparence (le joueur garde l'ancienne option et un message le prévient). ply:SetBodygroup ne passe pas par ce hook.
PlayerSpawnNPCply, classetrue pour autoriser l'onglet PNJ
PlayerSpawnedNPC / NPCSpawnedply, pnj / pnj—
NPCTakeDamagepnj, dégâts, attaquant, typefalse annule, un nombre remplace
OnNPCKilledpnj, attaquant, cause—
NPCReachedGoal / NPCRemovedpnj, pos / pnj—
PlayerShouldTakeDamageply, cause, attaquantfalse pour annuler
ScalePlayerDamageply, hitgroup, dmginfotrue annule le dégât
PlayerHurtply, attaquant, vieRestante, dégâts—
OnPlayerHitGroundply, dansEau, surFlotteur, vitessetrue : pas de dégâts de chute
GetFallDamageply, vitesseun nombre : les dégâts de chute
PlayerDeathply, cause, attaquant—
PlayerDeathNoticeply, cause, attaquantfalse ou texte de remplacement
AddDeathNotice clienttueur, équipeTueur, inflicteur, victime, équipeVictimeune valeur : pas de ligne dans le fil par défaut
DrawDeathNotice clientx, yune valeur cache le fil par défaut
CanPlayerSuicideplyfalse bloque /kill
PlayerChangedTeamply, ancienne, nouvelle—
PlayerCanRespawnplyfalse empêche de réapparaître d'un clic
EntityTakeDamageent, attaquant, dégâts, armetrue annule la poussée
PlayerSayply, textetexte de remplacement, ou "" pour bloquer
PlayerCanSeePlayersChattexte, équipeSeulement, auditeur, auteurfalse : cet auditeur ne voit pas le message
PlayerCanHearPlayersVoiceauditeur, parleurfalse pour couper la voix
PlayerDisconnectedply—
PlayerSpawnPropply, modèlefalse pour refuser
PropSpawnedprop, ply—
PlayerSpawnedPropply, modèle, ent—
OnEntityCreatedent—
EntityRemovedent—
EntityNetworkedVarChangedent, nom, ancienne, nouvelle—
ShouldCollideent1, ent2false : ils se traversent
EntityEmitSounddonnéesfalse bloque le son, true le joue modifié
EntityFireBulletstireur, ballefalse annule le tir, true l'applique modifié
ProtectionCanTouchply, ent, actiontrue / false tranche avant la protection des props
PhysgunPickupply, ent (prop, véhicule ou PNJ)false pour refuser
PhysgunDropply, ent—
OnPhysgunFreezeply, propfalse lâche sans figer
CanPlayerUnfreezeply, propfalse garde le prop figé
CanToolply, trace, outilfalse refuse l'action du toolgun
PlayerUseply, entfalse bloque E
PlayerSwitchWeaponply, ancienne, nouvelletrue bloque le changement d'arme
PlayerCanPickupWeaponply, idfalse : pas de ramassage
PlayerButtonDownply, touche—
PlayerButtonUpply, touche—
KeyPressply, IN_…—
KeyReleaseply, IN_…—
PlayerSwitchFlashlightply, alluméefalse refuse
PlayerStartGestureply, nomfalse refuse le geste
TriggerStartTouchzone, ent—
TriggerEndTouchzone, ent—
CanPlayerEnterVehicleply, veh, placefalse pour refuser
PlayerEnteredVehicleply, veh, place—
PlayerLeaveVehicleply, veh—
CanExitVehicleply, vehfalse empêche de descendre avec E
CanUndoply, entréefalse garde l'entrée (pas d'annulation)
OnUndonom, texte, ply—
CanCleanupply, catégoriefalse refuse le nettoyage
CanDuplicateply, listefalse refuse le collage d'une dupe
PreDuplicate / PostDuplicateply, liste / ply, créées—
PlayerSpawnSENTply, classefalse refuse l'entité (onglet Entités)
PlayerSpawnedSENTply, ent—
CanPropertyply, nom, entfalse cache et refuse une action du menu contextuel
EnvChangedquoi—
PlayerVRGrabply, ent, mainfalse empêche d'attraper
PlayerVRDropply, ent, main—
ClientReady client——
PlayerFireWeaponply, idfalse annule le tir (armes d'addon)
PlayerReloadply, idfalse empêche le rechargement
WeaponAnimEvent (client)ply, id, nom— Un « Événement Lua » d'une animation faite dans l'éditeur d'arme
WeaponExplosionpos, rayon, attaquant, id—
HUDPaint client——
PreDrawHUD, HUDPaintBackground, PostDrawHUD client——
HUDShouldDraw clientnomfalse pour cacher
SpawnMenuOpen client—false pour bloquer
ScoreboardShow client—true : le gamemode affiche son tableau
ScoreboardHide client——
OnPlayerChat clientply, texte, équipe, morttrue cache la ligne par défaut
ChatText clientindex, nom, texte, typetrue cache la ligne
CalcView clientply, origine, angles, fov, znear, zfartable {origin, angles, fov, drawviewer}
CalcViewModelView clientarme, vm, ancPos, ancAng, pos, angpos, ang du modèle de vue
PreDrawViewModel / PostDrawViewModel clientvm, ply, armetrue cache le modèle de vue (Pre)
CalcMainActivity clientply, vitessenom d'un clip du playermodel
UpdateAnimation clientply, vitesse, vitesseMaxvitesse de lecture
DoAnimationEvent clientply, évènement, actiontrue : pas de geste ; un nom de clip le remplace
PrePlayerDraw / PostPlayerDraw clientplytrue cache le joueur (Pre)
PlayerFootstep clientply, pos, pied, son, volumetrue : pas de bruit de pas
PlayerBindPress clientply, action, appuyétrue bloque l'action
ContextMenuOpen client—false empêche d'ouvrir le menu contextuel
OnContextMenuOpen / OnContextMenuClose client——
AddToolMenuTabs, AddToolMenuCategories, PopulateToolMenu client——
StartCommand clientply, cmd—
CreateMove clientcmd—
SetupMove clientply, mv, cmd—
Move clientply, mvtrue remplace le déplacement du jeu
FinishMove clientply, mv—
PreDrawHalos client——
PostDrawOpaqueRenderables clientfalse, false—
PostDrawTranslucentRenderables clientfalse, false—
PreRender, PostRender client——
RenderScreenspaceEffects client——
ForceDermaSkin client—nom d'une peau Derma

Sauf mention client, les événements sont déclenchés sur le serveur. Initialize, Think, ShutDown, EntityRemoved, PlayerButtonDown, PlayerButtonUp, KeyPress, KeyRelease, CanTool, CanProperty, PlayerSwitchWeapon, Tick, PostGamemodeLoaded, OnReloaded, OnEntityCreated, EntityNetworkedVarChanged, ShouldCollide, EntityEmitSound et EntityFireBullets existent des deux côtés.

Les armes et outils Lua ont leurs propres fonctions (SWEP:PrimaryAttack, TOOL:LeftClick…).

Les entités scriptées ont en plus leurs propres fonctions (ENT:Use, ENT:PhysicsCollide, ENT:KeyValue…).

Initialize

Une fois, quand tous les scripts sont chargés (juste après PostGamemodeLoaded), et après chaque redémarrage des scripts (bouton Tester, F5). Un simple enregistrement de fichier lance OnReloaded à la place.

Think

Appelé à chaque image physique (60 fois par seconde). dt est la durée de l'image en secondes (≈ 0,0167). Garde ce code léger.

local total = 0
hook.Add("Think", "monaddon_horloge", function(dt)
	total = total + dt
	if total >= 60 then
		total = 0
		PrintMessage("Une minute de plus sur le serveur.")
	end
end)

Tick

Serveur et client, à chaque image physique (60 fois par seconde), juste après Think, sans argument. C'est le nom de Garry's Mod pour le même moment : utilise l'un ou l'autre.

PostGamemodeLoaded

Serveur et client, une fois, quand tous les fichiers du gamemode et des addons ont été lancés, juste avant Initialize.

OnReloaded

Serveur et client : un fichier Lua enregistré pendant la partie vient d'être ré-exécuté (autorefresh), sans redémarrage. Les variables, joueurs et entités sont gardés : c'est l'endroit pour reconstruire ce qui dépend du fichier (menus ouverts, caches…). Le bouton Tester (F5) redémarre tout et lance Initialize à la place.

hook.Add("OnReloaded", "monaddon_menu", function()
	if CLIENT and IsValid(MonAddonMenu) then MonAddonMenu:Remove() end
end)

ShutDown

Serveur et client : la partie se termine, la map change (game.ChangeMap), le serveur s'arrête ou les scripts sont rechargés. C'est le dernier moment pour sauvegarder.

local scores = {} -- rempli pendant la partie
hook.Add("ShutDown", "monaddon_sauvegarde", function()
	if SERVER then file.Write("scores.json", util.TableToJSON(scores)) end
end)

InitPostEntity et PostCleanupMap

Serveur. InitPostEntity est appelé une fois par lancement des scripts, quand la map est chargée et ses props et entités placées créés (aussi sur une map intégrée) : c'est là qu'on lit les points et zones de la map, encore vides pendant Initialize. PostCleanupMap est appelé après game.CleanUpMap(), quand les props et entités de la map ont été recréés.

CheckPassword

Serveur, à la connexion d'un joueur, avant tout le reste. Arguments : steamID64, ip, mot de passe du serveur, mot de passe donné par le joueur, nom. return false, "raison" refuse (la raison est affichée au joueur) ; return true laisse entrer sans vérifier le mot de passe ; ne rien renvoyer applique les règles normales. Les bans et le nombre de places restent toujours vérifiés.

local liste_blanche = { ["76561198000000000"] = true }
hook.Add("CheckPassword", "monserveur_whitelist", function(steamid64, ip, mdp_serveur, mdp_donne, nom)
	if not liste_blanche[steamid64] then
		return false, "Serveur privé : demande l'accès sur notre Discord."
	end
end)

PlayerInitialSpawn

Un joueur apparaît pour la première fois après avoir rejoint (ou l'hôte au lancement de la partie). Idéal pour un message de bienvenue.

PlayerAuthed

Serveur : un joueur arrive, juste avant PlayerInitialSpawn. La vérification Steam est déjà faite à ce moment (un joueur non vérifié n'entre pas). steamid et uniqueid valent tous deux son SteamID64 en texte.

PlayerSpawn

Un joueur apparaît : à son arrivée (juste après PlayerInitialSpawn) et à chaque réapparition après une mort.

hook.Add("PlayerSpawn", "monaddon_armure", function(ply)
	ply:SetArmor(50)
end)

PlayerLoadout

Le gamemode Base l'appelle à chaque apparition après avoir retiré les armes : donne ici les armes de départ avec ply:Give(...) (identifiants dans Armes). Sandbox donne toutes les armes : physgun, toolgun, pied-de-biche, pistolet, fusil à pompe et fusil d'assaut.

function GM:PlayerLoadout(ply)
	ply:Give("crowbar")
	ply:Give("pistol")
end

PlayerGiveWeapon

Un joueur clique sur une arme dans l'onglet Armes du menu de spawn. Renvoie true pour la lui donner (avec un plein de munitions) ; sinon il reçoit un message de refus. Base renvoie false, Sandbox true. ply:Give dans un script n'appelle pas ce hook.

-- Seuls les admins peuvent prendre le fusil d'assaut.
hook.Add("PlayerGiveWeapon", "monaddon_armes", function(ply, arme)
	if arme == "rifle" and not ply:IsAdmin() then
		return false
	end
end)

PlayerNoClip

Appelé à chaque apparition : renvoie true pour que le joueur puisse utiliser le noclip (V). Base renvoie false, Sandbox true. Un script peut aussi utiliser ply:SetNoclipAllowed(b).

PlayerShouldTakeDamage

Avant chaque dégât (chute, prop, arme…) : renvoie false pour l'annuler. attaquant est le joueur qui a tiré ou frappé avec une arme du jeu, sinon nil. ply:Kill() et ply:SetHealth(0) passent toujours. Les armes ne blessent les autres joueurs que si le réglage serveur pvp (« Dégâts entre joueurs ») est activé.

-- Pas de tir ami entre coéquipiers.
hook.Add("PlayerShouldTakeDamage", "monmode_equipes", function(ply, cause, attaquant)
	if attaquant and attaquant:Team() ~= 0 and attaquant:Team() == ply:Team() then
		return false
	end
end)

ScalePlayerDamage

Avant chaque dégât sur un joueur (après PlayerShouldTakeDamage). Renvoie true pour l'annuler, ou modifie dmginfo. hitgroup vaut HITGROUP_HEAD (tête), HITGROUP_CHEST (torse) ou HITGROUP_LEFTLEG (jambes) pour les balles des armes du jeu et des armes d'addon, sinon HITGROUP_GENERIC.

Méthode de dmginfoRôle
:GetDamage(), :SetDamage(n), :ScaleDamage(f), :AddDamage(n), :SubtractDamage(n)Lire ou changer le montant
:GetAttacker(), :GetInflictor()Le joueur responsable, l'id de l'arme
:GetDamageType(), :IsDamageType(DMG_…)Type : DMG_GENERIC, DMG_BULLET, DMG_CLUB (corps à corps), DMG_BLAST, DMG_FALL, DMG_BURN, DMG_CRUSH, DMG_SLASH
:IsBulletDamage(), :IsFallDamage(), :IsExplosionDamage()Raccourcis
:GetCause(), :GetHitGroup()Texte de mort, zone touchée
-- Moitié des dégâts dans la tête, double dans les jambes, pas de dégâts de chute.
hook.Add("ScalePlayerDamage", "zones", function(ply, hitgroup, dmg)
	if hitgroup == HITGROUP_HEAD then dmg:ScaleDamage(0.5) elseif hitgroup == HITGROUP_LEFTLEG then dmg:ScaleDamage(2) end
	if dmg:IsFallDamage() then return true end
end)

PlayerHurt

Après chaque dégât sur un joueur, y compris le coup fatal : attaquant (ou nil), la vie restante et les dégâts subis.

hook.Add("PlayerHurt", "monmode_touche", function(ply, attaquant, vie, degats)
	if IsValid(attaquant) and attaquant ~= ply then
		attaquant:ChatPrint("Touché ! " .. degats .. " dégâts (" .. vie .. " PV restants)")
	end
end)

OnPlayerHitGround et GetFallDamage

Serveur : un joueur touche le sol après une chute. OnPlayerHitGround(ply, dansEau, surFlotteur, vitesse) (vitesse de chute en m/s ; surFlotteur vaut toujours false) : renvoie true pour qu'il ne prenne aucun dégât. Sinon, au-delà d'environ 13,4 m/s, GetFallDamage(ply, vitesse) peut renvoyer les dégâts (10 par défaut ; 0 = aucun). OnPlayerHitGround est appelé dès 2 m/s si un hook ou le gamemode l'utilise.

-- Dégâts de chute qui grandissent avec la vitesse.
hook.Add("GetFallDamage", "chute_realiste", function(ply, vitesse)
	return math.floor((vitesse - 13) * 8)
end)

PlayerDeath

Un joueur vient de mourir. cause est la fin de la phrase affichée dans le chat, par exemple "s'est écrasé au sol", "s'est suicidé", "est mort" ou "a été abattu par Alex (pistolet)". attaquant est le tueur (arme du jeu), sinon nil ; il gagne automatiquement un point (Frags).

PlayerDeathNotice

Avant l'annonce d'une mort dans le chat. Renvoie false (ou "") pour ne rien annoncer, ou un texte pour remplacer l'annonce (une phrase complète).

hook.Add("PlayerDeathNotice", "monmode_annonce", function(ply, cause, attaquant)
	if attaquant then return attaquant:Nick() .. " a éliminé " .. ply:Nick() .. "." end
	return false -- les autres morts restent discrètes
end)

AddDeathNotice et DrawDeathNotice

Client, pour le fil des éliminations en haut à droite. AddDeathNotice(tueur, équipeTueur, inflicteur, victime, équipeVictime) : une mort arrive ; les noms sont des textes (tueur vaut "" et son équipe -1 s'il n'y a personne ; un PNJ tueur donne son nom), inflicteur la classe de l'arme du tueur ou la cause ("fall", "explosion", "suicide"…). Un hook qui renvoie une valeur, ou une fonction GM:AddDeathNotice, remplace l'ajout au fil par défaut. DrawDeathNotice(x, y) (position du fil en fractions de l'écran) est appelé pendant HUDPaint quand le fil a des lignes : renvoyer une valeur le cache.

-- Remplace le fil par des lignes de chat.
hook.Add("AddDeathNotice", "fil_chat", function(tueur, eqT, arme, victime, eqV)
	chat.AddText(Color(255, 120, 80), tueur ~= "" and (tueur .. " [" .. arme .. "] ") or "", Color(255, 255, 255), victime)
	return true
end)

CanPlayerSuicide

Un joueur tape /kill : renvoie false pour l'en empêcher (par exemple pendant une manche).

PlayerChangedTeam

Après ply:SetTeam, si l'équipe change : ply, ancienne, nouvelle.

hook.Add("PlayerChangedTeam", "monmode_equipe", function(ply, ancienne, nouvelle)
	PrintMessage(ply:Nick() .. " rejoint " .. team.GetName(nouvelle))
end)

PlayerCanRespawn

Un joueur mort clique pour réapparaître. Renvoie false pour refuser : il reste mort, par exemple jusqu'à la fin de la manche. ply:Spawn() le fait toujours réapparaître.

EntityTakeDamage

Une arme touche un prop : balles, coups, projectiles et explosions, des armes du jeu comme des armes d'addon. attaquant est le tireur, dégâts ce qu'aurait pris un joueur (après la baisse avec la distance) et arme l'id de l'arme. Renvoie true pour que le prop ne soit pas poussé. Aussi lancé par ent:TakeDamage(montant, attaquant, inflicteur) (avec arme = l'inflicteur, sans poussée). Ensuite, si aucun hook n'a renvoyé true, le jeu appelle ENT:OnTakeDamage(dmginfo) de l'entité scriptée touchée. Voir l'exemple Prop Hunt dans Objets.

PlayerSay

Un joueur envoie un message dans le chat (hors commandes /…, qui passent par concommand).

hook.Add("PlayerSay", "monaddon_filtre", function(ply, texte)
	if string.find(string.lower(texte), "gros mot") then
		ply:ChatPrint("Message bloqué.")
		return ""
	end
end)

PlayerCanSeePlayersChat

Pour chaque joueur qui pourrait lire un message du chat : renvoie false pour que cet auditeur ne le voie pas (chat de proximité, chat des morts…). équipeSeulement vaut toujours false.

-- Chat de proximité : 20 m.
hook.Add("PlayerCanSeePlayersChat", "monmode_proximite", function(texte, equipe, auditeur, auteur)
	if IsValid(auteur) and auditeur:GetPos():Distance(auteur:GetPos()) > 20 then return false end
end)

PlayerCanHearPlayersVoice

Chat vocal : parleur parle (touche X par défaut, modifiable dans Options → Touches) et le serveur demande si auditeur peut l'entendre. Renvoie false pour qu'il ne l'entende pas ; ne renvoie rien pour laisser tout le monde s'entendre. La réponse est gardée une seconde pour chaque paire de joueurs. En plus de cette règle, chaque joueur peut couper la voix d'un autre pour lui seul (maintenir Tab et cliquer sur son micro dans le tableau des scores) et choisir des voix en 3D, qui viennent de la tête du joueur et baissent avec la distance (Options → Audio, activé par défaut).

-- Chacun n'entend que son équipe.
hook.Add("PlayerCanHearPlayersVoice", "monmode_equipes", function(auditeur, parleur)
	return auditeur:Team() == parleur:Team()
end)

PlayerDisconnected

Un joueur quitte la partie. Il est encore valide pendant l'appel (tu peux lire son nom, ses props…).

PlayerSpawnProp

Un joueur demande à faire apparaître un prop : depuis le menu de spawn, en collant une dupe, ou en posant un gadget avec le toolgun (gadget:thruster…). Renvoie false pour refuser. N'est pas appelé pour ents.SpawnProp.

hook.Add("PlayerSpawnProp", "monaddon_pas_de_beton", function(ply, modele)
	if modele == "builtin:concrete_block" then
		ply:ChatPrint("Le béton est interdit ici !")
		return false
	end
end)

PropSpawned

Un prop vient d'apparaître. ply est le joueur qui l'a créé, ou nil s'il vient de ents.SpawnProp ou de la map (props posés dans l'éditeur). Teste toujours if ply then avant d'utiliser le joueur.

PlayerSpawnedProp

Serveur : le nom de Garry's Mod pour PropSpawned quand un joueur a créé le prop : ply, modèle (l'id du prop) et l'entité. Pas d'appel pour ents.SpawnProp ni pour les props de la map.

OnEntityCreated

Serveur et client : un prop, un véhicule ou une entité scriptée vient d'apparaître (y compris ceux de la map et de ents.SpawnProp). Appelé à l'image suivante, quand l'entité est prête ; pas pour les joueurs ni les PNJ. Seulement si un hook ou le gamemode l'utilise.

Physgun et toolgun

Serveur. PhysgunDrop(ply, prop) : le joueur lâche un prop du physgun (information). OnPhysgunFreeze(ply, prop) : clic droit en tenant un prop ; false le lâche sans le figer. CanPlayerUnfreeze(ply, prop) : R au physgun sur un prop figé ; false le garde figé.

CanTool

Serveur et client, avant chaque action du toolgun (outils du jeu et outils Lua ; clic, clic droit, R). outil est l'id de l'outil ("remover", "color", "weld"…, ou le nom d'un outil Lua). Renvoie false pour refuser ; pour une contrainte, le hook est appelé pour chacun des deux props. Côté client, l'action refusée n'est même pas envoyée.

-- Seul le propriétaire (ou un admin) peut modifier un prop.
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)

PlayerUse

Serveur : le joueur appuie sur E en visant un prop à portée (4 m du bord du prop, plus pour un véhicule). Renvoie false pour bloquer l'usage : monter dans un véhicule, ENT:Use, bouton d'un gadget, ramasser une arme au sol. 8 usages par seconde au plus.

PlayerSwitchWeapon

Serveur et client : le joueur change d'arme (ancienne et nouvelle sont des ids : "pistol", une classe Lua…). Renvoie true pour bloquer le changement (client : avant le changement ; serveur : le joueur est renvoyé sur l'ancienne arme). ply:SelectWeapon côté serveur ne passe pas par ce hook.

PlayerCanPickupWeapon

Serveur : le joueur marche sur une arme au sol ou la vise avec E. Renvoie false pour qu'il ne la ramasse pas. Voir Armes au sol.

EntityRemoved

Serveur et client : un prop ou une entité va disparaître. Elle est encore valide pendant l'appel.

EntityNetworkedVarChanged

Serveur et client : une variable NW a changé (ent, nom, ancienne, nouvelle), après le proxy de ent:SetNWVarProxy. Côté client, à l'arrivée de la nouvelle valeur. Pour une variable globale (SetGlobal…), ent vaut nil.

ShouldCollide

Sur chaque machine (le serveur, et chaque joueur pour ce qu'il simule) : un corps arrive à moins de 50 cm d'une entité marquée par ent:SetCustomCollisionCheck(true). Renvoie false pour que les deux se traversent (jusqu'à ent:CollisionRulesChanged()). Le même code doit donner la même réponse partout : mets-le dans un fichier partagé. Voir Entités scriptées.

hook.Add("ShouldCollide", "fantome", function(a, b)
	if a:GetClass() == "mur_fantome" and istable(b) and b.IsPlayer and b:IsPlayer() then return false end
end)

EntityEmitSound

Serveur et client, avant chaque son joué par Lua (ent:EmitSound, sound.Play), seulement si un hook ou le gamemode l'utilise. données : SoundName, OriginalSoundName, Pos, SoundLevel, Pitch, Volume, Entity. Renvoie false pour bloquer le son, true pour le jouer avec les champs que tu as changés.

-- Tous les sons plus graves pendant le ralenti.
hook.Add("EntityEmitSound", "ralenti", function(data)
	if GetGlobalBool("ralenti") then data.Pitch = data.Pitch * 0.6 return true end
end)

EntityFireBullets

Serveur et client : une arme Lua tire avec SWEP:FireBullets(balle) (aussi SWEP:ShootBullet, qui passe par là). tireur est le joueur, balle la table { Damage, Num, Spread, Distance, Force }. Renvoie false pour annuler le tir, true (ou rien) pour l'appliquer avec la table modifiée.

-- Munitions explosives : double dégâts pour tout le monde.
hook.Add("EntityFireBullets", "double", function(tireur, balle)
	balle.Damage = (balle.Damage or 10) * 2
	return true
end)

PhysgunPickup

Un joueur essaie d'attraper un prop, un véhicule ou un PNJ (ent:IsNPC()) avec le physgun. Renvoie false pour l'en empêcher. Ce hook passe après la protection des props (qui a déjà refusé les props des autres selon les règles du serveur) : il ne peut que refuser en plus. Les PNJ ne sont attrapables que si le gamemode le permet : Base les refuse, Sandbox les accepte (en multijoueur, la protection décide pour ceux des autres). Un PNJ tenu reste debout, suit le faisceau et retombe quand on le lâche (le clic droit le lâche aussi : un PNJ ne se fige pas).

-- Les props lourds ne s'attrapent pas, même les siens.
hook.Add("PhysgunPickup", "monaddon_lourds", function(ply, ent)
	if ent.GetMass and ent:GetMass() > 2000 then -- les PNJ n'ont pas de GetMass
		return false
	end
end)

ProtectionCanTouch

Serveur (et client, pour l'affichage à côté du viseur et le refus immédiat) : avant chaque règle de la protection des props. ent est un prop, un véhicule ou un PNJ ; action vaut "physgun", "toolgun", "use", "damage" ou "enter" (monter dans un véhicule). Renvoie true pour autoriser, false pour refuser (même au propriétaire), rien pour laisser décider les règles du menu. Les hooks PhysgunPickup, CanTool, PlayerUse… passent ensuite. Pour couper toute la protection dans un gamemode : GM.PropProtection = false (dans shared.lua, pour que les joueurs le sachent aussi).

-- Gamemode RP : la police peut fouiller (toolgun) et déplacer tous les véhicules.
hook.Add("ProtectionCanTouch", "rp_police", function(ply, ent, action)
	if ply:Team() == TEAM_POLICE and ent.IsVehicle and ent:IsVehicle() and (action == "physgun" or action == "toolgun") then
		return true
	end
end)

PlayerButtonDown

Un joueur appuie sur une touche ou un bouton de souris (PlayerButtonUp quand il la relâche). touche est un code KEY_* ou MOUSE_*. Côté client, seulement pour son propre joueur ; côté serveur, pour chaque joueur. Pas d'appel pendant la saisie de texte ni dans les menus du jeu. Voir Touches et souris.

hook.Add("PlayerButtonDown", "monaddon_f3", function(ply, touche)
	if CLIENT and touche == KEY_F3 then
		Derma_Message("Bienvenue sur le serveur !", "Aide")
	end
end)

KeyPress et KeyRelease

Serveur et client : le joueur appuie sur une action du jeu (IN_JUMP, IN_ATTACK, IN_USE…) puis la relâche. Contrairement à PlayerButtonDown (touches physiques KEY_*), ces constantes suivent les touches choisies par le joueur. Côté serveur pour chaque joueur, côté client pour son propre joueur. Liste des constantes et ply:KeyDown : voir Objets.

hook.Add("KeyPress", "monmode_utiliser", function(ply, touche)
	if SERVER and touche == IN_RELOAD and ply:KeyDown(IN_SPEED) then
		ply:ChatPrint("Rechargement rapide !")
	end
end)

PlayerSwitchFlashlight

Serveur : le joueur appuie sur la touche de la lampe torche (F). allumée est le nouvel état demandé ; renvoie false pour refuser.

hook.Add("PlayerSwitchFlashlight", "monmode_lampe", function(ply, allumee)
	if allumee and ply:Team() == 2 then return false end -- les chasseurs n'ont pas de lampe
end)

PlayerStartGesture

Serveur : un joueur lance un geste lui-même (roue d'emotes G, ou ply:PlayGesture côté client). nom est le nom du geste ("dance", "sit"…, voir Taille et gestes) ; renvoie false pour refuser. Un ply:PlayGesture appelé par le serveur ne passe pas par ce hook.

hook.Add("PlayerStartGesture", "monmode_gestes", function(ply, nom)
	if ply:Team() == 2 then return false end -- pas de gestes pour les chasseurs
end)

TriggerStartTouch et TriggerEndTouch

Serveur : un joueur ou un prop entre dans une zone déclencheur placée dans l'éditeur de map, puis en sort. Voir Points, zones et entités de map.

CanExitVehicle

Serveur : un joueur appuie sur E pour descendre d'un véhicule. Renvoie false pour l'en empêcher ; veh:EjectAll() et ply:ExitVehicle() restent possibles.

CanUndo

Serveur : le joueur appuie sur Annuler. entrée est la dernière entrée de sa pile : une entrée undo.Create (Name, Entities, Functions, Owner, CustomUndoText), ou une table de même forme pour celles du jeu (Name = "Prop", "Dupe", "NPC" ou "Constraint"). false la garde : le joueur lit « Impossible d'annuler : nom. »

OnUndo

Serveur : une annulation vient de réussir. nom et texte valent tous deux le nom de l'entrée (celui du message « Annulé : … »), ply est le joueur.

CanCleanup

Serveur : un bouton de l'onglet Nettoyage ou cleanup.CC_Cleanup / CC_AdminCleanup. catégorie : "props", "vehicles", "npcs", "sents", "constraints", une catégorie de cleanup.Register, ou "" (tout). false refuse. Voir Nettoyage.

CanDuplicate, PreDuplicate et PostDuplicate

Serveur, autour du collage d'une dupe (toolgun, onglet Dupes, duplicator.Paste). CanDuplicate(ply, liste) : liste = { { Class = …, Model = … }, … }, false refuse la dupe entière. PreDuplicate(ply, liste) suit si elle est acceptée. PostDuplicate(ply, créées) : après le collage, avec les entités créées. ply vaut nil pour un collage sans joueur. Voir Dupes.

-- Pas de coffres dans les dupes des joueurs non admins.
hook.Add("CanDuplicate", "pas_de_coffres", function(ply, liste)
	if not IsValid(ply) or ply:IsAdmin() then return end
	for _, entree in ipairs(liste) do
		if entree.Class == "coffre" then return false end
	end
end)

PlayerSpawnSENT et PlayerSpawnedSENT

Serveur : un joueur fait apparaître une entité scriptée depuis l'onglet Entités du menu de spawn. PlayerSpawnSENT(ply, classe) : false refuse (« Le mode de jeu n'autorise pas cette entité. »). PlayerSpawnedSENT(ply, ent) : l'entité vient d'apparaître. Voir Entités dans le menu de spawn.

CanProperty

Serveur et client : demandé par les actions "remove" et "freeze" du gamemode Sandbox (et par les propriétés d'addon qui l'appellent dans leur Filter). nom : le nom de la propriété. false la cache du menu contextuel (client) et la refuse (serveur).

EnvChanged

Serveur et client : une fonction env.Set… a changé le soleil, le ciel, l'heure, la lumière ambiante ou le brouillard. quoi dit quoi : "sun_angle", "sun_color", "sun_brightness", "sky_color", "sky_time", "time_scale", "ambient", "fog" ou "sky_texture" (env.SetSkyTexture). Lancé dans le realm qui appelle ; un appel serveur le lance aussi côté client chez chaque joueur. L'horloge qui avance toute seule (env.SetTimeScale) ne le lance pas.

PlayerVRGrab

Serveur : un joueur en réalité virtuelle serre le grip près d'un prop (main : "left" ou "right"), après la protection des props. Renvoie false pour qu'il ne l'attrape pas. PlayerVRDrop(ply, ent, main) : il le lâche (le prop garde sa vitesse).

ClientReady

Client : le joueur vient d'entrer dans la partie (map, addons du serveur et scripts client chargés, écran de chargement du jeu fermé). Appelé à chaque arrivée, et aussi après un changement de map ou de gamemode. Idéal pour un écran de bienvenue ou pour précharger les modèles.

HUDPaint

Client, à chaque image : dessine le HUD avec draw.* et surface.*. Dans l'ordre de GMod : PreDrawHUD, HUDPaintBackground, HUDPaint, puis PostDrawHUD (dessiné par-dessus). Voir Dessiner le HUD.

ChatText

Client : une ligne sans joueur arrive dans le chat (messages du serveur, PrintMessage, arrivées et départs). Arguments : 0, "Console", le texte, et le type "joinleave" (« a rejoint / a quitté la partie ») ou "none". Renvoie true pour cacher la ligne.

HUDShouldDraw

Client : renvoie false pour cacher "Health", "Weapon", "WeaponSelection", "Voice", "Crosshair", "PropOwner", "Damage" ou "Scoreboard" (le tableau des scores du jeu). Voir Cacher des parties du HUD.

SpawnMenuOpen

Client, quand le joueur appuie sur la touche du menu de spawn : false pour l'en empêcher. Base renvoie false, Sandbox true. Côté serveur, PlayerSpawnProp refuse en plus les apparitions.

ScoreboardShow et ScoreboardHide

Client : la touche du tableau des scores (Tab) est enfoncée, puis relâchée. Si ScoreboardShow renvoie true, le gamemode affiche son propre tableau : celui du jeu ne s'ouvre pas (et la souris reste capturée). ScoreboardHide est toujours appelé. Exemple dans Tableau des scores.

OnPlayerChat

Client : une ligne de chat d'un joueur arrive (après PlayerSay sur le serveur). Renvoie true pour cacher la ligne par défaut, par exemple pour l'afficher autrement avec chat.AddText. ply peut être nil (joueur parti) ; équipe vaut toujours false ; mort : le joueur est mort. Exemple dans Chat en couleurs.

CalcView

Client, à chaque image, avec la caméra prévue (ply, origine, angles, fov, znear, zfar). Renvoie une table { origin = Vector, angles = Angle, fov = nombre, drawviewer = booléen } (tous les champs sont facultatifs) pour remplacer la caméra ; ne rien renvoyer garde la caméra normale. drawviewer = true affiche son propre corps (vue de dessus, cinématique).

-- Vue de dessus façon jeu d'arcade.
hook.Add("CalcView", "vue_dessus", function(ply, pos, ang, fov)
	return { origin = ply:GetPos() + Vector(0, 15, 0), angles = Angle(-89, 0, 0), fov = 70, drawviewer = true }
end)

CalcViewModelView, PreDrawViewModel et PostDrawViewModel

Client, à chaque image, pour le modèle de vue d'une arme Lua (SWEP.ViewModel). CalcViewModelView(arme, vm, ancPos, ancAng, pos, ang) renvoie pos, ang (dans le monde) pour le déplacer, après SWEP:GetViewModelPosition et SWEP:CalcViewModelView. PreDrawViewModel(vm, ply, arme) : true le cache pour cette image ; PostDrawViewModel(vm, ply, arme) suit. vm vaut toujours nil (pas d'entité de modèle de vue).

Hooks d'animation du joueur

Client, à chaque image, pour chaque joueur, seulement si un hook ou le gamemode les utilise :

-- Les autres joueurs accroupis sont invisibles.
hook.Add("PrePlayerDraw", "furtif", function(ply)
	if ply ~= LocalPlayer() and ply:Crouching() then return true end
end)

PlayerFootstep

Client, à chaque pas d'un joueur (ply, pos, pied, son, volume ; pied : 0 ou 1 ; son : "player/footstep_concrete", …_wood, …_metal ou …_grass). Renvoie true pour ne pas jouer le bruit. Seulement si un hook ou le gamemode l'utilise.

PlayerBindPress

Client : une action du jeu est pressée (appuyé vaut toujours true : le relâchement n'appelle pas ce hook). action est le nom de l'action : "jump", "attack", "attack2", "use", "reload", "spawn_menu", "noclip", "third_person", "flashlight", "chat", "scoreboard", "crouch", "sprint", "move_forward"… (voir Paramètres → Touches). Renvoie true pour bloquer l'action (les déplacements restent bloqués tant que la touche est enfoncée). Pas d'appel pendant la saisie de texte.

-- Pas de saut pendant la préparation.
hook.Add("PlayerBindPress", "pas_de_saut", function(ply, action, appuye)
	if action == "jump" and GetGlobalBool("preparation") then return true end
end)

ContextMenuOpen, OnContextMenuOpen et OnContextMenuClose

Client : le joueur maintient la touche Menu contextuel (N par défaut). ContextMenuOpen() : false l'empêche de s'ouvrir. OnContextMenuOpen() : il vient de s'ouvrir ; OnContextMenuClose() : il se ferme (touche relâchée, Échap). Voir Menu contextuel.

AddToolMenuTabs, AddToolMenuCategories et PopulateToolMenu

Client, dans cet ordre, une fois par lancement des scripts, quand le menu de spawn a besoin de ses onglets et options d'outils pour la première fois. C'est là qu'on appelle spawnmenu.AddToolTab, AddToolCategory et AddToolMenuOption. Voir Options d'outils.

Hooks de déplacement

Client, pour le joueur local, à chaque image physique, seulement si un hook ou le gamemode les utilise : StartCommand(ply, cmd), CreateMove(cmd), SetupMove(ply, mv, cmd), Move(ply, mv) (true : le jeu ne déplace pas le joueur, mv donne sa vitesse et sa position), puis FinishMove(ply, mv) après le déplacement. cmd est un CUserCmd, mv un CMoveData. Si le serveur a aussi un de ces hooks (fichier partagé), son anti-triche ne contrôle plus la vitesse ni le vol. Exemple de jetpack dans Déplacement du joueur.

Hooks de rendu

Client, à chaque image, dans cet ordre : PreRender, PreDrawHalos (pour halo.Add), RenderScreenspaceEffects (pour DrawColorModify, DrawBloom…, remis à zéro à chaque image), PostRender. PostDrawOpaqueRenderables et PostDrawTranslucentRenderables servent à cam.Start3D2D et render.Draw*. Le dessin 3D de l'image (render.DrawBeam, mesh…) se fait depuis n'importe lequel de ces hooks. Voir Rendu 3D et effets.

ForceDermaSkin

Client : renvoie le nom d'une peau Derma (derma.DefineSkin) pour qu'elle serve de peau par défaut à tous les panneaux.

Tes propres événements

hook.Run accepte n'importe quel nom : tes addons peuvent s'envoyer des événements.

-- Addon A
hook.Add("MonJeu_ManchePerdue", "addon_a", function(equipe)
	PrintMessage("L'équipe " .. equipe .. " a perdu la manche.")
end)
-- Addon B
hook.Run("MonJeu_ManchePerdue", "rouge")