dobrograd-13-06-2022/garrysmod/addons/util-apg/lua/apg/modules/ghosting.lua
Jonny_Bro (Nikita) e4d5311906 first commit
2023-11-16 15:01:19 +05:00

345 lines
10 KiB
Lua

--[[------------------------------------------
A.P.G. - a lightweight Anti Prop Griefing solution (v2.2.0)
Made by :
- While True (http://steamcommunity.com/id/76561197972967270)
- LuaTenshi (http://steamcommunity.com/id/76561198096713277)
============================
GHOSTING/UNGHOSTING MODULE
============================
Developper informations :
---------------------------------
Used variables :
ghost_color = { value = Color(34, 34, 34, 220), desc = "Color set on ghosted props" }
bad_ents = {
value = {
["prop_physics"] = true,
["wire_"] = false,
["gmod_"] = false },
desc = "Entities to ghost/control/secure"}
alwaysFrozen = { value = false, desc = "Set to true to auto freeze props on physgun drop" }
]]--------------------------------------------
local mod = "ghosting"
local disabledClasses = {
gmod_sent_vehicle_fphysics_base = true,
gmod_sent_vehicle_fphysics_wheel = true,
gmod_sent_vehicle_fphysics_attachment = true,
}
--[[------------------------------------------
Override base functions
]]--------------------------------------------
local ENT = FindMetaTable( "Entity" )
APG.oSetColGroup = APG.oSetColGroup or ENT.SetCollisionGroup
function ENT:SetCollisionGroup( group )
if not disabledClasses[self:GetClass()] and APG.isBadEnt( self ) and APG.getOwner( self ) then
if group == COLLISION_GROUP_NONE then
if not self.APG_Frozen then
group = COLLISION_GROUP_INTERACTIVE
end
--[[ elseif group == COLLISION_GROUP_INTERACTIVE and APG.isTrap( self ) then
group = COLLISION_GROUP_DEBRIS_TRIGGER --]]
end
end
return APG.oSetColGroup( self, group )
end
local PhysObj = FindMetaTable("PhysObj")
APG.oEnableMotion = APG.oEnableMotion or PhysObj.EnableMotion
function PhysObj:EnableMotion( bool )
local sent = self:GetEntity()
if not disabledClasses[sent:GetClass()] and APG.isBadEnt( sent ) and APG.getOwner( sent ) then
sent.APG_Frozen = not bool
if not sent.APG_Frozen then
sent:SetCollisionGroup(COLLISION_GROUP_INTERACTIVE)
end
end
return APG.oEnableMotion( self, bool)
end
function APG.isTrap( ent, output )
local check = false
local center = ent:LocalToWorld(ent:OBBCenter())
local bRadius = ent:BoundingRadius()
local cache = {}
if not IsValid(ent:GetParent()) then
for _,v in next, ents.FindInSphere(center, bRadius) do
if (v:IsPlayer() and v:Alive() and not v:IsGhost()) then
local pos = v:GetPos()
local trace = { start = pos, endpos = pos, filter = v }
local tr = util.TraceEntity( trace, v )
if tr.Entity == ent then
if output then
table.insert(cache, v)
else
check = v
end
end
elseif v:IsVehicle() then
-- Check if the distance between the spheres centers is less than the sum of their radius.
local vCenter = v:LocalToWorld(v:OBBCenter())
if center:Distance( vCenter ) < v:BoundingRadius() then
check = v
end
end
if check then break end
end
end
if output then
return istable(cache) and cache or {}
end
return check or false
end
function APG.entGhost( ent, enforce, noCollide )
if not APG.modules[ mod ] or not APG.isBadEnt( ent ) then return end
if ent.jailWall or ent.apgIgnore then return end
if disabledClasses[ent:GetClass()] then return end
if not ent.APG_Ghosted then
ent.FPPAntiSpamIsGhosted = nil -- Override FPP Ghosting.
DropEntityIfHeld(ent)
ent:ForcePlayerDrop()
ent.APG_oColGroup = ent:GetCollisionGroup()
if not enforce then
-- If and old collision group was set get it.
if ent.OldCollisionGroup then ent.APG_oColGroup = ent.OldCollisionGroup end -- For FPP
if ent.DPP_oldCollision then ent.APG_oColGroup = ent.DPP_oldCollision end -- For DPP
ent.OldCollisionGroup = nil
ent.DPP_oldCollision = nil
end
ent.APG_Ghosted = true
timer.Simple(0, function()
if not IsValid(ent) then return end
if not ent.APG_oldColor then
ent.APG_oldColor = ent:GetColor()
if not enforce then
if ent.OldColor then ent.APG_oldColor = ent.OldColor end -- For FPP
if ent.__DPPColor then ent.APG_oldColor = ent.__DPPColor end -- For DPP
ent.OldColor = nil
ent.__DPPColor = nil
end
end
ent:SetColor( APG.cfg["ghost_color"].value )
if noCollide then
ent:SetCollisionGroup( COLLISION_GROUP_WORLD )
else
ent:SetCollisionGroup( COLLISION_GROUP_DEBRIS_TRIGGER )
end
end)
-- ent:SetRenderMode(RENDERMODE_TRANSALPHA)
ent:DrawShadow(false)
if noCollide then
ent:SetCollisionGroup( COLLISION_GROUP_WORLD )
else
ent:SetCollisionGroup( COLLISION_GROUP_DEBRIS_TRIGGER )
end
end
end
function APG.entUnGhost( ent, ply )
if not APG.modules[ mod ] or not APG.isBadEnt( ent ) then return end
if ent.APG_HeldBy and #ent.APG_HeldBy > 1 then return end
if disabledClasses[ent:GetClass()] then return end
if ent.APG_Ghosted != false and not ent.APG_Picked then
ent.APG_isTrap = APG.isTrap(ent)
if not ent.APG_isTrap then
ent.APG_Ghosted = false
ent:DrawShadow(true)
ent:SetColor( ent.APG_oldColor or Color(255,255,255,255))
ent.APG_oldColor = false
local newColGroup = COLLISION_GROUP_INTERACTIVE
if ent.APG_oColGroup == COLLISION_GROUP_WORLD then
newColGroup = ent.APG_oColGroup
elseif ent.APG_Frozen then
newColGroup = COLLISION_GROUP_NONE
end
ent:SetCollisionGroup( newColGroup )
else
APG.notify("There is something in this prop!", ply, 1)
ent:SetCollisionGroup( COLLISION_GROUP_WORLD )
end
end
ent.APG_Busy = nil
end
function APG.ConstrainApply( ent, callback )
local constrained = constraint.GetAllConstrainedEntities(ent)
for _,v in next, constrained do
if IsValid(v) and v != ent then
callback( v )
end
end
end
--[[------------------------------------------
Hooks/Timers
]]--------------------------------------------
APG.hookRegister( mod, "PhysgunPickup","APG_makeGhost",function(ply, ent)
if ent.APG_Busy then return false end
if not APG.canPhysGun( ent, ply ) then return end
if not APG.modules[ mod ] or not APG.isBadEnt( ent ) then return end
if disabledClasses[ent:GetClass()] then return end
ent.APG_Picked = true
APG.entGhost(ent, false, true)
APG.ConstrainApply( ent, function( _ent )
if not _ent.APG_Frozen then
_ent.APG_Picked = true
APG.entGhost( _ent, false, true )
end
end) -- Apply ghost to all constrained ents
end)
APG.hookRegister( mod, "PlayerUnfrozeObject", "APG_unFreezeInteract", function (ply, ent, object)
if not APG.canPhysGun( ent, ply ) then return end
if not APG.modules[ mod ] or not APG.isBadEnt( ent ) then return end
if disabledClasses[ent:GetClass()] then return end
if APG.cfg["alwaysFrozen"].value then return false end -- Do not unfreeze if Always Frozen is enabled !
if ent:GetCollisionGroup( ) != COLLISION_GROUP_WORLD then
ent:SetCollisionGroup( COLLISION_GROUP_INTERACTIVE )
end
end)
APG.dJobRegister( "unghost", 0.1, 50, function( ent )
if not IsValid( ent ) then return end
APG.entUnGhost( ent )
end)
APG.hookRegister( mod, "PhysgunDrop", "APG_pGunDropUnghost", function( ply, ent )
if not APG.modules[ mod ] or not APG.isBadEnt( ent ) then return end
if disabledClasses[ent:GetClass()] then return end
local changed = true
local getallconst = constraint.GetAllConstrainedEntities( ent )
if getallconst then
for k,_ent in pairs(getallconst) do
if _ent.APG_Picked and _ent ~= ent then
changed = false
end
end
end
if changed then
ent.APG_Picked = false
if APG.cfg["alwaysFrozen"].value then
APG.freezeIt( ent )
end
APG.entUnGhost( ent, ply )
APG.ConstrainApply( ent, function( _ent )
_ent.APG_Picked = false
APG.startDJob( "unghost", _ent )
end) -- Apply unghost to all constrained ents
end
end)
local function fixCollision(ent)
if not IsValid( ent ) then return end
if disabledClasses[ent:GetClass()] then
ent:SetCustomCollisionCheck(true)
ent:CollisionRulesChanged()
return
end
if not APG.modules[ mod ] or not APG.isBadEnt( ent ) then return end
--timer.Simple(.1, function()
APG.entGhost( ent, false, true )
--end)
ent.APG_Busy = true
timer.Simple(0, function()
local owner = APG.getOwner( ent )
if IsValid( owner ) and owner:IsPlayer() then
local pObj = ent:GetPhysicsObject()
if IsValid(pObj) and APG.cfg["alwaysFrozen"].value then
ent.APG_Frozen = true
pObj:EnableMotion(false)
elseif IsValid(pObj) and pObj:IsMoveable() then
ent.APG_Frozen = false
ent:SetCollisionGroup(COLLISION_GROUP_INTERACTIVE)
end
end
APG.startDJob( "unghost", ent )
end)
end
APG.hookRegister(mod, "PlayerSpawnedEffect", "APG_noColOnCreate", function(_, _, ent) fixCollision(ent) end)
APG.hookRegister(mod, "PlayerSpawnedSENT", "APG_noColOnCreate", function(_, ent) fixCollision(ent) end)
APG.hookRegister(mod, "PlayerSpawnedProp", "APG_noColOnCreate", function(_, _, ent) fixCollision(ent) end)
APG.hookRegister(mod, "PlayerSpawnedProp", "APG_freeze", function(_, _, ent)
local phys = ent:GetPhysicsObject()
if IsValid(phys) then
phys:EnableMotion(false)
end
end)
local BlockedProperties = {"collision", "persist", "editentity", "drive", "ignite", "statue"}
APG.hookRegister(mod, "CanProperty", "APG_canProperty", function(ply, prop, ent)
local prop = tostring(prop)
if( table.HasValue(BlockedProperties,prop) and ent.APG_Ghosted ) then
APG.log("Cannot set "..prop.." properties on ghosted entities!", ply)
return false
end
end)
-- Custom Hooks --
APG.hookRegister(mod, "APG.FadingDoorToggle", "APG_FadingDoor", function(ent, isFading)
if not disabledClasses[ent:GetClass()] and APG.isBadEnt(ent) and APG.cfg["FadingDoorGhosting"].value then
local ply = APG.getOwner( ent )
if IsValid(ply) then
if not isFading then
local find = APG.isTrap(ent, true)
for _,v in next, find do
if v.IsPlayer and v:IsPlayer() then
local dir = v:GetForward(); dir.z = 0
v:SetCollisionGroup(COLLISION_GROUP_PUSHAWAY)
v:SetAbsVelocity((dir * 600) + Vector(0,0,60))
timer.Simple(1, function()
v:SetCollisionGroup(COLLISION_GROUP_PLAYER)
end)
end
end
elseif ent.APG_Ghosted then
APG.startDJob( "unghost", ent )
end
end
end
end)
--[[------------------------------------------
Load hooks and timers
]]--------------------------------------------
for k, v in next, APG[mod]["hooks"] do
hook.Add( v.event, v.identifier, v.func )
end
for k, v in next, APG[mod]["timers"] do
timer.Create( v.identifier, v.delay, v.repetitions, v.func )
end