Garry's Mod

Garry's Mod

Build Mode (chat command)
 This topic has been pinned, so it's probably important
Cédric GÉRILLE [GiletJaune]  [developer] 19 Jan, 2016 @ 4:39am
Source code
The source code is available on this page.

garrysmod\addons\build_pvp\lua\autorun\server\build_pvp.lua
local min_time = 30 CreateConVar( "build_pvp_antispam", "30", {FCVAR_ARCHIVE, FCVAR_NOTIFY}, "Antispam delay in seconds for Build mode." ) cvars.AddChangeCallback( "build_pvp_antispam", function( convar, oldValue, newValue ) min_time = tonumber( newValue ) end, "build_pvp" ) min_time = GetConVar( "build_pvp_antispam" ):GetInt() local admin_spam = 1 CreateConVar( "build_pvp_adminspam", "1", {FCVAR_ARCHIVE, FCVAR_NOTIFY}, "Admins can spam Build mode: 2 = superadmins only, 1 = admins, 0 = nobody" ) cvars.AddChangeCallback( "build_pvp_adminspam", function( convar, oldValue, newValue ) admin_spam = tonumber( newValue ) end, "build_pvp" ) admin_spam = GetConVar( "build_pvp_adminspam" ):GetInt() local noclip = true CreateConVar( "build_pvp_noclip", "1", {FCVAR_ARCHIVE, FCVAR_NOTIFY}, "Players in Build mode always can noclip: 1/0" ) cvars.AddChangeCallback( "build_pvp_noclip", function( convar, oldValue, newValue ) noclip = tobool( tonumber( newValue ) ) end, "build_pvp" ) noclip = GetConVar( "build_pvp_noclip" ):GetBool() hook.Add( "PlayerNoClip", "build_pvp", function( ply, desiredState ) if desiredState then if noclip and ply.BuildMode then -- Always allow players in Build mode to enable noclip. return true end else if noclip then -- Always allow players to disable noclip. return true end end end ) local function CanAdminSpam( sender ) if admin_spam >= 2 then return sender:IsSuperAdmin() elseif admin_spam < 1 then return false else return sender:IsAdmin() end end hook.Add( "PlayerSay", "build_pvp", function( sender, text ) if text == "!build" then if !sender.BuildModeNextChange or RealTime() > sender.BuildModeNextChange or CanAdminSpam( sender ) then sender.BuildMode = true sender:SetNWBool( "build_pvp", true ) sender:GodEnable() sender.BuildModeNextChange = RealTime() + min_time sender:ChatPrint( "Build mode enabled! Enter !pvp to leave." ) else sender:ChatPrint( "The minimum delay is "..math.ceil( min_time ).." seconds before you can enter in Build mode." ) end return "" elseif text == "!pvp" then if !sender.BuildModeNextChange or RealTime() > sender.BuildModeNextChange or CanAdminSpam( sender ) then sender.BuildMode = false sender:SetNWBool( "build_pvp", false ) sender:GodDisable() if noclip then -- Disable noclip. sender:SetMoveType( MOVETYPE_WALK ) end sender.BuildModeNextChange = RealTime() + min_time sender:ChatPrint( "Build mode disabled!" ) else sender:ChatPrint( "The minimum delay is "..math.ceil( min_time ).." seconds before you can leave Build mode." ) end return "" end end ) -- Remember exiting drivers (4 seconds until driver is forgotten) local previousDrivers = {} hook.Add( "PlayerLeaveVehicle", "build_pvp", function( driver, vehicle ) previousDrivers[vehicle] = driver timer.Create( "build_pvp:vehicle"..vehicle:GetCreationID(), 4, 1, function() previousDrivers[vehicle] = nil end ) end ) hook.Add( "PlayerEnteredVehicle", "build_pvp", function( driver, vehicle ) previousDrivers[vehicle] = nil end ) local function getAttackerFromVehicle( attacker ) if IsValid( attacker ) then if attacker:IsVehicle() then local vehicle = attacker attacker = vehicle:GetDriver() if not IsValid( attacker ) then attacker = previousDrivers[vehicle] end attacker = IsValid( attacker ) and attacker or nil end else attacker = nil end return attacker end hook.Add( "EntityTakeDamage", "build_pvp", function( target, dmg ) if IsValid( target ) and target:IsPlayer() then local attacker = getAttackerFromVehicle( dmg:GetAttacker() ) if attacker and attacker:IsPlayer() and attacker.BuildMode then dmg:SetDamage( 0 ) -- probably not needed return true end end end ) -- Security #1 in cases of EntityTakeDamage conflicts: hook.Add( "PlayerShouldTakeDamage", "build_pvp", function( ply, attacker ) attacker = getAttackerFromVehicle( attacker ) if attacker and attacker:IsPlayer() and attacker.BuildMode then return false end end ) -- Security #2 in cases of EntityTakeDamage conflicts: hook.Add( "ScalePlayerDamage", "build_pvp", function( ply, hitgroup, dmginfo ) local attacker = getAttackerFromVehicle( dmginfo:GetAttacker() ) if attacker and attacker:IsPlayer() and attacker.BuildMode then dmginfo:SetDamage( 0 ) -- probably not needed return true end end ) -- Set the god mode for respawning players: hook.Add( "PlayerSpawn", "build_pvp", function( ply ) if ply.BuildMode then local function timerFunction() if IsValid( ply ) and ply.BuildMode then ply:GodEnable() end end timer.Simple( 0, timerFunction ) -- Just in case (baby god): timer.Simple( 5, timerFunction ) timer.Simple( 10, timerFunction ) end end )

garrysmod\addons\build_pvp\lua\autorun\client\build_pvp.lua
This file can be removed if you do not need the HUD text.
local color = Color( 192, 255, 192 ) local null_ang = Angle( 0,0,0 ) local me local min,max local center, toscreen, my_eyes, direction, trace, dist, font hook.Add( "HUDPaint", "build_pvp", function() me = LocalPlayer() my_eyes = EyePos() for _,ply in ipairs( player.GetAll() ) do -- if ply != me and ply:HasGodMode() then -- BUG: Player:HasGodMode() does not work if ply != me and ply:GetNWBool( "build_pvp" ) then -- player in build bounds? min,max = ply:GetCollisionBounds() center = ply:LocalToWorld( ( min + max )/2 ) toscreen = center:ToScreen() if toscreen.visible then -- player in screen bounds? font = nil dist = my_eyes:DistToSqr( center ) if dist<400000. then font = "Trebuchet24" elseif dist<2000000. then font = "Default" end if font then direction = WorldToLocal( center, null_ang, my_eyes, null_ang ) trace = util.QuickTrace( my_eyes, direction, me ) if !trace.HitWorld then -- player visible? draw.SimpleText( "Builder", font, toscreen.x, toscreen.y, color, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP ) end end end end end end )
Last edited by Cédric GÉRILLE [GiletJaune]; 28 Jul, 2018 @ 4:39am