mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
Upload
This commit is contained in:
71
gamemodes/sandbox/entities/effects/balloon_pop.lua
Normal file
71
gamemodes/sandbox/entities/effects/balloon_pop.lua
Normal file
@@ -0,0 +1,71 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
local vOffset = data:GetOrigin()
|
||||
local Color = data:GetStart()
|
||||
|
||||
sound.Play( "garrysmod/balloon_pop_cute.wav", vOffset, 90, math.random( 90, 120 ) )
|
||||
|
||||
local NumParticles = 32
|
||||
|
||||
local emitter = ParticleEmitter( vOffset, true )
|
||||
|
||||
for i = 0, NumParticles do
|
||||
|
||||
local Pos = Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), math.Rand( -1, 1 ) )
|
||||
|
||||
local particle = emitter:Add( "particles/balloon_bit", vOffset + Pos * 8 )
|
||||
if ( particle ) then
|
||||
|
||||
particle:SetVelocity( Pos * 500 )
|
||||
|
||||
particle:SetLifeTime( 0 )
|
||||
particle:SetDieTime( 10 )
|
||||
|
||||
particle:SetStartAlpha( 255 )
|
||||
particle:SetEndAlpha( 255 )
|
||||
|
||||
local Size = math.Rand( 1, 3 )
|
||||
particle:SetStartSize( Size )
|
||||
particle:SetEndSize( 0 )
|
||||
|
||||
particle:SetRoll( math.Rand( 0, 360 ) )
|
||||
particle:SetRollDelta( math.Rand( -2, 2 ) )
|
||||
|
||||
particle:SetAirResistance( 100 )
|
||||
particle:SetGravity( Vector( 0, 0, -300 ) )
|
||||
|
||||
local RandDarkness = math.Rand( 0.8, 1.0 )
|
||||
particle:SetColor( Color.r * RandDarkness, Color.g * RandDarkness, Color.b * RandDarkness )
|
||||
|
||||
particle:SetCollide( true )
|
||||
|
||||
particle:SetAngleVelocity( Angle( math.Rand( -160, 160 ), math.Rand( -160, 160 ), math.Rand( -160, 160 ) ) )
|
||||
|
||||
particle:SetBounce( 1 )
|
||||
particle:SetLighting( true )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
emitter:Finish()
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
return false
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
end
|
||||
39
gamemodes/sandbox/entities/effects/camera_flash.lua
Normal file
39
gamemodes/sandbox/entities/effects/camera_flash.lua
Normal file
@@ -0,0 +1,39 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
local vOffset = data:GetOrigin()
|
||||
local ent = data:GetEntity()
|
||||
|
||||
local dlight = DynamicLight( ent:EntIndex() )
|
||||
|
||||
if ( dlight ) then
|
||||
|
||||
dlight.Pos = vOffset
|
||||
dlight.r = 255
|
||||
dlight.g = 255
|
||||
dlight.b = 255
|
||||
dlight.Brightness = 10
|
||||
dlight.Size = 512
|
||||
dlight.DieTime = CurTime() + 0.02
|
||||
dlight.Decay = 512
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
return false
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
end
|
||||
63
gamemodes/sandbox/entities/effects/entity_remove.lua
Normal file
63
gamemodes/sandbox/entities/effects/entity_remove.lua
Normal file
@@ -0,0 +1,63 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
if ( GetConVarNumber( "gmod_drawtooleffects" ) == 0 ) then return end
|
||||
|
||||
local TargetEntity = data:GetEntity()
|
||||
if ( !IsValid( TargetEntity ) ) then return end
|
||||
|
||||
local vOffset = TargetEntity:GetPos()
|
||||
local Low, High = TargetEntity:WorldSpaceAABB()
|
||||
|
||||
local NumParticles = TargetEntity:BoundingRadius()
|
||||
NumParticles = NumParticles * 4
|
||||
|
||||
NumParticles = math.Clamp( NumParticles, 32, 256 )
|
||||
|
||||
local emitter = ParticleEmitter( vOffset )
|
||||
|
||||
for i = 0, NumParticles do
|
||||
|
||||
local vPos = Vector( math.Rand( Low.x, High.x ), math.Rand( Low.y, High.y ), math.Rand( Low.z, High.z ) )
|
||||
local particle = emitter:Add( "effects/spark", vPos )
|
||||
if ( particle ) then
|
||||
|
||||
particle:SetVelocity( ( vPos - vOffset ) * 5 )
|
||||
particle:SetLifeTime( 0 )
|
||||
particle:SetDieTime( math.Rand( 0.5, 1.0 ) )
|
||||
particle:SetStartAlpha( math.Rand( 200, 255 ) )
|
||||
particle:SetEndAlpha( 0 )
|
||||
particle:SetStartSize( 2 )
|
||||
particle:SetEndSize( 0 )
|
||||
particle:SetRoll( math.Rand( 0, 360 ) )
|
||||
particle:SetRollDelta( 0 )
|
||||
|
||||
particle:SetAirResistance( 100 )
|
||||
particle:SetGravity( Vector( 0, 0, -700 ) )
|
||||
particle:SetCollide( true )
|
||||
particle:SetBounce( 0.3 )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
emitter:Finish()
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
return false
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
end
|
||||
56
gamemodes/sandbox/entities/effects/inflator_magic.lua
Normal file
56
gamemodes/sandbox/entities/effects/inflator_magic.lua
Normal file
@@ -0,0 +1,56 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
if ( GetConVarNumber( "gmod_drawtooleffects" ) == 0 ) then return end
|
||||
|
||||
local vOffset = data:GetOrigin()
|
||||
|
||||
local NumParticles = 16
|
||||
|
||||
local emitter = ParticleEmitter( vOffset )
|
||||
|
||||
for i = 0, NumParticles do
|
||||
|
||||
local particle = emitter:Add( "effects/spark", vOffset )
|
||||
if ( particle ) then
|
||||
|
||||
particle:SetDieTime( 0.5 )
|
||||
|
||||
particle:SetStartAlpha( 255 )
|
||||
particle:SetEndAlpha( 0 )
|
||||
|
||||
particle:SetStartSize( 1 )
|
||||
particle:SetEndSize( 0 )
|
||||
|
||||
particle:SetRoll( math.Rand( 0, 360 ) )
|
||||
particle:SetRollDelta( math.Rand( -200, 200 ) )
|
||||
|
||||
particle:SetAirResistance( 400 )
|
||||
|
||||
particle:SetVelocity( VectorRand() * 50 )
|
||||
particle:SetGravity( Vector( 0, 0, 100 ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
emitter:Finish()
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
return false
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
end
|
||||
76
gamemodes/sandbox/entities/effects/lasertracer.lua
Normal file
76
gamemodes/sandbox/entities/effects/lasertracer.lua
Normal file
@@ -0,0 +1,76 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
EFFECT.Mat = Material( "effects/spark" )
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
self.StartPos = data:GetStart()
|
||||
self.EndPos = data:GetOrigin()
|
||||
|
||||
local ent = data:GetEntity()
|
||||
local attid = data:GetAttachment()
|
||||
|
||||
if ( IsValid( ent ) && attid > 0 ) then
|
||||
if ( ent.Owner == LocalPlayer() && LocalPlayer():GetViewModel() == LocalPlayer() ) then ent = ent.Owner:GetViewModel() end
|
||||
|
||||
local att = ent:GetAttachment( attid )
|
||||
if ( att ) then
|
||||
self.StartPos = att.Pos
|
||||
end
|
||||
end
|
||||
|
||||
self.Dir = self.EndPos - self.StartPos
|
||||
|
||||
self:SetRenderBoundsWS( self.StartPos, self.EndPos )
|
||||
|
||||
self.TracerTime = math.min( 1, self.StartPos:Distance( self.EndPos ) / 10000 )
|
||||
self.Length = math.Rand( 0.1, 0.15 )
|
||||
|
||||
-- Die when it reaches its target
|
||||
self.DieTime = CurTime() + self.TracerTime
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
|
||||
if ( CurTime() > self.DieTime ) then
|
||||
|
||||
-- Awesome End Sparks
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self.EndPos + self.Dir:GetNormalized() * -2 )
|
||||
effectdata:SetNormal( self.Dir:GetNormalized() * -3 )
|
||||
effectdata:SetMagnitude( 1 )
|
||||
effectdata:SetScale( 1 )
|
||||
effectdata:SetRadius( 6 )
|
||||
util.Effect( "Sparks", effectdata )
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
|
||||
local fDelta = ( self.DieTime - CurTime() ) / self.TracerTime
|
||||
fDelta = math.Clamp( fDelta, 0, 1 ) ^ 0.5
|
||||
|
||||
render.SetMaterial( self.Mat )
|
||||
|
||||
local sinWave = math.sin( fDelta * math.pi )
|
||||
|
||||
render.DrawBeam( self.EndPos - self.Dir * ( fDelta - sinWave * self.Length ),
|
||||
self.EndPos - self.Dir * ( fDelta + sinWave * self.Length ),
|
||||
2 + sinWave * 16, 1, 0, Color( 0, 255, 0, 255 ) )
|
||||
|
||||
end
|
||||
41
gamemodes/sandbox/entities/effects/phys_freeze.lua
Normal file
41
gamemodes/sandbox/entities/effects/phys_freeze.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local effects_freeze = CreateClientConVar( "effects_freeze", "1", true, false, "Whether to display Physics Gun freeze effects?" )
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
if ( effects_freeze:GetBool() == false ) then return end
|
||||
|
||||
self.Target = data:GetEntity()
|
||||
self.StartTime = CurTime()
|
||||
self.Length = 0.3
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
|
||||
if ( effects_freeze:GetBool() == false ) then return false end
|
||||
return self.StartTime + self.Length > CurTime()
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
|
||||
if ( !IsValid( self.Target ) ) then return end
|
||||
|
||||
local delta = ( ( CurTime() - self.StartTime ) / self.Length ) ^ 0.5
|
||||
local idelta = 1 - delta
|
||||
|
||||
local size = 1
|
||||
halo.Add( { self.Target }, Color( 0, 255, 0, 255 * idelta ), size, size, 1, true, false )
|
||||
|
||||
end
|
||||
41
gamemodes/sandbox/entities/effects/phys_unfreeze.lua
Normal file
41
gamemodes/sandbox/entities/effects/phys_unfreeze.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local effects_unfreeze = CreateClientConVar( "effects_unfreeze", "1", true, false, "Whether to display Physics Gun unfreeze effects?" )
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
if ( effects_unfreeze:GetBool() == false ) then return end
|
||||
|
||||
self.Target = data:GetEntity()
|
||||
self.StartTime = CurTime()
|
||||
self.Length = 0.3
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
|
||||
if ( effects_unfreeze:GetBool() == false ) then return false end
|
||||
return self.StartTime + self.Length > CurTime()
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
|
||||
if ( !IsValid( self.Target ) ) then return end
|
||||
|
||||
local delta = ( ( CurTime() - self.StartTime ) / self.Length ) ^ 0.5
|
||||
local idelta = 1 - delta
|
||||
|
||||
local size = 1
|
||||
halo.Add( { self.Target }, Color( 255, 0, 0, 255 * idelta ), size, size, 1, true, false )
|
||||
|
||||
end
|
||||
149
gamemodes/sandbox/entities/effects/propspawn.lua
Normal file
149
gamemodes/sandbox/entities/effects/propspawn.lua
Normal file
@@ -0,0 +1,149 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local cl_drawspawneffect = CreateConVar( "cl_drawspawneffect", "1", { FCVAR_ARCHIVE }, "Whether to draw the spawn effect when spawning objects." )
|
||||
|
||||
local matRefract = Material( "models/spawn_effect" )
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
if ( !cl_drawspawneffect:GetBool() ) then return end
|
||||
|
||||
-- This is how long the spawn effect
|
||||
-- takes from start to finish.
|
||||
self.Time = 0.5
|
||||
self.LifeTime = CurTime() + self.Time
|
||||
|
||||
local ent = data:GetEntity()
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
if ( !ent:GetModel() ) then return end
|
||||
|
||||
self.ParentEntity = ent
|
||||
self:SetModel( ent:GetModel() )
|
||||
self:SetPos( ent:GetPos() )
|
||||
self:SetAngles( ent:GetAngles() )
|
||||
self:SetParent( ent )
|
||||
|
||||
self.OldRenderOverride = self.ParentEntity.RenderOverride
|
||||
self.ParentEntity.SpawnEffect = self
|
||||
self.ParentEntity.RenderOverride = self.RenderParent
|
||||
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
|
||||
if ( !cl_drawspawneffect:GetBool() ) then return false end
|
||||
if ( !IsValid( self.ParentEntity ) ) then return false end
|
||||
|
||||
local PPos = self.ParentEntity:GetPos()
|
||||
self:SetPos( PPos + ( EyePos() - PPos ):GetNormal() )
|
||||
|
||||
if ( self.LifeTime > CurTime() ) then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Remove the override only if our override was not overridden.
|
||||
if ( self.ParentEntity.RenderOverride == self.RenderParent ) then
|
||||
self.ParentEntity.RenderOverride = self.OldRenderOverride
|
||||
end
|
||||
self.ParentEntity.SpawnEffect = nil
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
end
|
||||
|
||||
function EFFECT:RenderOverlay( entity )
|
||||
|
||||
local Fraction = ( self.LifeTime - CurTime() ) / self.Time
|
||||
local ColFrac = ( Fraction - 0.5 ) * 2
|
||||
|
||||
Fraction = math.Clamp( Fraction, 0, 1 )
|
||||
ColFrac = math.Clamp( ColFrac, 0, 1 )
|
||||
|
||||
-- Change our model's alpha so the texture will fade out
|
||||
--entity:SetColor( 255, 255, 255, 1 + 254 * (ColFrac) )
|
||||
|
||||
-- Place the camera a tiny bit closer to the entity.
|
||||
-- It will draw a big bigger and we will skip any z buffer problems
|
||||
local EyeNormal = entity:GetPos() - EyePos()
|
||||
local Distance = EyeNormal:Length()
|
||||
EyeNormal:Normalize()
|
||||
|
||||
local Pos = EyePos() + EyeNormal * Distance * 0.01
|
||||
|
||||
-- Start the new 3d camera position
|
||||
local bClipping = self:StartClip( entity, 1.2 )
|
||||
cam.Start3D( Pos, EyeAngles() )
|
||||
|
||||
-- If our card is DX8 or above draw the refraction effect
|
||||
if ( render.GetDXLevel() >= 80 ) then
|
||||
|
||||
-- Update the refraction texture with whatever is drawn right now
|
||||
render.UpdateRefractTexture()
|
||||
|
||||
matRefract:SetFloat( "$refractamount", Fraction * 0.1 )
|
||||
|
||||
-- Draw model with refraction texture
|
||||
render.MaterialOverride( matRefract )
|
||||
entity:DrawModel()
|
||||
render.MaterialOverride()
|
||||
|
||||
end
|
||||
|
||||
-- Set the camera back to how it was
|
||||
cam.End3D()
|
||||
render.PopCustomClipPlane()
|
||||
render.EnableClipping( bClipping )
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:RenderParent()
|
||||
|
||||
if ( !IsValid( self ) ) then return end
|
||||
if ( !IsValid( self.SpawnEffect ) ) then self.RenderOverride = nil return end
|
||||
|
||||
local bClipping = self.SpawnEffect:StartClip( self, 1 )
|
||||
|
||||
self:DrawModel()
|
||||
|
||||
render.PopCustomClipPlane()
|
||||
render.EnableClipping( bClipping )
|
||||
|
||||
self.SpawnEffect:RenderOverlay( self )
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:StartClip( model, spd )
|
||||
|
||||
local mn, mx = model:GetRenderBounds()
|
||||
local Up = ( mx - mn ):GetNormal()
|
||||
local Bottom = model:GetPos() + mn
|
||||
local Top = model:GetPos() + mx
|
||||
|
||||
local Fraction = ( self.LifeTime - CurTime() ) / self.Time
|
||||
Fraction = math.Clamp( Fraction / spd, 0, 1 )
|
||||
|
||||
local Lerped = LerpVector( Fraction, Bottom, Top )
|
||||
|
||||
local normal = Up
|
||||
local distance = normal:Dot( Lerped )
|
||||
|
||||
local bEnabled = render.EnableClipping( true )
|
||||
render.PushCustomClipPlane( normal, distance )
|
||||
|
||||
return bEnabled
|
||||
|
||||
end
|
||||
65
gamemodes/sandbox/entities/effects/selection_indicator.lua
Normal file
65
gamemodes/sandbox/entities/effects/selection_indicator.lua
Normal file
@@ -0,0 +1,65 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
EFFECT.Mat = Material( "effects/select_dot" )
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
local pos = data:GetOrigin()
|
||||
local att = data:GetAttachment()
|
||||
local ent = data:GetEntity()
|
||||
local nrml = data:GetNormal()
|
||||
|
||||
self:SetRenderBounds( Vector( -8, -8, -8 ), Vector( 8, 8, 8 ) )
|
||||
self:SetPos( pos )
|
||||
|
||||
-- This 0.01 is a hack.. to prevent the angle being weird and messing up when we change it back to a normal
|
||||
self:SetAngles( nrml:Angle() + Angle( 0.01, 0.01, 0.01 ) )
|
||||
|
||||
if ( IsValid( ent ) ) then
|
||||
self:SetParentPhysNum( att )
|
||||
self:SetParent( ent )
|
||||
end
|
||||
|
||||
self.Size = 4
|
||||
self.Alpha = 255
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetNormal( nrml )
|
||||
effectdata:SetEntity( ent )
|
||||
effectdata:SetAttachment( att )
|
||||
|
||||
for i = 0, 5 do
|
||||
|
||||
util.Effect( "selection_ring", effectdata )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
|
||||
self.Alpha = self.Alpha - 255 * FrameTime()
|
||||
if ( self.Alpha < 0 ) then return false end
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
|
||||
if ( self.Alpha < 1 ) then return end
|
||||
|
||||
render.SetMaterial( self.Mat )
|
||||
|
||||
render.DrawQuadEasy( self:GetPos(), self:GetAngles():Forward(), self.Size, self.Size, Color( 255, 255, 255, self.Alpha ) )
|
||||
|
||||
end
|
||||
61
gamemodes/sandbox/entities/effects/selection_ring.lua
Normal file
61
gamemodes/sandbox/entities/effects/selection_ring.lua
Normal file
@@ -0,0 +1,61 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
EFFECT.Mat = Material( "effects/select_ring" )
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
local size = 8
|
||||
self:SetCollisionBounds( Vector( -size, -size, -size ), Vector( size, size, size ) )
|
||||
|
||||
local Pos = data:GetOrigin() + data:GetNormal() * 2
|
||||
|
||||
self:SetPos( Pos )
|
||||
|
||||
-- This 0.01 is a hack.. to prevent the angle being weird and messing up when we change it back to a normal
|
||||
self:SetAngles( data:GetNormal():Angle() + Angle( 0.01, 0.01, 0.01 ) )
|
||||
|
||||
self:SetParentPhysNum( data:GetAttachment() )
|
||||
|
||||
if ( IsValid( data:GetEntity() ) ) then
|
||||
self:SetParent( data:GetEntity() )
|
||||
end
|
||||
|
||||
self.Pos = data:GetOrigin()
|
||||
self.Normal = data:GetNormal()
|
||||
|
||||
self.Speed = math.Rand( 0.5, 1.5 )
|
||||
self.Size = 4
|
||||
self.Alpha = 255
|
||||
|
||||
self.Life = 0.5
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
|
||||
self.Alpha = self.Alpha - FrameTime() * 255 * 5 * self.Speed
|
||||
self.Size = self.Size + FrameTime() * 256 * self.Speed
|
||||
|
||||
if ( self.Alpha < 0 ) then return false end
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
|
||||
if ( self.Alpha < 1 ) then return end
|
||||
|
||||
render.SetMaterial( self.Mat )
|
||||
|
||||
render.DrawQuadEasy( self:GetPos(), self:GetAngles():Forward(), self.Size, self.Size, Color( math.Rand( 10, 150 ), math.Rand( 170, 220 ), math.Rand( 240, 255 ), self.Alpha ) )
|
||||
|
||||
end
|
||||
67
gamemodes/sandbox/entities/effects/wheel_indicator.lua
Normal file
67
gamemodes/sandbox/entities/effects/wheel_indicator.lua
Normal file
@@ -0,0 +1,67 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
EFFECT.Mat = Material( "effects/wheel_ring" )
|
||||
|
||||
function EFFECT:Init( data )
|
||||
|
||||
self.Wheel = data:GetEntity()
|
||||
if ( !IsValid( self.Wheel ) ) then return end
|
||||
|
||||
self.Axis = data:GetOrigin() / 100 -- see gmod_wheel.lua
|
||||
self.Direction = data:GetScale()
|
||||
|
||||
-- This 0.01 is a hack.. to prevent the angle being weird and messing up when we change it back to a normal
|
||||
-- Removed, we are never even setting the normal on effect data
|
||||
--self:SetAngles( data:GetNormal():Angle() + Angle( 0.01, 0.01, 0.01 ) )
|
||||
|
||||
self.Alpha = 1
|
||||
|
||||
self.Size = self.Wheel:BoundingRadius() + 8
|
||||
|
||||
self:SetPos( self.Wheel:LocalToWorld( self.Axis ) )
|
||||
self:SetParent( self.Wheel )
|
||||
|
||||
local size = 64
|
||||
self:SetCollisionBounds( Vector( -size, -size, -size ), Vector( size, size, size ) )
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
|
||||
if ( !IsValid( self.Wheel ) ) then return false end
|
||||
|
||||
local speed = FrameTime()
|
||||
|
||||
self.Alpha = self.Alpha - speed * 0.8
|
||||
self.Size = self.Size + speed * 5
|
||||
|
||||
if ( self.Alpha < 0 ) then return false end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
|
||||
if ( !IsValid( self.Wheel ) ) then return end
|
||||
if ( self.Alpha < 0 ) then return end
|
||||
|
||||
render.SetMaterial( self.Mat )
|
||||
|
||||
local offset = self.Wheel:LocalToWorld( self.Axis ) - self.Wheel:GetPos()
|
||||
|
||||
render.DrawQuadEasy( self.Wheel:GetPos() + offset,
|
||||
offset:GetNormalized() * self.Direction,
|
||||
self.Size, self.Size,
|
||||
Color( 255, 255, 255, ( self.Alpha ^ 1.1 ) * 255 ),
|
||||
self.Alpha * 200 )
|
||||
|
||||
end
|
||||
63
gamemodes/sandbox/entities/entities/base_edit.lua
Normal file
63
gamemodes/sandbox/entities/entities/base_edit.lua
Normal file
@@ -0,0 +1,63 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_anim" )
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
ENT.Editable = true
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
self:SetModel( "models/maxofs2d/cube_tool.mdl" )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetUseType( ONOFF_USE )
|
||||
|
||||
end
|
||||
|
||||
function ENT:SpawnFunction( ply, tr, ClassName )
|
||||
|
||||
if ( !tr.Hit ) then return end
|
||||
|
||||
local SpawnPos = tr.HitPos + tr.HitNormal * 10
|
||||
local SpawnAng = ply:EyeAngles()
|
||||
SpawnAng.p = 0
|
||||
SpawnAng.y = SpawnAng.y + 180
|
||||
|
||||
-- Make sure the spawn position is not out of bounds
|
||||
local oobTr = util.TraceLine( {
|
||||
start = tr.HitPos,
|
||||
endpos = SpawnPos,
|
||||
mask = MASK_SOLID_BRUSHONLY
|
||||
} )
|
||||
|
||||
if ( oobTr.Hit ) then
|
||||
SpawnPos = oobTr.HitPos + oobTr.HitNormal * ( tr.HitPos:Distance( oobTr.HitPos ) / 2 )
|
||||
end
|
||||
|
||||
local ent = ents.Create( ClassName )
|
||||
ent:SetPos( SpawnPos )
|
||||
ent:SetAngles( SpawnAng )
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
return ent
|
||||
|
||||
end
|
||||
|
||||
function ENT:EnableForwardArrow()
|
||||
|
||||
self:SetBodygroup( 1, 1 )
|
||||
|
||||
end
|
||||
154
gamemodes/sandbox/entities/entities/base_gmodentity.lua
Normal file
154
gamemodes/sandbox/entities/entities/base_gmodentity.lua
Normal file
@@ -0,0 +1,154 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_anim" )
|
||||
|
||||
ENT.Spawnable = false
|
||||
|
||||
if ( CLIENT ) then
|
||||
ENT.MaxWorldTipDistance = 256
|
||||
|
||||
function ENT:BeingLookedAtByLocalPlayer()
|
||||
local ply = LocalPlayer()
|
||||
if ( !IsValid( ply ) ) then return false end
|
||||
|
||||
local view = ply:GetViewEntity()
|
||||
local dist = self.MaxWorldTipDistance
|
||||
dist = dist * dist
|
||||
|
||||
-- If we're spectating a player, perform an eye trace
|
||||
if ( view:IsPlayer() ) then
|
||||
return view:EyePos():DistToSqr( self:GetPos() ) <= dist && view:GetEyeTrace().Entity == self
|
||||
end
|
||||
|
||||
-- If we're not spectating a player, perform a manual trace from the entity's position
|
||||
local pos = view:GetPos()
|
||||
|
||||
if ( pos:DistToSqr( self:GetPos() ) <= dist ) then
|
||||
return util.TraceLine( {
|
||||
start = pos,
|
||||
endpos = pos + ( view:GetAngles():Forward() * dist ),
|
||||
filter = view
|
||||
} ).Entity == self
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
local text = self:GetOverlayText()
|
||||
|
||||
if ( text != "" && self:BeingLookedAtByLocalPlayer() && !self:GetNoDraw() ) then
|
||||
AddWorldTip( self:EntIndex(), text, 0.5, self:GetPos(), self )
|
||||
|
||||
halo.Add( { self }, color_white, 1, 1, 1, true, true )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:SetOverlayText( text )
|
||||
self:SetNWString( "GModOverlayText", text )
|
||||
end
|
||||
|
||||
function ENT:GetOverlayText()
|
||||
|
||||
local txt = self:GetNWString( "GModOverlayText" )
|
||||
|
||||
if ( txt == "" ) then
|
||||
return ""
|
||||
end
|
||||
|
||||
if ( game.SinglePlayer() ) then
|
||||
return txt
|
||||
end
|
||||
|
||||
local PlayerName = self:GetPlayerName()
|
||||
|
||||
if ( !PlayerName or PlayerName == "" ) then
|
||||
return txt
|
||||
end
|
||||
|
||||
return txt .. "\n(" .. PlayerName .. ")"
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetPlayer( ply )
|
||||
|
||||
self.Founder = ply
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
|
||||
self:SetNWString( "FounderName", ply:Nick() )
|
||||
self.FounderSID = ply:SteamID64()
|
||||
self.FounderIndex = ply:UniqueID()
|
||||
|
||||
else
|
||||
|
||||
self:SetNWString( "FounderName", "" )
|
||||
self.FounderSID = nil
|
||||
self.FounderIndex = nil
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetPlayer()
|
||||
|
||||
if ( self.Founder == nil ) then
|
||||
|
||||
-- SetPlayer has not been called
|
||||
return NULL
|
||||
|
||||
elseif ( IsValid( self.Founder ) ) then
|
||||
|
||||
-- Normal operations
|
||||
return self.Founder
|
||||
|
||||
end
|
||||
|
||||
-- See if the player has left the server then rejoined
|
||||
local ply = player.GetBySteamID64( self.FounderSID )
|
||||
if ( !IsValid( ply ) ) then
|
||||
|
||||
-- Oh well
|
||||
return NULL
|
||||
|
||||
end
|
||||
|
||||
-- Save us the check next time
|
||||
self:SetPlayer( ply )
|
||||
return ply
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetPlayerIndex()
|
||||
|
||||
return self.FounderIndex or 0
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetPlayerSteamID()
|
||||
|
||||
return self.FounderSID or ""
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetPlayerName()
|
||||
|
||||
local ply = self:GetPlayer()
|
||||
if ( IsValid( ply ) ) then
|
||||
return ply:Nick()
|
||||
end
|
||||
|
||||
return self:GetNWString( "FounderName", "" )
|
||||
|
||||
end
|
||||
112
gamemodes/sandbox/entities/entities/edit_fog.lua
Normal file
112
gamemodes/sandbox/entities/entities/edit_fog.lua
Normal file
@@ -0,0 +1,112 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_edit" )
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
ENT.PrintName = "Fog Editor"
|
||||
ENT.Category = "Editors"
|
||||
ENT.Information = "Right click on this entity via the context menu (hold C by default) and select 'Edit Properties' to edit the fog."
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
BaseClass.Initialize( self )
|
||||
|
||||
self:SetMaterial( "gmod/edit_fog" )
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
hook.Add( "SetupWorldFog", self, self.SetupWorldFog )
|
||||
hook.Add( "SetupSkyboxFog", self, self.SetupSkyFog )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetupWorldFog()
|
||||
|
||||
render.FogMode( MATERIAL_FOG_LINEAR )
|
||||
render.FogStart( self:GetFogStart() )
|
||||
render.FogEnd( self:GetFogEnd() )
|
||||
render.FogMaxDensity( self:GetDensity() )
|
||||
|
||||
local col = self:GetFogColor()
|
||||
render.FogColor( col.x * 255, col.y * 255, col.z * 255 )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetupSkyFog( skyboxscale )
|
||||
|
||||
render.FogMode( MATERIAL_FOG_LINEAR )
|
||||
render.FogStart( self:GetFogStart() * skyboxscale )
|
||||
render.FogEnd( self:GetFogEnd() * skyboxscale )
|
||||
render.FogMaxDensity( self:GetDensity() )
|
||||
|
||||
local col = self:GetFogColor()
|
||||
render.FogColor( col.x * 255, col.y * 255, col.z * 255 )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Float", 0, "FogStart", { KeyName = "fogstart", Edit = { type = "Float", min = 0, max = 1000000, order = 1 } } )
|
||||
self:NetworkVar( "Float", 1, "FogEnd", { KeyName = "fogend", Edit = { type = "Float", min = 0, max = 1000000, order = 2 } } )
|
||||
self:NetworkVar( "Float", 2, "Density", { KeyName = "density", Edit = { type = "Float", min = 0, max = 1, order = 3 } } )
|
||||
|
||||
self:NetworkVar( "Vector", 0, "FogColor", { KeyName = "fogcolor", Edit = { type = "VectorColor", order = 3 } } )
|
||||
|
||||
--
|
||||
-- TODO: Should skybox fog be edited seperately?
|
||||
--
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
-- defaults
|
||||
self:SetFogStart( 0.0 )
|
||||
self:SetFogEnd( 10000 )
|
||||
self:SetDensity( 0.9 )
|
||||
self:SetFogColor( Vector( 0.6, 0.7, 0.8 ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- This edits something global - so always network - even when not in PVS
|
||||
--
|
||||
function ENT:UpdateTransmitState()
|
||||
|
||||
return TRANSMIT_ALWAYS
|
||||
|
||||
end
|
||||
|
||||
-- Player just spawned this entity from the spawnmenu - not from a duplication.
|
||||
-- Copy over the settings of the map
|
||||
hook.Add( "PlayerSpawnedSENT", "CopyOverEditFogSettings", function( ply, ent )
|
||||
|
||||
if ( ent:GetClass() != "edit_fog" ) then return end
|
||||
|
||||
local fogCntrl = ents.FindByClass( "env_fog_controller" )[ 1 ];
|
||||
if ( !IsValid( fogCntrl ) ) then return end
|
||||
|
||||
ent:SetFogStart( fogCntrl:GetInternalVariable( "fogstart" ) )
|
||||
ent:SetFogEnd( fogCntrl:GetInternalVariable( "fogend" ) )
|
||||
ent:SetDensity( fogCntrl:GetInternalVariable( "fogmaxdensity" ) )
|
||||
ent:SetFogColor( Vector( fogCntrl:GetInternalVariable( "fogcolor" ) ) / 255 )
|
||||
|
||||
end )
|
||||
117
gamemodes/sandbox/entities/entities/edit_sky.lua
Normal file
117
gamemodes/sandbox/entities/entities/edit_sky.lua
Normal file
@@ -0,0 +1,117 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_edit" )
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
ENT.PrintName = "Sky Editor"
|
||||
ENT.Category = "Editors"
|
||||
ENT.Information = "Right click on this entity via the context menu (hold C by default) and select 'Edit Properties' to edit the sky."
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
BaseClass.Initialize( self )
|
||||
self:SetMaterial( "gmod/edit_sky" )
|
||||
|
||||
--
|
||||
-- Over-ride the sky controller with this.
|
||||
--
|
||||
if ( CLIENT ) then
|
||||
|
||||
g_SkyPaint = self
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
|
||||
--
|
||||
-- Find an env_sun - if we don't already have one.
|
||||
--
|
||||
if ( SERVER and self.EnvSun == nil ) then
|
||||
|
||||
-- so this closure only gets called once - even if it fails
|
||||
self.EnvSun = false
|
||||
|
||||
local list = ents.FindByClass( "env_sun" )
|
||||
if ( #list > 0 ) then
|
||||
self.EnvSun = list[ 1 ]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- If we have a sun - force our sun normal to its value
|
||||
--
|
||||
if ( SERVER and IsValid( self.EnvSun ) ) then
|
||||
|
||||
local vec = self.EnvSun:GetInternalVariable( "m_vDirection" )
|
||||
|
||||
if ( isvector( vec ) ) then
|
||||
self:SetSunNormal( vec )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- This needs to be a 1:1 copy of env_skypaint
|
||||
--
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
local SetupDataTables = scripted_ents.GetMember( "env_skypaint", "SetupDataTables" )
|
||||
SetupDataTables( self )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- This edits something global - so always network - even when not in PVS
|
||||
--
|
||||
function ENT:UpdateTransmitState()
|
||||
|
||||
return TRANSMIT_ALWAYS
|
||||
|
||||
end
|
||||
|
||||
-- Player just spawned this entity from the spawnmenu - not from a duplication.
|
||||
-- Copy over the settings of the maps' skypaint
|
||||
hook.Add( "PlayerSpawnedSENT", "CopyOverEditSkySettings", function( ply, ent )
|
||||
|
||||
if ( ent:GetClass() != "edit_sky" ) then return end
|
||||
|
||||
local skyPaint = ents.FindByClass( "env_skypaint" )[ 1 ];
|
||||
if ( !IsValid( skyPaint ) ) then return end
|
||||
|
||||
ent:SetTopColor( skyPaint:GetTopColor() )
|
||||
ent:SetBottomColor( skyPaint:GetBottomColor() )
|
||||
ent:SetFadeBias( skyPaint:GetFadeBias() )
|
||||
ent:SetHDRScale( skyPaint:GetHDRScale() )
|
||||
|
||||
ent:SetStarLayers( skyPaint:GetStarLayers() )
|
||||
ent:SetDrawStars( skyPaint:GetDrawStars() )
|
||||
ent:SetStarTexture( skyPaint:GetStarTexture() )
|
||||
ent:SetStarSpeed( skyPaint:GetStarSpeed() )
|
||||
ent:SetStarFade( skyPaint:GetStarFade() )
|
||||
ent:SetStarFade( skyPaint:GetStarFade() )
|
||||
|
||||
ent:SetDuskIntensity( skyPaint:GetDuskIntensity() )
|
||||
ent:SetDuskScale( skyPaint:GetDuskScale() )
|
||||
ent:SetDuskColor( skyPaint:GetDuskColor() )
|
||||
|
||||
ent:SetSunSize( skyPaint:GetSunSize() )
|
||||
ent:SetSunColor( skyPaint:GetSunColor() )
|
||||
|
||||
end )
|
||||
135
gamemodes/sandbox/entities/entities/edit_sun.lua
Normal file
135
gamemodes/sandbox/entities/entities/edit_sun.lua
Normal file
@@ -0,0 +1,135 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_edit" )
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
ENT.PrintName = "Sun Editor"
|
||||
ENT.Category = "Editors"
|
||||
ENT.Information = "Right click on this entity via the context menu (hold C by default) and select 'Edit Properties' to edit the sun. Rotate the entity to move the sun."
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
BaseClass.Initialize( self )
|
||||
self:EnableForwardArrow()
|
||||
|
||||
self:SetMaterial( "gmod/edit_sun" )
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
--
|
||||
-- Notify us when the entity angle changes, so we can update the sun entity
|
||||
--
|
||||
self:AddCallback( "OnAngleChange", self.OnAngleChange )
|
||||
|
||||
--
|
||||
-- Find an env_sun entity
|
||||
--
|
||||
local list = ents.FindByClass( "env_sun" )
|
||||
if ( #list > 0 ) then
|
||||
self.EnvSun = list[ 1 ]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Float", 0, "SunSize", { KeyName = "sunsize", Edit = { type = "Float", min = 0, max = 100, order = 1 } } )
|
||||
self:NetworkVar( "Float", 1, "OverlaySize", { KeyName = "overlaysize", Edit = { type = "Float", min = 0, max = 200, order = 2 } } )
|
||||
self:NetworkVar( "Vector", 0, "SunColor", { KeyName = "suncolor", Edit = { type = "VectorColor", order = 3 } } )
|
||||
self:NetworkVar( "Vector", 1, "OverlayColor", { KeyName = "overlaycolor", Edit = { type = "VectorColor", order = 4 } } )
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
-- defaults
|
||||
self:SetSunSize( 20 )
|
||||
self:SetOverlaySize( 20 )
|
||||
self:SetOverlayColor( Vector( 1, 1, 1 ) )
|
||||
self:SetSunColor( Vector( 1, 1, 1 ) )
|
||||
|
||||
-- call this function when something changes these variables
|
||||
self:NetworkVarNotify( "SunSize", self.OnVariableChanged )
|
||||
self:NetworkVarNotify( "OverlaySize", self.OnVariableChanged )
|
||||
self:NetworkVarNotify( "SunColor", self.OnVariableChanged )
|
||||
self:NetworkVarNotify( "OverlayColor", self.OnVariableChanged )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Callback - serverside - added in :Initialize
|
||||
--
|
||||
function ENT:OnAngleChange( newang )
|
||||
|
||||
if ( IsValid( self.EnvSun ) ) then
|
||||
self.EnvSun:SetKeyValue( "sun_dir", tostring( newang:Forward() ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Force update everything after being pasted in
|
||||
--
|
||||
function ENT:PostEntityPaste( ply, ent )
|
||||
|
||||
self:OnAngleChange( ent:GetAngles() )
|
||||
self:OnVariableChanged()
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Update all the variables on the sun, from our variables in this entity
|
||||
--
|
||||
function ENT:OnVariableChanged()
|
||||
|
||||
if ( !IsValid( self.EnvSun ) ) then return end
|
||||
|
||||
self.EnvSun:SetKeyValue( "size", self:GetSunSize() )
|
||||
self.EnvSun:SetKeyValue( "overlaysize", self:GetOverlaySize() )
|
||||
|
||||
local overlay = self:GetOverlayColor()
|
||||
self.EnvSun:SetKeyValue( "overlaycolor", Format( "%i %i %i", overlay.x * 255, overlay.y * 255, overlay.z * 255 ) )
|
||||
|
||||
local sun = self:GetSunColor()
|
||||
self.EnvSun:SetKeyValue( "suncolor", Format( "%i %i %i", sun.x * 255, sun.y * 255, sun.z * 255 ) )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- This edits something global - so always network - even when not in PVS
|
||||
--
|
||||
function ENT:UpdateTransmitState()
|
||||
|
||||
return TRANSMIT_ALWAYS
|
||||
|
||||
end
|
||||
|
||||
-- Player just spawned this entity from the spawnmenu - not from a duplication.
|
||||
-- Copy over the settings of the map
|
||||
hook.Add( "PlayerSpawnedSENT", "CopyOverEditSunSettings", function( ply, ent )
|
||||
|
||||
if ( ent:GetClass() != "edit_sun" ) then return end
|
||||
|
||||
local envSun = ents.FindByClass( "env_sun" )[ 1 ];
|
||||
if ( !IsValid( envSun ) ) then return end
|
||||
|
||||
ent:SetSunSize( envSun:GetInternalVariable( "size" ) )
|
||||
ent:SetOverlaySize( envSun:GetInternalVariable( "overlaysize" ) )
|
||||
ent:SetOverlayColor( Vector( envSun:GetInternalVariable( "overlaycolor" ) ) / 255 )
|
||||
ent:SetSunColor( Vector( envSun:GetInternalVariable( "rendercolor" ) ) / 255 )
|
||||
|
||||
end )
|
||||
36
gamemodes/sandbox/entities/entities/gmod_anchor.lua
Normal file
36
gamemodes/sandbox/entities/entities/gmod_anchor.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.PrintName = "World Anchor"
|
||||
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
self:SetModel( "models/Combine_Helicopter/helicopter_bomb01.mdl" )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
|
||||
self:SetNotSolid( true )
|
||||
self:SetNoDraw( true )
|
||||
self:DrawShadow( false )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then
|
||||
phys:EnableMotion( false )
|
||||
phys:EnableCollisions( false )
|
||||
end
|
||||
|
||||
self:SetUnFreezable( true )
|
||||
|
||||
end
|
||||
96
gamemodes/sandbox/entities/entities/gmod_balloon.lua
Normal file
96
gamemodes/sandbox/entities/entities/gmod_balloon.lua
Normal file
@@ -0,0 +1,96 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_gmodentity" )
|
||||
|
||||
ENT.PrintName = "Balloon"
|
||||
ENT.Editable = true
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Float", 0, "Force", { KeyName = "force", Edit = { type = "Float", order = 1, min = -2000, max = 2000, title = "#tool.balloon.force" } } )
|
||||
|
||||
if ( SERVER ) then
|
||||
self:NetworkVarNotify( "Force", function() self:PhysWake() end )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetRenderMode( RENDERMODE_TRANSCOLOR )
|
||||
|
||||
-- Set up our physics object here
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then
|
||||
phys:SetMass( 100 )
|
||||
phys:Wake()
|
||||
phys:EnableGravity( false )
|
||||
end
|
||||
|
||||
self:SetForce( 1 )
|
||||
self:StartMotionController()
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetOverlayText()
|
||||
|
||||
local txt = "Force: " .. math.floor( self:GetForce() )
|
||||
|
||||
if ( txt == "" ) then return "" end
|
||||
if ( game.SinglePlayer() ) then return txt end
|
||||
|
||||
return txt .. "\n(" .. self:GetPlayerName() .. ")"
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
|
||||
if ( self.Indestructible ) then return end
|
||||
|
||||
local c = self:GetColor()
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self:GetPos() )
|
||||
effectdata:SetStart( Vector( c.r, c.g, c.b ) )
|
||||
util.Effect( "balloon_pop", effectdata )
|
||||
|
||||
if ( self.Explosive ) then
|
||||
|
||||
local ed_expl = EffectData()
|
||||
ed_expl:SetOrigin( self:GetPos() )
|
||||
ed_expl:SetScale( 1 )
|
||||
ed_expl:SetMagnitude( 25 )
|
||||
util.Effect( "Explosion", ed_expl, true, true )
|
||||
|
||||
end
|
||||
|
||||
local attacker = dmginfo:GetAttacker()
|
||||
if ( IsValid( attacker ) && attacker:IsPlayer() ) then
|
||||
attacker:SendLua( "achievements.BalloonPopped()" )
|
||||
end
|
||||
|
||||
self:Remove()
|
||||
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate( phys, deltatime )
|
||||
|
||||
local vLinear = Vector( 0, 0, self:GetForce() * 5000 ) * deltatime
|
||||
local vAngular = vector_origin
|
||||
|
||||
return vAngular, vLinear, SIM_GLOBAL_FORCE
|
||||
|
||||
end
|
||||
164
gamemodes/sandbox/entities/entities/gmod_button.lua
Normal file
164
gamemodes/sandbox/entities/entities/gmod_button.lua
Normal file
@@ -0,0 +1,164 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_gmodentity" )
|
||||
|
||||
ENT.PrintName = "Button"
|
||||
ENT.Editable = true
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Int", 0, "Key" )
|
||||
self:NetworkVar( "Bool", 0, "On" )
|
||||
self:NetworkVar( "Bool", 1, "IsToggle", { KeyName = "tg", Edit = { type = "Boolean", order = 1, title = "#tool.button.toggle" } } )
|
||||
self:NetworkVar( "String", 0, "Label", { KeyName = "lbl", Edit = { type = "Generic", order = 2, title = "#tool.button.text" } } )
|
||||
|
||||
if ( SERVER ) then
|
||||
self:SetOn( false )
|
||||
self:SetIsToggle( false )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetUseType( ONOFF_USE )
|
||||
|
||||
else
|
||||
|
||||
self.PosePosition = 0
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetOverlayText()
|
||||
|
||||
local text = self:GetLabel()
|
||||
|
||||
text = string.gsub( text, "\\", "" )
|
||||
text = string.sub( text, 0, 20 )
|
||||
|
||||
if ( text == "" ) then return "" end
|
||||
|
||||
local txt = "\"" .. text .. "\""
|
||||
|
||||
if ( txt == "" ) then return "" end
|
||||
if ( game.SinglePlayer() ) then return txt end
|
||||
|
||||
return txt .. "\n(" .. self:GetPlayerName() .. ")"
|
||||
|
||||
end
|
||||
|
||||
function ENT:Use( activator, caller, type, value )
|
||||
|
||||
if ( !activator:IsPlayer() ) then return end -- Who the frig is pressing this shit!?
|
||||
|
||||
if ( self:GetIsToggle() ) then
|
||||
|
||||
if ( type == USE_ON ) then
|
||||
self:Toggle( !self:GetOn(), activator )
|
||||
end
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
if ( IsValid( self.LastUser ) ) then return end -- Someone is already using this button
|
||||
|
||||
--
|
||||
-- Switch off
|
||||
--
|
||||
if ( self:GetOn() ) then
|
||||
self:Toggle( false, activator )
|
||||
return
|
||||
end
|
||||
|
||||
--
|
||||
-- Switch on
|
||||
--
|
||||
self:Toggle( true, activator )
|
||||
self:NextThink( CurTime() )
|
||||
self.LastUser = activator
|
||||
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
|
||||
-- Add a world tip if the player is looking at it
|
||||
self.BaseClass.Think( self )
|
||||
|
||||
-- Update the animation
|
||||
if ( CLIENT ) then
|
||||
|
||||
self:UpdateLever()
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- If the player looks away while holding down use it will stay on
|
||||
-- Lets fix that..
|
||||
--
|
||||
if ( SERVER && self:GetOn() && !self:GetIsToggle() ) then
|
||||
|
||||
if ( !IsValid( self.LastUser ) || !self.LastUser:KeyDown( IN_USE ) ) then
|
||||
|
||||
self:Toggle( false, self.LastUser )
|
||||
self.LastUser = nil
|
||||
|
||||
end
|
||||
|
||||
self:NextThink( CurTime() )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Makes the button trigger the keys
|
||||
--
|
||||
function ENT:Toggle( bEnable, ply )
|
||||
|
||||
-- If a button has a valid player on it, use that, if not, use activator
|
||||
local targetPly = self:GetPlayer()
|
||||
if ( !IsValid( targetPly ) ) then targetPly = ply end
|
||||
|
||||
if ( bEnable ) then
|
||||
|
||||
numpad.Activate( targetPly, self:GetKey(), true )
|
||||
self:SetOn( true )
|
||||
|
||||
else
|
||||
|
||||
numpad.Deactivate( targetPly, self:GetKey(), true )
|
||||
self:SetOn( false )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Update the lever animation
|
||||
--
|
||||
function ENT:UpdateLever()
|
||||
|
||||
local TargetPos = 0.0
|
||||
if ( self:GetOn() ) then TargetPos = 1.0 end
|
||||
|
||||
self.PosePosition = math.Approach( self.PosePosition, TargetPos, FrameTime() * 5.0 )
|
||||
|
||||
self:SetPoseParameter( "switch", self.PosePosition )
|
||||
self:InvalidateBoneCache()
|
||||
|
||||
end
|
||||
219
gamemodes/sandbox/entities/entities/gmod_cameraprop.lua
Normal file
219
gamemodes/sandbox/entities/entities/gmod_cameraprop.lua
Normal file
@@ -0,0 +1,219 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
if ( CLIENT ) then
|
||||
CreateConVar( "cl_drawcameras", "1", 0, "Should Sandbox cameras be visible?" )
|
||||
end
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.PrintName = "Camera"
|
||||
|
||||
local CAMERA_MODEL = Model( "models/dav0r/camera.mdl" )
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Int", 0, "Key" )
|
||||
self:NetworkVar( "Bool", 0, "On" )
|
||||
self:NetworkVar( "Vector", 0, "vecTrack" )
|
||||
self:NetworkVar( "Entity", 0, "entTrack" )
|
||||
self:NetworkVar( "Entity", 1, "Player" )
|
||||
|
||||
end
|
||||
|
||||
-- Custom drive mode
|
||||
function ENT:GetEntityDriveMode()
|
||||
|
||||
return "drive_noclip"
|
||||
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
self:SetModel( CAMERA_MODEL )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:DrawShadow( false )
|
||||
|
||||
-- Don't collide with the player
|
||||
self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then phys:Sleep() end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetTracking( Ent, LPos )
|
||||
|
||||
if ( IsValid( Ent ) ) then
|
||||
|
||||
self:SetMoveType( MOVETYPE_NONE )
|
||||
self:SetSolid( SOLID_BBOX )
|
||||
|
||||
else
|
||||
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
|
||||
end
|
||||
|
||||
self:NextThink( CurTime() )
|
||||
|
||||
self:SetvecTrack( LPos )
|
||||
self:SetentTrack( Ent )
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetLocked( locked )
|
||||
|
||||
if ( locked == 1 ) then
|
||||
|
||||
self.PhysgunDisabled = true
|
||||
|
||||
self:SetMoveType( MOVETYPE_NONE )
|
||||
self:SetSolid( SOLID_BBOX )
|
||||
|
||||
self:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
|
||||
else
|
||||
|
||||
self.PhysgunDisabled = false
|
||||
|
||||
end
|
||||
|
||||
self.locked = locked
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
if ( self.locked ) then return end
|
||||
self:TakePhysicsDamage( dmginfo )
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
|
||||
if ( IsValid( self.UsingPlayer ) ) then
|
||||
|
||||
self.UsingPlayer:SetViewEntity( self.UsingPlayer )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
numpad.Register( "Camera_On", function( ply, ent )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
if ( !IsValid( ply ) ) then return false end
|
||||
|
||||
ply:SetViewEntity( ent )
|
||||
ply.UsingCamera = ent
|
||||
ent.UsingPlayer = ply
|
||||
|
||||
end )
|
||||
|
||||
numpad.Register( "Camera_Toggle", function( ply, ent, idx, buttoned )
|
||||
|
||||
-- The camera was deleted or something - return false to remove this entry
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
if ( !IsValid( ply ) ) then return false end
|
||||
|
||||
-- Something else changed players view entity
|
||||
if ( ply.UsingCamera and ply.UsingCamera == ent and ply:GetViewEntity() != ent ) then
|
||||
ply.UsingCamera = nil
|
||||
ent.UsingPlayer = nil
|
||||
end
|
||||
|
||||
if ( ply.UsingCamera and ply.UsingCamera == ent ) then
|
||||
|
||||
ply:SetViewEntity( ply )
|
||||
ply.UsingCamera = nil
|
||||
ent.UsingPlayer = nil
|
||||
|
||||
else
|
||||
|
||||
ply:SetViewEntity( ent )
|
||||
ply.UsingCamera = ent
|
||||
ent.UsingPlayer = ply
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
numpad.Register( "Camera_Off", function( ply, ent )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
if ( !IsValid( ply ) ) then return false end
|
||||
|
||||
if ( ply.UsingCamera and ply.UsingCamera == ent ) then
|
||||
ply:SetViewEntity( ply )
|
||||
ply.UsingCamera = nil
|
||||
ent.UsingPlayer = nil
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self:TrackEntity( self:GetentTrack(), self:GetvecTrack() )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:TrackEntity( ent, lpos )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local WPos = ent:LocalToWorld( lpos )
|
||||
|
||||
if ( ent:IsPlayer() ) then
|
||||
WPos = WPos + ent:GetViewOffset() * 0.85
|
||||
end
|
||||
|
||||
local CamPos = self:GetPos()
|
||||
local Ang = WPos - CamPos
|
||||
|
||||
Ang = Ang:Angle()
|
||||
self:SetAngles( Ang )
|
||||
|
||||
end
|
||||
|
||||
function ENT:CanTool( ply, trace, mode, tool, click )
|
||||
|
||||
if ( self:GetMoveType() == MOVETYPE_NONE ) then return false end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function ENT:Draw( flags )
|
||||
|
||||
if ( GetConVarNumber( "cl_drawcameras" ) == 0 ) then return end
|
||||
|
||||
-- Don't draw the camera if we're taking pics
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
if ( IsValid( wep ) and wep:GetClass() == "gmod_camera" ) then
|
||||
return
|
||||
end
|
||||
|
||||
self:DrawModel( flags )
|
||||
|
||||
end
|
||||
88
gamemodes/sandbox/entities/entities/gmod_dynamite.lua
Normal file
88
gamemodes/sandbox/entities/entities/gmod_dynamite.lua
Normal file
@@ -0,0 +1,88 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_gmodentity" )
|
||||
|
||||
ENT.PrintName = "Dynamite"
|
||||
ENT.Editable = true
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Bool", 0, "ShouldRemove", { KeyName = "sr", Edit = { type = "Boolean", order = 1, title = "#tool.dynamite.remove" } } )
|
||||
self:NetworkVar( "Float", 0, "Damage", { KeyName = "force", Edit = { type = "Float", order = 2, min = 0, max = 500, title = "#tool.dynamite.damage" } } )
|
||||
self:NetworkVar( "Float", 1, "Delay", { KeyName = "delay", Edit = { type = "Float", order = 3, min = 0, max = 10, title = "#tool.dynamite.delay" } } )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( SERVER ) then
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:Setup( damage )
|
||||
|
||||
self:SetDamage( damage )
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetOverlayText()
|
||||
|
||||
local txt = string.format( "Damage: %g\nDelay: %g", math.Clamp( self:GetDamage(), 0, 1500 ), self:GetDelay() )
|
||||
|
||||
if ( game.SinglePlayer() ) then return txt end
|
||||
|
||||
return txt .. "\n(" .. self:GetPlayerName() .. ")"
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
|
||||
if ( dmginfo:GetInflictor():GetClass() == "gmod_dynamite" ) then return end
|
||||
|
||||
self:TakePhysicsDamage( dmginfo )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Blow that mother fucker up, BAATCHH
|
||||
--
|
||||
function ENT:Explode( delay, ply )
|
||||
|
||||
if ( !IsValid( self ) ) then return end
|
||||
|
||||
if ( !IsValid( ply ) ) then ply = self end
|
||||
|
||||
local _delay = delay or self:GetDelay()
|
||||
|
||||
if ( _delay == 0 ) then
|
||||
|
||||
local radius = 300
|
||||
|
||||
util.BlastDamage( self, ply, self:GetPos(), radius, math.Clamp( self:GetDamage(), 0, 1500 ) )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self:GetPos() )
|
||||
util.Effect( "Explosion", effectdata, true, true )
|
||||
|
||||
if ( self:GetShouldRemove() ) then self:Remove() return end
|
||||
if ( self:GetMaxHealth() > 0 && self:Health() <= 0 ) then self:SetHealth( self:GetMaxHealth() ) end
|
||||
|
||||
else
|
||||
|
||||
timer.Simple( _delay, function() if ( !IsValid( self ) ) then return end self:Explode( 0, ply ) end )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
413
gamemodes/sandbox/entities/entities/gmod_emitter.lua
Normal file
413
gamemodes/sandbox/entities/entities/gmod_emitter.lua
Normal file
@@ -0,0 +1,413 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_gmodentity" )
|
||||
|
||||
ENT.PrintName = "Emitter"
|
||||
ENT.Editable = true
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Bool", 1, "On", { KeyName = "on", Edit = { type = "Boolean", order = 1, title = "#entedit.enabled" } } )
|
||||
self:NetworkVar( "Bool", 0, "Toggle", { KeyName = "tg", Edit = { type = "Boolean", order = 1, title = "#tool.emitter.toggle" } } )
|
||||
self:NetworkVar( "Float", 0, "Delay", { KeyName = "dl", Edit = { type = "Float", order = 1, min = 0.01, max = 2, title = "#tool.emitter.delay" } } )
|
||||
self:NetworkVar( "Float", 1, "Scale", { KeyName = "sc", Edit = { type = "Float", order = 1, min = 0, max = 6, title = "#tool.emitter.scale" } } )
|
||||
self:NetworkVar( "String", 0, "Effect" )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
self:SetModel( "models/props_lab/tpplug.mdl" ) -- TODO: Find something better than this
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
|
||||
self:DrawShadow( false )
|
||||
self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then phys:Wake() end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:Draw( flags )
|
||||
|
||||
-- Don't draw if the player is holding Camera SWEP in their hands
|
||||
local ply = LocalPlayer()
|
||||
local wep = ply:GetActiveWeapon()
|
||||
|
||||
if ( IsValid( wep ) ) then
|
||||
|
||||
local weapon_name = wep:GetClass()
|
||||
if ( weapon_name == "gmod_camera" ) then return end
|
||||
|
||||
end
|
||||
|
||||
BaseClass.Draw( self, flags )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
BaseClass.Think( self )
|
||||
|
||||
if ( !self:GetOn() ) then return end
|
||||
|
||||
self.Delay = self.Delay or 0
|
||||
|
||||
if ( self.Delay > CurTime() ) then return end
|
||||
self.Delay = CurTime() + self:GetDelay()
|
||||
|
||||
--
|
||||
-- Find our effect table
|
||||
--
|
||||
local Effect = self:GetEffect()
|
||||
|
||||
local EffectTable = list.Get( "EffectType" )[ Effect ]
|
||||
if ( !EffectTable ) then return end
|
||||
|
||||
local Angle = self:GetAngles()
|
||||
EffectTable.func( self, self:GetPos() + Angle:Forward() * 12, Angle, self:GetScale() )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Overridden because I want to show the name of the player that spawned it..
|
||||
-----------------------------------------------------------]]
|
||||
function ENT:GetOverlayText()
|
||||
|
||||
return self:GetPlayerName()
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
numpad.Register( "Emitter_On", function( ply, ent )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
if ( ent:GetToggle() ) then
|
||||
ent:SetOn( !ent:GetOn() )
|
||||
return end
|
||||
|
||||
ent:SetOn( true )
|
||||
|
||||
end )
|
||||
|
||||
numpad.Register( "Emitter_Off", function( ply, ent )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
if ( ent:GetToggle() ) then return end
|
||||
|
||||
ent:SetOn( false )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
game.AddParticles( "particles/gmod_effects.pcf" )
|
||||
PrecacheParticleSystem( "generic_smoke" )
|
||||
|
||||
list.Set( "EffectType", "smoke", {
|
||||
print = "#effecttype.smoke",
|
||||
material = "gui/effects/smoke.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
ParticleEffect( "generic_smoke", pos, angle, ent )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "sparks", {
|
||||
print = "#effecttype.sparks",
|
||||
material = "gui/effects/sparks.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetNormal( angle:Forward() * scale )
|
||||
effectdata:SetMagnitude( scale / 2 )
|
||||
effectdata:SetRadius( 8 - scale )
|
||||
util.Effect( "Sparks", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "stunstickimpact", {
|
||||
print = "#effecttype.stunstick",
|
||||
material = "gui/effects/stunstickimpact.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetNormal( angle:Forward() )
|
||||
util.Effect( "stunstickimpact", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "manhacksparks", {
|
||||
print = "#effecttype.manhack",
|
||||
material = "gui/effects/manhacksparks.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetNormal( angle:Forward() * scale )
|
||||
util.Effect( "manhacksparks", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "bloodspray", {
|
||||
print = "#effecttype.blood",
|
||||
material = "gui/effects/bloodspray.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetNormal( angle:Forward() * math.max( 3, scale ) / 3 )
|
||||
effectdata:SetMagnitude( 1 )
|
||||
effectdata:SetScale( scale + 9 )
|
||||
effectdata:SetColor( 0 )
|
||||
effectdata:SetFlags( 3 )
|
||||
util.Effect( "bloodspray", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "striderblood", {
|
||||
print = "#effecttype.strider",
|
||||
material = "gui/effects/striderblood.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetNormal( angle:Forward() * ( 6 - scale ) / 2 )
|
||||
effectdata:SetScale( scale / 2 )
|
||||
util.Effect( "StriderBlood", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "shells", {
|
||||
print = "#effecttype.pistol",
|
||||
material = "gui/effects/shells.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetAngles( angle )
|
||||
util.Effect( "ShellEject", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "rifleshells", {
|
||||
print = "#effecttype.rifle",
|
||||
material = "gui/effects/rifleshells.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetAngles( angle )
|
||||
util.Effect( "RifleShellEject", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "shotgunshells", {
|
||||
print = "#effecttype.shotgun",
|
||||
material = "gui/effects/shotgunshells.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetAngles( angle )
|
||||
util.Effect( "ShotgunShellEject", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "cball_explode", {
|
||||
print = "#effecttype.cball_explode",
|
||||
material = "gui/effects/cball_explode.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
util.Effect( "cball_explode", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "cball_bounce", {
|
||||
print = "#effecttype.cball_bounce",
|
||||
material = "gui/effects/cball_bounce.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetNormal( angle:Forward() * scale / 4 )
|
||||
effectdata:SetRadius( scale * 2 )
|
||||
util.Effect( "cball_bounce", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "thumperdust", {
|
||||
print = "#effecttype.thumperdust",
|
||||
material = "gui/effects/thumperdust.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetScale( scale * 24 )
|
||||
util.Effect( "ThumperDust", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "ar2impact", {
|
||||
print = "#effecttype.ar2impact",
|
||||
material = "gui/effects/ar2impact.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetNormal( angle:Forward() )
|
||||
util.Effect( "AR2Impact", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "ar2explosion", {
|
||||
print = "#effecttype.ar2explosion",
|
||||
material = "gui/effects/ar2explosion.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetRadius( scale * 4 )
|
||||
effectdata:SetNormal( angle:Forward() )
|
||||
util.Effect( "AR2Explosion", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "explosion", {
|
||||
print = "#effecttype.explosion",
|
||||
material = "gui/effects/explosion.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetFlags( 4 )
|
||||
util.Effect( "explosion", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "helicoptermegabomb", {
|
||||
print = "#effecttype.helicoptermegabomb",
|
||||
material = "gui/effects/helicoptermegabomb.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
util.Effect( "helicoptermegabomb", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "underwaterexplosion", {
|
||||
print = "#effecttype.waterexplosion",
|
||||
material = "gui/effects/waterexplosion.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
util.Effect( "WaterSurfaceExplosion", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "watersplash", {
|
||||
print = "#effecttype.watersplash",
|
||||
material = "gui/effects/watersplash.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetScale( scale * 2 )
|
||||
effectdata:SetFlags( 0 )
|
||||
util.Effect( "WaterSplash", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "dirtywatersplash", {
|
||||
print = "#effecttype.dirtywatersplash",
|
||||
material = "gui/effects/dirtywatersplash.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
effectdata:SetScale( scale * 2 )
|
||||
effectdata:SetFlags( 1 )
|
||||
util.Effect( "WaterSplash", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "glassimpact", {
|
||||
print = "#effecttype.glassimpact",
|
||||
material = "gui/effects/glassimpact.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
util.Effect( "GlassImpact", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "bloodimpact", {
|
||||
print = "#effecttype.bloodimpact",
|
||||
material = "gui/effects/bloodimpact.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos )
|
||||
util.Effect( "BloodImpact", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "EffectType", "muzzleeffect", {
|
||||
print = "#effecttype.muzzleeffect",
|
||||
material = "gui/effects/muzzleeffect.png",
|
||||
func = function( ent, pos, angle, scale )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( pos + angle:Forward() * 4 )
|
||||
effectdata:SetAngles( angle )
|
||||
effectdata:SetScale( scale )
|
||||
util.Effect( "MuzzleEffect", effectdata, true, true )
|
||||
|
||||
end
|
||||
} )
|
||||
43
gamemodes/sandbox/entities/entities/gmod_ghost.lua
Normal file
43
gamemodes/sandbox/entities/entities/gmod_ghost.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_gmodentity" )
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.PrintName = "Tool Ghost"
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( SERVER ) then
|
||||
self:PhysicsInitBox( Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetNetworkedBonePosition( i, Pos, Angle )
|
||||
|
||||
self:SetNWVector( "Vector" .. i, Pos )
|
||||
self:SetNWAngle( "Angle" .. i, Angle )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Draw( flags )
|
||||
|
||||
-- Don't draw it if we're a ragdoll and haven't
|
||||
-- received all of the bone positions yet.
|
||||
if ( self:GetModelPhysBoneCount() > 1 and !self:GetNWVector( "Vector0", false ) ) then
|
||||
return
|
||||
end
|
||||
|
||||
BaseClass.Draw( self, flags )
|
||||
|
||||
end
|
||||
268
gamemodes/sandbox/entities/entities/gmod_hoverball.lua
Normal file
268
gamemodes/sandbox/entities/entities/gmod_hoverball.lua
Normal file
@@ -0,0 +1,268 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_gmodentity" )
|
||||
|
||||
ENT.PrintName = "Hoverball"
|
||||
ENT.Editable = true
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Bool", 0, "Enabled" )
|
||||
|
||||
self:NetworkVar( "Float", 0, "TargetZ" )
|
||||
self:NetworkVar( "Float", 1, "SpeedVar", { KeyName = "speed", Edit = { type = "Float", order = 1, min = 0, max = 20, title = "#tool.hoverball.speed" } } )
|
||||
self:NetworkVar( "Float", 2, "AirResistanceVar", { KeyName = "resistance", Edit = { type = "Float", order = 2, min = 0, max = 10, title = "#tool.hoverball.resistance" } } )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self.Glow = Material( "sprites/light_glow02_add" )
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
|
||||
-- Wake up our physics object so we don't start asleep
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then
|
||||
phys:EnableGravity( !self:GetEnabled() )
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
-- Start the motion controller (so PhysicsSimulate gets called)
|
||||
self:StartMotionController()
|
||||
|
||||
self.Fraction = 0
|
||||
self.ZVelocity = 0
|
||||
self:SetTargetZ( self:GetPos().z )
|
||||
self:SetSpeed( 1 )
|
||||
self:SetEnabled( true )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnRestore()
|
||||
|
||||
self.ZVelocity = 0
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetSpeed()
|
||||
|
||||
if ( !game.SinglePlayer() ) then return math.Clamp( self:GetSpeedVar(), 0, 10 ) end
|
||||
|
||||
return self:GetSpeedVar()
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetSpeed( s )
|
||||
|
||||
self:SetSpeedVar( s )
|
||||
self:UpdateLabel()
|
||||
|
||||
end
|
||||
|
||||
function ENT:UpdateLabel()
|
||||
|
||||
local strength = 0
|
||||
if ( self:GetPhysicsObject() ) then strength = self:GetPhysicsObject():GetMass() / 150 end
|
||||
|
||||
self:SetOverlayText( string.format( "Speed: %g\nResistance: %g\nStrength: %g", self:GetSpeed(), self:GetAirResistance(), strength ) )
|
||||
|
||||
end
|
||||
|
||||
function ENT:DrawEffects()
|
||||
if ( !self:GetEnabled() ) then return end
|
||||
|
||||
local vOffset = self:GetPos()
|
||||
local vPlayerEyes = LocalPlayer():EyePos()
|
||||
local vDiff = ( vOffset - vPlayerEyes ):GetNormalized()
|
||||
|
||||
render.SetMaterial( self.Glow )
|
||||
local color = Color( 70, 180, 255, 255 )
|
||||
render.DrawSprite( vOffset - vDiff * 2, 22, 22, color )
|
||||
|
||||
local Distance = math.abs( ( self:GetTargetZ() - self:GetPos().z ) * math.sin( CurTime() * 20 ) ) * 0.05
|
||||
color.r = color.r * math.Clamp( Distance, 0, 1 )
|
||||
color.b = color.b * math.Clamp( Distance, 0, 1 )
|
||||
color.g = color.g * math.Clamp( Distance, 0, 1 )
|
||||
|
||||
render.DrawSprite( vOffset + vDiff * 4, 48, 48, color )
|
||||
render.DrawSprite( vOffset + vDiff * 4, 52, 52, color )
|
||||
end
|
||||
|
||||
ENT.WantsTranslucency = true -- If model is opaque, still call DrawTranslucent
|
||||
function ENT:DrawTranslucent( flags )
|
||||
self:DrawEffects()
|
||||
BaseClass.DrawTranslucent( self, flags )
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate( phys, deltatime )
|
||||
|
||||
if ( !self:GetEnabled() ) then return end
|
||||
|
||||
if ( self.ZVelocity != 0 ) then
|
||||
|
||||
self:SetTargetZ( self:GetTargetZ() + ( self.ZVelocity * deltatime * self:GetSpeed() ) )
|
||||
self:GetPhysicsObject():Wake()
|
||||
|
||||
end
|
||||
|
||||
phys:Wake()
|
||||
|
||||
local Pos = phys:GetPos()
|
||||
local Distance = self:GetTargetZ() - Pos.z
|
||||
local AirResistance = self:GetAirResistance()
|
||||
|
||||
if ( Distance == 0 ) then return end
|
||||
|
||||
local Exponent = Distance^2
|
||||
|
||||
if ( Distance < 0 ) then
|
||||
Exponent = Exponent * -1
|
||||
end
|
||||
|
||||
Exponent = Exponent * deltatime * 300
|
||||
|
||||
local physVel = phys:GetVelocity()
|
||||
local zVel = physVel.z
|
||||
|
||||
Exponent = Exponent - ( zVel * deltatime * 600 * ( AirResistance + 1 ) )
|
||||
-- The higher you make this 300 the less it will flop about
|
||||
-- I'm thinking it should actually be relative to any objects we're connected to
|
||||
-- Since it seems to flop more and more the heavier the object
|
||||
|
||||
Exponent = math.Clamp( Exponent, -5000, 5000 )
|
||||
|
||||
local Linear = Vector( 0, 0, Exponent )
|
||||
|
||||
if ( AirResistance > 0 ) then
|
||||
|
||||
Linear.y = physVel.y * -1 * AirResistance
|
||||
Linear.x = physVel.x * -1 * AirResistance
|
||||
|
||||
end
|
||||
|
||||
return vector_origin, Linear, SIM_GLOBAL_ACCELERATION
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetZVelocity( z )
|
||||
|
||||
if ( z != 0 ) then
|
||||
self:GetPhysicsObject():Wake()
|
||||
end
|
||||
|
||||
self.ZVelocity = z * FrameTime() * 5000
|
||||
|
||||
end
|
||||
|
||||
function ENT:Toggle()
|
||||
|
||||
self:SetEnabled( !self:GetEnabled() )
|
||||
|
||||
if ( self:GetEnabled() ) then
|
||||
self:SetTargetZ( self:GetPos().z )
|
||||
end
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then
|
||||
phys:EnableGravity( !self:GetEnabled() )
|
||||
phys:Wake()
|
||||
|
||||
-- Make the mass not insane when they are turned off
|
||||
if ( self.Strength ) then
|
||||
if ( self:GetEnabled() ) then
|
||||
phys:SetMass( 150 * self.Strength )
|
||||
else
|
||||
phys:SetMass( 15 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetAirResistance()
|
||||
return self:GetAirResistanceVar()
|
||||
end
|
||||
|
||||
function ENT:SetAirResistance( num )
|
||||
self:SetAirResistanceVar( num )
|
||||
self:UpdateLabel()
|
||||
end
|
||||
|
||||
function ENT:SetStrength( strength )
|
||||
|
||||
self.Strength = strength
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then
|
||||
phys:SetMass( 150 * self.Strength )
|
||||
end
|
||||
|
||||
self:UpdateLabel()
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- This gets called after the entity has been duplicated.
|
||||
-- We use it to set the target z to the spawned z.. because we want
|
||||
-- to hover in place rather than zoom up to the saved level!
|
||||
--
|
||||
function ENT:OnDuplicated( v )
|
||||
|
||||
self:SetTargetZ( v.Pos.z )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) && !self:GetEnabled() ) then
|
||||
phys:SetMass( 15 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
numpad.Register( "Hoverball_Up", function( ply, ent, keydown )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
if ( keydown ) then ent:SetZVelocity( 1 ) else ent:SetZVelocity( 0 ) end
|
||||
return true
|
||||
|
||||
end )
|
||||
|
||||
numpad.Register( "Hoverball_Down", function( ply, ent, keydown )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
if ( keydown ) then ent:SetZVelocity( -1 ) else ent:SetZVelocity( 0 ) end
|
||||
return true
|
||||
|
||||
end )
|
||||
|
||||
numpad.Register( "Hoverball_Toggle", function( ply, ent )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
ent:Toggle()
|
||||
return true
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
270
gamemodes/sandbox/entities/entities/gmod_lamp.lua
Normal file
270
gamemodes/sandbox/entities/entities/gmod_lamp.lua
Normal file
@@ -0,0 +1,270 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_gmodentity" )
|
||||
|
||||
ENT.PrintName = "Lamp"
|
||||
ENT.Editable = true
|
||||
|
||||
AccessorFunc( ENT, "Texture", "FlashlightTexture" )
|
||||
|
||||
-- Set up our data table
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Bool", 0, "On", { KeyName = "on", Edit = { type = "Boolean", order = 1, title = "#entedit.enabled" } } )
|
||||
self:NetworkVar( "Bool", 1, "Toggle", { KeyName = "toggle", Edit = { type = "Boolean", order = 2, title = "#tool.lamp.toggle" } } )
|
||||
self:NetworkVar( "Float", 0, "LightFOV", { KeyName = "fov", Edit = { type = "Float", order = 3, min = 10, max = 170, title = "#tool.lamp.fov" } } )
|
||||
self:NetworkVar( "Float", 1, "Distance", { KeyName = "dist", Edit = { type = "Float", order = 4, min = 64, max = 2048, title = "#tool.lamp.distance" } } )
|
||||
self:NetworkVar( "Float", 2, "Brightness", { KeyName = "bright", Edit = { type = "Float", order = 5, min = 0, max = 8, title = "#tool.lamp.brightness" } } )
|
||||
|
||||
if ( SERVER ) then
|
||||
self:NetworkVarNotify( "On", self.OnUpdateLight )
|
||||
self:NetworkVarNotify( "LightFOV", self.OnUpdateLight )
|
||||
self:NetworkVarNotify( "Brightness", self.OnUpdateLight )
|
||||
self:NetworkVarNotify( "Distance", self.OnUpdateLight )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Custom drive mode
|
||||
function ENT:GetEntityDriveMode()
|
||||
|
||||
return "drive_noclip"
|
||||
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:DrawShadow( false )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then phys:Wake() end
|
||||
|
||||
local lightInfo = self:GetLightInfo()
|
||||
self:SetSkin( lightInfo.Skin )
|
||||
|
||||
end
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self.PixVis = util.GetPixelVisibleHandle()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local defaultOffset = Vector( 5, 0, 0 )
|
||||
local defaultAngle = Angle( 0, 0, 0 )
|
||||
function ENT:GetLightInfo()
|
||||
|
||||
local lightInfo = {}
|
||||
if ( list.Get( "LampModels" )[ self:GetModel() ] ) then
|
||||
lightInfo = list.Get( "LampModels" )[ self:GetModel() ]
|
||||
end
|
||||
|
||||
lightInfo.Offset = lightInfo.Offset or defaultOffset
|
||||
lightInfo.Angle = lightInfo.Angle or defaultAngle
|
||||
lightInfo.NearZ = lightInfo.NearZ or 12
|
||||
lightInfo.Scale = lightInfo.Scale or 2
|
||||
lightInfo.Skin = lightInfo.Skin or 1
|
||||
|
||||
return lightInfo
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function ENT:Think()
|
||||
|
||||
self.BaseClass.Think( self )
|
||||
|
||||
if ( !IsValid( self.flashlight ) ) then return end
|
||||
|
||||
if ( string.FromColor( self.flashlight:GetColor() ) != string.FromColor( self:GetColor() ) ) then
|
||||
self.flashlight:SetColor( self:GetColor() )
|
||||
self:UpdateLight()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
|
||||
self:TakePhysicsDamage( dmginfo )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Switch( bOn )
|
||||
self:SetOn( bOn )
|
||||
end
|
||||
|
||||
function ENT:OnSwitch( bOn )
|
||||
|
||||
if ( bOn && IsValid( self.flashlight ) ) then return end
|
||||
|
||||
if ( !bOn ) then
|
||||
|
||||
SafeRemoveEntity( self.flashlight )
|
||||
self.flashlight = nil
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
local lightInfo = self:GetLightInfo()
|
||||
|
||||
self.flashlight = ents.Create( "env_projectedtexture" )
|
||||
self.flashlight:SetParent( self )
|
||||
|
||||
-- The local positions are the offsets from parent..
|
||||
local offset = lightInfo.Offset * -1
|
||||
offset.x = offset.x + 5 -- Move the position a bit back to preserve old behavior. Ideally this would be moved by NearZ?
|
||||
|
||||
self.flashlight:SetLocalPos( -offset )
|
||||
self.flashlight:SetLocalAngles( lightInfo.Angle )
|
||||
|
||||
self.flashlight:SetKeyValue( "enableshadows", 1 )
|
||||
self.flashlight:SetKeyValue( "nearz", lightInfo.NearZ )
|
||||
self.flashlight:SetKeyValue( "lightfov", math.Clamp( self:GetLightFOV(), 10, 170 ) )
|
||||
|
||||
local dist = self:GetDistance()
|
||||
if ( !game.SinglePlayer() ) then dist = math.Clamp( dist, 64, 2048 ) end
|
||||
self.flashlight:SetKeyValue( "farz", dist )
|
||||
|
||||
local c = self:GetColor()
|
||||
local b = self:GetBrightness()
|
||||
if ( !game.SinglePlayer() ) then b = math.Clamp( b, 0, 8 ) end
|
||||
self.flashlight:SetKeyValue( "lightcolor", Format( "%i %i %i 255", c.r * b, c.g * b, c.b * b ) )
|
||||
|
||||
self.flashlight:Spawn()
|
||||
|
||||
self.flashlight:Input( "SpotlightTexture", NULL, NULL, self:GetFlashlightTexture() )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Toggle()
|
||||
|
||||
self:SetOn( !self:GetOn() )
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnUpdateLight( name, old, new )
|
||||
|
||||
if ( name == "On" ) then
|
||||
self:OnSwitch( new )
|
||||
end
|
||||
|
||||
if ( !IsValid( self.flashlight ) ) then return end
|
||||
|
||||
if ( name == "LightFOV" ) then
|
||||
self.flashlight:Input( "FOV", NULL, NULL, tostring( math.Clamp( new, 10, 170 ) ) )
|
||||
elseif ( name == "Distance" ) then
|
||||
if ( !game.SinglePlayer() ) then new = math.Clamp( new, 64, 2048 ) end
|
||||
self.flashlight:SetKeyValue( "farz", new )
|
||||
elseif ( name == "Brightness" ) then
|
||||
local c = self:GetColor()
|
||||
local b = new
|
||||
if ( !game.SinglePlayer() ) then b = math.Clamp( b, 0, 8 ) end
|
||||
self.flashlight:SetKeyValue( "lightcolor", Format( "%i %i %i 255", c.r * b, c.g * b, c.b * b ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:UpdateLight()
|
||||
|
||||
if ( !IsValid( self.flashlight ) ) then return end
|
||||
|
||||
self.flashlight:Input( "SpotlightTexture", NULL, NULL, self:GetFlashlightTexture() )
|
||||
self.flashlight:Input( "FOV", NULL, NULL, tostring( math.Clamp( self:GetLightFOV(), 10, 170 ) ) )
|
||||
|
||||
local dist = self:GetDistance()
|
||||
if ( !game.SinglePlayer() ) then dist = math.Clamp( dist, 64, 2048 ) end
|
||||
self.flashlight:SetKeyValue( "farz", dist )
|
||||
|
||||
local c = self:GetColor()
|
||||
local b = self:GetBrightness()
|
||||
if ( !game.SinglePlayer() ) then b = math.Clamp( b, 0, 8 ) end
|
||||
self.flashlight:SetKeyValue( "lightcolor", Format( "%i %i %i 255", c.r * b, c.g * b, c.b * b ) )
|
||||
|
||||
end
|
||||
|
||||
-- The rest is for client only
|
||||
return
|
||||
end
|
||||
|
||||
-- Show the name of the player that spawned it..
|
||||
function ENT:GetOverlayText()
|
||||
|
||||
return self:GetPlayerName()
|
||||
|
||||
end
|
||||
|
||||
local matLight = Material( "sprites/light_ignorez" )
|
||||
--local matBeam = Material( "effects/lamp_beam" )
|
||||
function ENT:DrawEffects()
|
||||
|
||||
-- No glow if we're not switched on!
|
||||
if ( !self:GetOn() ) then return end
|
||||
|
||||
local lightInfo = self:GetLightInfo()
|
||||
|
||||
local LightPos = self:LocalToWorld( lightInfo.Offset )
|
||||
local LightNrm = self:LocalToWorldAngles( lightInfo.Angle ):Forward()
|
||||
|
||||
-- glow sprite
|
||||
--[[
|
||||
render.SetMaterial( matBeam )
|
||||
|
||||
local BeamDot = BeamDot = 0.25
|
||||
|
||||
render.StartBeam( 3 )
|
||||
render.AddBeam( LightPos + LightNrm * 1, 128, 0.0, Color( r, g, b, 255 * BeamDot) )
|
||||
render.AddBeam( LightPos - LightNrm * 100, 128, 0.5, Color( r, g, b, 64 * BeamDot) )
|
||||
render.AddBeam( LightPos - LightNrm * 200, 128, 1, Color( r, g, b, 0) )
|
||||
render.EndBeam()
|
||||
--]]
|
||||
|
||||
local ViewNormal = self:GetPos() - EyePos()
|
||||
local Distance = ViewNormal:Length()
|
||||
ViewNormal:Normalize()
|
||||
local ViewDot = ViewNormal:Dot( LightNrm * -1 )
|
||||
|
||||
if ( ViewDot >= 0 ) then
|
||||
|
||||
render.SetMaterial( matLight )
|
||||
local Visibile = util.PixelVisible( LightPos, 16, self.PixVis )
|
||||
|
||||
if ( !Visibile ) then return end
|
||||
|
||||
local Size = math.Clamp( Distance * Visibile * ViewDot * lightInfo.Scale, 64, 512 )
|
||||
|
||||
Distance = math.Clamp( Distance, 32, 800 )
|
||||
local Alpha = math.Clamp( ( 1000 - Distance ) * Visibile * ViewDot, 0, 100 )
|
||||
local Col = self:GetColor()
|
||||
Col.a = Alpha
|
||||
|
||||
render.DrawSprite( LightPos, Size, Size, Col )
|
||||
render.DrawSprite( LightPos, Size * 0.4, Size * 0.4, Color( 255, 255, 255, Alpha ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
ENT.WantsTranslucency = true -- If model is opaque, still call DrawTranslucent
|
||||
function ENT:DrawTranslucent( flags )
|
||||
|
||||
BaseClass.DrawTranslucent( self, flags )
|
||||
self:DrawEffects()
|
||||
|
||||
end
|
||||
|
||||
136
gamemodes/sandbox/entities/entities/gmod_light.lua
Normal file
136
gamemodes/sandbox/entities/entities/gmod_light.lua
Normal file
@@ -0,0 +1,136 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_gmodentity" )
|
||||
|
||||
ENT.PrintName = "Light"
|
||||
ENT.Editable = true
|
||||
|
||||
local MODEL = Model( "models/maxofs2d/light_tubular.mdl" )
|
||||
|
||||
--
|
||||
-- Set up our data table
|
||||
--
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Bool", 0, "On", { KeyName = "on", Edit = { type = "Boolean", order = 1, title = "#entedit.enabled" } } )
|
||||
self:NetworkVar( "Bool", 1, "Toggle", { KeyName = "tg", Edit = { type = "Boolean", order = 2, title = "#tool.light.toggle" } } )
|
||||
self:NetworkVar( "Float", 1, "LightSize", { KeyName = "sz", Edit = { type = "Float", order = 3, min = 0, max = 1024, title = "#tool.light.size" } } )
|
||||
self:NetworkVar( "Float", 2, "Brightness", { KeyName = "br", Edit = { type = "Int", order = 4, min = 0, max = 6, title = "#tool.light.brightness" } } )
|
||||
|
||||
self:NetworkVar( "Bool", 2, "LightWorld", { KeyName = "world", Edit = { type = "Boolean", order = 5, title = "#tool.light.noworld", category = "#entedit.advanced" } } )
|
||||
self:NetworkVar( "Bool", 3, "LightModels", { KeyName = "models", Edit = { type = "Boolean", order = 6, title = "#tool.light.nomodels", category = "#entedit.advanced" } } )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self.PixVis = util.GetPixelVisibleHandle()
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then -- Lights are rolling around even though the model isn't round!!
|
||||
|
||||
self:SetModel( MODEL )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:DrawShadow( false )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then phys:Wake() end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
-- React to physics damage
|
||||
self:TakePhysicsDamage( dmginfo )
|
||||
end
|
||||
|
||||
function ENT:Toggle()
|
||||
self:SetOn( !self:GetOn() )
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
|
||||
self.BaseClass.Think( self )
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
if ( !self:GetOn() ) then return end
|
||||
|
||||
local noworld = self:GetLightWorld()
|
||||
local dlight = DynamicLight( self:EntIndex(), noworld )
|
||||
|
||||
if ( dlight ) then
|
||||
|
||||
local c = self:GetColor()
|
||||
|
||||
local size = self:GetLightSize()
|
||||
local brght = self:GetBrightness()
|
||||
-- Clamp for multiplayer
|
||||
if ( !game.SinglePlayer() ) then
|
||||
size = math.Clamp( size, 0, 1024 )
|
||||
brght = math.Clamp( brght, 0, 6 )
|
||||
end
|
||||
|
||||
dlight.Pos = self:GetPos()
|
||||
dlight.r = c.r
|
||||
dlight.g = c.g
|
||||
dlight.b = c.b
|
||||
dlight.Brightness = brght
|
||||
dlight.Decay = size * 5
|
||||
dlight.Size = size
|
||||
dlight.DieTime = CurTime() + 1
|
||||
|
||||
dlight.noworld = noworld
|
||||
dlight.nomodel = self:GetLightModels()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetOverlayText()
|
||||
return self:GetPlayerName()
|
||||
end
|
||||
|
||||
local matLight = Material( "sprites/light_ignorez" )
|
||||
function ENT:DrawEffects()
|
||||
|
||||
if ( !self:GetOn() ) then return end
|
||||
|
||||
local LightPos = self:GetPos()
|
||||
|
||||
local Visibile = util.PixelVisible( LightPos, 4, self.PixVis )
|
||||
if ( !Visibile || Visibile < 0.1 ) then return end
|
||||
|
||||
local c = self:GetColor()
|
||||
local Alpha = 255 * Visibile
|
||||
local up = self:GetAngles():Up()
|
||||
|
||||
render.SetMaterial( matLight )
|
||||
render.DrawSprite( LightPos - up * 2, 8, 8, Color( 255, 255, 255, Alpha ) )
|
||||
render.DrawSprite( LightPos - up * 4, 8, 8, Color( 255, 255, 255, Alpha ) )
|
||||
render.DrawSprite( LightPos - up * 6, 8, 8, Color( 255, 255, 255, Alpha ) )
|
||||
render.DrawSprite( LightPos - up * 5, 64, 64, Color( c.r, c.g, c.b, 64 ) )
|
||||
|
||||
end
|
||||
|
||||
ENT.WantsTranslucency = true -- If model is opaque, still call DrawTranslucent
|
||||
function ENT:DrawTranslucent( flags )
|
||||
BaseClass.DrawTranslucent( self, flags )
|
||||
self:DrawEffects()
|
||||
end
|
||||
567
gamemodes/sandbox/entities/entities/gmod_thruster.lua
Normal file
567
gamemodes/sandbox/entities/entities/gmod_thruster.lua
Normal file
@@ -0,0 +1,567 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_gmodentity" )
|
||||
|
||||
ENT.PrintName = "Thruster"
|
||||
|
||||
if ( CLIENT ) then
|
||||
CreateConVar( "cl_drawthrusterseffects", "1", 0, "Should Sandbox Thruster effects be visible?" )
|
||||
end
|
||||
|
||||
function ENT:SetEffect( name )
|
||||
self:SetNWString( "Effect", name )
|
||||
end
|
||||
|
||||
function ENT:GetEffect()
|
||||
return self:GetNWString( "Effect", "" )
|
||||
end
|
||||
|
||||
function ENT:SetOn( on )
|
||||
self:SetNWBool( "On", on )
|
||||
end
|
||||
|
||||
function ENT:IsOn()
|
||||
return self:GetNWBool( "On", false )
|
||||
end
|
||||
|
||||
function ENT:SetOffset( v )
|
||||
self:SetNWVector( "Offset", v )
|
||||
end
|
||||
|
||||
function ENT:GetOffset()
|
||||
return self:GetNWVector( "Offset" )
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self.ShouldDraw = true
|
||||
|
||||
-- Make the render bounds a bigger so the effect doesn't get snipped off
|
||||
local mx, mn = self:GetRenderBounds()
|
||||
self:SetRenderBounds( mn + Vector( 0, 0, 128 ), mx )
|
||||
|
||||
self.Seed = math.Rand( 0, 10000 )
|
||||
|
||||
else
|
||||
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then phys:Wake() end
|
||||
|
||||
local max = self:OBBMaxs()
|
||||
local min = self:OBBMins()
|
||||
|
||||
self.ThrustOffset = Vector( 0, 0, max.z )
|
||||
self.ThrustOffsetR = Vector( 0, 0, min.z )
|
||||
self.ForceAngle = self.ThrustOffset:GetNormalized() * -1
|
||||
|
||||
self:SetForce( 2000 )
|
||||
|
||||
self:SetEffect( "Fire" )
|
||||
|
||||
self:SetOffset( self.ThrustOffset )
|
||||
self:StartMotionController()
|
||||
|
||||
self:Switch( false )
|
||||
self.ActivateOnDamage = true
|
||||
|
||||
self.SoundName = Sound( "PhysicsCannister.ThrusterLoop" )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( CLIENT ) then
|
||||
function ENT:DrawEffects()
|
||||
|
||||
if ( !self:IsOn() ) then return end
|
||||
if ( self.ShouldDraw == false ) then return end
|
||||
|
||||
if ( self:GetEffect() == "" or self:GetEffect() == "none" ) then return end
|
||||
|
||||
for id, t in pairs( list.GetForEdit( "ThrusterEffects" ) ) do
|
||||
if ( t.thruster_effect != self:GetEffect() or !t.effectDraw ) then continue end
|
||||
|
||||
t.effectDraw( self )
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
ENT.WantsTranslucency = true -- If model is opaque, still call DrawTranslucent
|
||||
function ENT:DrawTranslucent( flags )
|
||||
|
||||
BaseClass.DrawTranslucent( self, flags )
|
||||
|
||||
self:DrawEffects()
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
|
||||
BaseClass.Think( self )
|
||||
|
||||
if ( SERVER and self.SwitchOffTime and self.SwitchOffTime < CurTime() ) then
|
||||
self.SwitchOffTime = nil
|
||||
self:Switch( false )
|
||||
end
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self.ShouldDraw = GetConVarNumber( "cl_drawthrusterseffects" ) != 0
|
||||
|
||||
if ( !self:IsOn() ) then self.OnStart = nil return end
|
||||
self.OnStart = self.OnStart or CurTime()
|
||||
|
||||
if ( self.ShouldDraw == false ) then return end
|
||||
if ( self:GetEffect() == "" or self:GetEffect() == "none" ) then return end
|
||||
|
||||
for id, t in pairs( list.GetForEdit( "ThrusterEffects" ) ) do
|
||||
if ( t.thruster_effect != self:GetEffect() or !t.effectThink ) then continue end
|
||||
|
||||
t.effectThink( self )
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( CLIENT ) then
|
||||
--[[---------------------------------------------------------
|
||||
Use the same emitter, but get a new one every 2 seconds
|
||||
This will fix any draw order issues
|
||||
-----------------------------------------------------------]]
|
||||
function ENT:GetEmitter( Pos, b3D )
|
||||
|
||||
if ( self.Emitter and self.EmitterIs3D == b3D and self.EmitterTime > CurTime() ) then
|
||||
return self.Emitter
|
||||
end
|
||||
|
||||
if ( IsValid( self.Emitter ) ) then
|
||||
self.Emitter:Finish()
|
||||
end
|
||||
|
||||
self.Emitter = ParticleEmitter( Pos, b3D )
|
||||
self.EmitterIs3D = b3D
|
||||
self.EmitterTime = CurTime() + 2
|
||||
return self.Emitter
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
|
||||
if ( IsValid( self.Emitter ) ) then
|
||||
self.Emitter:Finish()
|
||||
end
|
||||
|
||||
if ( self.Sound ) then
|
||||
self.Sound:Stop()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
function ENT:SetForce( force, mul )
|
||||
|
||||
if ( force ) then self.force = force end
|
||||
mul = mul or 1
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( !IsValid( phys ) ) then
|
||||
Msg( "Warning: [gmod_thruster] Physics object isn't valid!\n" )
|
||||
return
|
||||
end
|
||||
|
||||
-- Get the data in worldspace
|
||||
local ThrusterWorldPos = phys:LocalToWorld( self.ThrustOffset )
|
||||
local ThrusterWorldForce = phys:LocalToWorldVector( self.ThrustOffset * -1 )
|
||||
|
||||
-- Calculate the velocity
|
||||
ThrusterWorldForce = ThrusterWorldForce * self.force * mul * 50
|
||||
|
||||
local motionEnabled = phys:IsMotionEnabled()
|
||||
phys:EnableMotion( true ) -- Dirty hack for PhysObj.CalculateVelocityOffset while frozen
|
||||
self.ForceLinear, self.ForceAngle = phys:CalculateVelocityOffset( ThrusterWorldForce, ThrusterWorldPos )
|
||||
phys:EnableMotion( motionEnabled )
|
||||
|
||||
self.ForceLinear = phys:WorldToLocalVector( self.ForceLinear )
|
||||
|
||||
if ( mul > 0 ) then
|
||||
self:SetOffset( self.ThrustOffset )
|
||||
else
|
||||
self:SetOffset( self.ThrustOffsetR )
|
||||
end
|
||||
|
||||
self:SetNWVector( "1", self.ForceAngle )
|
||||
self:SetNWVector( "2", self.ForceLinear )
|
||||
|
||||
self:SetOverlayText( "Force: " .. math.floor( self.force ) )
|
||||
|
||||
end
|
||||
|
||||
function ENT:AddMul( mul, bDown )
|
||||
|
||||
if ( self:GetToggle() ) then
|
||||
|
||||
if ( !bDown ) then return end
|
||||
|
||||
if ( self.Multiply == mul ) then
|
||||
self.Multiply = 0
|
||||
else
|
||||
self.Multiply = mul
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
self.Multiply = self.Multiply or 0
|
||||
self.Multiply = self.Multiply + mul
|
||||
|
||||
end
|
||||
|
||||
self:SetForce( nil, self.Multiply )
|
||||
self:Switch( self.Multiply != 0 )
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
|
||||
self:TakePhysicsDamage( dmginfo )
|
||||
|
||||
if ( !self.ActivateOnDamage ) then return end
|
||||
|
||||
self:Switch( true )
|
||||
|
||||
self.SwitchOffTime = CurTime() + 5
|
||||
|
||||
end
|
||||
|
||||
function ENT:Use( activator, caller )
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate( phys, deltatime )
|
||||
|
||||
if ( !self:IsOn() ) then return SIM_NOTHING end
|
||||
|
||||
return self.ForceAngle, self.ForceLinear, SIM_LOCAL_ACCELERATION
|
||||
|
||||
end
|
||||
|
||||
-- Switch thruster on or off
|
||||
function ENT:Switch( on )
|
||||
|
||||
if ( !IsValid( self ) ) then return false end
|
||||
|
||||
self:SetOn( on )
|
||||
|
||||
if ( on ) then
|
||||
|
||||
self:StartThrustSound()
|
||||
|
||||
else
|
||||
|
||||
self:StopThrustSound()
|
||||
|
||||
end
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( IsValid( phys ) ) then phys:Wake() end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetSound( sound )
|
||||
|
||||
-- No change, don't do shit
|
||||
if ( self.SoundName == sound ) then return end
|
||||
|
||||
-- Gracefully shutdown
|
||||
if ( self:IsOn() ) then
|
||||
self:StopThrustSound()
|
||||
end
|
||||
|
||||
self.SoundName = Sound( sound )
|
||||
self.Sound = nil
|
||||
|
||||
-- Now start the new sound
|
||||
if ( self:IsOn() ) then
|
||||
self:StartThrustSound()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Starts the looping sound
|
||||
function ENT:StartThrustSound()
|
||||
|
||||
if ( !self.SoundName or self.SoundName == "" ) then return end
|
||||
|
||||
local valid = false
|
||||
for _, v in pairs( list.Get( "ThrusterSounds" ) ) do
|
||||
if ( v.thruster_soundname == self.SoundName ) then valid = true break end
|
||||
end
|
||||
|
||||
if ( !valid ) then return end
|
||||
|
||||
if ( !self.Sound ) then
|
||||
-- Make sure the fadeout gets to every player!
|
||||
local filter = RecipientFilter()
|
||||
filter:AddPAS( self:GetPos() )
|
||||
self.Sound = CreateSound( self, self.SoundName, filter )
|
||||
end
|
||||
|
||||
self.Sound:PlayEx( 0.5, 100 )
|
||||
|
||||
end
|
||||
|
||||
-- Stop the looping sound
|
||||
function ENT:StopThrustSound()
|
||||
|
||||
if ( self.Sound ) then
|
||||
self.Sound:ChangeVolume( 0.0, 0.25 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Sets whether this is a toggle thruster or not
|
||||
function ENT:SetToggle( tog )
|
||||
self.Toggle = tog
|
||||
end
|
||||
|
||||
-- Returns true if this is a toggle thruster
|
||||
function ENT:GetToggle()
|
||||
return self.Toggle
|
||||
end
|
||||
|
||||
numpad.Register( "Thruster_On", function( ply, ent, mul )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
ent:AddMul( mul, true )
|
||||
return true
|
||||
|
||||
end )
|
||||
|
||||
numpad.Register( "Thruster_Off", function( ply, ent, mul )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
ent:AddMul( mul * -1, false )
|
||||
return true
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Register the effects
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
list.Set( "ThrusterEffects", "#thrustereffect.none", { thruster_effect = "none" } )
|
||||
|
||||
local matHeatWave = Material( "sprites/heatwave" )
|
||||
local matFire = Material( "effects/fire_cloud1" )
|
||||
list.Set( "ThrusterEffects", "#thrustereffect.flames", {
|
||||
thruster_effect = "fire",
|
||||
effectDraw = function( self )
|
||||
local vOffset = self:LocalToWorld( self:GetOffset() )
|
||||
local vNormal = ( vOffset - self:GetPos() ):GetNormalized()
|
||||
|
||||
local scroll = self.Seed + ( CurTime() * -10 )
|
||||
|
||||
local size = self:OBBMaxs() - self:OBBMins()
|
||||
size = math.min( size.x, size.y, 50 )
|
||||
|
||||
local Scale = math.Clamp( ( CurTime() - self.OnStart ) * 5, 0, 1 )
|
||||
|
||||
render.SetMaterial( matFire )
|
||||
|
||||
render.StartBeam( 3 )
|
||||
render.AddBeam( vOffset, size * Scale, scroll, Color( 0, 0, 255, 128 ) )
|
||||
render.AddBeam( vOffset + vNormal * 60 * Scale, 32 * Scale, scroll + 1, Color( 255, 255, 255, 128 ) )
|
||||
render.AddBeam( vOffset + vNormal * 148 * Scale, 32 * Scale, scroll + 3, Color( 255, 255, 255, 0 ) )
|
||||
render.EndBeam()
|
||||
|
||||
scroll = scroll * 0.5
|
||||
|
||||
render.UpdateRefractTexture()
|
||||
render.SetMaterial( matHeatWave )
|
||||
render.StartBeam( 3 )
|
||||
render.AddBeam( vOffset, size * Scale, scroll, Color( 0, 0, 255, 128 ) )
|
||||
render.AddBeam( vOffset + vNormal * 32 * Scale, 32 * Scale, scroll + 2, color_white )
|
||||
render.AddBeam( vOffset + vNormal * 128 * Scale, 48 * Scale, scroll + 5, Color( 0, 0, 0, 0 ) )
|
||||
render.EndBeam()
|
||||
|
||||
|
||||
scroll = scroll * 1.3
|
||||
render.SetMaterial( matFire )
|
||||
render.StartBeam( 3 )
|
||||
render.AddBeam( vOffset, size * Scale, scroll, Color( 0, 0, 255, 128 ) )
|
||||
render.AddBeam( vOffset + vNormal * 60 * Scale, 16 * Scale, scroll + 1, Color( 255, 255, 255, 128 ) )
|
||||
render.AddBeam( vOffset + vNormal * 148 * Scale, 16 * Scale, scroll + 3, Color( 255, 255, 255, 0 ) )
|
||||
render.EndBeam()
|
||||
end
|
||||
} )
|
||||
|
||||
local matPlasma = Material( "effects/strider_muzzle" )
|
||||
list.Set( "ThrusterEffects", "#thrustereffect.plasma", {
|
||||
thruster_effect = "plasma",
|
||||
effectDraw = function( self )
|
||||
|
||||
local vOffset = self:LocalToWorld( self:GetOffset() )
|
||||
local vNormal = ( vOffset - self:GetPos() ):GetNormalized()
|
||||
|
||||
local scroll = self.Seed + ( CurTime() * -20 )
|
||||
local size = self:OBBMaxs() - self:OBBMins()
|
||||
size = math.min( size.x, size.y ) * 1.5
|
||||
|
||||
render.SetMaterial( matPlasma )
|
||||
|
||||
scroll = scroll * 0.9
|
||||
|
||||
render.StartBeam( 3 )
|
||||
render.AddBeam( vOffset, size, scroll, Color( 0, 255, 255, 255 ) )
|
||||
render.AddBeam( vOffset + vNormal * 8, size, scroll + 0.01, color_white )
|
||||
render.AddBeam( vOffset + vNormal * 64, size, scroll + 0.02, Color( 0, 255, 255, 0 ) )
|
||||
render.EndBeam()
|
||||
|
||||
scroll = scroll * 0.9
|
||||
|
||||
render.StartBeam( 3 )
|
||||
render.AddBeam( vOffset, size, scroll, Color( 0, 255, 255, 255 ) )
|
||||
render.AddBeam( vOffset + vNormal * 8, size, scroll + 0.01, color_white )
|
||||
render.AddBeam( vOffset + vNormal * 64, size, scroll + 0.02, Color( 0, 255, 255, 0 ) )
|
||||
render.EndBeam()
|
||||
|
||||
scroll = scroll * 0.9
|
||||
|
||||
render.StartBeam( 3 )
|
||||
render.AddBeam( vOffset, size, scroll, Color( 0, 255, 255, 255 ) )
|
||||
render.AddBeam( vOffset + vNormal * 8, size, scroll + 0.01, color_white )
|
||||
render.AddBeam( vOffset + vNormal * 64, size, scroll + 0.02, Color( 0, 255, 255, 0 ) )
|
||||
render.EndBeam()
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "ThrusterEffects", "#thrustereffect.magic", {
|
||||
thruster_effect = "magic",
|
||||
effectThink = function( self )
|
||||
|
||||
self.SmokeTimer = self.SmokeTimer or 0
|
||||
if ( self.SmokeTimer > CurTime() ) then return end
|
||||
|
||||
self.SmokeTimer = CurTime() + 0.01
|
||||
|
||||
local vOffset = self:LocalToWorld( self:GetOffset() )
|
||||
local vNormal = ( vOffset - self:GetPos() ):GetNormalized()
|
||||
|
||||
local size = self:OBBMaxs() - self:OBBMins()
|
||||
|
||||
vOffset = vOffset + VectorRand() * math.min( size.x, size.y ) / 3
|
||||
|
||||
local emitter = self:GetEmitter( vOffset, false )
|
||||
if ( !IsValid( emitter ) ) then return end
|
||||
|
||||
local particle = emitter:Add( "sprites/gmdm_pickups/light", vOffset )
|
||||
if ( !particle ) then return end
|
||||
|
||||
particle:SetVelocity( vNormal * math.Rand( 80, 160 ) )
|
||||
particle:SetDieTime( 0.5 )
|
||||
particle:SetStartAlpha( 255 )
|
||||
particle:SetEndAlpha( 255 )
|
||||
particle:SetStartSize( math.Rand( 1, 3 ) )
|
||||
particle:SetEndSize( 0 )
|
||||
particle:SetRoll( math.Rand( -0.2, 0.2 ) )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "ThrusterEffects", "#thrustereffect.rings", {
|
||||
thruster_effect = "rings",
|
||||
effectThink = function( self )
|
||||
|
||||
self.RingTimer = self.RingTimer or 0
|
||||
if ( self.RingTimer > CurTime() ) then return end
|
||||
self.RingTimer = CurTime() + 0.01
|
||||
|
||||
local vOffset = self:LocalToWorld( self:GetOffset() )
|
||||
local vNormal = ( vOffset - self:GetPos() ):GetNormalized()
|
||||
|
||||
local size = self:OBBMaxs() - self:OBBMins()
|
||||
|
||||
vOffset = vOffset + vNormal * 5
|
||||
|
||||
local emitter = self:GetEmitter( vOffset, true )
|
||||
if ( !IsValid( emitter ) ) then return end
|
||||
|
||||
local particle = emitter:Add( "effects/select_ring", vOffset )
|
||||
if ( !particle ) then return end
|
||||
|
||||
particle:SetVelocity( vNormal * 300 )
|
||||
particle:SetLifeTime( 0 )
|
||||
particle:SetDieTime( 0.2 )
|
||||
particle:SetStartAlpha( 255 )
|
||||
particle:SetEndAlpha( 0 )
|
||||
particle:SetStartSize( math.min( size.x, size.y ) / 2 )
|
||||
particle:SetEndSize( 10 )
|
||||
particle:SetAngles( vNormal:Angle() )
|
||||
particle:SetColor( math.Rand( 10, 100 ), math.Rand( 100, 220 ), math.Rand( 240, 255 ) )
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "ThrusterEffects", "#thrustereffect.smoke", {
|
||||
thruster_effect = "smoke",
|
||||
effectThink = function( self )
|
||||
|
||||
self.SmokeTimer = self.SmokeTimer or 0
|
||||
if ( self.SmokeTimer > CurTime() ) then return end
|
||||
|
||||
self.SmokeTimer = CurTime() + 0.015
|
||||
|
||||
local size = self:OBBMaxs() - self:OBBMins()
|
||||
size = math.min( size.x, size.y ) / 2
|
||||
|
||||
local vOffset = self:LocalToWorld( self:GetOffset() )
|
||||
|
||||
-- Make the offset farther so the normal isn't jumping around crazily on certain models
|
||||
local vNormalRand = vOffset + ( vOffset - self:GetPos() ):GetNormalized() * 32 + VectorRand() * 3
|
||||
local vNormal = ( vNormalRand - self:GetPos() ):GetNormalized()
|
||||
|
||||
local emitter = self:GetEmitter( vOffset, false )
|
||||
if ( !IsValid( emitter ) ) then return end
|
||||
|
||||
local particle = emitter:Add( "particles/smokey", vOffset + VectorRand() * 3 )
|
||||
if ( !particle ) then return end
|
||||
|
||||
local vel_scale = math.Rand( 10, 30 ) * 10 / math.Clamp( self:GetVelocity():Length() / 200, 1, 10 )
|
||||
local velocity = vNormal * vel_scale
|
||||
|
||||
particle:SetVelocity( velocity )
|
||||
particle:SetDieTime( 2.0 )
|
||||
particle:SetGravity( Vector( 0, 0, 32 ) )
|
||||
particle:SetStartAlpha( math.Rand( 50, 150 ) )
|
||||
particle:SetStartSize( size )
|
||||
particle:SetEndSize( math.Rand( 64, 128 ) )
|
||||
particle:SetRoll( math.Rand( -0.2, 0.2 ) )
|
||||
particle:SetColor( 200, 200, 210 )
|
||||
|
||||
end
|
||||
} )
|
||||
214
gamemodes/sandbox/entities/entities/gmod_wheel.lua
Normal file
214
gamemodes/sandbox/entities/entities/gmod_wheel.lua
Normal file
@@ -0,0 +1,214 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "base_gmodentity" )
|
||||
|
||||
ENT.PrintName = "Wheel"
|
||||
|
||||
-- Set up our data table
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Bool", 0, "Toggle" )
|
||||
self:NetworkVar( "Float", 0, "Direction" )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
|
||||
self:SetToggle( false )
|
||||
|
||||
self.ToggleState = false
|
||||
self.BaseTorque = 1
|
||||
self.TorqueScale = 1
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Sets the base torque
|
||||
function ENT:SetBaseTorque( base )
|
||||
|
||||
self.BaseTorque = base
|
||||
if ( self.BaseTorque == 0 ) then self.BaseTorque = 1 end
|
||||
self:UpdateOverlayText()
|
||||
|
||||
end
|
||||
|
||||
-- Refresh the entity overlay text
|
||||
function ENT:UpdateOverlayText()
|
||||
|
||||
self:SetOverlayText( "Torque: " .. math.floor( self.BaseTorque ) )
|
||||
|
||||
end
|
||||
|
||||
-- Sets the axis (world space)
|
||||
function ENT:SetAxis( vec )
|
||||
|
||||
self.Axis = self:GetPos() + vec * 512
|
||||
self.Axis = self:NearestPoint( self.Axis )
|
||||
self.Axis = self:WorldToLocal( self.Axis )
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
|
||||
self:TakePhysicsDamage( dmginfo )
|
||||
|
||||
end
|
||||
|
||||
-- Set the motor constraint
|
||||
function ENT:SetMotor( Motor )
|
||||
|
||||
self.Motor = Motor
|
||||
|
||||
end
|
||||
|
||||
-- Get the motor constraint :)
|
||||
function ENT:GetMotor()
|
||||
|
||||
-- Fuck knows why it's doing this here.
|
||||
if ( !IsValid( self.Motor ) ) then
|
||||
|
||||
self.Motor = constraint.FindConstraintEntity( self, "Motor" )
|
||||
|
||||
end
|
||||
|
||||
return self.Motor
|
||||
|
||||
end
|
||||
|
||||
-- Forward key is pressed/released
|
||||
function ENT:Forward( onoff, mul )
|
||||
|
||||
--
|
||||
-- Is this entity invalid now?
|
||||
-- If so return false to remove it
|
||||
--
|
||||
if ( !IsValid( self ) ) then return false end
|
||||
|
||||
local Motor = self:GetMotor()
|
||||
if ( !IsValid( Motor ) ) then return false end
|
||||
|
||||
local toggle = self:GetToggle()
|
||||
|
||||
--
|
||||
-- If we're toggle mode and the key has been
|
||||
-- released then just return.
|
||||
--
|
||||
if ( toggle and !onoff ) then return true end
|
||||
|
||||
mul = mul or 1
|
||||
local Speed = Motor.direction * mul * self.TorqueScale
|
||||
|
||||
if ( !onoff ) then Speed = 0 end
|
||||
|
||||
if ( toggle and onoff ) then
|
||||
|
||||
self.ToggleState = !self.ToggleState
|
||||
|
||||
if ( !self.ToggleState ) then
|
||||
Speed = 0
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Motor:Fire( "Scale", Speed, 0 )
|
||||
Motor.forcescale = Speed
|
||||
Motor:Fire( "Activate", "", 0 )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Reverse key is pressed/released
|
||||
function ENT:Reverse( onoff )
|
||||
return self:Forward( onoff, -1 )
|
||||
end
|
||||
|
||||
-- Register numpad functions
|
||||
if ( SERVER ) then
|
||||
|
||||
numpad.Register( "WheelForward", function( ply, ent, onoff )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
return ent:Forward( onoff )
|
||||
|
||||
end )
|
||||
|
||||
numpad.Register( "WheelReverse", function( ply, ent, onoff )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
return ent:Reverse( onoff )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
-- Todo? Scale Motor.direction?
|
||||
function ENT:SetTorque( torque )
|
||||
|
||||
if ( self.BaseTorque == 0 ) then self.BaseTorque = 1 end
|
||||
|
||||
self.TorqueScale = torque / self.BaseTorque
|
||||
|
||||
local Motor = self:GetMotor()
|
||||
if ( !IsValid( Motor ) ) then return end
|
||||
Motor:Fire( "Scale", Motor.direction * Motor.forcescale * self.TorqueScale, 0 )
|
||||
|
||||
self:SetOverlayText( "Torque: " .. math.floor( torque ) )
|
||||
|
||||
end
|
||||
|
||||
-- Creates the direction arrows on the wheel
|
||||
function ENT:DoDirectionEffect()
|
||||
|
||||
local Motor = self:GetMotor()
|
||||
|
||||
if ( !IsValid( Motor ) ) then return end
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self.Axis * 100 ) -- Ugly hack, but necessary due to network precision problems of EffectData()
|
||||
effectdata:SetEntity( self )
|
||||
effectdata:SetScale( Motor.direction )
|
||||
util.Effect( "wheel_indicator", effectdata, true, true )
|
||||
|
||||
end
|
||||
|
||||
-- Reverse the wheel direction when a player uses the wheel
|
||||
function ENT:Use( activator, caller, type, value )
|
||||
|
||||
local Motor = self:GetMotor()
|
||||
local Owner = self:GetPlayer()
|
||||
|
||||
if ( IsValid( Motor ) and ( Owner == nil or Owner == activator ) ) then
|
||||
|
||||
if ( Motor.direction == 1 ) then
|
||||
Motor.direction = -1
|
||||
else
|
||||
Motor.direction = 1
|
||||
end
|
||||
|
||||
Motor:Fire( "Scale", Motor.direction * Motor.forcescale * self.TorqueScale, 0 )
|
||||
self:SetDirection( Motor.direction )
|
||||
|
||||
self:DoDirectionEffect()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
255
gamemodes/sandbox/entities/entities/gmod_winch_controller.lua
Normal file
255
gamemodes/sandbox/entities/entities/gmod_winch_controller.lua
Normal file
@@ -0,0 +1,255 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
ENT.Type = "point"
|
||||
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
local DIR_BACKWARD = -1
|
||||
local DIR_NONE = 0
|
||||
local DIR_FORWARD = 1
|
||||
|
||||
local TYPE_NORMAL = 0
|
||||
local TYPE_MUSCLE = 1
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
self.last_time = CurTime()
|
||||
self.init_time = CurTime()
|
||||
self.min_length = self.min_length or 1
|
||||
self.type = self.type or TYPE_NORMAL
|
||||
self.ctime = self.ctime or 0
|
||||
self.isexpanded = false
|
||||
|
||||
end
|
||||
|
||||
function ENT:KeyValue( key, value )
|
||||
if ( key == "minlength" ) then self.min_length = tonumber( value )
|
||||
elseif ( key == "maxlength" ) then self.max_length = tonumber( value )
|
||||
elseif ( key == "type" ) then self.type = tonumber( value )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
|
||||
self:NextThink( CurTime() + 0.01 )
|
||||
local TimeDiff = CurTime() - self.last_time
|
||||
self.last_time = CurTime()
|
||||
|
||||
if ( !self.constraint ) then return true end
|
||||
if ( !self.direction ) then return true end
|
||||
if ( self.direction == DIR_NONE ) then return true end
|
||||
|
||||
local current_length = self.current_length
|
||||
|
||||
if ( self.type == TYPE_NORMAL ) then
|
||||
|
||||
local dist = 0
|
||||
|
||||
if ( self.direction == DIR_FORWARD ) then
|
||||
local speed = self.constraint.fwd_speed
|
||||
dist = speed * TimeDiff
|
||||
elseif ( self.direction == DIR_BACKWARD ) then
|
||||
local speed = self.constraint.bwd_speed
|
||||
dist = -speed * TimeDiff
|
||||
end
|
||||
|
||||
if ( dist == 0 ) then return true end
|
||||
|
||||
current_length = current_length + dist
|
||||
|
||||
if ( self.min_length && current_length < self.min_length ) then
|
||||
|
||||
current_length = self.min_length
|
||||
if ( self.toggle ) then self.direction = DIR_NONE end
|
||||
|
||||
end
|
||||
|
||||
if ( self.max_length ) then
|
||||
|
||||
if ( current_length > self.max_length ) then
|
||||
|
||||
current_length = self.max_length
|
||||
self.isexpanded = true
|
||||
if ( self.toggle ) then self.direction = DIR_NONE end
|
||||
|
||||
else
|
||||
|
||||
self.isexpanded = false
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
elseif ( self.type == TYPE_MUSCLE ) then
|
||||
|
||||
local amp = self.constraint.amplitude
|
||||
local per = self.constraint.period
|
||||
|
||||
if ( per == 0 ) then return true end
|
||||
|
||||
local spos = ( math.sin( self.ctime * math.pi * per ) + 1 ) * ( amp / 2 )
|
||||
|
||||
if ( spos > amp ) then spos = amp end
|
||||
if ( spos < 0 ) then spos = 0 end
|
||||
|
||||
if ( self.direction != DIR_NONE ) then
|
||||
current_length = self.min_length + spos
|
||||
end
|
||||
self.ctime = self.ctime + TimeDiff
|
||||
|
||||
end
|
||||
|
||||
self.current_length = current_length
|
||||
|
||||
self.constraint:Fire( "SetSpringLength", current_length, 0 )
|
||||
if ( self.rope ) then self.rope:Fire( "SetLength", current_length, 0 ) end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetSomePos( ent, phys, lpos )
|
||||
|
||||
if ( ent:EntIndex() == 0 ) then
|
||||
return lpos
|
||||
end
|
||||
|
||||
if ( IsValid( phys ) ) then
|
||||
return phys:LocalToWorld( lpos )
|
||||
else
|
||||
return ent:LocalToWorld( lpos )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetConstraint( c )
|
||||
|
||||
self.constraint = c
|
||||
self.direction = DIR_NONE
|
||||
self.toggle = c.toggle
|
||||
|
||||
local p1 = self:GetSomePos( c.Ent1, c.Phys1, c.LPos1 )
|
||||
local p2 = self:GetSomePos( c.Ent2, c.Phys2, c.LPos2 )
|
||||
local dist = ( p1 - p2 ):Length()
|
||||
|
||||
self.current_length = dist
|
||||
|
||||
if ( self.max_length ) then
|
||||
self.isexpanded = ( self.current_length >= self.max_length )
|
||||
end
|
||||
|
||||
if ( self.type == TYPE_MUSCLE ) then
|
||||
local amp = self.constraint.amplitude
|
||||
local per = self.constraint.period
|
||||
local spos = self.current_length - self.min_length
|
||||
spos = spos / ( amp * 2 )
|
||||
spos = spos - 1
|
||||
spos = math.Clamp( spos, -1, 1 ) -- just in case!
|
||||
spos = math.asin( spos )
|
||||
spos = spos / ( per * math.pi )
|
||||
self.ctime = spos
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetRope( r )
|
||||
self.rope = r
|
||||
end
|
||||
|
||||
function ENT:SetDirection( n )
|
||||
self.direction = n
|
||||
end
|
||||
|
||||
function ENT:GetDirection()
|
||||
return self.direction
|
||||
end
|
||||
|
||||
function ENT:IsExpanded()
|
||||
return self.isexpanded
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
HydraulicToggle - Toggle hydraulic on and off
|
||||
------------------------------------------------------------------------]]
|
||||
local function HydraulicToggle( ply, hyd )
|
||||
|
||||
if ( !IsValid( hyd ) ) then return false end
|
||||
|
||||
-- I hate this, shouldn't we just be calling hyd:Toggle()
|
||||
|
||||
if ( hyd:GetDirection() == 0 ) then
|
||||
if ( hyd:IsExpanded() ) then
|
||||
hyd:SetDirection( -1 )
|
||||
else
|
||||
hyd:SetDirection( 1 )
|
||||
end
|
||||
|
||||
elseif ( hyd:GetDirection() == -1 ) then
|
||||
|
||||
hyd:SetDirection( 1 )
|
||||
|
||||
elseif ( hyd:GetDirection() == 1 ) then
|
||||
|
||||
hyd:SetDirection( -1 )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
numpad.Register( "HydraulicToggle", HydraulicToggle )
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
WinchOn - Called to switch the winch on
|
||||
------------------------------------------------------------------------]]
|
||||
local function WinchOn( ply, winch, dir )
|
||||
if ( !IsValid( winch ) ) then return false end
|
||||
winch:SetDirection( dir )
|
||||
end
|
||||
numpad.Register( "WinchOn", WinchOn )
|
||||
numpad.Register( "HydraulicDir", WinchOn ) -- A little cheat
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
WinchOff - Called to switch the winch off
|
||||
------------------------------------------------------------------------]]
|
||||
local function WinchOff( ply, winch )
|
||||
if ( !IsValid( winch ) ) then return false end
|
||||
winch:SetDirection( 0 )
|
||||
end
|
||||
numpad.Register( "WinchOff", WinchOff )
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
WinchToggle - Called to toggle the winch
|
||||
------------------------------------------------------------------------]]
|
||||
local function WinchToggle( ply, winch, dir )
|
||||
if ( !IsValid( winch ) ) then return false end
|
||||
if ( winch:GetDirection() == dir ) then
|
||||
winch:SetDirection( 0 )
|
||||
else
|
||||
winch:SetDirection( dir )
|
||||
end
|
||||
end
|
||||
numpad.Register( "WinchToggle", WinchToggle )
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
MuscleToggle - Called to toggle the muslce
|
||||
------------------------------------------------------------------------]]
|
||||
local function MuscleToggle( ply, hyd )
|
||||
|
||||
if ( !IsValid( hyd ) ) then return false end
|
||||
|
||||
if ( hyd:GetDirection() == 0 ) then
|
||||
hyd:SetDirection( 1 )
|
||||
else
|
||||
hyd:SetDirection( 0 )
|
||||
end
|
||||
|
||||
end
|
||||
numpad.Register( "MuscleToggle", MuscleToggle )
|
||||
246
gamemodes/sandbox/entities/weapons/gmod_camera.lua
Normal file
246
gamemodes/sandbox/entities/weapons/gmod_camera.lua
Normal file
@@ -0,0 +1,246 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.ViewModel = Model( "models/weapons/c_arms_animations.mdl" )
|
||||
SWEP.WorldModel = Model( "models/MaxOfS2D/camera.mdl" )
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.PrintName = "#GMOD_Camera"
|
||||
SWEP.Author = "Facepunch"
|
||||
|
||||
SWEP.Slot = 5
|
||||
SWEP.SlotPos = 1
|
||||
|
||||
SWEP.DrawAmmo = false
|
||||
SWEP.DrawCrosshair = false
|
||||
SWEP.Spawnable = true
|
||||
|
||||
SWEP.ShootSound = Sound( "NPC_CScanner.TakePhoto" )
|
||||
|
||||
SWEP.AutoSwitchTo = false
|
||||
SWEP.AutoSwitchFrom = false
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
--
|
||||
-- A concommand to quickly switch to the camera
|
||||
--
|
||||
concommand.Add( "gmod_camera", function( ply, cmd, args )
|
||||
|
||||
ply:SelectWeapon( "gmod_camera" )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Network/Data Tables
|
||||
--
|
||||
function SWEP:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Float", 0, "Zoom" )
|
||||
self:NetworkVar( "Float", 1, "Roll" )
|
||||
|
||||
if ( SERVER ) then
|
||||
self:SetZoom( 70 )
|
||||
self:SetRoll( 0 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Initialize Stuff
|
||||
--
|
||||
function SWEP:Initialize()
|
||||
|
||||
self:SetHoldType( "camera" )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Reload resets the FOV and Roll
|
||||
--
|
||||
function SWEP:Reload()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if ( !owner:KeyDown( IN_ATTACK2 ) ) then self:SetZoom( owner:IsBot() && 75 || owner:GetInfoNum( "fov_desired", 75 ) ) end
|
||||
self:SetRoll( 0 )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- PrimaryAttack - make a screenshot
|
||||
--
|
||||
function SWEP:PrimaryAttack()
|
||||
|
||||
self:DoShootEffect()
|
||||
|
||||
-- If we're multiplayer this can be done totally clientside
|
||||
if ( !game.SinglePlayer() && SERVER ) then return end
|
||||
if ( CLIENT && !IsFirstTimePredicted() ) then return end
|
||||
|
||||
self:GetOwner():ConCommand( "jpeg" )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- SecondaryAttack - Nothing. See Tick for zooming.
|
||||
--
|
||||
function SWEP:SecondaryAttack()
|
||||
end
|
||||
|
||||
--
|
||||
-- Mouse 2 action
|
||||
--
|
||||
function SWEP:Tick()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if ( CLIENT && owner != LocalPlayer() ) then return end -- If someone is spectating a player holding this weapon, bail
|
||||
|
||||
local cmd = owner:GetCurrentCommand()
|
||||
|
||||
if ( !cmd:KeyDown( IN_ATTACK2 ) ) then return end -- Not holding Mouse 2, bail
|
||||
|
||||
self:SetZoom( math.Clamp( self:GetZoom() + cmd:GetMouseY() * FrameTime() * 6.6, 0.1, 175 ) ) -- Handles zooming
|
||||
self:SetRoll( self:GetRoll() + cmd:GetMouseX() * FrameTime() * 1.65 ) -- Handles rotation
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Override players Field Of View
|
||||
--
|
||||
function SWEP:TranslateFOV( current_fov )
|
||||
|
||||
return self:GetZoom()
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Deploy - Allow lastinv
|
||||
--
|
||||
function SWEP:Deploy()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Set FOV to players desired FOV
|
||||
--
|
||||
function SWEP:Equip()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if ( self:GetZoom() == 70 && owner:IsPlayer() && !owner:IsBot() ) then
|
||||
self:SetZoom( owner:GetInfoNum( "fov_desired", 75 ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function SWEP:ShouldDropOnDie() return false end
|
||||
|
||||
--
|
||||
-- The effect when a weapon is fired successfully
|
||||
--
|
||||
function SWEP:DoShootEffect()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
self:EmitSound( self.ShootSound )
|
||||
self:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
|
||||
owner:SetAnimation( PLAYER_ATTACK1 )
|
||||
|
||||
if ( SERVER && !game.SinglePlayer() ) then
|
||||
|
||||
--
|
||||
-- Note that the flash effect is only
|
||||
-- shown to other players!
|
||||
--
|
||||
|
||||
local vPos = owner:GetShootPos()
|
||||
local vForward = owner:GetAimVector()
|
||||
|
||||
local trace = {}
|
||||
trace.start = vPos
|
||||
trace.endpos = vPos + vForward * 256
|
||||
trace.filter = owner
|
||||
|
||||
local tr = util.TraceLine( trace )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( tr.HitPos )
|
||||
util.Effect( "camera_flash", effectdata, true )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then return end -- Only clientside lua after this line
|
||||
|
||||
SWEP.WepSelectIcon = surface.GetTextureID( "vgui/gmod_camera" )
|
||||
|
||||
-- Don't draw the weapon info on the weapon selection thing
|
||||
function SWEP:DrawHUD() end
|
||||
function SWEP:PrintWeaponInfo( x, y, alpha ) end
|
||||
|
||||
function SWEP:HUDShouldDraw( name )
|
||||
|
||||
-- So we can change weapons
|
||||
if ( name == "CHudWeaponSelection" ) then return true end
|
||||
if ( name == "CHudChat" ) then return true end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
function SWEP:FreezeMovement()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
-- Don't aim if we're holding the right mouse button
|
||||
if ( owner:KeyDown( IN_ATTACK2 ) || owner:KeyReleased( IN_ATTACK2 ) ) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
function SWEP:CalcView( ply, origin, angles, fov )
|
||||
|
||||
if ( self:GetRoll() != 0 ) then
|
||||
angles.Roll = self:GetRoll()
|
||||
end
|
||||
|
||||
return origin, angles, fov
|
||||
|
||||
end
|
||||
|
||||
function SWEP:AdjustMouseSensitivity()
|
||||
|
||||
if ( self:GetOwner():KeyDown( IN_ATTACK2 ) ) then return 1 end
|
||||
|
||||
return self:GetZoom() / 80
|
||||
|
||||
end
|
||||
226
gamemodes/sandbox/entities/weapons/gmod_tool/cl_init.lua
Normal file
226
gamemodes/sandbox/entities/weapons/gmod_tool/cl_init.lua
Normal file
@@ -0,0 +1,226 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local gmod_drawhelp = CreateClientConVar( "gmod_drawhelp", "1", true, false, "Should the tool HUD be displayed when the tool gun is active?" )
|
||||
local gmod_toolmode = CreateClientConVar( "gmod_toolmode", "rope", true, true, "Currently selected tool mode for the Tool Gun." )
|
||||
CreateClientConVar( "gmod_drawtooleffects", "1", true, false, "Should tools draw certain UI elements or effects? (Will not work for all tools)" )
|
||||
|
||||
cvars.AddChangeCallback( "gmod_toolmode", function( name, old, new )
|
||||
if ( old == new ) then return end
|
||||
spawnmenu.ActivateTool( new, true )
|
||||
end, "gmod_toolmode_panel" )
|
||||
|
||||
include( "shared.lua" )
|
||||
include( "cl_viewscreen.lua" )
|
||||
|
||||
SWEP.Slot = 5
|
||||
SWEP.SlotPos = 6
|
||||
SWEP.DrawAmmo = false
|
||||
SWEP.DrawCrosshair = true
|
||||
|
||||
SWEP.WepSelectIcon = surface.GetTextureID( "vgui/gmod_tool" )
|
||||
SWEP.Gradient = surface.GetTextureID( "gui/gradient" )
|
||||
SWEP.InfoIcon = surface.GetTextureID( "gui/info" )
|
||||
|
||||
SWEP.ToolNameHeight = 0
|
||||
SWEP.InfoBoxHeight = 0
|
||||
|
||||
surface.CreateFont( "GModToolName", {
|
||||
font = "Roboto Bk",
|
||||
size = 80,
|
||||
weight = 1000
|
||||
} )
|
||||
|
||||
surface.CreateFont( "GModToolSubtitle", {
|
||||
font = "Roboto Bk",
|
||||
size = 24,
|
||||
weight = 1000
|
||||
} )
|
||||
|
||||
surface.CreateFont( "GModToolHelp", {
|
||||
font = "Roboto Bk",
|
||||
size = 17,
|
||||
weight = 1000
|
||||
} )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Draws the help on the HUD (disabled if gmod_drawhelp is 0)
|
||||
-----------------------------------------------------------]]
|
||||
function SWEP:DrawHUD()
|
||||
|
||||
local mode = gmod_toolmode:GetString()
|
||||
local toolObject = self:GetToolObject()
|
||||
|
||||
-- Don't draw help for a nonexistant tool!
|
||||
if ( !toolObject ) then return end
|
||||
|
||||
toolObject:DrawHUD()
|
||||
|
||||
if ( !gmod_drawhelp:GetBool() ) then return end
|
||||
|
||||
-- This could probably all suck less than it already does
|
||||
|
||||
local x, y = 50, 40
|
||||
local w, h = 0, 0
|
||||
|
||||
local TextTable = {}
|
||||
local QuadTable = {}
|
||||
|
||||
QuadTable.texture = self.Gradient
|
||||
QuadTable.color = Color( 10, 10, 10, 180 )
|
||||
|
||||
QuadTable.x = 0
|
||||
QuadTable.y = y - 8
|
||||
QuadTable.w = 600
|
||||
QuadTable.h = self.ToolNameHeight - ( y - 8 )
|
||||
draw.TexturedQuad( QuadTable )
|
||||
|
||||
TextTable.font = "GModToolName"
|
||||
TextTable.color = Color( 240, 240, 240, 255 )
|
||||
TextTable.pos = { x, y }
|
||||
TextTable.text = "#tool." .. mode .. ".name"
|
||||
w, h = draw.TextShadow( TextTable, 2 )
|
||||
y = y + h
|
||||
|
||||
TextTable.font = "GModToolSubtitle"
|
||||
TextTable.pos = { x, y }
|
||||
TextTable.text = "#tool." .. mode .. ".desc"
|
||||
w, h = draw.TextShadow( TextTable, 1 )
|
||||
y = y + h + 8
|
||||
|
||||
self.ToolNameHeight = y
|
||||
|
||||
QuadTable.y = y
|
||||
QuadTable.h = self.InfoBoxHeight
|
||||
local alpha = math.Clamp( 255 + ( toolObject.LastMessage - CurTime() ) * 800, 10, 255 )
|
||||
QuadTable.color = Color( alpha, alpha, alpha, 230 )
|
||||
draw.TexturedQuad( QuadTable )
|
||||
|
||||
y = y + 4
|
||||
|
||||
TextTable.font = "GModToolHelp"
|
||||
|
||||
if ( !toolObject.Information ) then
|
||||
TextTable.pos = { x + self.InfoBoxHeight, y }
|
||||
TextTable.text = toolObject:GetHelpText()
|
||||
w, h = draw.TextShadow( TextTable, 1 )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetTexture( self.InfoIcon )
|
||||
surface.DrawTexturedRect( x + 1, y + 1, h - 3, h - 3 )
|
||||
|
||||
self.InfoBoxHeight = h + 8
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local h2 = 0
|
||||
|
||||
for _, v in pairs( toolObject.Information ) do
|
||||
if ( isstring( v ) ) then v = { name = v } end
|
||||
|
||||
local name = v.name
|
||||
|
||||
if ( !name ) then continue end
|
||||
if ( v.stage && v.stage != self:GetStage() ) then continue end
|
||||
if ( v.op && v.op != toolObject:GetOperation() ) then continue end
|
||||
|
||||
local txt = "#tool." .. GetConVarString( "gmod_toolmode" ) .. "." .. name
|
||||
if ( name == "info" ) then txt = toolObject:GetHelpText() end
|
||||
|
||||
TextTable.text = txt
|
||||
TextTable.pos = { x + 21, y + h2 }
|
||||
|
||||
w, h = draw.TextShadow( TextTable, 1 )
|
||||
|
||||
local icon1 = v.icon
|
||||
local icon2 = v.icon2
|
||||
|
||||
if ( !icon1 ) then
|
||||
if ( string.StartsWith( name, "info" ) ) then icon1 = "gui/info" end
|
||||
if ( string.StartsWith( name, "left" ) ) then icon1 = "gui/lmb.png" end
|
||||
if ( string.StartsWith( name, "right" ) ) then icon1 = "gui/rmb.png" end
|
||||
if ( string.StartsWith( name, "reload" ) ) then icon1 = "gui/r.png" end
|
||||
if ( string.StartsWith( name, "use" ) ) then icon1 = "gui/e.png" end
|
||||
end
|
||||
if ( !icon2 && !string.StartsWith( name, "use" ) && string.EndsWith( name, "use" ) ) then icon2 = "gui/e.png" end
|
||||
|
||||
self.Icons = self.Icons or {}
|
||||
if ( icon1 && !self.Icons[ icon1 ] ) then self.Icons[ icon1 ] = Material( icon1 ) end
|
||||
if ( icon2 && !self.Icons[ icon2 ] ) then self.Icons[ icon2 ] = Material( icon2 ) end
|
||||
|
||||
if ( icon1 && self.Icons[ icon1 ] && !self.Icons[ icon1 ]:IsError() ) then
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetMaterial( self.Icons[ icon1 ] )
|
||||
surface.DrawTexturedRect( x, y + h2, 16, 16 )
|
||||
end
|
||||
|
||||
if ( icon2 && self.Icons[ icon2 ] && !self.Icons[ icon2 ]:IsError() ) then
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetMaterial( self.Icons[ icon2 ] )
|
||||
surface.DrawTexturedRect( x - 25, y + h2, 16, 16 )
|
||||
|
||||
draw.SimpleText( "+", "default", x - 8, y + h2 + 2, color_white )
|
||||
end
|
||||
|
||||
h2 = h2 + h
|
||||
|
||||
end
|
||||
|
||||
self.InfoBoxHeight = h2 + 8
|
||||
|
||||
end
|
||||
|
||||
function SWEP:SetStage( ... )
|
||||
|
||||
if ( !self:GetToolObject() ) then return end
|
||||
return self:GetToolObject():SetStage( ... )
|
||||
|
||||
end
|
||||
|
||||
function SWEP:GetStage( ... )
|
||||
|
||||
if ( !self:GetToolObject() ) then return end
|
||||
return self:GetToolObject():GetStage( ... )
|
||||
|
||||
end
|
||||
|
||||
function SWEP:ClearObjects( ... )
|
||||
|
||||
if ( !self:GetToolObject() ) then return end
|
||||
self:GetToolObject():ClearObjects( ... )
|
||||
|
||||
end
|
||||
|
||||
function SWEP:StartGhostEntities( ... )
|
||||
|
||||
if ( !self:GetToolObject() ) then return end
|
||||
self:GetToolObject():StartGhostEntities( ... )
|
||||
|
||||
end
|
||||
|
||||
function SWEP:PrintWeaponInfo( x, y, alpha )
|
||||
end
|
||||
|
||||
function SWEP:FreezeMovement()
|
||||
|
||||
if ( !self:GetToolObject() ) then return false end
|
||||
|
||||
return self:GetToolObject():FreezeMovement()
|
||||
|
||||
end
|
||||
|
||||
function SWEP:OnReloaded()
|
||||
|
||||
-- TODO: Reload the tool control panels
|
||||
-- controlpanel.Clear()
|
||||
|
||||
end
|
||||
@@ -0,0 +1,84 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local matScreen = Material( "models/weapons/v_toolgun/screen" )
|
||||
local txBackground = surface.GetTextureID( "models/weapons/v_toolgun/screen_bg" )
|
||||
local toolmode = GetConVar( "gmod_toolmode" )
|
||||
local TEX_SIZE = 256
|
||||
|
||||
-- GetRenderTarget returns the texture if it exists, or creates it if it doesn't
|
||||
local RTTexture = GetRenderTarget( "GModToolgunScreen", TEX_SIZE, TEX_SIZE )
|
||||
|
||||
surface.CreateFont( "GModToolScreen", {
|
||||
font = "Helvetica",
|
||||
size = 60,
|
||||
weight = 900
|
||||
} )
|
||||
|
||||
local function DrawScrollingText( text, y, texwide )
|
||||
|
||||
local w, h = surface.GetTextSize( text )
|
||||
w = w + 64
|
||||
|
||||
y = y - h / 2 -- Center text to y position
|
||||
|
||||
local x = RealTime() * 250 % w * -1
|
||||
|
||||
while ( x < texwide ) do
|
||||
|
||||
surface.SetTextColor( 0, 0, 0, 255 )
|
||||
surface.SetTextPos( x + 3, y + 3 )
|
||||
surface.DrawText( text )
|
||||
|
||||
surface.SetTextColor( 255, 255, 255, 255 )
|
||||
surface.SetTextPos( x, y )
|
||||
surface.DrawText( text )
|
||||
|
||||
x = x + w
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
We use this opportunity to draw to the toolmode
|
||||
screen's rendertarget texture.
|
||||
-----------------------------------------------------------]]
|
||||
function SWEP:RenderScreen()
|
||||
|
||||
-- Set the material of the screen to our render target
|
||||
matScreen:SetTexture( "$basetexture", RTTexture )
|
||||
|
||||
-- Set up our view for drawing to the texture
|
||||
render.PushRenderTarget( RTTexture )
|
||||
cam.Start2D()
|
||||
|
||||
-- Background
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetTexture( txBackground )
|
||||
surface.DrawTexturedRect( 0, 0, TEX_SIZE, TEX_SIZE )
|
||||
|
||||
-- Give our toolmode the opportunity to override the drawing
|
||||
if ( self:GetToolObject() && self:GetToolObject().DrawToolScreen ) then
|
||||
|
||||
self:GetToolObject():DrawToolScreen( TEX_SIZE, TEX_SIZE )
|
||||
|
||||
else
|
||||
|
||||
surface.SetFont( "GModToolScreen" )
|
||||
DrawScrollingText( "#tool." .. toolmode:GetString() .. ".name", 104, TEX_SIZE )
|
||||
|
||||
end
|
||||
|
||||
cam.End2D()
|
||||
render.PopRenderTarget()
|
||||
|
||||
end
|
||||
135
gamemodes/sandbox/entities/weapons/gmod_tool/ghostentity.lua
Normal file
135
gamemodes/sandbox/entities/weapons/gmod_tool/ghostentity.lua
Normal file
@@ -0,0 +1,135 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Starts up the ghost entity
|
||||
The most important part of this is making sure it gets deleted properly
|
||||
-----------------------------------------------------------]]
|
||||
function ToolObj:MakeGhostEntity( model, pos, angle )
|
||||
|
||||
util.PrecacheModel( model )
|
||||
|
||||
-- We do ghosting serverside in single player
|
||||
-- It's done clientside in multiplayer
|
||||
if ( SERVER && !game.SinglePlayer() ) then return end
|
||||
if ( CLIENT && game.SinglePlayer() ) then return end
|
||||
|
||||
-- The reason we need this is because in multiplayer, when you holster a tool serverside,
|
||||
-- either by using the spawnnmenu's Weapons tab or by simply entering a vehicle,
|
||||
-- the Think hook is called once after Holster is called on the client, recreating the ghost entity right after it was removed.
|
||||
if ( !IsFirstTimePredicted() ) then return end
|
||||
|
||||
-- Release the old ghost entity
|
||||
self:ReleaseGhostEntity()
|
||||
|
||||
-- Don't allow ragdolls/effects to be ghosts
|
||||
if ( !util.IsValidProp( model ) ) then return end
|
||||
|
||||
if ( CLIENT ) then
|
||||
self.GhostEntity = ents.CreateClientProp( model )
|
||||
else
|
||||
self.GhostEntity = ents.Create( "prop_physics" )
|
||||
end
|
||||
|
||||
-- If there's too many entities we might not spawn..
|
||||
if ( !IsValid( self.GhostEntity ) ) then
|
||||
self.GhostEntity = nil
|
||||
return
|
||||
end
|
||||
|
||||
self.GhostEntity:SetModel( model )
|
||||
self.GhostEntity:SetPos( pos )
|
||||
self.GhostEntity:SetAngles( angle )
|
||||
self.GhostEntity:Spawn()
|
||||
|
||||
-- We do not want physics at all
|
||||
self.GhostEntity:PhysicsDestroy()
|
||||
|
||||
-- SOLID_NONE causes issues with Entity.NearestPoint used by Wheel tool
|
||||
--self.GhostEntity:SetSolid( SOLID_NONE )
|
||||
self.GhostEntity:SetMoveType( MOVETYPE_NONE )
|
||||
self.GhostEntity:SetNotSolid( true )
|
||||
self.GhostEntity:SetRenderMode( RENDERMODE_TRANSCOLOR )
|
||||
self.GhostEntity:SetColor( Color( 255, 255, 255, 150 ) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Starts up the ghost entity
|
||||
The most important part of this is making sure it gets deleted properly
|
||||
-----------------------------------------------------------]]
|
||||
function ToolObj:StartGhostEntity( ent )
|
||||
|
||||
-- We do ghosting serverside in single player
|
||||
-- It's done clientside in multiplayer
|
||||
if ( SERVER && !game.SinglePlayer() ) then return end
|
||||
if ( CLIENT && game.SinglePlayer() ) then return end
|
||||
|
||||
self:MakeGhostEntity( ent:GetModel(), ent:GetPos(), ent:GetAngles() )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Releases up the ghost entity
|
||||
-----------------------------------------------------------]]
|
||||
function ToolObj:ReleaseGhostEntity()
|
||||
|
||||
if ( self.GhostEntity ) then
|
||||
if ( !IsValid( self.GhostEntity ) ) then self.GhostEntity = nil return end
|
||||
self.GhostEntity:Remove()
|
||||
self.GhostEntity = nil
|
||||
end
|
||||
|
||||
-- This is unused!
|
||||
if ( self.GhostEntities ) then
|
||||
|
||||
for k, v in pairs( self.GhostEntities ) do
|
||||
if ( IsValid( v ) ) then v:Remove() end
|
||||
self.GhostEntities[ k ] = nil
|
||||
end
|
||||
|
||||
self.GhostEntities = nil
|
||||
end
|
||||
|
||||
-- This is unused!
|
||||
if ( self.GhostOffset ) then
|
||||
|
||||
for k, v in pairs( self.GhostOffset ) do
|
||||
self.GhostOffset[ k ] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Update the ghost entity
|
||||
-----------------------------------------------------------]]
|
||||
function ToolObj:UpdateGhostEntity()
|
||||
|
||||
if ( self.GhostEntity == nil ) then return end
|
||||
if ( !IsValid( self.GhostEntity ) ) then self.GhostEntity = nil return end
|
||||
|
||||
local trace = self:GetOwner():GetEyeTrace()
|
||||
if ( !trace.Hit ) then return end
|
||||
|
||||
local Ang1, Ang2 = self:GetNormal( 1 ):Angle(), ( trace.HitNormal * -1 ):Angle()
|
||||
local TargetAngle = self:GetEnt( 1 ):AlignAngles( Ang1, Ang2 )
|
||||
|
||||
self.GhostEntity:SetPos( self:GetEnt( 1 ):GetPos() )
|
||||
self.GhostEntity:SetAngles( TargetAngle )
|
||||
|
||||
local TranslatedPos = self.GhostEntity:LocalToWorld( self:GetLocalPos( 1 ) )
|
||||
local TargetPos = trace.HitPos + ( self:GetEnt( 1 ):GetPos() - TranslatedPos ) + trace.HitNormal
|
||||
|
||||
self.GhostEntity:SetPos( TargetPos )
|
||||
|
||||
end
|
||||
45
gamemodes/sandbox/entities/weapons/gmod_tool/init.lua
Normal file
45
gamemodes/sandbox/entities/weapons/gmod_tool/init.lua
Normal file
@@ -0,0 +1,45 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile( "cl_init.lua" )
|
||||
AddCSLuaFile( "shared.lua" )
|
||||
AddCSLuaFile( "ghostentity.lua" )
|
||||
AddCSLuaFile( "object.lua" )
|
||||
AddCSLuaFile( "stool.lua" )
|
||||
AddCSLuaFile( "cl_viewscreen.lua" )
|
||||
AddCSLuaFile( "stool_cl.lua" )
|
||||
|
||||
include( "shared.lua" )
|
||||
|
||||
SWEP.Weight = 5
|
||||
SWEP.AutoSwitchTo = false
|
||||
SWEP.AutoSwitchFrom = false
|
||||
|
||||
-- Should this weapon be dropped when its owner dies?
|
||||
function SWEP:ShouldDropOnDie()
|
||||
return false
|
||||
end
|
||||
|
||||
-- Console Command to switch weapon/toolmode
|
||||
local function CC_GMOD_Tool( ply, command, arguments )
|
||||
|
||||
local targetMode = arguments[1]
|
||||
|
||||
if ( targetMode == nil ) then return end
|
||||
if ( GetConVarNumber( "toolmode_allow_" .. targetMode ) != 1 ) then return end
|
||||
|
||||
ply:ConCommand( "gmod_toolmode " .. targetMode )
|
||||
|
||||
-- Switch weapons
|
||||
ply:SelectWeapon( "gmod_tool" )
|
||||
|
||||
end
|
||||
concommand.Add( "gmod_tool", CC_GMOD_Tool, nil, nil, { FCVAR_SERVER_CAN_EXECUTE } )
|
||||
175
gamemodes/sandbox/entities/weapons/gmod_tool/object.lua
Normal file
175
gamemodes/sandbox/entities/weapons/gmod_tool/object.lua
Normal file
@@ -0,0 +1,175 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function ToolObj:UpdateData()
|
||||
|
||||
self:SetStage( self:NumObjects() )
|
||||
|
||||
end
|
||||
|
||||
function ToolObj:SetStage( i )
|
||||
|
||||
if ( SERVER ) then
|
||||
self:GetWeapon():SetNWInt( "Stage", i )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ToolObj:GetStage()
|
||||
return self:GetWeapon():GetNWInt( "Stage", 0 )
|
||||
end
|
||||
|
||||
function ToolObj:SetOperation( i )
|
||||
|
||||
if ( SERVER ) then
|
||||
self:GetWeapon():SetNWInt( "Op", i )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ToolObj:GetOperation()
|
||||
return self:GetWeapon():GetNWInt( "Op", 0 )
|
||||
end
|
||||
|
||||
|
||||
-- Clear the selected objects
|
||||
function ToolObj:ClearObjects()
|
||||
|
||||
self:ReleaseGhostEntity()
|
||||
self.Objects = {}
|
||||
self:SetStage( 0 )
|
||||
self:SetOperation( 0 )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Since we're going to be expanding this a lot I've tried
|
||||
to add accessors for all of this crap to make it harder
|
||||
for us to mess everything up.
|
||||
-----------------------------------------------------------]]
|
||||
function ToolObj:GetEnt( i )
|
||||
|
||||
if ( !self.Objects[i] ) then return NULL end
|
||||
|
||||
return self.Objects[i].Ent
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns the world position of the numbered object hit
|
||||
We store it as a local vector then convert it to world
|
||||
That way even if the object moves it's still valid
|
||||
-----------------------------------------------------------]]
|
||||
function ToolObj:GetPos( i )
|
||||
|
||||
if ( self.Objects[i].Ent:EntIndex() == 0 ) then
|
||||
return self.Objects[i].Pos
|
||||
else
|
||||
if ( IsValid( self.Objects[i].Phys ) ) then
|
||||
return self.Objects[i].Phys:LocalToWorld( self.Objects[i].Pos )
|
||||
else
|
||||
return self.Objects[i].Ent:LocalToWorld( self.Objects[i].Pos )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Returns the local position of the numbered hit
|
||||
function ToolObj:GetLocalPos( i )
|
||||
return self.Objects[i].Pos
|
||||
end
|
||||
|
||||
-- Returns the physics bone number of the hit (ragdolls)
|
||||
function ToolObj:GetBone( i )
|
||||
return self.Objects[i].Bone
|
||||
end
|
||||
|
||||
function ToolObj:GetNormal( i )
|
||||
if ( self.Objects[i].Ent:EntIndex() == 0 ) then
|
||||
return self.Objects[i].Normal
|
||||
else
|
||||
local norm
|
||||
if ( IsValid( self.Objects[i].Phys ) ) then
|
||||
norm = self.Objects[i].Phys:LocalToWorld( self.Objects[i].Normal )
|
||||
else
|
||||
norm = self.Objects[i].Ent:LocalToWorld( self.Objects[i].Normal )
|
||||
end
|
||||
|
||||
return norm - self:GetPos( i )
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns the physics object for the numbered hit
|
||||
function ToolObj:GetPhys( i )
|
||||
|
||||
if ( self.Objects[i].Phys == nil ) then
|
||||
return self:GetEnt( i ):GetPhysicsObject()
|
||||
end
|
||||
|
||||
return self.Objects[i].Phys
|
||||
end
|
||||
|
||||
|
||||
-- Sets a selected object
|
||||
function ToolObj:SetObject( i, ent, pos, phys, bone, norm )
|
||||
|
||||
self.Objects[i] = {}
|
||||
self.Objects[i].Ent = ent
|
||||
self.Objects[i].Phys = phys
|
||||
self.Objects[i].Bone = bone
|
||||
self.Objects[i].Normal = norm
|
||||
|
||||
-- Worldspawn is a special case
|
||||
if ( ent:EntIndex() == 0 ) then
|
||||
|
||||
self.Objects[i].Phys = nil
|
||||
self.Objects[i].Pos = pos
|
||||
|
||||
else
|
||||
|
||||
norm = norm + pos
|
||||
|
||||
-- Convert the position to a local position - so it's still valid when the object moves
|
||||
if ( IsValid( phys ) ) then
|
||||
self.Objects[i].Normal = self.Objects[i].Phys:WorldToLocal( norm )
|
||||
self.Objects[i].Pos = self.Objects[i].Phys:WorldToLocal( pos )
|
||||
else
|
||||
self.Objects[i].Normal = self.Objects[i].Ent:WorldToLocal( norm )
|
||||
self.Objects[i].Pos = self.Objects[i].Ent:WorldToLocal( pos )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- TODO: Make sure the client got the same info
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Returns the number of objects in the list
|
||||
function ToolObj:NumObjects()
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
return self:GetStage()
|
||||
|
||||
end
|
||||
|
||||
return #self.Objects
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Returns the number of objects in the list
|
||||
function ToolObj:GetHelpText()
|
||||
|
||||
return "#tool." .. GetConVarString( "gmod_toolmode" ) .. "." .. self:GetStage()
|
||||
|
||||
end
|
||||
396
gamemodes/sandbox/entities/weapons/gmod_tool/shared.lua
Normal file
396
gamemodes/sandbox/entities/weapons/gmod_tool/shared.lua
Normal file
@@ -0,0 +1,396 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Variables that are used on both client and server
|
||||
|
||||
SWEP.PrintName = "#GMOD_ToolGun"
|
||||
SWEP.Author = "Facepunch"
|
||||
SWEP.Contact = ""
|
||||
SWEP.Purpose = ""
|
||||
SWEP.Instructions = ""
|
||||
|
||||
SWEP.ViewModel = "models/weapons/c_toolgun.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_toolgun.mdl"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.Spawnable = true
|
||||
|
||||
-- Be nice, precache the models
|
||||
util.PrecacheModel( SWEP.ViewModel )
|
||||
util.PrecacheModel( SWEP.WorldModel )
|
||||
|
||||
-- Todo, make/find a better sound.
|
||||
SWEP.ShootSound = Sound( "Airboat.FireGunRevDown" )
|
||||
|
||||
SWEP.Tool = {}
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.CanHolster = true
|
||||
SWEP.CanDeploy = true
|
||||
|
||||
function SWEP:InitializeTools()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
local temp = {}
|
||||
|
||||
for k, v in pairs( self.Tool ) do
|
||||
|
||||
temp[k] = table.Copy( v )
|
||||
temp[k].SWEP = self
|
||||
temp[k].Owner = owner
|
||||
temp[k].Weapon = self
|
||||
temp[k]:Init()
|
||||
|
||||
end
|
||||
|
||||
self.Tool = temp
|
||||
|
||||
end
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Entity", 0, "TargetEntity1" )
|
||||
self:NetworkVar( "Entity", 1, "TargetEntity2" )
|
||||
self:NetworkVar( "Entity", 2, "TargetEntity3" )
|
||||
self:NetworkVar( "Entity", 3, "TargetEntity4" )
|
||||
|
||||
end
|
||||
|
||||
-- Convenience function to check object limits
|
||||
function SWEP:CheckLimit( str )
|
||||
return self:GetOwner():CheckLimit( str )
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
|
||||
self:SetHoldType( "revolver" )
|
||||
|
||||
self:InitializeTools()
|
||||
|
||||
-- We create these here. The problem is that these are meant to be constant values.
|
||||
-- in the toolmode they're not because some tools can be automatic while some tools aren't.
|
||||
-- Since this is a global table it's shared between all instances of the gun.
|
||||
-- By creating new tables here we're making it so each tool has its own instance of the table
|
||||
-- So changing it won't affect the other tools.
|
||||
|
||||
self.Primary = {
|
||||
ClipSize = -1,
|
||||
DefaultClip = -1,
|
||||
Automatic = false,
|
||||
Ammo = "none"
|
||||
}
|
||||
|
||||
self.Secondary = {
|
||||
ClipSize = -1,
|
||||
DefaultClip = -1,
|
||||
Automatic = false,
|
||||
Ammo = "none"
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
function SWEP:OnRestore()
|
||||
|
||||
self:InitializeTools()
|
||||
|
||||
end
|
||||
|
||||
function SWEP:Precache()
|
||||
|
||||
util.PrecacheSound( self.ShootSound )
|
||||
|
||||
end
|
||||
|
||||
-- Returns the mode we're in
|
||||
function SWEP:GetMode()
|
||||
|
||||
return self.Mode
|
||||
|
||||
end
|
||||
|
||||
-- Think does stuff every frame
|
||||
function SWEP:Think()
|
||||
|
||||
-- SWEP:Think is called one more time clientside
|
||||
-- after holstering using Player:SelectWeapon in multiplayer
|
||||
if ( CLIENT and self.m_uHolsterFrame == FrameNumber() ) then return end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
if ( !owner:IsPlayer() ) then return end
|
||||
|
||||
local curmode = owner:GetInfo( "gmod_toolmode" )
|
||||
self.Mode = curmode
|
||||
|
||||
local tool = self:GetToolObject( curmode )
|
||||
if ( !tool ) then return end
|
||||
|
||||
tool:CheckObjects()
|
||||
|
||||
local lastmode = self.current_mode
|
||||
self.last_mode = lastmode
|
||||
self.current_mode = curmode
|
||||
|
||||
-- Release ghost entities if we're not allowed to use this new mode?
|
||||
if ( !tool:Allowed() ) then
|
||||
if ( lastmode ) then
|
||||
local lastmode_obj = self:GetToolObject( lastmode )
|
||||
|
||||
if ( lastmode_obj ) then
|
||||
lastmode_obj:ReleaseGhostEntity() -- In case tool overwrites the default Holster
|
||||
lastmode_obj:Holster( true )
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if ( lastmode and lastmode ~= curmode ) then
|
||||
local lastmode_obj = self:GetToolObject( lastmode )
|
||||
|
||||
if ( lastmode_obj ) then
|
||||
-- We want to release the ghost entity just in case
|
||||
lastmode_obj:ReleaseGhostEntity()
|
||||
lastmode_obj:Holster( true )
|
||||
end
|
||||
|
||||
-- Deploy the new tool
|
||||
tool:Deploy( true )
|
||||
end
|
||||
|
||||
self.Primary.Automatic = tool.LeftClickAutomatic or false
|
||||
self.Secondary.Automatic = tool.RightClickAutomatic or false
|
||||
self.RequiresTraceHit = tool.RequiresTraceHit or true
|
||||
|
||||
tool:Think()
|
||||
|
||||
end
|
||||
|
||||
-- The shoot effect
|
||||
function SWEP:DoShootEffect( hitpos, hitnormal, entity, physbone, bFirstTimePredicted )
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
self:EmitSound( self.ShootSound )
|
||||
self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) -- View model animation
|
||||
|
||||
-- There's a bug with the model that's causing a muzzle to
|
||||
-- appear on everyone's screen when we fire this animation.
|
||||
owner:SetAnimation( PLAYER_ATTACK1 ) -- 3rd Person Animation
|
||||
|
||||
if ( !bFirstTimePredicted ) then return end
|
||||
if ( GetConVarNumber( "gmod_drawtooleffects" ) == 0 ) then return end
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( hitpos )
|
||||
effectdata:SetNormal( hitnormal )
|
||||
effectdata:SetEntity( entity )
|
||||
effectdata:SetAttachment( physbone )
|
||||
util.Effect( "selection_indicator", effectdata )
|
||||
|
||||
local effect_tr = EffectData()
|
||||
effect_tr:SetOrigin( hitpos )
|
||||
effect_tr:SetStart( owner:GetShootPos() )
|
||||
effect_tr:SetAttachment( 1 )
|
||||
effect_tr:SetEntity( self )
|
||||
util.Effect( "ToolTracer", effect_tr )
|
||||
|
||||
end
|
||||
|
||||
local toolmask = bit.bor( CONTENTS_SOLID, CONTENTS_MOVEABLE, CONTENTS_MONSTER, CONTENTS_WINDOW, CONTENTS_DEBRIS, CONTENTS_GRATE, CONTENTS_AUX )
|
||||
|
||||
-- Trace a line then send the result to a mode function
|
||||
function SWEP:PrimaryAttack()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
local tr = util.GetPlayerTrace( owner )
|
||||
tr.mask = toolmask
|
||||
tr.mins = vector_origin
|
||||
tr.maxs = tr.mins
|
||||
local trace = util.TraceLine( tr )
|
||||
if ( !trace.Hit ) then trace = util.TraceHull( tr ) end
|
||||
if ( !trace.Hit ) then return end
|
||||
|
||||
local tool = self:GetToolObject()
|
||||
if ( !tool ) then return end
|
||||
|
||||
tool:CheckObjects()
|
||||
|
||||
-- Does the server setting say it's ok?
|
||||
if ( !tool:Allowed() ) then return end
|
||||
|
||||
-- Ask the gamemode if it's ok to do this
|
||||
local mode = self:GetMode()
|
||||
if ( !gamemode.Call( "CanTool", owner, trace, mode, tool, 1 ) ) then return end
|
||||
|
||||
if ( !tool:LeftClick( trace ) ) then return end
|
||||
|
||||
self:DoShootEffect( trace.HitPos, trace.HitNormal, trace.Entity, trace.PhysicsBone, IsFirstTimePredicted() )
|
||||
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
local tr = util.GetPlayerTrace( owner )
|
||||
tr.mask = toolmask
|
||||
tr.mins = vector_origin
|
||||
tr.maxs = tr.mins
|
||||
local trace = util.TraceLine( tr )
|
||||
if ( !trace.Hit ) then trace = util.TraceHull( tr ) end
|
||||
if ( !trace.Hit ) then return end
|
||||
|
||||
local tool = self:GetToolObject()
|
||||
if ( !tool ) then return end
|
||||
|
||||
tool:CheckObjects()
|
||||
|
||||
-- Does the server setting say it's ok?
|
||||
if ( !tool:Allowed() ) then return end
|
||||
|
||||
-- Ask the gamemode if it's ok to do this
|
||||
local mode = self:GetMode()
|
||||
if ( !gamemode.Call( "CanTool", owner, trace, mode, tool, 2 ) ) then return end
|
||||
|
||||
if ( !tool:RightClick( trace ) ) then return end
|
||||
|
||||
self:DoShootEffect( trace.HitPos, trace.HitNormal, trace.Entity, trace.PhysicsBone, IsFirstTimePredicted() )
|
||||
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
-- This makes the reload a semi-automatic thing rather than a continuous thing
|
||||
if ( !owner:KeyPressed( IN_RELOAD ) ) then return end
|
||||
|
||||
local tr = util.GetPlayerTrace( owner )
|
||||
tr.mask = toolmask
|
||||
tr.mins = vector_origin
|
||||
tr.maxs = tr.mins
|
||||
local trace = util.TraceLine( tr )
|
||||
if ( !trace.Hit ) then trace = util.TraceHull( tr ) end
|
||||
if ( !trace.Hit ) then return end
|
||||
|
||||
local tool = self:GetToolObject()
|
||||
if ( !tool ) then return end
|
||||
|
||||
tool:CheckObjects()
|
||||
|
||||
-- Does the server setting say it's ok?
|
||||
if ( !tool:Allowed() ) then return end
|
||||
|
||||
-- Ask the gamemode if it's ok to do this
|
||||
local mode = self:GetMode()
|
||||
if ( !gamemode.Call( "CanTool", owner, trace, mode, tool, 3 ) ) then return end
|
||||
|
||||
if ( !tool:Reload( trace ) ) then return end
|
||||
|
||||
self:DoShootEffect( trace.HitPos, trace.HitNormal, trace.Entity, trace.PhysicsBone, IsFirstTimePredicted() )
|
||||
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
|
||||
local toolobj = self:GetToolObject()
|
||||
local CanHolster
|
||||
|
||||
if ( toolobj ) then
|
||||
CanHolster = toolobj:Holster()
|
||||
if ( CanHolster == nil ) then CanHolster = self.CanHolster end
|
||||
else
|
||||
-- Just do what the SWEP wants to do if there's no tool
|
||||
CanHolster = self.CanHolster
|
||||
end
|
||||
|
||||
-- Save the frame the weapon was holstered on to prevent
|
||||
-- the extra Think call after calling Player:SelectWeapon in multiplayer
|
||||
if ( CLIENT and CanHolster == true ) then self.m_uHolsterFrame = FrameNumber() end
|
||||
|
||||
if ( CanHolster == true and toolobj ) then toolobj:ReleaseGhostEntity() end
|
||||
|
||||
return CanHolster
|
||||
|
||||
end
|
||||
|
||||
-- Delete ghosts here in case the weapon gets deleted all of a sudden somehow
|
||||
function SWEP:OnRemove()
|
||||
|
||||
if ( !self:GetToolObject() ) then return end
|
||||
|
||||
self:GetToolObject():ReleaseGhostEntity()
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- This will remove any ghosts when a player dies and drops the weapon
|
||||
function SWEP:OwnerChanged()
|
||||
|
||||
if ( !self:GetToolObject() ) then return end
|
||||
|
||||
self:GetToolObject():ReleaseGhostEntity()
|
||||
|
||||
end
|
||||
|
||||
-- Deploy
|
||||
function SWEP:Deploy()
|
||||
|
||||
-- Just do what the SWEP wants to do if there is no tool
|
||||
if ( !self:GetToolObject() ) then return self.CanDeploy end
|
||||
|
||||
self:GetToolObject():UpdateData()
|
||||
|
||||
local CanDeploy = self:GetToolObject():Deploy()
|
||||
if ( CanDeploy ~= nil ) then return CanDeploy end
|
||||
|
||||
return self.CanDeploy
|
||||
|
||||
end
|
||||
|
||||
function SWEP:GetToolObject( tool )
|
||||
|
||||
local mode = tool or self:GetMode()
|
||||
|
||||
if ( !mode ) then
|
||||
local owner = self:GetOwner()
|
||||
if ( IsValid( owner ) and owner:IsPlayer() and ( SERVER or owner == LocalPlayer() ) ) then
|
||||
mode = owner:GetInfo( "gmod_toolmode" )
|
||||
end
|
||||
end
|
||||
|
||||
if ( !self.Tool[ mode ] ) then return false end
|
||||
|
||||
return self.Tool[ mode ]
|
||||
|
||||
end
|
||||
|
||||
function SWEP:FireAnimationEvent( pos, ang, event, options )
|
||||
|
||||
-- Disables animation based muzzle event
|
||||
if ( event == 21 ) then return true end
|
||||
-- Disable thirdperson muzzle flash
|
||||
if ( event == 5003 ) then return true end
|
||||
|
||||
end
|
||||
|
||||
include( "stool.lua" )
|
||||
281
gamemodes/sandbox/entities/weapons/gmod_tool/stool.lua
Normal file
281
gamemodes/sandbox/entities/weapons/gmod_tool/stool.lua
Normal file
@@ -0,0 +1,281 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
ToolObj = {}
|
||||
|
||||
include( "ghostentity.lua" )
|
||||
include( "object.lua" )
|
||||
|
||||
if ( CLIENT ) then
|
||||
include( "stool_cl.lua" )
|
||||
end
|
||||
|
||||
function ToolObj:Create()
|
||||
|
||||
local o = {}
|
||||
|
||||
setmetatable( o, self )
|
||||
self.__index = self
|
||||
|
||||
o.Mode = nil
|
||||
o.SWEP = nil
|
||||
o.Owner = nil
|
||||
o.ClientConVar = {}
|
||||
o.ServerConVar = {}
|
||||
o.Objects = {}
|
||||
o.Stage = 0
|
||||
o.Message = "start"
|
||||
o.LastMessage = 0
|
||||
o.AllowedCVar = 0
|
||||
|
||||
return o
|
||||
|
||||
end
|
||||
|
||||
function ToolObj:CreateConVars()
|
||||
|
||||
local mode = self:GetMode()
|
||||
|
||||
self.AllowedCVar = CreateConVar( "toolmode_allow_" .. mode, "1", { FCVAR_NOTIFY, FCVAR_REPLICATED }, "Set to 0 to disallow players being able to use the \"" .. mode .. "\" tool." )
|
||||
self.ClientConVars = {}
|
||||
self.ServerConVars = {}
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
for cvar, default in pairs( self.ClientConVar ) do
|
||||
self.ClientConVars[ cvar ] = CreateClientConVar( mode .. "_" .. cvar, default, true, true, "Tool specific client setting (" .. mode .. ")" )
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
for cvar, default in pairs( self.ServerConVar ) do
|
||||
self.ServerConVars[ cvar ] = CreateConVar( mode .. "_" .. cvar, default, FCVAR_ARCHIVE, "Tool specific server setting (" .. mode .. ")" )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ToolObj:GetServerInfo( property )
|
||||
|
||||
if ( self.ServerConVars[ property ] and SERVER ) then
|
||||
return self.ServerConVars[ property ]:GetString()
|
||||
end
|
||||
|
||||
return GetConVarString( self:GetMode() .. "_" .. property )
|
||||
|
||||
end
|
||||
|
||||
function ToolObj:GetClientInfo( property )
|
||||
|
||||
if ( self.ClientConVars[ property ] and CLIENT ) then
|
||||
return self.ClientConVars[ property ]:GetString()
|
||||
end
|
||||
|
||||
return self:GetOwner():GetInfo( self:GetMode() .. "_" .. property )
|
||||
|
||||
end
|
||||
|
||||
function ToolObj:GetClientNumber( property, default )
|
||||
|
||||
if ( self.ClientConVars[ property ] and CLIENT ) then
|
||||
return self.ClientConVars[ property ]:GetFloat()
|
||||
end
|
||||
|
||||
return self:GetOwner():GetInfoNum( self:GetMode() .. "_" .. property, tonumber( default ) or 0 )
|
||||
|
||||
end
|
||||
|
||||
function ToolObj:GetClientBool( property, default )
|
||||
|
||||
if ( self.ClientConVars[ property ] and CLIENT ) then
|
||||
return self.ClientConVars[ property ]:GetBool()
|
||||
end
|
||||
|
||||
return math.floor( self:GetOwner():GetInfoNum( self:GetMode() .. "_" .. property, tonumber( default ) or 0 ) ) != 0
|
||||
|
||||
end
|
||||
|
||||
function ToolObj:BuildConVarList()
|
||||
|
||||
local mode = self:GetMode()
|
||||
local convars = {}
|
||||
|
||||
for k, v in pairs( self.ClientConVar ) do convars[ mode .. "_" .. k ] = v end
|
||||
|
||||
return convars
|
||||
|
||||
end
|
||||
|
||||
function ToolObj:Allowed()
|
||||
|
||||
return self.AllowedCVar:GetBool()
|
||||
|
||||
end
|
||||
|
||||
-- Now for all the ToolObj redirects
|
||||
|
||||
function ToolObj:Init() end
|
||||
|
||||
function ToolObj:GetMode() return self.Mode end
|
||||
function ToolObj:GetWeapon() return self.SWEP end
|
||||
function ToolObj:GetOwner() return self:GetWeapon():GetOwner() or self.Owner end
|
||||
function ToolObj:GetSWEP() return self:GetWeapon() end
|
||||
|
||||
function ToolObj:LeftClick() return false end
|
||||
function ToolObj:RightClick() return false end
|
||||
function ToolObj:Reload() self:ClearObjects() end
|
||||
function ToolObj:Deploy() self:ReleaseGhostEntity() return end
|
||||
function ToolObj:Holster() self:ReleaseGhostEntity() return end
|
||||
function ToolObj:Think() self:ReleaseGhostEntity() end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Checks the objects before any action is taken
|
||||
This is to make sure that the entities haven't been removed
|
||||
-----------------------------------------------------------]]
|
||||
function ToolObj:CheckObjects()
|
||||
|
||||
for k, v in pairs( self.Objects ) do
|
||||
|
||||
if ( !v.Ent:IsWorld() and !v.Ent:IsValid() ) then
|
||||
self:ClearObjects()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
for _, val in ipairs( file.Find( SWEP.Folder .. "/stools/*.lua", "LUA" ) ) do
|
||||
|
||||
local _, _, toolmode = string.find( val, "([%w_]*).lua" )
|
||||
|
||||
TOOL = ToolObj:Create()
|
||||
TOOL.Mode = toolmode
|
||||
|
||||
AddCSLuaFile( "stools/" .. val )
|
||||
include( "stools/" .. val )
|
||||
|
||||
TOOL:CreateConVars()
|
||||
|
||||
if ( hook.Run( "PreRegisterTOOL", TOOL, toolmode ) != false ) then
|
||||
SWEP.Tool[ toolmode ] = TOOL
|
||||
end
|
||||
|
||||
TOOL = nil
|
||||
|
||||
end
|
||||
|
||||
ToolObj = nil
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
-- Keep the tool list handy
|
||||
local TOOLS_LIST = SWEP.Tool
|
||||
|
||||
-- Add the STOOLS to the tool menu
|
||||
hook.Add( "PopulateToolMenu", "AddSToolsToMenu", function()
|
||||
|
||||
for ToolName, tool in pairs( TOOLS_LIST ) do
|
||||
|
||||
if ( tool.AddToMenu != false ) then
|
||||
|
||||
spawnmenu.AddToolMenuOption(
|
||||
tool.Tab or "Main",
|
||||
tool.Category or "New Category",
|
||||
ToolName,
|
||||
tool.Name or "#" .. ToolName,
|
||||
tool.Command or "gmod_tool " .. ToolName,
|
||||
tool.ConfigName or ToolName,
|
||||
tool.BuildCPanel
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
--
|
||||
-- Search
|
||||
--
|
||||
search.AddProvider( function( str )
|
||||
|
||||
local list = {}
|
||||
|
||||
for k, v in pairs( TOOLS_LIST ) do
|
||||
|
||||
local niceName = v.Name or "#" .. k
|
||||
if ( niceName:StartsWith( "#" ) ) then niceName = language.GetPhrase( niceName:sub( 2 ) ) end
|
||||
|
||||
if ( !k:lower():find( str, nil, true ) and !niceName:lower():find( str, nil, true ) ) then continue end
|
||||
|
||||
local entry = {
|
||||
text = niceName,
|
||||
icon = spawnmenu.CreateContentIcon( "tool", nil, {
|
||||
spawnname = k,
|
||||
nicename = v.Name or "#" .. k
|
||||
} ),
|
||||
words = { k }
|
||||
}
|
||||
|
||||
table.insert( list, entry )
|
||||
|
||||
if ( #list >= GetConVarNumber( "sbox_search_maxresults" ) / 32 ) then break end
|
||||
|
||||
end
|
||||
|
||||
return list
|
||||
|
||||
end )
|
||||
|
||||
--
|
||||
-- Tool spawnmenu icon
|
||||
--
|
||||
spawnmenu.AddContentType( "tool", function( container, obj )
|
||||
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "tool" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename or "#tool." .. obj.spawnname .. ".name" )
|
||||
icon:SetMaterial( "gui/tool.png" )
|
||||
|
||||
icon.DoClick = function()
|
||||
|
||||
spawnmenu.ActivateTool( obj.spawnname )
|
||||
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
|
||||
end
|
||||
|
||||
icon.OpenMenu = function( pnl )
|
||||
|
||||
-- Do not allow removal from read only panels
|
||||
if ( IsValid( pnl:GetParent() ) and pnl:GetParent().GetReadOnly and pnl:GetParent():GetReadOnly() ) then return end
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function()
|
||||
pnl:Remove()
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end ):SetIcon( "icon16/bin_closed.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
|
||||
30
gamemodes/sandbox/entities/weapons/gmod_tool/stool_cl.lua
Normal file
30
gamemodes/sandbox/entities/weapons/gmod_tool/stool_cl.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Tool should return true if freezing the view angles
|
||||
function ToolObj:FreezeMovement()
|
||||
return false
|
||||
end
|
||||
|
||||
-- The tool's opportunity to draw to the HUD
|
||||
function ToolObj:DrawHUD()
|
||||
end
|
||||
|
||||
-- Force rebuild the Control Panel
|
||||
function ToolObj:RebuildControlPanel( ... )
|
||||
|
||||
local cPanel = controlpanel.Get( self.Mode )
|
||||
if ( !cPanel ) then ErrorNoHalt( "Couldn't find control panel to rebuild!" ) return end
|
||||
|
||||
cPanel:ClearControls()
|
||||
self.BuildCPanel( cPanel, ... )
|
||||
|
||||
end
|
||||
230
gamemodes/sandbox/entities/weapons/gmod_tool/stools/axis.lua
Normal file
230
gamemodes/sandbox/entities/weapons/gmod_tool/stools/axis.lua
Normal file
@@ -0,0 +1,230 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.axis.name"
|
||||
|
||||
TOOL.ClientConVar[ "forcelimit" ] = 0
|
||||
TOOL.ClientConVar[ "torquelimit" ] = 0
|
||||
TOOL.ClientConVar[ "hingefriction" ] = 0
|
||||
TOOL.ClientConVar[ "nocollide" ] = 0
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1, op = 1 },
|
||||
{ name = "right", stage = 0 },
|
||||
{ name = "right_1", stage = 1, op = 2 },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( self:GetOperation() == 2 ) then return false end
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
-- todo: Don't attempt to constrain the first object if it's already constrained to a static object
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
-- Don't allow us to choose the world as the first object
|
||||
if ( iNum == 0 && !IsValid( trace.Entity ) ) then return false end
|
||||
|
||||
-- Don't do jeeps (crash protection until we get it fixed)
|
||||
if ( iNum == 0 && trace.Entity:GetClass() == "prop_vehicle_jeep" ) then return false end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
self:SetOperation( 1 )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
-- Clientside can bail out now
|
||||
if ( CLIENT ) then
|
||||
|
||||
self:ClearObjects()
|
||||
self:ReleaseGhostEntity()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local nocollide = self:GetClientNumber( "nocollide", 0 )
|
||||
local forcelimit = self:GetClientNumber( "forcelimit", 0 )
|
||||
local torquelimit = self:GetClientNumber( "torquelimit", 0 )
|
||||
local friction = self:GetClientNumber( "hingefriction", 0 )
|
||||
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local Norm1, Norm2 = self:GetNormal( 1 ), self:GetNormal( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
local Phys1 = self:GetPhys( 1 )
|
||||
local WPos2 = self:GetPos( 2 )
|
||||
|
||||
-- Note: To keep stuff ragdoll friendly try to treat things as physics objects rather than entities
|
||||
local Ang1, Ang2 = Norm1:Angle(), ( -Norm2 ):Angle()
|
||||
local TargetAngle = Phys1:AlignAngles( Ang1, Ang2 )
|
||||
|
||||
Phys1:SetAngles( TargetAngle )
|
||||
|
||||
-- Move the object so that the hitpos on our object is at the second hitpos
|
||||
local TargetPos = WPos2 + ( Phys1:GetPos() - self:GetPos( 1 ) ) + ( Norm2 * 0.2 )
|
||||
|
||||
-- Set the position
|
||||
Phys1:SetPos( TargetPos )
|
||||
|
||||
-- Wake up the physics object so that the entity updates
|
||||
Phys1:Wake()
|
||||
|
||||
-- Set the hinge Axis perpendicular to the trace hit surface
|
||||
LPos1 = Phys1:WorldToLocal( WPos2 + Norm2 )
|
||||
|
||||
-- Create a constraint axis
|
||||
local constr = constraint.Axis( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, forcelimit, torquelimit, friction, nocollide )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Axis" )
|
||||
undo.AddEntity( constr )
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "constraints", constr )
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
self:ReleaseGhostEntity()
|
||||
|
||||
else
|
||||
|
||||
self:StartGhostEntity( trace.Entity )
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( self:GetOperation() == 1 ) then return false end
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
-- Don't allow us to choose the world as the first object
|
||||
if ( iNum == 0 && !IsValid( trace.Entity ) ) then return false end
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
self:SetOperation( 2 )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
-- Clientside can bail out now
|
||||
if ( CLIENT ) then
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local nocollide = self:GetClientNumber( "nocollide", 0 )
|
||||
local forcelimit = self:GetClientNumber( "forcelimit", 0 )
|
||||
local torquelimit = self:GetClientNumber( "torquelimit", 0 )
|
||||
local friction = self:GetClientNumber( "hingefriction", 0 )
|
||||
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local Norm1, Norm2 = self:GetNormal( 1 ), self:GetNormal( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
local Phys1 = self:GetPhys( 1 )
|
||||
local WPos2 = self:GetPos( 2 )
|
||||
|
||||
-- Note: To keep stuff ragdoll friendly try to treat things as physics objects rather than entities
|
||||
--local Ang1, Ang2 = Norm1:Angle(), ( -Norm2 ):Angle()
|
||||
--local TargetAngle = Phys1:AlignAngles( Ang1, Ang2 )
|
||||
|
||||
--Phys1:SetAngles( TargetAngle )
|
||||
|
||||
Phys1:Wake()
|
||||
|
||||
-- Set the hinge Axis perpendicular to the trace hit surface
|
||||
LPos1 = Phys1:WorldToLocal( WPos2 + Norm2 )
|
||||
|
||||
local constr = constraint.Axis( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, forcelimit, torquelimit, friction, nocollide )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Axis" )
|
||||
undo.AddEntity( constr )
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "constraints", constr )
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
self:ReleaseGhostEntity()
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Axis" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
if ( self:NumObjects() != 1 ) then return end
|
||||
|
||||
self:UpdateGhostEntity()
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.axis.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "axis", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.forcelimit", Command = "axis_forcelimit", Type = "Float", Min = 0, Max = 50000, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.torquelimit", Command = "axis_torquelimit", Type = "Float", Min = 0, Max = 50000, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.hingefriction", Command = "axis_hingefriction", Type = "Float", Min = 0, Max = 200, Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.nocollide", Command = "axis_nocollide", Help = true } )
|
||||
|
||||
end
|
||||
253
gamemodes/sandbox/entities/weapons/gmod_tool/stools/balloon.lua
Normal file
253
gamemodes/sandbox/entities/weapons/gmod_tool/stools/balloon.lua
Normal file
@@ -0,0 +1,253 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.balloon.name"
|
||||
|
||||
TOOL.ClientConVar[ "ropelength" ] = "64"
|
||||
TOOL.ClientConVar[ "force" ] = "500"
|
||||
TOOL.ClientConVar[ "r" ] = "255"
|
||||
TOOL.ClientConVar[ "g" ] = "255"
|
||||
TOOL.ClientConVar[ "b" ] = "0"
|
||||
TOOL.ClientConVar[ "model" ] = "normal_skin1"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" }
|
||||
}
|
||||
|
||||
cleanup.Register( "balloons" )
|
||||
|
||||
function TOOL:LeftClick( trace, attach )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
--
|
||||
-- Right click calls this with attach = false
|
||||
--
|
||||
if ( attach == nil ) then
|
||||
attach = true
|
||||
end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && attach && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then
|
||||
return false
|
||||
end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local material = "cable/rope"
|
||||
local r = self:GetClientNumber( "r", 255 )
|
||||
local g = self:GetClientNumber( "g", 0 )
|
||||
local b = self:GetClientNumber( "b", 0 )
|
||||
local model = self:GetClientInfo( "model" )
|
||||
local force = math.Clamp( self:GetClientNumber( "force", 500 ), -1E34, 1E34 )
|
||||
local length = self:GetClientNumber( "ropelength", 64 )
|
||||
|
||||
local modeltable = list.Get( "BalloonModels" )[ model ]
|
||||
|
||||
--
|
||||
-- Model is a table index on BalloonModels
|
||||
-- If the model isn't defined then it can't be spawned.
|
||||
--
|
||||
if ( !modeltable ) then return false end
|
||||
|
||||
--
|
||||
-- The model table can disable colouring for its model
|
||||
--
|
||||
if ( modeltable.nocolor ) then
|
||||
r = 255
|
||||
g = 255
|
||||
b = 255
|
||||
end
|
||||
|
||||
--
|
||||
-- Clicked on a balloon - modify the force/color/whatever
|
||||
--
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:GetClass() == "gmod_balloon" && trace.Entity.Player == ply ) then
|
||||
|
||||
if ( IsValid( trace.Entity:GetPhysicsObject() ) ) then trace.Entity:GetPhysicsObject():Wake() end
|
||||
trace.Entity:SetColor( Color( r, g, b, 255 ) )
|
||||
trace.Entity:SetForce( force )
|
||||
trace.Entity.force = force
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Hit the balloon limit, bail
|
||||
--
|
||||
if ( !self:GetWeapon():CheckLimit( "balloons" ) ) then return false end
|
||||
|
||||
local balloon = MakeBalloon( ply, r, g, b, force, { Pos = trace.HitPos, Model = modeltable.model, Skin = modeltable.skin } )
|
||||
if ( !IsValid( balloon ) ) then return false end
|
||||
|
||||
local CurPos = balloon:GetPos()
|
||||
local NearestPoint = balloon:NearestPoint( CurPos - ( trace.HitNormal * 512 ) )
|
||||
local Offset = CurPos - NearestPoint
|
||||
|
||||
local Pos = trace.HitPos + Offset
|
||||
|
||||
balloon:SetPos( Pos )
|
||||
|
||||
undo.Create( "Balloon" )
|
||||
undo.AddEntity( balloon )
|
||||
|
||||
if ( attach ) then
|
||||
|
||||
-- The real model should have an attachment!
|
||||
local LPos1 = balloon:WorldToLocal( Pos )
|
||||
local LPos2 = trace.Entity:WorldToLocal( trace.HitPos )
|
||||
|
||||
if ( IsValid( trace.Entity ) ) then
|
||||
|
||||
local phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
if ( IsValid( phys ) ) then LPos2 = phys:WorldToLocal( trace.HitPos ) end
|
||||
|
||||
end
|
||||
|
||||
local constr, rope = constraint.Rope( balloon, trace.Entity, 0, trace.PhysicsBone, LPos1, LPos2, 0, length, 0, 0.5, material )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.AddEntity( constr )
|
||||
ply:AddCleanup( "balloons", constr )
|
||||
end
|
||||
|
||||
if ( IsValid( rope ) ) then
|
||||
undo.AddEntity( rope )
|
||||
ply:AddCleanup( "balloons", rope )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
return self:LeftClick( trace, false )
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function MakeBalloon( ply, r, g, b, force, Data )
|
||||
|
||||
if ( IsValid( ply ) && !ply:CheckLimit( "balloons" ) ) then return end
|
||||
|
||||
local balloon = ents.Create( "gmod_balloon" )
|
||||
if ( !IsValid( balloon ) ) then return end
|
||||
|
||||
duplicator.DoGeneric( balloon, Data )
|
||||
|
||||
balloon:Spawn()
|
||||
|
||||
DoPropSpawnedEffect( balloon )
|
||||
|
||||
duplicator.DoGenericPhysics( balloon, ply, Data )
|
||||
|
||||
force = math.Clamp( force, -1E34, 1E34 )
|
||||
|
||||
balloon:SetColor( Color( r, g, b, 255 ) )
|
||||
balloon:SetForce( force )
|
||||
balloon:SetPlayer( ply )
|
||||
|
||||
balloon.Player = ply
|
||||
balloon.r = r
|
||||
balloon.g = g
|
||||
balloon.b = b
|
||||
balloon.force = force
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "balloons", balloon )
|
||||
ply:AddCleanup( "balloons", balloon )
|
||||
end
|
||||
|
||||
return balloon
|
||||
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass( "gmod_balloon", MakeBalloon, "r", "g", "b", "force", "Data" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostBalloon( ent, ply )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
if ( !trace.Hit || IsValid( trace.Entity ) && ( trace.Entity:IsPlayer() || trace.Entity:GetClass() == "gmod_balloon" ) ) then
|
||||
ent:SetNoDraw( true )
|
||||
return
|
||||
end
|
||||
|
||||
local CurPos = ent:GetPos()
|
||||
local NearestPoint = ent:NearestPoint( CurPos - ( trace.HitNormal * 512 ) )
|
||||
local Offset = CurPos - NearestPoint
|
||||
|
||||
local pos = trace.HitPos + Offset
|
||||
|
||||
local modeltable = list.Get( "BalloonModels" )[ self:GetClientInfo( "model" ) ]
|
||||
if ( modeltable.skin ) then ent:SetSkin( modeltable.skin ) end
|
||||
|
||||
ent:SetPos( pos )
|
||||
ent:SetAngles( angle_zero )
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) || self.GhostEntity.model != self:GetClientInfo( "model" ) ) then
|
||||
|
||||
local modeltable = list.Get( "BalloonModels" )[ self:GetClientInfo( "model" ) ]
|
||||
if ( !modeltable ) then self:ReleaseGhostEntity() return end
|
||||
|
||||
self:MakeGhostEntity( modeltable.model, vector_origin, angle_zero )
|
||||
if ( IsValid( self.GhostEntity ) ) then self.GhostEntity.model = self:GetClientInfo( "model" ) end
|
||||
|
||||
end
|
||||
|
||||
self:UpdateGhostBalloon( self.GhostEntity, self:GetOwner() )
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.balloon.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "balloon", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.balloon.ropelength", Type = "Float", Command = "balloon_ropelength", Min = 5, Max = 1000 } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.balloon.force", Type = "Float", Command = "balloon_force", Min = -1000, Max = 2000, Help = true } )
|
||||
CPanel:AddControl( "Color", { Label = "#tool.balloon.color", Red = "balloon_r", Green = "balloon_g", Blue = "balloon_b" } )
|
||||
|
||||
CPanel:AddControl( "PropSelect", { Label = "#tool.balloon.model", ConVar = "balloon_model", Height = 0, ModelsTable = list.Get( "BalloonModels" ) } )
|
||||
|
||||
end
|
||||
|
||||
list.Set( "BalloonModels", "normal", { model = "models/maxofs2d/balloon_classic.mdl", skin = 0 } )
|
||||
list.Set( "BalloonModels", "normal_skin1", { model = "models/maxofs2d/balloon_classic.mdl", skin = 1 } )
|
||||
list.Set( "BalloonModels", "normal_skin2", { model = "models/maxofs2d/balloon_classic.mdl", skin = 2 } )
|
||||
list.Set( "BalloonModels", "normal_skin3", { model = "models/maxofs2d/balloon_classic.mdl", skin = 3 } )
|
||||
|
||||
list.Set( "BalloonModels", "gman", { model = "models/maxofs2d/balloon_gman.mdl", nocolor = true } )
|
||||
list.Set( "BalloonModels", "mossman", { model = "models/maxofs2d/balloon_mossman.mdl", nocolor = true } )
|
||||
|
||||
list.Set( "BalloonModels", "dog", { model = "models/balloons/balloon_dog.mdl" } )
|
||||
list.Set( "BalloonModels", "heart", { model = "models/balloons/balloon_classicheart.mdl" } )
|
||||
list.Set( "BalloonModels", "star", { model = "models/balloons/balloon_star.mdl" } )
|
||||
@@ -0,0 +1,107 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.ballsocket.name"
|
||||
|
||||
TOOL.ClientConVar[ "forcelimit" ] = "0"
|
||||
--TOOL.ClientConVar[ "torquelimit" ] = "0"
|
||||
TOOL.ClientConVar[ "nocollide" ] = "0"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1 },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self:ClearObjects()
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local nocollide = self:GetClientNumber( "nocollide", 0 )
|
||||
local forcelimit = self:GetClientNumber( "forcelimit", 0 )
|
||||
|
||||
-- Force this to 0 for now, it does not do anything, and if we fix it in the future, this way existing contraptions won't break
|
||||
local torquelimit = 0 --self:GetClientNumber( "torquelimit", 0 )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos = self:GetLocalPos( 2 )
|
||||
|
||||
local constr = constraint.Ballsocket( Ent1, Ent2, Bone1, Bone2, LPos, forcelimit, torquelimit, nocollide )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "BallSocket" )
|
||||
undo.AddEntity( constr )
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "constraints", constr )
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Ballsocket" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.ballsocket.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "ballsocket", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.forcelimit", Command = "ballsocket_forcelimit", Type = "Float", Min = 0, Max = 50000, Help = true } )
|
||||
--CPanel:AddControl( "Slider", { Label = "#tool.torquelimit", Command = "ballsocket_torquelimit", Type = "Float", Min = 0, Max = 50000, Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.nocollide", Command = "ballsocket_nocollide", Help = true } )
|
||||
|
||||
end
|
||||
207
gamemodes/sandbox/entities/weapons/gmod_tool/stools/button.lua
Normal file
207
gamemodes/sandbox/entities/weapons/gmod_tool/stools/button.lua
Normal file
@@ -0,0 +1,207 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.button.name"
|
||||
|
||||
TOOL.ClientConVar[ "model" ] = "models/maxofs2d/button_05.mdl"
|
||||
TOOL.ClientConVar[ "keygroup" ] = "37"
|
||||
TOOL.ClientConVar[ "description" ] = ""
|
||||
TOOL.ClientConVar[ "toggle" ] = "1"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" }
|
||||
}
|
||||
|
||||
cleanup.Register( "buttons" )
|
||||
|
||||
local function IsValidButtonModel( model )
|
||||
for mdl, _ in pairs( list.Get( "ButtonModels" ) ) do
|
||||
if ( mdl:lower() == model:lower() ) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace, worldweld )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return false end
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local model = self:GetClientInfo( "model" )
|
||||
local key = self:GetClientNumber( "keygroup" )
|
||||
local description = self:GetClientInfo( "description" )
|
||||
local toggle = self:GetClientNumber( "toggle" ) == 1
|
||||
local ply = self:GetOwner()
|
||||
|
||||
-- If we shot a button change its settings
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:GetClass() == "gmod_button" && trace.Entity:GetPlayer() == ply ) then
|
||||
trace.Entity:SetKey( key )
|
||||
trace.Entity:SetLabel( description )
|
||||
trace.Entity:SetIsToggle( toggle )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- Check the model's validity
|
||||
if ( !util.IsValidModel( model ) || !util.IsValidProp( model ) || !IsValidButtonModel( model ) ) then return false end
|
||||
if ( !self:GetWeapon():CheckLimit( "buttons" ) ) then return false end
|
||||
|
||||
local Ang = trace.HitNormal:Angle()
|
||||
Ang.pitch = Ang.pitch + 90
|
||||
|
||||
local button = MakeButton( ply, model, Ang, trace.HitPos, key, description, toggle )
|
||||
if ( !IsValid( button ) ) then return false end
|
||||
|
||||
local min = button:OBBMins()
|
||||
button:SetPos( trace.HitPos - trace.HitNormal * min.z )
|
||||
|
||||
undo.Create( "Button" )
|
||||
undo.AddEntity( button )
|
||||
|
||||
if ( worldweld && trace.Entity != NULL ) then
|
||||
local weld = constraint.Weld( button, trace.Entity, 0, trace.PhysicsBone, 0, 0, true )
|
||||
if ( IsValid( weld ) ) then
|
||||
ply:AddCleanup( "buttons", weld )
|
||||
undo.AddEntity( weld )
|
||||
end
|
||||
|
||||
if ( IsValid( button:GetPhysicsObject() ) ) then button:GetPhysicsObject():EnableCollisions( false ) end
|
||||
button:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
button.nocollide = true
|
||||
end
|
||||
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
return self:RightClick( trace, true )
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function MakeButton( ply, model, ang, pos, key, description, toggle, nocollide, Data )
|
||||
|
||||
if ( IsValid( ply ) && !ply:CheckLimit( "buttons" ) ) then return false end
|
||||
if ( !IsValidButtonModel( model ) ) then return false end
|
||||
|
||||
local button = ents.Create( "gmod_button" )
|
||||
if ( !IsValid( button ) ) then return false end
|
||||
|
||||
duplicator.DoGeneric( button, Data )
|
||||
button:SetModel( model ) -- Backwards compatible for addons directly calling this function
|
||||
button:SetAngles( ang )
|
||||
button:SetPos( pos )
|
||||
button:Spawn()
|
||||
|
||||
DoPropSpawnedEffect( button )
|
||||
duplicator.DoGenericPhysics( button, ply, Data )
|
||||
|
||||
button:SetPlayer( ply )
|
||||
button:SetKey( key )
|
||||
button:SetLabel( description )
|
||||
button:SetIsToggle( toggle )
|
||||
|
||||
if ( nocollide == true ) then
|
||||
if ( IsValid( button:GetPhysicsObject() ) ) then button:GetPhysicsObject():EnableCollisions( false ) end
|
||||
button:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
end
|
||||
|
||||
table.Merge( button:GetTable(), {
|
||||
key = key,
|
||||
pl = ply,
|
||||
toggle = toggle,
|
||||
nocollide = nocollide,
|
||||
description = description
|
||||
} )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "buttons", button )
|
||||
ply:AddCleanup( "buttons", button )
|
||||
end
|
||||
|
||||
return button
|
||||
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass( "gmod_button", MakeButton, "Model", "Ang", "Pos", "key", "description", "toggle", "nocollide", "Data" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostButton( ent, ply )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
if ( !trace.Hit || IsValid( trace.Entity ) && ( trace.Entity:GetClass() == "gmod_button" || trace.Entity:IsPlayer() ) ) then
|
||||
ent:SetNoDraw( true )
|
||||
return
|
||||
end
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch + 90
|
||||
|
||||
local min = ent:OBBMins()
|
||||
ent:SetPos( trace.HitPos - trace.HitNormal * min.z )
|
||||
ent:SetAngles( ang )
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
local mdl = self:GetClientInfo( "model" )
|
||||
if ( !IsValidButtonModel( mdl ) ) then self:ReleaseGhostEntity() return end
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) || self.GhostEntity:GetModel() != mdl ) then
|
||||
self:MakeGhostEntity( mdl, vector_origin, angle_zero )
|
||||
end
|
||||
|
||||
self:UpdateGhostButton( self.GhostEntity, self:GetOwner() )
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.button.desc" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "button", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.button.key", Command = "button_keygroup" } )
|
||||
|
||||
CPanel:AddControl( "TextBox", { Label = "#tool.button.text", Command = "button_description", MaxLenth = "20" } )
|
||||
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.button.toggle", Command = "button_toggle", Help = true } )
|
||||
|
||||
CPanel:AddControl( "PropSelect", { Label = "#tool.button.model", ConVar = "button_model", Height = 0, Models = list.Get( "ButtonModels" ) } )
|
||||
|
||||
end
|
||||
|
||||
list.Set( "ButtonModels", "models/maxofs2d/button_01.mdl", {} )
|
||||
list.Set( "ButtonModels", "models/maxofs2d/button_02.mdl", {} )
|
||||
list.Set( "ButtonModels", "models/maxofs2d/button_03.mdl", {} )
|
||||
list.Set( "ButtonModels", "models/maxofs2d/button_04.mdl", {} )
|
||||
list.Set( "ButtonModels", "models/maxofs2d/button_05.mdl", {} )
|
||||
list.Set( "ButtonModels", "models/maxofs2d/button_06.mdl", {} )
|
||||
list.Set( "ButtonModels", "models/maxofs2d/button_slider.mdl", {} )
|
||||
|
||||
--list.Set( "ButtonModels", "models/dav0r/buttons/button.mdl", {} )
|
||||
--list.Set( "ButtonModels", "models/dav0r/buttons/switch.mdl", {} )
|
||||
160
gamemodes/sandbox/entities/weapons/gmod_tool/stools/camera.lua
Normal file
160
gamemodes/sandbox/entities/weapons/gmod_tool/stools/camera.lua
Normal file
@@ -0,0 +1,160 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Render"
|
||||
TOOL.Name = "#tool.camera.name"
|
||||
|
||||
TOOL.ClientConVar[ "locked" ] = "0"
|
||||
TOOL.ClientConVar[ "key" ] = "37"
|
||||
TOOL.ClientConVar[ "toggle" ] = "1"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" }
|
||||
}
|
||||
|
||||
cleanup.Register( "cameras" )
|
||||
|
||||
local function CheckLimit( ply, key )
|
||||
|
||||
-- TODO: Clientside prediction
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local found = false
|
||||
for id, camera in ipairs( ents.FindByClass( "gmod_cameraprop" ) ) do
|
||||
if ( !camera.controlkey || camera.controlkey != key ) then continue end
|
||||
if ( IsValid( camera:GetPlayer() ) && ply != camera:GetPlayer() ) then continue end
|
||||
found = true
|
||||
break
|
||||
end
|
||||
|
||||
if ( !found && !ply:CheckLimit( "cameras" ) ) then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
local function MakeCamera( ply, key, locked, toggle, Data )
|
||||
if ( IsValid( ply ) && !CheckLimit( ply, key ) ) then return false end
|
||||
|
||||
local ent = ents.Create( "gmod_cameraprop" )
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
duplicator.DoGeneric( ent, Data )
|
||||
|
||||
if ( key ) then
|
||||
for id, camera in ipairs( ents.FindByClass( "gmod_cameraprop" ) ) do
|
||||
if ( !camera.controlkey || camera.controlkey != key ) then continue end
|
||||
if ( IsValid( ply ) && IsValid( camera:GetPlayer() ) && ply != camera:GetPlayer() ) then continue end
|
||||
camera:Remove()
|
||||
end
|
||||
|
||||
ent:SetKey( key )
|
||||
ent.controlkey = key
|
||||
end
|
||||
|
||||
ent:SetPlayer( ply )
|
||||
|
||||
ent.toggle = toggle
|
||||
ent.locked = locked
|
||||
|
||||
ent:Spawn()
|
||||
|
||||
DoPropSpawnedEffect( ent )
|
||||
duplicator.DoGenericPhysics( ent, ply, Data )
|
||||
|
||||
ent:SetTracking( NULL, Vector( 0 ) )
|
||||
ent:SetLocked( locked )
|
||||
|
||||
if ( toggle == 1 ) then
|
||||
numpad.OnDown( ply, key, "Camera_Toggle", ent )
|
||||
else
|
||||
numpad.OnDown( ply, key, "Camera_On", ent )
|
||||
numpad.OnUp( ply, key, "Camera_Off", ent )
|
||||
end
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCleanup( "cameras", ent )
|
||||
ply:AddCount( "cameras", ent )
|
||||
end
|
||||
|
||||
return ent
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
duplicator.RegisterEntityClass( "gmod_cameraprop", MakeCamera, "controlkey", "locked", "toggle", "Data" )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local key = self:GetClientNumber( "key" )
|
||||
if ( key == -1 ) then return false end
|
||||
|
||||
if ( !CheckLimit( ply, key ) ) then return false end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local locked = self:GetClientNumber( "locked" )
|
||||
local toggle = self:GetClientNumber( "toggle" )
|
||||
|
||||
local ent = MakeCamera( ply, key, locked, toggle, { Pos = trace.StartPos, Angle = ply:EyeAngles() } )
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
undo.Create( "Camera" )
|
||||
undo.AddEntity( ent )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true, ent
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
local _, camera = self:LeftClick( trace, true )
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
if ( !IsValid( camera ) ) then return false end
|
||||
|
||||
if ( trace.Entity:IsWorld() ) then
|
||||
|
||||
trace.Entity = self:GetOwner()
|
||||
trace.HitPos = trace.Entity:GetPos()
|
||||
|
||||
end
|
||||
|
||||
-- We apply the view offset for players in camera entity
|
||||
if ( trace.Entity:IsPlayer() ) then
|
||||
trace.HitPos = trace.Entity:GetPos()
|
||||
end
|
||||
|
||||
camera:SetTracking( trace.Entity, trace.Entity:WorldToLocal( trace.HitPos ) )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "camera", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.camera.key", Command = "camera_key" } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.camera.static", Command = "camera_locked", Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.toggle", Command = "camera_toggle" } )
|
||||
|
||||
end
|
||||
143
gamemodes/sandbox/entities/weapons/gmod_tool/stools/colour.lua
Normal file
143
gamemodes/sandbox/entities/weapons/gmod_tool/stools/colour.lua
Normal file
@@ -0,0 +1,143 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Render"
|
||||
TOOL.Name = "#tool.colour.name"
|
||||
|
||||
TOOL.ClientConVar[ "r" ] = 255
|
||||
TOOL.ClientConVar[ "g" ] = 255
|
||||
TOOL.ClientConVar[ "b" ] = 255
|
||||
TOOL.ClientConVar[ "a" ] = 255
|
||||
TOOL.ClientConVar[ "mode" ] = "0"
|
||||
TOOL.ClientConVar[ "fx" ] = "0"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
local function SetColour( ply, ent, data )
|
||||
|
||||
--
|
||||
-- If we're trying to make them transparent them make the render mode
|
||||
-- a transparent type. This used to fix in the engine - but made HL:S props invisible(!)
|
||||
--
|
||||
if ( data.Color && data.Color.a < 255 && data.RenderMode == RENDERMODE_NORMAL ) then
|
||||
data.RenderMode = RENDERMODE_TRANSCOLOR
|
||||
end
|
||||
|
||||
if ( data.Color ) then ent:SetColor( Color( data.Color.r, data.Color.g, data.Color.b, data.Color.a ) ) end
|
||||
if ( data.RenderMode ) then ent:SetRenderMode( data.RenderMode ) end
|
||||
if ( data.RenderFX ) then ent:SetKeyValue( "renderfx", data.RenderFX ) end
|
||||
|
||||
if ( SERVER ) then
|
||||
duplicator.StoreEntityModifier( ent, "colour", data )
|
||||
end
|
||||
|
||||
end
|
||||
if ( SERVER ) then
|
||||
duplicator.RegisterEntityModifier( "colour", SetColour )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
|
||||
if ( !IsValid( ent ) ) then return false end -- The entity is valid and isn't worldspawn
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local r = self:GetClientNumber( "r", 0 )
|
||||
local g = self:GetClientNumber( "g", 0 )
|
||||
local b = self:GetClientNumber( "b", 0 )
|
||||
local a = self:GetClientNumber( "a", 0 )
|
||||
local fx = self:GetClientNumber( "fx", 0 )
|
||||
local mode = self:GetClientNumber( "mode", 0 )
|
||||
|
||||
SetColour( self:GetOwner(), ent, { Color = Color( r, g, b, a ), RenderMode = mode, RenderFX = fx } )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
|
||||
if ( !IsValid( ent ) ) then return false end -- The entity is valid and isn't worldspawn
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local clr = ent:GetColor()
|
||||
self:GetOwner():ConCommand( "colour_r " .. clr.r )
|
||||
self:GetOwner():ConCommand( "colour_g " .. clr.g )
|
||||
self:GetOwner():ConCommand( "colour_b " .. clr.b )
|
||||
self:GetOwner():ConCommand( "colour_a " .. clr.a )
|
||||
self:GetOwner():ConCommand( "colour_fx " .. ent:GetRenderFX() )
|
||||
self:GetOwner():ConCommand( "colour_mode " .. ent:GetRenderMode() )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end -- The entity is valid and isn't worldspawn
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
SetColour( self:GetOwner(), ent, { Color = Color( 255, 255, 255, 255 ), RenderMode = 0, RenderFX = 0 } )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.colour.desc" } )
|
||||
|
||||
CPanel:ToolPresets( "colour", ConVarsDefault )
|
||||
|
||||
CPanel:ColorPicker( "#tool.colour.color", "colour_r", "colour_g", "colour_b", "colour_a" )
|
||||
|
||||
CPanel:AddControl( "ListBox", { Label = "#tool.colour.mode", Options = list.Get( "RenderModes" ) } )
|
||||
CPanel:AddControl( "ListBox", { Label = "#tool.colour.fx", Options = list.Get( "RenderFX" ) } )
|
||||
|
||||
end
|
||||
|
||||
list.Set( "RenderModes", "#rendermode.normal", { colour_mode = 0 } )
|
||||
list.Set( "RenderModes", "#rendermode.transcolor", { colour_mode = 1 } )
|
||||
list.Set( "RenderModes", "#rendermode.transtexture", { colour_mode = 2 } )
|
||||
list.Set( "RenderModes", "#rendermode.glow", { colour_mode = 3 } )
|
||||
list.Set( "RenderModes", "#rendermode.transalpha", { colour_mode = 4 } )
|
||||
list.Set( "RenderModes", "#rendermode.transadd", { colour_mode = 5 } )
|
||||
list.Set( "RenderModes", "#rendermode.transalphaadd", { colour_mode = 8 } )
|
||||
list.Set( "RenderModes", "#rendermode.worldglow", { colour_mode = 9 } )
|
||||
|
||||
list.Set( "RenderFX", "#renderfx.none", { colour_fx = 0 } )
|
||||
list.Set( "RenderFX", "#renderfx.pulseslow", { colour_fx = 1 } )
|
||||
list.Set( "RenderFX", "#renderfx.pulsefast", { colour_fx = 2 } )
|
||||
list.Set( "RenderFX", "#renderfx.pulseslowwide", { colour_fx = 3 } )
|
||||
list.Set( "RenderFX", "#renderfx.pulsefastwide", { colour_fx = 4 } )
|
||||
list.Set( "RenderFX", "#renderfx.fadeslow", { colour_fx = 5 } )
|
||||
list.Set( "RenderFX", "#renderfx.fadefast", { colour_fx = 6 } )
|
||||
list.Set( "RenderFX", "#renderfx.solidslow", { colour_fx = 7 } )
|
||||
list.Set( "RenderFX", "#renderfx.solidfast", { colour_fx = 8 } )
|
||||
list.Set( "RenderFX", "#renderfx.strobeslow", { colour_fx = 9 } )
|
||||
list.Set( "RenderFX", "#renderfx.strobefast", { colour_fx = 10 } )
|
||||
list.Set( "RenderFX", "#renderfx.strobefaster", { colour_fx = 11 } )
|
||||
list.Set( "RenderFX", "#renderfx.flickerslow", { colour_fx = 12 } )
|
||||
list.Set( "RenderFX", "#renderfx.flickerfast", { colour_fx = 13 } )
|
||||
list.Set( "RenderFX", "#renderfx.distort", { colour_fx = 15 } )
|
||||
list.Set( "RenderFX", "#renderfx.hologram", { colour_fx = 16 } )
|
||||
list.Set( "RenderFX", "#renderfx.pulsefastwider", { colour_fx = 24 } )
|
||||
@@ -0,0 +1,51 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.AddToMenu = false
|
||||
TOOL.ClientConVar[ "type" ] = "0"
|
||||
TOOL.ClientConVar[ "name" ] = "0"
|
||||
TOOL.ClientConVar[ "arg" ] = "0"
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
function TOOL:LeftClick( trace, attach )
|
||||
|
||||
local type = self:GetClientNumber( "type", 0 )
|
||||
local name = self:GetClientInfo( "name" )
|
||||
local arg = self:GetClientInfo( "arg" )
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
if ( type == 0 ) then
|
||||
|
||||
Spawn_SENT( self:GetOwner(), name, trace )
|
||||
|
||||
elseif ( type == 1 ) then
|
||||
|
||||
Spawn_Vehicle( self:GetOwner(), name, trace )
|
||||
|
||||
elseif ( type == 2 ) then
|
||||
|
||||
Spawn_NPC( self:GetOwner(), name, arg, trace )
|
||||
|
||||
elseif ( type == 3 ) then
|
||||
|
||||
Spawn_Weapon( self:GetOwner(), name, trace )
|
||||
|
||||
elseif ( type == 4 ) then
|
||||
|
||||
CCSpawn( self:GetOwner(), nil, { name } ) -- Props
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
@@ -0,0 +1,252 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "duplicator/transport.lua" )
|
||||
include( "duplicator/arming.lua" )
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
include( "duplicator/icon.lua" )
|
||||
|
||||
else
|
||||
|
||||
AddCSLuaFile( "duplicator/arming.lua" )
|
||||
AddCSLuaFile( "duplicator/transport.lua" )
|
||||
AddCSLuaFile( "duplicator/icon.lua" )
|
||||
util.AddNetworkString( "CopiedDupe" )
|
||||
|
||||
end
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.duplicator.name"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" }
|
||||
}
|
||||
|
||||
cleanup.Register( "duplicates" )
|
||||
|
||||
--
|
||||
-- PASTE
|
||||
--
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
--
|
||||
-- Get the copied dupe. We store it on the player so it will still exist if they die and respawn.
|
||||
--
|
||||
local dupe = self:GetOwner().CurrentDupe
|
||||
if ( !dupe ) then return false end
|
||||
|
||||
--
|
||||
-- We want to spawn it flush on thr ground. So get the point that we hit
|
||||
-- and take away the mins.z of the bounding box of the dupe.
|
||||
--
|
||||
local SpawnCenter = trace.HitPos
|
||||
SpawnCenter.z = SpawnCenter.z - dupe.Mins.z
|
||||
|
||||
--
|
||||
-- Spawn it rotated with the player - but not pitch.
|
||||
--
|
||||
local SpawnAngle = self:GetOwner():EyeAngles()
|
||||
SpawnAngle.pitch = 0
|
||||
SpawnAngle.roll = 0
|
||||
|
||||
--
|
||||
-- Spawn them all at our chosen positions
|
||||
--
|
||||
duplicator.SetLocalPos( SpawnCenter )
|
||||
duplicator.SetLocalAng( SpawnAngle )
|
||||
|
||||
DisablePropCreateEffect = true
|
||||
|
||||
local Ents = duplicator.Paste( self:GetOwner(), dupe.Entities, dupe.Constraints )
|
||||
|
||||
DisablePropCreateEffect = nil
|
||||
|
||||
duplicator.SetLocalPos( vector_origin )
|
||||
duplicator.SetLocalAng( angle_zero )
|
||||
|
||||
--
|
||||
-- Create one undo for the whole creation
|
||||
--
|
||||
undo.Create( "Duplicator" )
|
||||
|
||||
for k, ent in pairs( Ents ) do
|
||||
undo.AddEntity( ent )
|
||||
end
|
||||
|
||||
for k, ent in pairs( Ents ) do
|
||||
self:GetOwner():AddCleanup( "duplicates", ent )
|
||||
end
|
||||
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Copy
|
||||
--
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
--
|
||||
-- Set the position to our local position (so we can paste relative to our `hold`)
|
||||
--
|
||||
duplicator.SetLocalPos( trace.HitPos )
|
||||
duplicator.SetLocalAng( Angle( 0, self:GetOwner():EyeAngles().yaw, 0 ) )
|
||||
|
||||
local Dupe = duplicator.Copy( trace.Entity )
|
||||
|
||||
duplicator.SetLocalPos( vector_origin )
|
||||
duplicator.SetLocalAng( angle_zero )
|
||||
|
||||
if ( !Dupe ) then return false end
|
||||
|
||||
--
|
||||
-- Tell the clientside that they're holding something new
|
||||
--
|
||||
net.Start( "CopiedDupe" )
|
||||
net.WriteUInt( 1, 1 )
|
||||
net.WriteVector( Dupe.Mins )
|
||||
net.WriteVector( Dupe.Maxs )
|
||||
net.WriteString( "Unsaved dupe" )
|
||||
net.WriteUInt( table.Count( Dupe.Entities ), 24 )
|
||||
net.WriteUInt( 0, 16 )
|
||||
net.Send( self:GetOwner() )
|
||||
|
||||
--
|
||||
-- Store the dupe on the player
|
||||
--
|
||||
self:GetOwner().CurrentDupeArmed = false
|
||||
self:GetOwner().CurrentDupe = Dupe
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
--
|
||||
-- Builds the context menu
|
||||
--
|
||||
function TOOL.BuildCPanel( CPanel, tool )
|
||||
|
||||
CPanel:ClearControls()
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.duplicator.desc" } )
|
||||
|
||||
CPanel:AddControl( "Button", { Text = "#tool.duplicator.showsaves", Command = "dupe_show" } )
|
||||
|
||||
if ( !tool && IsValid( LocalPlayer() ) ) then tool = LocalPlayer():GetTool( "duplicator" ) end
|
||||
if ( !tool || !tool.CurrentDupeName ) then return end
|
||||
|
||||
local info = "Name: " .. tool.CurrentDupeName
|
||||
info = info .. "\nEntities: " .. tool.CurrentDupeEntCount
|
||||
|
||||
CPanel:AddControl( "Label", { Text = info } )
|
||||
|
||||
if ( tool.CurrentDupeWSIDs && #tool.CurrentDupeWSIDs > 0 ) then
|
||||
CPanel:AddControl( "Label", { Text = "Required workshop content:" } )
|
||||
for _, wsid in pairs( tool.CurrentDupeWSIDs ) do
|
||||
local subbed = ""
|
||||
if ( steamworks.IsSubscribed( wsid ) ) then subbed = " (Subscribed)" end
|
||||
local b = CPanel:AddControl( "Button", { Text = wsid .. subbed } )
|
||||
b.DoClick = function( s, ... ) steamworks.ViewFile( wsid ) end
|
||||
steamworks.FileInfo( wsid, function( result )
|
||||
if ( !IsValid( b ) ) then return end
|
||||
b:SetText( result.title .. subbed )
|
||||
end )
|
||||
end
|
||||
end
|
||||
|
||||
if ( tool.CurrentDupeCanSave ) then
|
||||
local b = CPanel:AddControl( "Button", { Text = "#dupes.savedupe", Command = "dupe_save" } )
|
||||
hook.Add( "DupeSaveUnavailable", b, function() b:Remove() end )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RefreshCPanel()
|
||||
local CPanel = controlpanel.Get( "duplicator" )
|
||||
if ( !CPanel ) then return end
|
||||
|
||||
self.BuildCPanel( CPanel, self )
|
||||
end
|
||||
|
||||
--
|
||||
-- Received by the client to alert us that we have something copied
|
||||
-- This allows us to enable the save button in the spawn menu
|
||||
--
|
||||
net.Receive( "CopiedDupe", function( len, client )
|
||||
|
||||
local canSave = net.ReadUInt( 1 )
|
||||
if ( canSave == 1 ) then
|
||||
hook.Run( "DupeSaveAvailable" )
|
||||
else
|
||||
hook.Run( "DupeSaveUnavailable" )
|
||||
end
|
||||
|
||||
local ply = LocalPlayer()
|
||||
if ( !IsValid( ply ) || !ply.GetTool ) then return end
|
||||
|
||||
local tool = ply:GetTool( "duplicator" )
|
||||
if ( !tool ) then return end
|
||||
|
||||
tool.CurrentDupeCanSave = canSave == 1
|
||||
tool.CurrentDupeMins = net.ReadVector()
|
||||
tool.CurrentDupeMaxs = net.ReadVector()
|
||||
|
||||
tool.CurrentDupeName = net.ReadString()
|
||||
tool.CurrentDupeEntCount = net.ReadUInt( 24 )
|
||||
|
||||
local workshopCount = net.ReadUInt( 16 )
|
||||
local addons = {}
|
||||
for i = 1, workshopCount do
|
||||
table.insert( addons, net.ReadString() )
|
||||
end
|
||||
tool.CurrentDupeWSIDs = addons
|
||||
|
||||
tool:RefreshCPanel()
|
||||
|
||||
end )
|
||||
|
||||
-- This is not perfect, but let the player see roughly the outline of what they are about to paste
|
||||
function TOOL:DrawHUD()
|
||||
|
||||
local ply = LocalPlayer()
|
||||
if ( !IsValid( ply ) || !self.CurrentDupeMins || !self.CurrentDupeMaxs ) then return end
|
||||
|
||||
local tr = LocalPlayer():GetEyeTrace()
|
||||
|
||||
local pos = tr.HitPos
|
||||
pos.z = pos.z - self.CurrentDupeMins.z
|
||||
|
||||
local ang = LocalPlayer():GetAngles()
|
||||
ang.p = 0
|
||||
ang.r = 0
|
||||
|
||||
cam.Start3D()
|
||||
render.DrawWireframeBox( pos, ang, self.CurrentDupeMins, self.CurrentDupeMaxs )
|
||||
cam.End3D()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,141 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local DUPE_SEND_SIZE = 60000
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
--
|
||||
-- Called by the client to save a dupe they're holding on the server
|
||||
-- into a file on their computer.
|
||||
--
|
||||
local LastDupeArm = 0
|
||||
concommand.Add( "dupe_arm", function( ply, cmd, arg )
|
||||
|
||||
if ( !arg[ 1 ] ) then return end
|
||||
|
||||
if ( LastDupeArm > CurTime() and !game.SinglePlayer() ) then ply:ChatPrint( "Please wait a second before trying to load another duplication!" ) return end
|
||||
LastDupeArm = CurTime() + 1
|
||||
|
||||
-- Server doesn't allow us to do this, don't even try to send them data
|
||||
local res, msg = hook.Run( "CanArmDupe", ply )
|
||||
if ( res == false ) then ply:ChatPrint( msg or "Refusing to load dupe, server has blocked usage of the Duplicator tool!" ) return end
|
||||
|
||||
-- Load the dupe (engine takes care of making sure it's a dupe)
|
||||
local dupe = engine.OpenDupe( arg[ 1 ] )
|
||||
if ( !dupe ) then ply:ChatPrint( "Error loading dupe.. (" .. tostring( arg[ 1 ] ) .. ")" ) return end
|
||||
|
||||
local uncompressed = util.Decompress( dupe.data, 5242880 )
|
||||
if ( !uncompressed ) then ply:ChatPrint( "That dupe seems to be corrupted!" ) return end
|
||||
|
||||
--
|
||||
-- And send it to the server
|
||||
--
|
||||
local length = dupe.data:len()
|
||||
local parts = math.ceil( length / DUPE_SEND_SIZE )
|
||||
|
||||
local start = 0
|
||||
for i = 1, parts do
|
||||
local endbyte = math.min( start + DUPE_SEND_SIZE, length )
|
||||
local size = endbyte - start
|
||||
|
||||
net.Start( "ArmDupe" )
|
||||
net.WriteUInt( i, 8 )
|
||||
net.WriteUInt( parts, 8 )
|
||||
|
||||
net.WriteUInt( size, 32 )
|
||||
net.WriteData( dupe.data:sub( start + 1, endbyte + 1 ), size )
|
||||
net.SendToServer()
|
||||
|
||||
start = endbyte
|
||||
end
|
||||
|
||||
end, nil, "Arm a dupe", { FCVAR_DONTRECORD } )
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
--
|
||||
-- Add the name of the net message to the string table (or it won't be able to send!)
|
||||
--
|
||||
util.AddNetworkString( "ArmDupe" )
|
||||
|
||||
net.Receive( "ArmDupe", function( size, client )
|
||||
|
||||
if ( !IsValid( client ) or size < 48 ) then return end
|
||||
|
||||
local res, msg = hook.Run( "CanArmDupe", client )
|
||||
if ( res == false ) then client:ChatPrint( msg or "Server has blocked usage of the Duplicator tool!" ) return end
|
||||
|
||||
local part = net.ReadUInt( 8 )
|
||||
local total = net.ReadUInt( 8 )
|
||||
|
||||
local length = net.ReadUInt( 32 )
|
||||
if ( length > DUPE_SEND_SIZE ) then return end
|
||||
|
||||
local datachunk = net.ReadData( length )
|
||||
|
||||
client.CurrentDupeBuffer = client.CurrentDupeBuffer or {}
|
||||
client.CurrentDupeBuffer[ part ] = datachunk
|
||||
|
||||
if ( part != total ) then return end
|
||||
|
||||
local data = table.concat( client.CurrentDupeBuffer )
|
||||
client.CurrentDupeBuffer = nil
|
||||
|
||||
if ( ( client.LastDupeArm or 0 ) > CurTime() and !game.SinglePlayer() ) then ServerLog( tostring( client ) .. " tried to arm a dupe too quickly!\n" ) return end
|
||||
client.LastDupeArm = CurTime() + 1
|
||||
|
||||
ServerLog( tostring( client ) .. " is arming a dupe, size: " .. data:len() .. "\n" )
|
||||
|
||||
local uncompressed = util.Decompress( data, 5242880 )
|
||||
if ( !uncompressed ) then
|
||||
client:ChatPrint( "Server failed to decompress the duplication!" )
|
||||
MsgN( "Couldn't decompress dupe from " .. client:Nick() .. "!" )
|
||||
return
|
||||
end
|
||||
|
||||
local Dupe = util.JSONToTable( uncompressed )
|
||||
if ( !istable( Dupe ) ) then return end
|
||||
if ( !istable( Dupe.Constraints ) ) then return end
|
||||
if ( !istable( Dupe.Entities ) ) then return end
|
||||
if ( !isvector( Dupe.Mins ) ) then return end
|
||||
if ( !isvector( Dupe.Maxs ) ) then return end
|
||||
|
||||
client.CurrentDupeArmed = true
|
||||
client.CurrentDupe = Dupe
|
||||
|
||||
client:ConCommand( "gmod_tool duplicator" )
|
||||
|
||||
--
|
||||
-- Tell the client we got a dupe on server, ready to paste
|
||||
--
|
||||
local workshopCount = 0
|
||||
if ( Dupe.RequiredAddons ) then workshopCount = #Dupe.RequiredAddons end
|
||||
|
||||
net.Start( "CopiedDupe" )
|
||||
net.WriteUInt( 0, 1 ) -- Can save
|
||||
net.WriteVector( Dupe.Mins )
|
||||
net.WriteVector( Dupe.Maxs )
|
||||
net.WriteString( "Loaded dupe" )
|
||||
net.WriteUInt( table.Count( Dupe.Entities ), 24 )
|
||||
net.WriteUInt( workshopCount, 16 )
|
||||
if ( Dupe.RequiredAddons ) then
|
||||
for _, wsid in ipairs( Dupe.RequiredAddons ) do
|
||||
net.WriteString( wsid )
|
||||
end
|
||||
end
|
||||
net.Send( client )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
@@ -0,0 +1,280 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
hook.Add( "PostRender", "RenderDupeIcon", function()
|
||||
|
||||
--
|
||||
-- g_ClientSaveDupe is set in transport.lua when receiving a dupe from the server
|
||||
--
|
||||
if ( !g_ClientSaveDupe ) then return end
|
||||
|
||||
--
|
||||
-- Remove the global straight away
|
||||
--
|
||||
local Dupe = g_ClientSaveDupe
|
||||
g_ClientSaveDupe = nil
|
||||
|
||||
local FOV = 17
|
||||
|
||||
--
|
||||
-- This is gonna take some cunning to look awesome!
|
||||
--
|
||||
local Size = Dupe.Maxs - Dupe.Mins
|
||||
local Radius = Size:Length() * 0.5
|
||||
local CamDist = Radius / math.sin( math.rad( FOV ) / 2 ) -- Works out how far the camera has to be away based on radius + fov!
|
||||
local Center = LerpVector( 0.5, Dupe.Mins, Dupe.Maxs )
|
||||
local CamPos = Center + Vector( -1, 0, 0.5 ):GetNormalized() * CamDist
|
||||
local EyeAng = ( Center - CamPos ):GetNormal():Angle()
|
||||
|
||||
--
|
||||
-- The base view
|
||||
--
|
||||
local view = {
|
||||
type = "3D",
|
||||
origin = CamPos,
|
||||
angles = EyeAng,
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 512,
|
||||
h = 512,
|
||||
aspect = 1,
|
||||
fov = FOV
|
||||
}
|
||||
|
||||
--
|
||||
-- Create a bunch of entities we're gonna use to render.
|
||||
--
|
||||
local entities = {}
|
||||
local i = 0
|
||||
for k, ent in pairs( Dupe.Entities ) do
|
||||
|
||||
if ( ent.Class == "prop_ragdoll" ) then
|
||||
|
||||
entities[ k ] = ClientsideRagdoll( ent.Model or "error.mdl", RENDERGROUP_OTHER )
|
||||
|
||||
if ( istable( ent.PhysicsObjects ) ) then
|
||||
|
||||
for boneid, v in pairs( ent.PhysicsObjects ) do
|
||||
|
||||
local obj = entities[ k ]:GetPhysicsObjectNum( boneid )
|
||||
if ( IsValid( obj ) ) then
|
||||
obj:SetPos( v.Pos )
|
||||
obj:SetAngles( v.Angle )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
entities[ k ]:InvalidateBoneCache()
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
entities[ k ] = ClientsideModel( ent.Model or "error.mdl", RENDERGROUP_OTHER )
|
||||
|
||||
end
|
||||
i = i + 1
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- DRAW THE BLUE BACKGROUND
|
||||
--
|
||||
render.SetMaterial( Material( "gui/dupe_bg.png" ) )
|
||||
render.DrawScreenQuadEx( 0, 0, 512, 512 )
|
||||
render.UpdateRefractTexture()
|
||||
|
||||
--
|
||||
-- BLACK OUTLINE
|
||||
-- AWESOME BRUTE FORCE METHOD
|
||||
--
|
||||
render.SuppressEngineLighting( true )
|
||||
|
||||
-- Rendering icon the way we do is kinda bad and will crash the game with too many entities in the dupe
|
||||
-- Try to mitigate that to some degree by not rendering the outline when we are above 800 entities
|
||||
-- 1000 was tested without problems, but we want to give it some space as 1000 was tested in "perfect conditions" with nothing else happening on the map
|
||||
if ( i < 800 ) then
|
||||
local BorderSize = CamDist * 0.004
|
||||
local Up = EyeAng:Up() * BorderSize
|
||||
local Right = EyeAng:Right() * BorderSize
|
||||
|
||||
render.SetColorModulation( 1, 1, 1 )
|
||||
render.SetBlend( 1 )
|
||||
render.MaterialOverride( Material( "models/debug/debugwhite" ) )
|
||||
|
||||
-- Render each entity in a circle
|
||||
for k, v in pairs( Dupe.Entities ) do
|
||||
|
||||
-- Set the skin and bodygroups
|
||||
entities[ k ]:SetSkin( v.Skin or 0 )
|
||||
for bg_k, bg_v in pairs( v.BodyG or {} ) do entities[ k ]:SetBodygroup( bg_k, bg_v ) end
|
||||
|
||||
for j = 0, math.pi * 2, 0.2 do
|
||||
|
||||
view.origin = CamPos + Up * math.sin( j ) + Right * math.cos( j )
|
||||
cam.Start( view )
|
||||
|
||||
render.Model( {
|
||||
model = v.Model,
|
||||
pos = v.Pos,
|
||||
angle = v.Angle
|
||||
}, entities[ k ] )
|
||||
|
||||
cam.End()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Because we just messed up the depth
|
||||
render.ClearDepth()
|
||||
render.SetColorModulation( 0, 0, 0 )
|
||||
render.SetBlend( 1 )
|
||||
|
||||
-- Try to keep the border size consistent with zoom size
|
||||
BorderSize = CamDist * 0.002
|
||||
Up = EyeAng:Up() * BorderSize
|
||||
Right = EyeAng:Right() * BorderSize
|
||||
|
||||
-- Render each entity in a circle
|
||||
for k, v in pairs( Dupe.Entities ) do
|
||||
|
||||
for j = 0, math.pi * 2, 0.2 do
|
||||
|
||||
view.origin = CamPos + Up * math.sin( j ) + Right * math.cos( j )
|
||||
cam.Start( view )
|
||||
|
||||
render.Model( {
|
||||
model = v.Model,
|
||||
pos = v.Pos,
|
||||
angle = v.Angle
|
||||
}, entities[ k ] )
|
||||
|
||||
cam.End()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- ACUAL RENDER!
|
||||
--
|
||||
|
||||
-- We just fucked the depth up - so clean it
|
||||
render.ClearDepth()
|
||||
|
||||
-- Set up the lighting. This is over-bright on purpose - to make the ents pop
|
||||
render.SetModelLighting( 0, 0, 0, 0 )
|
||||
render.SetModelLighting( 1, 2, 2, 2 )
|
||||
render.SetModelLighting( 2, 3, 2, 0 )
|
||||
render.SetModelLighting( 3, 0.5, 2.0, 2.5 )
|
||||
render.SetModelLighting( 4, 3, 3, 3 ) -- top
|
||||
render.SetModelLighting( 5, 0, 0, 0 )
|
||||
render.MaterialOverride( nil )
|
||||
|
||||
view.origin = CamPos
|
||||
cam.Start( view )
|
||||
|
||||
-- Render each model
|
||||
for k, v in pairs( Dupe.Entities ) do
|
||||
|
||||
render.SetColorModulation( 1, 1, 1 )
|
||||
render.SetBlend( 1 )
|
||||
|
||||
-- EntityMods override this
|
||||
if ( v._DuplicatedColor ) then
|
||||
render.SetColorModulation( v._DuplicatedColor.r / 255, v._DuplicatedColor.g / 255, v._DuplicatedColor.b / 255 )
|
||||
--render.SetBlend( v._DuplicatedColor.a / 255 )
|
||||
end
|
||||
if ( v._DuplicatedMaterial ) then render.MaterialOverride( Material( v._DuplicatedMaterial ) ) end
|
||||
|
||||
if ( istable( v.EntityMods ) ) then
|
||||
|
||||
if ( istable( v.EntityMods.colour ) ) then
|
||||
render.SetColorModulation( v.EntityMods.colour.Color.r / 255, v.EntityMods.colour.Color.g / 255, v.EntityMods.colour.Color.b / 255 )
|
||||
--render.SetBlend( v.EntityMods.colour.Color.a / 255 )
|
||||
end
|
||||
|
||||
if ( istable( v.EntityMods.material ) ) then
|
||||
render.MaterialOverride( Material( v.EntityMods.material.MaterialOverride ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
render.Model( {
|
||||
model = v.Model,
|
||||
pos = v.Pos,
|
||||
angle = v.Angle
|
||||
}, entities[ k ] )
|
||||
|
||||
render.MaterialOverride( nil )
|
||||
|
||||
end
|
||||
|
||||
cam.End()
|
||||
|
||||
-- Enable lighting again (or it will affect outside of this loop!)
|
||||
render.SuppressEngineLighting( false )
|
||||
render.SetColorModulation( 1, 1, 1 )
|
||||
render.SetBlend( 1 )
|
||||
|
||||
--
|
||||
-- Finished with the entities - remove them all
|
||||
--
|
||||
for k, v in pairs( entities ) do
|
||||
v:Remove()
|
||||
end
|
||||
|
||||
--
|
||||
-- This captures a square of the render target, copies it to a jpeg file
|
||||
-- and returns it to us as a (binary) string.
|
||||
--
|
||||
local jpegdata = render.Capture( {
|
||||
format = "jpeg",
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 512,
|
||||
h = 512,
|
||||
quality = 95
|
||||
} )
|
||||
|
||||
--
|
||||
-- Try to figure out if any of the models/materials/etc came from some addon
|
||||
--
|
||||
duplicator.FigureOutRequiredAddons( Dupe )
|
||||
|
||||
--
|
||||
-- Encode and compress the dupe
|
||||
--
|
||||
local DupeJSON = util.TableToJSON( Dupe )
|
||||
if ( !isstring( DupeJSON ) ) then
|
||||
MsgN( "There was an error converting the dupe to a json string" )
|
||||
end
|
||||
|
||||
DupeJSON = util.Compress( DupeJSON )
|
||||
|
||||
--
|
||||
-- And save it! (filename is automatic md5 in dupes/)
|
||||
--
|
||||
if ( engine.WriteDupe( DupeJSON, jpegdata ) ) then
|
||||
|
||||
-- Disable the save button!!
|
||||
hook.Run( "DupeSaveUnavailable" )
|
||||
hook.Run( "DupeSaved" )
|
||||
|
||||
MsgN( "Saved!" )
|
||||
|
||||
spawnmenu.SwitchCreationTab( "#spawnmenu.category.dupes" )
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,109 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
--
|
||||
-- Add the name of the net message to the string table (or it won't be able to send!)
|
||||
--
|
||||
util.AddNetworkString( "ReceiveDupe" )
|
||||
|
||||
--
|
||||
-- Called by the client to save a dupe they're holding on the server
|
||||
-- into a file on their computer.
|
||||
--
|
||||
concommand.Add( "dupe_save", function( ply, cmd, arg )
|
||||
|
||||
if ( !IsValid( ply ) ) then return end
|
||||
|
||||
-- No dupe to save
|
||||
if ( !ply.CurrentDupe ) then return end
|
||||
|
||||
-- Current dupe was armed from a file. Don't allow immediate resave.
|
||||
if ( ply.CurrentDupeArmed ) then return end
|
||||
|
||||
if ( ply.m_NextDupeSave && ply.m_NextDupeSave > CurTime() && !game.SinglePlayer() ) then
|
||||
ServerLog( tostring( ply ) .. " tried to save a dupe too quickly!\n" )
|
||||
return
|
||||
end
|
||||
ply.m_NextDupeSave = CurTime() + 1
|
||||
|
||||
-- Convert dupe to JSON
|
||||
local json = util.TableToJSON( ply.CurrentDupe )
|
||||
|
||||
-- Compress it
|
||||
local compressed = util.Compress( json )
|
||||
local length = compressed:len()
|
||||
local send_size = 60000
|
||||
local parts = math.ceil( length / send_size )
|
||||
|
||||
ServerLog( tostring( ply ) .. " requested a Dupe. Size: " .. json:len() .. " ( " .. length .. " compressed, " .. parts .. " parts )\n" )
|
||||
|
||||
-- And send it(!)
|
||||
local start = 0
|
||||
for i = 1, parts do
|
||||
|
||||
local endbyte = math.min( start + send_size, length )
|
||||
local size = endbyte - start
|
||||
|
||||
-- print( "S [ " .. i .. " / " .. parts .. " ] Size: " .. size .. " Start: " .. start .. " End: " .. endbyte )
|
||||
|
||||
net.Start( "ReceiveDupe" )
|
||||
net.WriteUInt( i, 8 )
|
||||
net.WriteUInt( parts, 8 )
|
||||
|
||||
net.WriteUInt( size, 32 )
|
||||
net.WriteData( compressed:sub( start + 1, endbyte + 1 ), size )
|
||||
net.Send( ply )
|
||||
|
||||
start = endbyte
|
||||
end
|
||||
|
||||
end, nil, "Save the current dupe!", { FCVAR_DONTRECORD } )
|
||||
|
||||
end
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
local buffer = ""
|
||||
net.Receive( "ReceiveDupe", function( len, client )
|
||||
|
||||
local part = net.ReadUInt( 8 )
|
||||
local total = net.ReadUInt( 8 )
|
||||
|
||||
local length = net.ReadUInt( 32 )
|
||||
local data = net.ReadData( length )
|
||||
|
||||
buffer = buffer .. data
|
||||
|
||||
-- MsgN( "R [ " .. part .. " / " .. total .. " ] Size: " .. data:len() )
|
||||
|
||||
if ( part != total ) then return end
|
||||
|
||||
MsgN( "Received dupe. Size: " .. buffer:len() )
|
||||
|
||||
local uncompressed = util.Decompress( buffer )
|
||||
buffer = ""
|
||||
|
||||
if ( !uncompressed ) then
|
||||
MsgN( "Received dupe - but couldn't decompress!?" )
|
||||
return
|
||||
end
|
||||
|
||||
--
|
||||
-- Set this global so we can pick it up when we're rendering a frame
|
||||
-- See icon.lua for this process
|
||||
--
|
||||
g_ClientSaveDupe = util.JSONToTable( uncompressed )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
190
gamemodes/sandbox/entities/weapons/gmod_tool/stools/dynamite.lua
Normal file
190
gamemodes/sandbox/entities/weapons/gmod_tool/stools/dynamite.lua
Normal file
@@ -0,0 +1,190 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.dynamite.name"
|
||||
|
||||
TOOL.ClientConVar[ "group" ] = 52
|
||||
TOOL.ClientConVar[ "damage" ] = 200
|
||||
TOOL.ClientConVar[ "delay" ] = 0
|
||||
TOOL.ClientConVar[ "model" ] = "models/dav0r/tnt/tnt.mdl"
|
||||
TOOL.ClientConVar[ "remove" ] = 0
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
cleanup.Register( "dynamite" )
|
||||
|
||||
local function IsValidDynamiteModel( model )
|
||||
for mdl, _ in pairs( list.Get( "DynamiteModels" ) ) do
|
||||
if ( mdl:lower() == model:lower() ) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( !trace.HitPos || IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
-- Get client's CVars
|
||||
local group = self:GetClientNumber( "group" )
|
||||
local delay = self:GetClientNumber( "delay" )
|
||||
local damage = self:GetClientNumber( "damage" )
|
||||
local model = self:GetClientInfo( "model" )
|
||||
local remove = self:GetClientNumber( "remove" ) == 1
|
||||
|
||||
-- If we shot a dynamite, change it's settings
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:GetClass() == "gmod_dynamite" && trace.Entity:GetPlayer() == ply ) then
|
||||
|
||||
trace.Entity:SetDamage( damage )
|
||||
trace.Entity:SetShouldRemove( remove )
|
||||
trace.Entity:SetDelay( delay )
|
||||
|
||||
numpad.Remove( trace.Entity.NumDown )
|
||||
trace.Entity.key = group
|
||||
trace.Entity.NumDown = numpad.OnDown( ply, group, "DynamiteBlow", trace.Entity )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if ( !util.IsValidModel( model ) || !util.IsValidProp( model ) || !IsValidDynamiteModel( model ) ) then return false end
|
||||
if ( !self:GetWeapon():CheckLimit( "dynamite" ) ) then return false end
|
||||
|
||||
local dynamite = MakeDynamite( ply, trace.HitPos, angle_zero, group, damage, model, remove, delay )
|
||||
if ( !IsValid( dynamite ) ) then return false end
|
||||
|
||||
local CurPos = dynamite:GetPos()
|
||||
local Offset = CurPos - dynamite:NearestPoint( CurPos - ( trace.HitNormal * 512 ) )
|
||||
|
||||
dynamite:SetPos( trace.HitPos + Offset )
|
||||
|
||||
undo.Create( "Dynamite" )
|
||||
undo.AddEntity( dynamite )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function MakeDynamite( ply, pos, ang, key, damage, model, remove, delay, Data )
|
||||
|
||||
if ( IsValid( ply ) && !ply:CheckLimit( "dynamite" ) ) then return nil end
|
||||
if ( !IsValidDynamiteModel( model ) ) then return nil end
|
||||
|
||||
local dynamite = ents.Create( "gmod_dynamite" )
|
||||
|
||||
duplicator.DoGeneric( dynamite, Data )
|
||||
dynamite:SetPos( pos ) -- Backwards compatible for addons directly calling this function
|
||||
dynamite:SetAngles( ang )
|
||||
dynamite:SetModel( model )
|
||||
|
||||
dynamite:SetShouldRemove( remove )
|
||||
dynamite:SetDamage( damage )
|
||||
dynamite:SetDelay( delay )
|
||||
dynamite:Spawn()
|
||||
|
||||
DoPropSpawnedEffect( dynamite )
|
||||
duplicator.DoGenericPhysics( dynamite, ply, Data )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
dynamite:SetPlayer( ply )
|
||||
end
|
||||
|
||||
table.Merge( dynamite:GetTable(), {
|
||||
key = key,
|
||||
pl = ply,
|
||||
Damage = damage,
|
||||
model = model,
|
||||
remove = remove,
|
||||
delay = delay
|
||||
} )
|
||||
|
||||
dynamite.NumDown = numpad.OnDown( ply, key, "DynamiteBlow", dynamite )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "dynamite", dynamite )
|
||||
ply:AddCleanup( "dynamite", dynamite )
|
||||
end
|
||||
|
||||
return dynamite
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityClass( "gmod_dynamite", MakeDynamite, "Pos", "Ang", "key", "Damage", "model", "remove", "delay", "Data" )
|
||||
|
||||
numpad.Register( "DynamiteBlow", function( ply, dynamite )
|
||||
|
||||
if ( !IsValid( dynamite ) ) then return end
|
||||
|
||||
dynamite:Explode( nil, ply )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostDynamite( ent, ply )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
if ( !trace.Hit || IsValid( trace.Entity ) && ( trace.Entity:IsPlayer() || trace.Entity:GetClass() == "gmod_dynamite" ) ) then
|
||||
ent:SetNoDraw( true )
|
||||
return
|
||||
end
|
||||
|
||||
ent:SetAngles( angle_zero )
|
||||
|
||||
local CurPos = ent:GetPos()
|
||||
local Offset = CurPos - ent:NearestPoint( CurPos - ( trace.HitNormal * 512 ) )
|
||||
|
||||
ent:SetPos( trace.HitPos + Offset )
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
local mdl = self:GetClientInfo( "model" )
|
||||
if ( !IsValidDynamiteModel( mdl ) ) then self:ReleaseGhostEntity() return end
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) || self.GhostEntity:GetModel() != mdl ) then
|
||||
self:MakeGhostEntity( mdl, vector_origin, angle_zero )
|
||||
end
|
||||
|
||||
self:UpdateGhostDynamite( self.GhostEntity, self:GetOwner() )
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.dynamite.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "dynamite", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.dynamite.explode", Command = "dynamite_group" } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.dynamite.damage", Command = "dynamite_damage", Type = "Float", Min = 0, Max = 500, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.dynamite.delay", Command = "dynamite_delay", Type = "Float", Min = 0, Max = 10, Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.dynamite.remove", Command = "dynamite_remove" } )
|
||||
|
||||
CPanel:AddControl( "PropSelect", { Label = "#tool.dynamite.model", ConVar = "dynamite_model", Height = 0, Models = list.Get( "DynamiteModels" ) } )
|
||||
|
||||
end
|
||||
|
||||
list.Set( "DynamiteModels", "models/dav0r/tnt/tnt.mdl", {} )
|
||||
list.Set( "DynamiteModels", "models/dav0r/tnt/tnttimed.mdl", {} )
|
||||
list.Set( "DynamiteModels", "models/dynamite/dynamite.mdl", {} )
|
||||
@@ -0,0 +1,64 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--
|
||||
-- This works - but I'm not certain that it's the way to go about it.
|
||||
-- better instead to use the right click properties?
|
||||
--
|
||||
|
||||
TOOL.AddToMenu = false
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.editentity.name"
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( !trace.Hit ) then return false end
|
||||
|
||||
self:GetWeapon():SetTargetEntity1( trace.Entity )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
return self:LeftClick( trace )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
local CurrentEditing = self:GetWeapon():GetTargetEntity1()
|
||||
|
||||
if ( CLIENT && self.LastEditing != CurrentEditing ) then
|
||||
|
||||
self.LastEditing = CurrentEditing
|
||||
|
||||
local CPanel = controlpanel.Get( "editentity" )
|
||||
if ( !CPanel ) then return end
|
||||
|
||||
CPanel:ClearControls()
|
||||
self.BuildCPanel( CPanel, CurrentEditing )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( CPanel, ent )
|
||||
|
||||
local control = vgui.Create( "DEntityProperties" )
|
||||
control:SetEntity( ent )
|
||||
control:SetSize( 10, 500 )
|
||||
|
||||
CPanel:AddPanel( control )
|
||||
|
||||
end
|
||||
130
gamemodes/sandbox/entities/weapons/gmod_tool/stools/elastic.lua
Normal file
130
gamemodes/sandbox/entities/weapons/gmod_tool/stools/elastic.lua
Normal file
@@ -0,0 +1,130 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.elastic.name"
|
||||
|
||||
TOOL.ClientConVar[ "constant" ] = "500"
|
||||
TOOL.ClientConVar[ "damping" ] = "3"
|
||||
TOOL.ClientConVar[ "rdamping" ] = "0.01"
|
||||
TOOL.ClientConVar[ "material" ] = "cable/cable"
|
||||
TOOL.ClientConVar[ "width" ] = "2"
|
||||
TOOL.ClientConVar[ "stretch_only" ] = "1"
|
||||
TOOL.ClientConVar[ "color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "color_g" ] = "255"
|
||||
TOOL.ClientConVar[ "color_b" ] = "255"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1 },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self:ClearObjects()
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local width = self:GetClientNumber( "width" )
|
||||
local material = self:GetClientInfo( "material" )
|
||||
local damping = self:GetClientNumber( "damping" )
|
||||
local rdamping = self:GetClientNumber( "rdamping" )
|
||||
local constant = self:GetClientNumber( "constant" )
|
||||
local stretchonly = self:GetClientNumber( "stretch_only" )
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
|
||||
-- Create the constraint
|
||||
local constr, rope = constraint.Elastic( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, constant, damping, rdamping, material, width, stretchonly, Color( colorR, colorG, colorB, 255 ) )
|
||||
|
||||
-- Create an undo if the constraint was created
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Elastic" )
|
||||
undo.AddEntity( constr )
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
|
||||
if ( IsValid( rope ) ) then
|
||||
undo.AddEntity( rope )
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", rope )
|
||||
end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Elastic" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.elastic.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "elastic", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.elastic.constant", Command = "elastic_constant", Type = "Float", Min = 0, Max = 4000, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.elastic.damping", Command = "elastic_damping", Type = "Float", Min = 0, Max = 50, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.elastic.rdamping", Command = "elastic_rdamping", Type = "Float", Min = 0, Max = 1, Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.elastic.stretchonly", Command = "elastic_stretch_only", Help = true } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.elastic.width", Command = "elastic_width", Type = "Float", Min = 0, Max = 20 } )
|
||||
CPanel:AddControl( "RopeMaterial", { Label = "#tool.elastic.material", ConVar = "elastic_material" } )
|
||||
CPanel:AddControl( "Color", { Label = "#tool.elastic.color", Red = "elastic_color_r", Green = "elastic_color_g", Blue = "elastic_color_b" } )
|
||||
|
||||
end
|
||||
216
gamemodes/sandbox/entities/weapons/gmod_tool/stools/emitter.lua
Normal file
216
gamemodes/sandbox/entities/weapons/gmod_tool/stools/emitter.lua
Normal file
@@ -0,0 +1,216 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.emitter.name"
|
||||
|
||||
TOOL.ClientConVar[ "key" ] = "51"
|
||||
TOOL.ClientConVar[ "delay" ] = "1"
|
||||
TOOL.ClientConVar[ "toggle" ] = "1"
|
||||
TOOL.ClientConVar[ "starton" ] = "0"
|
||||
TOOL.ClientConVar[ "effect" ] = "sparks"
|
||||
TOOL.ClientConVar[ "scale" ] = "1"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" }
|
||||
}
|
||||
|
||||
cleanup.Register( "emitters" )
|
||||
|
||||
function TOOL:LeftClick( trace, worldweld )
|
||||
|
||||
if ( trace.Entity && trace.Entity:IsPlayer() ) then return false end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local key = self:GetClientNumber( "key" )
|
||||
local effect = self:GetClientInfo( "effect" )
|
||||
local toggle = self:GetClientNumber( "toggle" ) == 1
|
||||
local starton = self:GetClientNumber( "starton" ) == 1
|
||||
local scale = math.Clamp( self:GetClientNumber( "scale" ), 0.1, 6 )
|
||||
local delay = math.Clamp( self:GetClientNumber( "delay" ), 0.05, 20 )
|
||||
|
||||
-- We shot an existing emitter - just change its values
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:GetClass() == "gmod_emitter" && trace.Entity.pl == ply ) then
|
||||
|
||||
trace.Entity:SetEffect( effect )
|
||||
trace.Entity:SetDelay( delay )
|
||||
trace.Entity:SetToggle( toggle )
|
||||
trace.Entity:SetScale( scale )
|
||||
|
||||
numpad.Remove( trace.Entity.NumDown )
|
||||
numpad.Remove( trace.Entity.NumUp )
|
||||
|
||||
trace.Entity.NumDown = numpad.OnDown( ply, key, "Emitter_On", trace.Entity )
|
||||
trace.Entity.NumUp = numpad.OnUp( ply, key, "Emitter_Off", trace.Entity )
|
||||
|
||||
trace.Entity.key = key
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( !self:GetWeapon():CheckLimit( "emitters" ) ) then return false end
|
||||
|
||||
local pos = trace.HitPos
|
||||
local shouldWeld = ( trace.Entity != NULL && ( !trace.Entity:IsWorld() or worldweld ) )
|
||||
if ( !shouldWeld ) then
|
||||
pos = pos + trace.HitNormal
|
||||
end
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang:RotateAroundAxis( trace.HitNormal, 0 )
|
||||
|
||||
local emitter = MakeEmitter( ply, key, delay, toggle, effect, starton, nil, scale, { Pos = pos, Angle = ang } )
|
||||
if ( !IsValid( emitter ) ) then return false end
|
||||
|
||||
undo.Create( "Emitter" )
|
||||
undo.AddEntity( emitter )
|
||||
|
||||
-- Don't weld to world
|
||||
if ( shouldWeld ) then
|
||||
local weld = constraint.Weld( emitter, trace.Entity, 0, trace.PhysicsBone, 0, true, true )
|
||||
if ( IsValid( weld ) ) then
|
||||
ply:AddCleanup( "emitters", weld )
|
||||
undo.AddEntity( weld )
|
||||
end
|
||||
|
||||
if ( IsValid( emitter:GetPhysicsObject() ) ) then emitter:GetPhysicsObject():EnableCollisions( false ) end
|
||||
emitter.nocollide = true
|
||||
end
|
||||
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
return self:LeftClick( trace, true )
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function MakeEmitter( ply, key, delay, toggle, effect, starton, nocollide, scale, Data )
|
||||
|
||||
if ( IsValid( ply ) && !ply:CheckLimit( "emitters" ) ) then return nil end
|
||||
|
||||
local emitter = ents.Create( "gmod_emitter" )
|
||||
if ( !IsValid( emitter ) ) then return false end
|
||||
|
||||
duplicator.DoGeneric( emitter, Data )
|
||||
emitter:SetEffect( effect )
|
||||
emitter:SetPlayer( ply )
|
||||
emitter:SetDelay( delay )
|
||||
emitter:SetToggle( toggle )
|
||||
emitter:SetOn( starton )
|
||||
emitter:SetScale( scale or 1 )
|
||||
|
||||
emitter:Spawn()
|
||||
|
||||
DoPropSpawnedEffect( emitter )
|
||||
duplicator.DoGenericPhysics( emitter, ply, Data )
|
||||
|
||||
emitter.NumDown = numpad.OnDown( ply, key, "Emitter_On", emitter )
|
||||
emitter.NumUp = numpad.OnUp( ply, key, "Emitter_Off", emitter )
|
||||
|
||||
if ( nocollide && IsValid( emitter:GetPhysicsObject() ) ) then
|
||||
emitter:GetPhysicsObject():EnableCollisions( false )
|
||||
end
|
||||
|
||||
local ttable = {
|
||||
key = key,
|
||||
delay = delay,
|
||||
toggle = toggle,
|
||||
effect = effect,
|
||||
pl = ply,
|
||||
nocollide = nocollide,
|
||||
starton = starton,
|
||||
scale = scale
|
||||
}
|
||||
|
||||
table.Merge( emitter:GetTable(), ttable )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "emitters", emitter )
|
||||
ply:AddCleanup( "emitters", emitter )
|
||||
end
|
||||
|
||||
return emitter
|
||||
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass( "gmod_emitter", MakeEmitter, "key", "delay", "toggle", "effect", "starton", "nocollide", "scale", "Data" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostEmitter( ent, ply )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
if ( !trace.Hit or IsValid( trace.Entity ) && ( trace.Entity:GetClass() == "gmod_emitter" or trace.Entity:IsPlayer() ) ) then
|
||||
|
||||
ent:SetNoDraw( true )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
ent:SetPos( trace.HitPos )
|
||||
ent:SetAngles( trace.HitNormal:Angle() )
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) or self.GhostEntity:GetModel() != "models/props_lab/tpplug.mdl" ) then
|
||||
self:MakeGhostEntity( "models/props_lab/tpplug.mdl", vector_origin, angle_zero )
|
||||
end
|
||||
|
||||
self:UpdateGhostEmitter( self.GhostEntity, self:GetOwner() )
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.emitter.desc" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "emitter", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.emitter.key", Command = "emitter_key" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.emitter.delay", Command = "emitter_delay", Type = "Float", Min = 0.01, Max = 2 } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.emitter.scale", Command = "emitter_scale", Type = "Float", Min = 0, Max = 6, Help = true } )
|
||||
|
||||
CPanel:AddControl( "Checkbox", { Label = "#tool.emitter.toggle", Command = "emitter_toggle" } )
|
||||
CPanel:AddControl( "Checkbox", { Label = "#tool.emitter.starton", Command = "emitter_starton" } )
|
||||
|
||||
local matselect = CPanel:MatSelect( "emitter_effect", nil, true, 0.25, 0.25 )
|
||||
for k, v in pairs( list.Get( "EffectType" ) ) do
|
||||
matselect:AddMaterialEx( v.print, v.material or "gui/effects/default.png", k, { emitter_effect = k } )
|
||||
end
|
||||
|
||||
CPanel:AddItem( matselect )
|
||||
|
||||
end
|
||||
@@ -0,0 +1,49 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Remove this to add it to the menu
|
||||
TOOL.AddToMenu = false
|
||||
|
||||
-- Define these!
|
||||
TOOL.Category = "My Category" -- Name of the category
|
||||
TOOL.Name = "#tool.example.name" -- Name to display. # means it will be translated ( see below )
|
||||
|
||||
if ( true ) then return end -- Don't actually run anything below, remove this to make everything below functional
|
||||
|
||||
if ( CLIENT ) then -- We can only use language.Add on client
|
||||
language.Add( "tool.example.name", "My example tool" ) -- Add translation
|
||||
end
|
||||
|
||||
-- An example clientside convar
|
||||
TOOL.ClientConVar[ "CLIENTSIDE" ] = "default"
|
||||
|
||||
-- An example serverside convar
|
||||
TOOL.ServerConVar[ "SERVERSIDE" ] = "default"
|
||||
|
||||
-- This function/hook is called when the player presses their left click
|
||||
function TOOL:LeftClick( trace )
|
||||
Msg( "PRIMARY FIRE\n" )
|
||||
end
|
||||
|
||||
-- This function/hook is called when the player presses their right click
|
||||
function TOOL:RightClick( trace )
|
||||
Msg( "ALT FIRE\n" )
|
||||
end
|
||||
|
||||
-- This function/hook is called when the player presses their reload key
|
||||
function TOOL:Reload( trace )
|
||||
-- The SWEP doesn't reload so this does nothing :(
|
||||
Msg( "RELOAD\n" )
|
||||
end
|
||||
|
||||
-- This function/hook is called every frame on client and every tick on the server
|
||||
function TOOL:Think()
|
||||
end
|
||||
344
gamemodes/sandbox/entities/weapons/gmod_tool/stools/eyeposer.lua
Normal file
344
gamemodes/sandbox/entities/weapons/gmod_tool/stools/eyeposer.lua
Normal file
@@ -0,0 +1,344 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Poser"
|
||||
TOOL.Name = "#tool.eyeposer.name"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "left_use" },
|
||||
{ name = "right" },
|
||||
{ name = "reload" },
|
||||
}
|
||||
|
||||
TOOL.ClientConVar[ "x" ] = "0"
|
||||
TOOL.ClientConVar[ "y" ] = "0"
|
||||
TOOL.ClientConVar[ "strabismus" ] = "0"
|
||||
|
||||
local function SetEyeTarget( ply, ent, data )
|
||||
|
||||
if ( data.EyeTarget ) then ent:SetEyeTarget( data.EyeTarget ) end
|
||||
|
||||
if ( SERVER ) then
|
||||
if ( data.EyeTarget == vector_origin ) then
|
||||
duplicator.ClearEntityModifier( ent, "eyetarget" )
|
||||
else
|
||||
duplicator.StoreEntityModifier( ent, "eyetarget", data )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
if ( SERVER ) then
|
||||
duplicator.RegisterEntityModifier( "eyetarget", SetEyeTarget )
|
||||
end
|
||||
|
||||
local function ConvertRelativeToEyesAttachment( ent, pos )
|
||||
|
||||
if ( ent:IsNPC() ) then return pos end
|
||||
|
||||
-- Convert relative to eye attachment
|
||||
local eyeattachment = ent:LookupAttachment( "eyes" )
|
||||
if ( eyeattachment == 0 ) then return end
|
||||
|
||||
local attachment = ent:GetAttachment( eyeattachment )
|
||||
if ( !attachment ) then return end
|
||||
|
||||
return WorldToLocal( pos, angle_zero, attachment.Pos, attachment.Ang )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:CalculateEyeTarget()
|
||||
|
||||
local x = math.Remap( self:GetClientNumber( "x" ), 0, 1, -1, 1 )
|
||||
local y = math.Remap( self:GetClientNumber( "y" ), 0, 1, -1, 1 )
|
||||
local fwd = Angle( y * 45, x * 45, 0 ):Forward()
|
||||
local s = math.Clamp( self:GetClientNumber( "strabismus" ), -1, 1 )
|
||||
local distance = 1000
|
||||
|
||||
if ( s < 0 ) then
|
||||
s = math.Remap( s, -1, 0, 0, 1 )
|
||||
distance = distance * math.pow( 10000, s - 1 )
|
||||
elseif ( s > 0 ) then
|
||||
distance = distance * -math.pow( 10000, -s )
|
||||
end
|
||||
|
||||
-- Gotta do this for NPCs...
|
||||
local ent = self:GetSelectedEntity()
|
||||
if ( IsValid( ent ) and ent:IsNPC() ) then
|
||||
local eyeattachment = ent:LookupAttachment( "eyes" )
|
||||
if ( eyeattachment == 0 ) then return fwd * distance end
|
||||
|
||||
local attachment = ent:GetAttachment( eyeattachment )
|
||||
if ( !attachment ) then return fwd * distance end
|
||||
|
||||
return LocalToWorld( fwd * distance, angle_zero, attachment.Pos, attachment.Ang )
|
||||
end
|
||||
|
||||
return fwd * distance
|
||||
|
||||
end
|
||||
|
||||
function TOOL:GetSelectedEntity()
|
||||
return self:GetWeapon():GetNWEntity( "eyeposer_ent" )
|
||||
end
|
||||
|
||||
function TOOL:SetSelectedEntity( ent )
|
||||
|
||||
if ( !IsValid( ent ) ) then self:SetOperation( 0 ) end
|
||||
|
||||
if ( IsValid( ent ) and ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
||||
return self:GetWeapon():SetNWEntity( "eyeposer_ent", ent )
|
||||
end
|
||||
|
||||
-- Selects entity and aims their eyes
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( self:GetOwner():KeyDown( IN_USE ) ) then
|
||||
return self:MakeLookAtMe( trace )
|
||||
end
|
||||
|
||||
if ( !IsValid( self:GetSelectedEntity() ) or self:GetOperation() != 1 ) then
|
||||
|
||||
self:SetSelectedEntity( trace.Entity )
|
||||
if ( !IsValid( self:GetSelectedEntity() ) ) then return false end
|
||||
|
||||
local eyeAtt = self:GetSelectedEntity():LookupAttachment( "eyes" )
|
||||
if ( eyeAtt == 0 ) then
|
||||
self:SetSelectedEntity( NULL )
|
||||
return false
|
||||
end
|
||||
|
||||
self:SetOperation( 1 ) -- For UI
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
local selectedEnt = self:GetSelectedEntity()
|
||||
|
||||
self:SetSelectedEntity( NULL )
|
||||
self:SetOperation( 0 )
|
||||
|
||||
if ( !IsValid( selectedEnt ) ) then return false end
|
||||
|
||||
local LocalPos = ConvertRelativeToEyesAttachment( selectedEnt, trace.HitPos )
|
||||
if ( !LocalPos ) then return false end
|
||||
|
||||
SetEyeTarget( self:GetOwner(), selectedEnt, { EyeTarget = LocalPos } )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Select the eyes for posing through UI
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
local hadEntity = IsValid( self:GetSelectedEntity() )
|
||||
|
||||
self:SetSelectedEntity( trace.Entity )
|
||||
if ( !IsValid( self:GetSelectedEntity() ) ) then return hadEntity end
|
||||
|
||||
local eyeAtt = self:GetSelectedEntity():LookupAttachment( "eyes" )
|
||||
if ( eyeAtt == 0 ) then
|
||||
self:SetSelectedEntity( NULL )
|
||||
return false
|
||||
end
|
||||
|
||||
-- TODO: Reset? Save and load these raw values from the entity modifier?
|
||||
--RunConsoleCommand( "eyeposer_x", 0.5 )
|
||||
--RunConsoleCommand( "eyeposer_y", 0.5 )
|
||||
--RunConsoleCommand( "eyeposer_strabismus", 0 )
|
||||
|
||||
self:SetOperation( 2 ) -- For UI
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Makes the eyes look at the player
|
||||
function TOOL:MakeLookAtMe( trace )
|
||||
|
||||
self:SetSelectedEntity( NULL )
|
||||
self:SetOperation( 0 )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent ) and ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local pos = self:GetOwner():EyePos()
|
||||
|
||||
local LocalPos = ConvertRelativeToEyesAttachment( ent, pos )
|
||||
if ( !LocalPos ) then return false end
|
||||
|
||||
SetEyeTarget( self:GetOwner(), ent, { EyeTarget = LocalPos } )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Reset eye position
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
self:SetSelectedEntity( NULL )
|
||||
self:SetOperation( 0 )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent ) and ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
SetEyeTarget( self:GetOwner(), ent, { EyeTarget = vector_origin } )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
local validEntityLast = false
|
||||
function TOOL:Think()
|
||||
|
||||
local ent = self:GetSelectedEntity()
|
||||
|
||||
-- If we're on the client just make sure the context menu is up to date
|
||||
if ( CLIENT ) then
|
||||
if ( IsValid( ent ) == validEntityLast ) then return end
|
||||
|
||||
validEntityLast = IsValid( ent )
|
||||
self:RebuildControlPanel( validEntityLast )
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if ( !IsValid( ent ) ) then self:SetOperation( 0 ) return end
|
||||
|
||||
if ( self:GetOperation() != 2 ) then return end
|
||||
|
||||
-- On the server we continually set the eye position
|
||||
SetEyeTarget( self:GetOwner(), ent, { EyeTarget = self:CalculateEyeTarget() } )
|
||||
|
||||
end
|
||||
|
||||
-- The rest of the code is clientside only, it is not used on server
|
||||
if ( SERVER ) then return end
|
||||
|
||||
local SelectionRing = surface.GetTextureID( "gui/faceposer_indicator" )
|
||||
|
||||
-- Draw a box indicating the face we have selected
|
||||
function TOOL:DrawHUD()
|
||||
|
||||
local selected = self:GetSelectedEntity()
|
||||
if ( !IsValid( selected ) ) then return end
|
||||
|
||||
local eyeattachment = selected:LookupAttachment( "eyes" )
|
||||
if ( eyeattachment == 0 ) then return end
|
||||
|
||||
local attachment = selected:GetAttachment( eyeattachment )
|
||||
local scrpos = attachment.Pos:ToScreen()
|
||||
if ( !scrpos.visible ) then return end
|
||||
|
||||
if ( self:GetOperation() == 1 ) then
|
||||
|
||||
-- Get Target
|
||||
local trace = self:GetOwner():GetEyeTrace()
|
||||
|
||||
-- Clientside preview
|
||||
local LocalPos = ConvertRelativeToEyesAttachment( selected, trace.HitPos )
|
||||
if ( LocalPos ) then
|
||||
selected:SetEyeTarget( LocalPos )
|
||||
end
|
||||
|
||||
-- Try to get each eye position.. this is a real guess and won't work on non-humans
|
||||
local Leye = ( attachment.Pos + attachment.Ang:Right() * 1.5 ):ToScreen()
|
||||
local Reye = ( attachment.Pos - attachment.Ang:Right() * 1.5 ):ToScreen()
|
||||
|
||||
-- Todo, make the line look less like ass
|
||||
local scrhit = trace.HitPos:ToScreen()
|
||||
local x = scrhit.x
|
||||
local y = scrhit.y
|
||||
|
||||
surface.SetDrawColor( 0, 0, 0, 100 )
|
||||
surface.DrawLine( Leye.x - 1, Leye.y + 1, x - 1, y + 1 )
|
||||
surface.DrawLine( Leye.x - 1, Leye.y - 1, x - 1, y - 1 )
|
||||
surface.DrawLine( Leye.x + 1, Leye.y + 1, x + 1, y + 1 )
|
||||
surface.DrawLine( Leye.x + 1, Leye.y - 1, x + 1, y - 1 )
|
||||
surface.DrawLine( Reye.x - 1, Reye.y + 1, x - 1, y + 1 )
|
||||
surface.DrawLine( Reye.x - 1, Reye.y - 1, x - 1, y - 1 )
|
||||
surface.DrawLine( Reye.x + 1, Reye.y + 1, x + 1, y + 1 )
|
||||
surface.DrawLine( Reye.x + 1, Reye.y - 1, x + 1, y - 1 )
|
||||
|
||||
surface.SetDrawColor( 0, 255, 0, 255 )
|
||||
surface.DrawLine( Leye.x, Leye.y, x, y )
|
||||
surface.DrawLine( Leye.x, Leye.y - 1, x, y - 1 )
|
||||
surface.DrawLine( Reye.x, Reye.y, x, y )
|
||||
surface.DrawLine( Reye.x, Reye.y - 1, x, y - 1 )
|
||||
|
||||
end
|
||||
|
||||
if ( self:GetOperation() == 2 ) then
|
||||
|
||||
-- Clientside preview
|
||||
--selected:SetEyeTarget( self:CalculateEyeTarget() )
|
||||
|
||||
-- Work out the side distance to give a rough headsize box..
|
||||
local player_eyes = LocalPlayer():EyeAngles()
|
||||
local side = ( attachment.Pos + player_eyes:Right() * 20 ):ToScreen()
|
||||
local size = math.abs( side.x - scrpos.x )
|
||||
|
||||
-- Draw the selection ring
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetTexture( SelectionRing )
|
||||
surface.DrawTexturedRect( scrpos.x - size, scrpos.y - size, size * 2, size * 2 )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( CPanel, hasEntity )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.eyeposer.desc" } )
|
||||
|
||||
if ( hasEntity ) then
|
||||
|
||||
-- Panel for Slider ( limiting edge )
|
||||
local SliderBackground = vgui.Create( "DPanel", CPanel )
|
||||
SliderBackground:Dock( TOP )
|
||||
SliderBackground:SetTall( 225 )
|
||||
CPanel:AddItem( SliderBackground )
|
||||
|
||||
-- 2 axis slider for the eye position
|
||||
local EyeSlider = vgui.Create( "DSlider", SliderBackground )
|
||||
EyeSlider:Dock( FILL )
|
||||
EyeSlider:SetLockY()
|
||||
EyeSlider:SetSlideX( 0.5 )
|
||||
EyeSlider:SetSlideY( 0.5 )
|
||||
EyeSlider:SetTrapInside( true )
|
||||
EyeSlider:SetConVarX( "eyeposer_x" )
|
||||
EyeSlider:SetConVarY( "eyeposer_y" )
|
||||
-- Draw the 'button' different from the slider
|
||||
EyeSlider.Knob.Paint = function( panel, w, h ) derma.SkinHook( "Paint", "Button", panel, w, h ) end
|
||||
|
||||
function EyeSlider:Paint( w, h )
|
||||
local knobX, knobY = self.Knob:GetPos()
|
||||
local knobW, knobH = self.Knob:GetSize()
|
||||
surface.SetDrawColor( 0, 0, 0, 250 )
|
||||
surface.DrawLine( knobX + knobW / 2, knobY + knobH / 2, w / 2, h / 2 )
|
||||
surface.DrawRect( w / 2 - 2, h / 2 - 2, 5, 5 )
|
||||
end
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.eyeposer.strabismus", Command = "eyeposer_strabismus", Type = "Float", Min = -1, Max = 1, Default = 0 } )
|
||||
|
||||
end
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.eyeposer.size_eyes", Command = "r_eyesize", Type = "Float", Min = -0.5, Max = 2, Help = true, Default = 0 } )
|
||||
|
||||
end
|
||||
@@ -0,0 +1,463 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Poser"
|
||||
TOOL.Name = "#tool.faceposer.name"
|
||||
|
||||
local MAXSTUDIOFLEXCTRL = 96
|
||||
|
||||
TOOL.FaceTimer = 0
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" }
|
||||
}
|
||||
|
||||
local function IsUselessFaceFlex( strName )
|
||||
|
||||
if ( strName == "gesture_rightleft" ) then return true end
|
||||
if ( strName == "gesture_updown" ) then return true end
|
||||
if ( strName == "head_forwardback" ) then return true end
|
||||
if ( strName == "chest_rightleft" ) then return true end
|
||||
if ( strName == "body_rightleft" ) then return true end
|
||||
if ( strName == "eyes_rightleft" ) then return true end
|
||||
if ( strName == "eyes_updown" ) then return true end
|
||||
if ( strName == "head_tilt" ) then return true end
|
||||
if ( strName == "head_updown" ) then return true end
|
||||
if ( strName == "head_rightleft" ) then return true end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
local function GenerateDefaultFlexValue( ent, flexID )
|
||||
local min, max = ent:GetFlexBounds( flexID )
|
||||
if ( !max || max - min == 0 ) then return 0 end
|
||||
return ( 0 - min ) / ( max - min )
|
||||
end
|
||||
|
||||
function TOOL:FacePoserEntity()
|
||||
return self:GetWeapon():GetNWEntity( 1 )
|
||||
end
|
||||
|
||||
function TOOL:SetFacePoserEntity( ent )
|
||||
if ( IsValid( ent ) && ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
||||
return self:GetWeapon():SetNWEntity( 1, ent )
|
||||
end
|
||||
|
||||
local LastFPEntity = NULL
|
||||
local LastFPEntityValid = false
|
||||
function TOOL:Think()
|
||||
|
||||
-- If we're on the client just make sure the context menu is up to date
|
||||
if ( CLIENT ) then
|
||||
|
||||
if ( self:FacePoserEntity() == LastFPEntity && IsValid( LastFPEntity ) == LastFPEntityValid ) then return end
|
||||
|
||||
LastFPEntity = self:FacePoserEntity()
|
||||
LastFPEntityValid = IsValid( LastFPEntity )
|
||||
self:RebuildControlPanel( self:FacePoserEntity() )
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- On the server we continually set the flex weights
|
||||
if ( self.FaceTimer > CurTime() ) then return end
|
||||
|
||||
local ent = self:FacePoserEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local FlexNum = ent:GetFlexNum()
|
||||
if ( FlexNum <= 0 ) then return end
|
||||
|
||||
for i = 0, FlexNum do
|
||||
|
||||
local num = self:GetClientNumber( "flex" .. i )
|
||||
ent:SetFlexWeight( i, num )
|
||||
|
||||
end
|
||||
|
||||
local num = self:GetClientNumber( "scale" )
|
||||
ent:SetFlexScale( num )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Alt fire sucks the facepose from the model's face
|
||||
-----------------------------------------------------------]]
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent ) && ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
||||
|
||||
if ( SERVER ) then
|
||||
self:SetFacePoserEntity( ent )
|
||||
end
|
||||
|
||||
if ( !IsValid( ent ) ) then return true end
|
||||
|
||||
local FlexNum = ent:GetFlexNum()
|
||||
if ( FlexNum == 0 ) then return false end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
-- This stops it applying the current sliders to the newly selected face..
|
||||
-- it should probably be linked to the ping somehow.. but 1 second seems pretty safe
|
||||
self.FaceTimer = CurTime() + 1
|
||||
|
||||
-- In multiplayer the rest is only done on the client to save bandwidth.
|
||||
-- We can't do that in single player because these functions don't get called on the client
|
||||
if ( !game.SinglePlayer() ) then return true end
|
||||
|
||||
end
|
||||
|
||||
for i = 0, FlexNum - 1 do
|
||||
|
||||
local Weight = "0.0"
|
||||
|
||||
if ( !ent:HasFlexManipulatior() ) then
|
||||
Weight = GenerateDefaultFlexValue( ent, i )
|
||||
elseif ( i <= FlexNum ) then
|
||||
Weight = ent:GetFlexWeight( i )
|
||||
end
|
||||
|
||||
self:GetOwner():ConCommand( "faceposer_flex" .. i .. " " .. Weight )
|
||||
|
||||
end
|
||||
|
||||
self:GetOwner():ConCommand( "faceposer_scale " .. ent:GetFlexScale() )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Just select as the current object
|
||||
Current settings will get applied
|
||||
-----------------------------------------------------------]]
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent ) && ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
if ( ent:GetFlexNum() == 0 ) then return false end
|
||||
|
||||
self.FaceTimer = 0
|
||||
self:SetFacePoserEntity( ent )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
local function CC_Face_Randomize( ply, command, arguments )
|
||||
|
||||
for i = 0, MAXSTUDIOFLEXCTRL do
|
||||
local num = math.Rand( 0, 1 )
|
||||
ply:ConCommand( "faceposer_flex" .. i .. " " .. string.format( "%.3f", num ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
concommand.Add( "faceposer_randomize", CC_Face_Randomize )
|
||||
|
||||
end
|
||||
|
||||
-- The rest of the code is clientside only, it is not used on server
|
||||
if ( SERVER ) then return end
|
||||
|
||||
for i = 0, MAXSTUDIOFLEXCTRL do
|
||||
TOOL.ClientConVar[ "flex" .. i ] = "0"
|
||||
end
|
||||
|
||||
TOOL.ClientConVar[ "scale" ] = "1.0"
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel, faceEntity )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.faceposer.desc" } )
|
||||
|
||||
if ( !IsValid( faceEntity ) || faceEntity:GetFlexNum() == 0 ) then return end
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "face", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
local QuickFace = vgui.Create( "MatSelect", CPanel )
|
||||
QuickFace:SetItemWidth( 64 )
|
||||
QuickFace:SetItemHeight( 32 )
|
||||
|
||||
QuickFace.List:SetSpacing( 1 )
|
||||
QuickFace.List:SetPadding( 0 )
|
||||
|
||||
QuickFace:SetAutoHeight( true )
|
||||
|
||||
local Clear = {}
|
||||
for i = 0, MAXSTUDIOFLEXCTRL do
|
||||
Clear[ "faceposer_flex" .. i ] = GenerateDefaultFlexValue( faceEntity, i )
|
||||
end
|
||||
QuickFace:AddMaterialEx( "#faceposer.clear", "vgui/face/clear", nil, Clear )
|
||||
|
||||
-- Todo: These really need to be the name of the flex.
|
||||
QuickFace:AddMaterialEx( "#faceposer.openeyes", "vgui/face/open_eyes", nil, {
|
||||
faceposer_flex0 = "1",
|
||||
faceposer_flex1 = "1",
|
||||
faceposer_flex2 = "0",
|
||||
faceposer_flex3 = "0",
|
||||
faceposer_flex4 = "0",
|
||||
faceposer_flex5 = "0",
|
||||
faceposer_flex6 = "0",
|
||||
faceposer_flex7 = "0",
|
||||
faceposer_flex8 = "0",
|
||||
faceposer_flex9 = "0"
|
||||
} )
|
||||
|
||||
QuickFace:AddMaterialEx( "#faceposer.closeeyes", "vgui/face/close_eyes", nil, {
|
||||
faceposer_flex0 = "0",
|
||||
faceposer_flex1 = "0",
|
||||
faceposer_flex2 = "1",
|
||||
faceposer_flex3 = "1",
|
||||
faceposer_flex4 = "1",
|
||||
faceposer_flex5 = "1",
|
||||
faceposer_flex6 = "1",
|
||||
faceposer_flex7 = "1",
|
||||
faceposer_flex8 = "1",
|
||||
faceposer_flex9 = "1"
|
||||
} )
|
||||
|
||||
QuickFace:AddMaterialEx( "#faceposer.angryeyebrows", "vgui/face/angry_eyebrows", nil, {
|
||||
faceposer_flex10 = "0",
|
||||
faceposer_flex11 = "0",
|
||||
faceposer_flex12 = "1",
|
||||
faceposer_flex13 = "1",
|
||||
faceposer_flex14 = "0.5",
|
||||
faceposer_flex15 = "0.5"
|
||||
} )
|
||||
|
||||
QuickFace:AddMaterialEx( "#faceposer.normaleyebrows", "vgui/face/normal_eyebrows", nil, {
|
||||
faceposer_flex10 = "0",
|
||||
faceposer_flex11 = "0",
|
||||
faceposer_flex12 = "0",
|
||||
faceposer_flex13 = "0",
|
||||
faceposer_flex14 = "0",
|
||||
faceposer_flex15 = "0"
|
||||
} )
|
||||
|
||||
QuickFace:AddMaterialEx( "#faceposer.sorryeyebrows", "vgui/face/sorry_eyebrows", nil, {
|
||||
faceposer_flex10 = "1",
|
||||
faceposer_flex11 = "1",
|
||||
faceposer_flex12 = "0",
|
||||
faceposer_flex13 = "0",
|
||||
faceposer_flex14 = "0",
|
||||
faceposer_flex15 = "0"
|
||||
} )
|
||||
|
||||
QuickFace:AddMaterialEx( "#faceposer.grin", "vgui/face/grin", nil, {
|
||||
faceposer_flex20 = "1",
|
||||
faceposer_flex21 = "1",
|
||||
faceposer_flex22 = "1",
|
||||
faceposer_flex23 = "1",
|
||||
faceposer_flex24 = "0",
|
||||
faceposer_flex25 = "0",
|
||||
faceposer_flex26 = "0",
|
||||
faceposer_flex27 = "1",
|
||||
faceposer_flex28 = "1",
|
||||
faceposer_flex29 = "0",
|
||||
faceposer_flex30 = "0",
|
||||
faceposer_flex31 = "0",
|
||||
faceposer_flex32 = "0",
|
||||
faceposer_flex33 = "1",
|
||||
faceposer_flex34 = "1",
|
||||
faceposer_flex35 = "0",
|
||||
faceposer_flex36 = "0",
|
||||
faceposer_flex37 = "0",
|
||||
faceposer_flex38 = "0",
|
||||
faceposer_flex39 = "1",
|
||||
faceposer_flex40 = "0",
|
||||
faceposer_flex41 = "0",
|
||||
faceposer_flex42 = "1",
|
||||
faceposer_flex43 = "1"
|
||||
} )
|
||||
|
||||
QuickFace:AddMaterialEx( "#faceposer.sad", "vgui/face/sad", nil, {
|
||||
faceposer_flex20 = "0",
|
||||
faceposer_flex21 = "0",
|
||||
faceposer_flex22 = "0",
|
||||
faceposer_flex23 = "0",
|
||||
faceposer_flex24 = "1",
|
||||
faceposer_flex25 = "1",
|
||||
faceposer_flex26 = "0.0",
|
||||
faceposer_flex27 = "0",
|
||||
faceposer_flex28 = "0",
|
||||
faceposer_flex29 = "0",
|
||||
faceposer_flex30 = "0",
|
||||
faceposer_flex31 = "0",
|
||||
faceposer_flex32 = "0",
|
||||
faceposer_flex33 = "0",
|
||||
faceposer_flex34 = "0",
|
||||
faceposer_flex35 = "0",
|
||||
faceposer_flex36 = "0",
|
||||
faceposer_flex37 = "0",
|
||||
faceposer_flex38 = "0.5",
|
||||
faceposer_flex39 = "0",
|
||||
faceposer_flex40 = "0",
|
||||
faceposer_flex41 = "0",
|
||||
faceposer_flex42 = "0",
|
||||
faceposer_flex43 = "0"
|
||||
} )
|
||||
|
||||
QuickFace:AddMaterialEx( "#faceposer.smile", "vgui/face/smile", nil, {
|
||||
faceposer_flex20 = "1",
|
||||
faceposer_flex21 = "1",
|
||||
faceposer_flex22 = "1",
|
||||
faceposer_flex23 = "1",
|
||||
faceposer_flex24 = "0",
|
||||
faceposer_flex25 = "0",
|
||||
faceposer_flex26 = "0",
|
||||
faceposer_flex27 = "0.6",
|
||||
faceposer_flex28 = "0.4",
|
||||
faceposer_flex29 = "0",
|
||||
faceposer_flex30 = "0",
|
||||
faceposer_flex31 = "0",
|
||||
faceposer_flex32 = "0",
|
||||
faceposer_flex33 = "1",
|
||||
faceposer_flex34 = "1",
|
||||
faceposer_flex35 = "0",
|
||||
faceposer_flex36 = "0",
|
||||
faceposer_flex37 = "0",
|
||||
faceposer_flex38 = "0",
|
||||
faceposer_flex39 = "0",
|
||||
faceposer_flex40 = "1",
|
||||
faceposer_flex41 = "1",
|
||||
faceposer_flex42 = "0",
|
||||
faceposer_flex43 = "0",
|
||||
faceposer_flex44 = "0",
|
||||
} )
|
||||
|
||||
CPanel:AddItem( QuickFace )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.faceposer.scale", Command = "faceposer_scale", Type = "Float", Min = -5, Max = 5, Help = true, Default = 1 } ):SetHeight( 16 )
|
||||
CPanel:AddControl( "Button", { Text = "#tool.faceposer.randomize", Command = "faceposer_randomize" } )
|
||||
|
||||
local filter = CPanel:AddControl( "TextBox", { Label = "#spawnmenu.quick_filter_tool" } )
|
||||
filter:SetUpdateOnType( true )
|
||||
|
||||
-- Group flex controllers by their type..
|
||||
local flexGroups = {}
|
||||
for i = 0, faceEntity:GetFlexNum() - 1 do
|
||||
local name = faceEntity:GetFlexName( i )
|
||||
|
||||
if ( !IsUselessFaceFlex( name ) ) then
|
||||
local group = faceEntity:GetFlexType( i )
|
||||
|
||||
if ( group == name ) then group = "Other" end
|
||||
|
||||
local min, max = faceEntity:GetFlexBounds( i )
|
||||
|
||||
flexGroups[ group ] = flexGroups[ group ] or {}
|
||||
table.insert( flexGroups[ group ], { name = name, id = i, min = min, max = max } )
|
||||
end
|
||||
end
|
||||
|
||||
local flexControllers = {}
|
||||
for group, items in pairs( flexGroups ) do
|
||||
|
||||
local groupForm = vgui.Create( "DForm", CPanel )
|
||||
groupForm:SetLabel( string.NiceName( group ) )
|
||||
|
||||
-- Give the DForm a nice outline
|
||||
groupForm.GetBackgroundColor = function() return color_white end
|
||||
|
||||
function groupForm:Paint( w, h )
|
||||
|
||||
derma.SkinHook( "Paint", "CategoryList", self, w, h )
|
||||
derma.SkinHook( "Paint", "CollapsibleCategory", self, w, h )
|
||||
|
||||
end
|
||||
|
||||
CPanel:AddItem( groupForm )
|
||||
|
||||
for id, item in pairs( items ) do
|
||||
|
||||
local ctrl = groupForm:NumSlider( string.NiceName( item.name ), "faceposer_flex" .. item.id, item.min, item.max, 2 )
|
||||
ctrl:SetDefaultValue( GenerateDefaultFlexValue( faceEntity, item.id ) )
|
||||
ctrl:SetHeight( 11 ) -- This makes the controls all bunched up like how we want
|
||||
ctrl:DockPadding( 0, -6, 0, -4 ) -- Try to make the lower part of the text visible
|
||||
ctrl.originalName = item.name
|
||||
table.insert( flexControllers, ctrl )
|
||||
|
||||
if ( item.id >= MAXSTUDIOFLEXCTRL ) then
|
||||
ctrl:SetEnabled( false )
|
||||
ctrl:SetTooltip( "#tool.faceposer.too_many_flexes" )
|
||||
end
|
||||
end
|
||||
|
||||
-- HACK: Add some padding to the bottom of the list, because Dock won't
|
||||
local padding = vgui.Create( "Panel", groupForm )
|
||||
padding:SetHeight( 0 )
|
||||
groupForm:AddItem( padding )
|
||||
|
||||
end
|
||||
|
||||
-- Actual searching
|
||||
filter.OnValueChange = function( pnl, txt )
|
||||
for id, flxpnl in ipairs( flexControllers ) do
|
||||
if ( !flxpnl:GetText():lower():find( txt:lower(), nil, true ) && !flxpnl.originalName:lower():find( txt:lower(), nil, true ) ) then
|
||||
flxpnl:SetVisible( false )
|
||||
else
|
||||
flxpnl:SetVisible( true )
|
||||
end
|
||||
|
||||
flxpnl:InvalidateParent()
|
||||
end
|
||||
CPanel:InvalidateChildren()
|
||||
end
|
||||
end
|
||||
|
||||
local FacePoser = surface.GetTextureID( "gui/faceposer_indicator" )
|
||||
|
||||
-- Draw a box indicating the face we have selected
|
||||
function TOOL:DrawHUD()
|
||||
|
||||
if ( GetConVarNumber( "gmod_drawtooleffects" ) == 0 ) then return end
|
||||
|
||||
local selected = self:FacePoserEntity()
|
||||
|
||||
if ( !IsValid( selected ) || selected:IsWorld() || selected:GetFlexNum() == 0 ) then return end
|
||||
|
||||
local pos = selected:GetPos()
|
||||
local eyeattachment = selected:LookupAttachment( "eyes" )
|
||||
if ( eyeattachment != 0 ) then
|
||||
local attachment = selected:GetAttachment( eyeattachment )
|
||||
pos = attachment.Pos
|
||||
else
|
||||
-- The model has no "eyes" attachment, try to find a bone with "head" in its name
|
||||
for i = 0, selected:GetBoneCount() - 1 do
|
||||
if ( selected:GetBoneName( i ) && selected:GetBoneName( i ):lower():find( "head" ) ) then
|
||||
pos = selected:GetBonePosition( i )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local scrpos = pos:ToScreen()
|
||||
if ( !scrpos.visible ) then return end
|
||||
|
||||
-- Work out the side distance to give a rough headsize box..
|
||||
local player_eyes = LocalPlayer():EyeAngles()
|
||||
local side = ( pos + player_eyes:Right() * 20 ):ToScreen()
|
||||
local size = math.abs( side.x - scrpos.x )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetTexture( FacePoser )
|
||||
surface.DrawTexturedRect( scrpos.x - size, scrpos.y - size, size * 2, size * 2 )
|
||||
|
||||
end
|
||||
636
gamemodes/sandbox/entities/weapons/gmod_tool/stools/finger.lua
Normal file
636
gamemodes/sandbox/entities/weapons/gmod_tool/stools/finger.lua
Normal file
@@ -0,0 +1,636 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Poser"
|
||||
TOOL.Name = "#tool.finger.name"
|
||||
|
||||
TOOL.RequiresTraceHit = true
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" }
|
||||
}
|
||||
|
||||
local VarsOnHand = 15
|
||||
|
||||
-- Returns true if it has TF2 hands
|
||||
local function HasTF2Hands( pEntity )
|
||||
return pEntity:LookupBone( "bip_hand_L" ) != nil
|
||||
end
|
||||
|
||||
-- Returns true if it has Portal 2 hands
|
||||
local function HasP2Hands( pEntity )
|
||||
return pEntity:LookupBone( "wrist_A_L" ) != nil || pEntity:LookupBone( "index_1_L" ) != nil
|
||||
end
|
||||
|
||||
local TranslateTable_TF2 = {}
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger0" ] = "bip_thumb_0_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger01" ] = "bip_thumb_1_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger02" ] = "bip_thumb_2_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger1" ] = "bip_index_0_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger11" ] = "bip_index_1_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger12" ] = "bip_index_2_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger2" ] = "bip_middle_0_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger21" ] = "bip_middle_1_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger22" ] = "bip_middle_2_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger3" ] = "bip_ring_0_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger31" ] = "bip_ring_1_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger32" ] = "bip_ring_2_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger4" ] = "bip_pinky_0_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger41" ] = "bip_pinky_1_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_L_Finger42" ] = "bip_pinky_2_L"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger0" ] = "bip_thumb_0_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger01" ] = "bip_thumb_1_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger02" ] = "bip_thumb_2_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger1" ] = "bip_index_0_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger11" ] = "bip_index_1_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger12" ] = "bip_index_2_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger2" ] = "bip_middle_0_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger21" ] = "bip_middle_1_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger22" ] = "bip_middle_2_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger3" ] = "bip_ring_0_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger31" ] = "bip_ring_1_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger32" ] = "bip_ring_2_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger4" ] = "bip_pinky_0_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger41" ] = "bip_pinky_1_R"
|
||||
TranslateTable_TF2[ "ValveBiped.Bip01_R_Finger42" ] = "bip_pinky_2_R"
|
||||
|
||||
local TranslateTable_Zeno = {}
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger0" ] = "Bip01_L_Finger0"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger01" ] = "Bip01_L_Finger01"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger02" ] = "Bip01_L_Finger02"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger1" ] = "Bip01_L_Finger1"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger11" ] = "Bip01_L_Finger11"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger12" ] = "Bip01_L_Finger12"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger2" ] = "Bip01_L_Finger2"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger21" ] = "Bip01_L_Finger21"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger22" ] = "Bip01_L_Finger22"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger3" ] = "Bip01_L_Finger3"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger31" ] = "Bip01_L_Finger31"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger32" ] = "Bip01_L_Finger32"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger4" ] = "Bip01_L_Finger4"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger41" ] = "Bip01_L_Finger41"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_L_Finger42" ] = "Bip01_L_Finger42"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger0" ] = "Bip01_R_Finger0"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger01" ] = "Bip01_R_Finger01"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger02" ] = "Bip01_R_Finger02"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger1" ] = "Bip01_R_Finger1"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger11" ] = "Bip01_R_Finger11"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger12" ] = "Bip01_R_Finger12"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger2" ] = "Bip01_R_Finger2"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger21" ] = "Bip01_R_Finger21"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger22" ] = "Bip01_R_Finger22"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger3" ] = "Bip01_R_Finger3"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger31" ] = "Bip01_R_Finger31"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger32" ] = "Bip01_R_Finger32"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger4" ] = "Bip01_R_Finger4"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger41" ] = "Bip01_R_Finger41"
|
||||
TranslateTable_Zeno[ "ValveBiped.Bip01_R_Finger42" ] = "Bip01_R_Finger42"
|
||||
|
||||
local TranslateTable_INS = {}
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger0" ] = "L Finger0"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger01" ] = "L Finger01"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger02" ] = "L Finger02"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger1" ] = "L Finger1"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger11" ] = "L Finger11"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger12" ] = "L Finger12"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger2" ] = "L Finger2"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger21" ] = "L Finger21"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger22" ] = "L Finger22"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger3" ] = "L Finger3"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger31" ] = "L Finger31"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger32" ] = "L Finger32"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger4" ] = "L Finger4"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger41" ] = "L Finger41"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_L_Finger42" ] = "L Finger42"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger0" ] = "R Finger0"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger01" ] = "R Finger01"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger02" ] = "R Finger02"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger1" ] = "R Finger1"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger11" ] = "R Finger11"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger12" ] = "R Finger12"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger2" ] = "R Finger2"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger21" ] = "R Finger21"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger22" ] = "R Finger22"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger3" ] = "R Finger3"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger31" ] = "R Finger31"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger32" ] = "R Finger32"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger4" ] = "R Finger4"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger41" ] = "R Finger41"
|
||||
TranslateTable_INS[ "ValveBiped.Bip01_R_Finger42" ] = "R Finger42"
|
||||
|
||||
local TranslateTable_Chell = {}
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger0" ] = "thumb_base_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger01" ] = "thumb_mid_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger02" ] = "thumb_end_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger1" ] = "index_base_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger11" ] = "index_mid_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger12" ] = "index_end_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger2" ] = "mid_base_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger21" ] = "mid_mid_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger22" ] = "mid_end_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger3" ] = "ring_base_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger31" ] = "ring_mid_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger32" ] = "ring_end_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger4" ] = "pinky_base_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger41" ] = "pinky_mid_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_L_Finger42" ] = "pinky_end_L"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger0" ] = "thumb_base_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger01" ] = "thumb_mid_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger02" ] = "thumb_end_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger1" ] = "index_base_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger11" ] = "index_mid_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger12" ] = "index_end_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger2" ] = "mid_base_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger21" ] = "mid_mid_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger22" ] = "mid_end_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger3" ] = "ring_base_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger31" ] = "ring_mid_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger32" ] = "ring_end_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger4" ] = "pinky_base_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger41" ] = "pinky_mid_R"
|
||||
TranslateTable_Chell[ "ValveBiped.Bip01_R_Finger42" ] = "pinky_end_R"
|
||||
|
||||
local TranslateTable_EggBot = {}
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_L_Finger0" ] = "thumb2_0_A_L"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_L_Finger01" ] = "thumb2_1_A_L"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_L_Finger02" ] = "thumb2_2_A_L"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_L_Finger1" ] = "index2_0_A_L"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_L_Finger11" ] = "index2_1_A_L"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_L_Finger12" ] = "index2_2_A_L"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_L_Finger2" ] = "mid2_0_A_L"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_L_Finger21" ] = "mid2_1_A_L"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_L_Finger22" ] = "mid2_2_A_L"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_R_Finger0" ] = "thumb3_0_A_R"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_R_Finger01" ] = "thumb3_1_A_R"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_R_Finger02" ] = "thumb3_2_A_R"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_R_Finger1" ] = "index3_0_A_R"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_R_Finger11" ] = "index3_1_A_R"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_R_Finger12" ] = "index3_2_A_R"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_R_Finger2" ] = "mid3_0_A_R"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_R_Finger21" ] = "mid3_1_A_R"
|
||||
TranslateTable_EggBot[ "ValveBiped.Bip01_R_Finger22" ] = "mid3_2_A_R"
|
||||
|
||||
local TranslateTable_Poral2 = {}
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger0" ] = "thumb_0_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger01" ] = "thumb_1_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger02" ] = "thumb_2_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger1" ] = "index_0_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger11" ] = "index_1_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger12" ] = "index_2_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger2" ] = "mid_0_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger21" ] = "mid_1_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger22" ] = "mid_2_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger3" ] = "ring_0_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger31" ] = "ring_1_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_L_Finger32" ] = "ring_2_L"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger0" ] = "thumb_0_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger01" ] = "thumb_1_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger02" ] = "thumb_2_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger1" ] = "index_0_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger11" ] = "index_1_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger12" ] = "index_2_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger2" ] = "mid_0_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger21" ] = "mid_1_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger22" ] = "mid_2_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger3" ] = "ring_0_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger31" ] = "ring_1_R"
|
||||
TranslateTable_Poral2[ "ValveBiped.Bip01_R_Finger32" ] = "ring_2_R"
|
||||
|
||||
local TranslateTable_DOG = {}
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_L_Finger0" ] = "Dog_Model.Thumb1_L"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_L_Finger01" ] = "Dog_Model.Thumb2_L"
|
||||
--TranslateTable_DOG[ "ValveBiped.Bip01_L_Finger02" ] = "Dog_Model.Thumb3_L"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_L_Finger1" ] = "Dog_Model.Index1_L"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_L_Finger11" ] = "Dog_Model.Index2_L"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_L_Finger12" ] = "Dog_Model.Index3_L"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_L_Finger4" ] = "Dog_Model.Pinky1_L"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_L_Finger41" ] = "Dog_Model.Pinky2_L"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_L_Finger42" ] = "Dog_Model.Pinky3_L"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_R_Finger0" ] = "Dog_Model.Thumb1_R"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_R_Finger01" ] = "Dog_Model.Thumb2_R"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_R_Finger02" ] = "Dog_Model.Thumb3_R"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_R_Finger1" ] = "Dog_Model.Index1_R"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_R_Finger11" ] = "Dog_Model.Index2_R"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_R_Finger12" ] = "Dog_Model.Index3_R"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_R_Finger4" ] = "Dog_Model.Pinky1_R"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_R_Finger41" ] = "Dog_Model.Pinky2_R"
|
||||
TranslateTable_DOG[ "ValveBiped.Bip01_R_Finger42" ] = "Dog_Model.Pinky3_R"
|
||||
|
||||
local TranslateTable_VORT = {}
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_L_Finger1" ] = "ValveBiped.index1_L"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_L_Finger11" ] = "ValveBiped.index2_L"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_L_Finger12" ] = "ValveBiped.index3_L"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_L_Finger4" ] = "ValveBiped.pinky1_L"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_L_Finger41" ] = "ValveBiped.pinky2_L"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_L_Finger42" ] = "ValveBiped.pinky3_L"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_R_Finger1" ] = "ValveBiped.index1_R"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_R_Finger11" ] = "ValveBiped.index2_R"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_R_Finger12" ] = "ValveBiped.index3_R"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_R_Finger4" ] = "ValveBiped.pinky1_R"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_R_Finger41" ] = "ValveBiped.pinky2_R"
|
||||
TranslateTable_VORT[ "ValveBiped.Bip01_R_Finger42" ] = "ValveBiped.pinky3_R"
|
||||
|
||||
function TOOL:HandEntity()
|
||||
return self:GetWeapon():GetNWEntity( "HandEntity" )
|
||||
end
|
||||
|
||||
function TOOL:HandNum()
|
||||
return self:GetWeapon():GetNWInt( "HandNum" )
|
||||
end
|
||||
|
||||
function TOOL:SetHand( ent, iHand )
|
||||
self:GetWeapon():SetNWEntity( "HandEntity", ent )
|
||||
self:GetWeapon():SetNWInt( "HandNum", iHand )
|
||||
end
|
||||
|
||||
-- Translate the fingernum, part and hand into an real bone number
|
||||
local function GetFingerBone( self, fingernum, part, hand )
|
||||
|
||||
---- START HL2 BONE LOOKUP ----------------------------------
|
||||
local Name = "ValveBiped.Bip01_L_Finger" .. fingernum
|
||||
if ( hand == 1 ) then Name = "ValveBiped.Bip01_R_Finger" .. fingernum end
|
||||
if ( part != 0 ) then Name = Name .. part end
|
||||
|
||||
local boneid = self:LookupBone( Name )
|
||||
if ( boneid ) then return boneid end
|
||||
---- END HL2 BONE LOOKUP ----------------------------------
|
||||
|
||||
---- START TF BONE LOOKUP ----------------------------------
|
||||
local TranslatedName = TranslateTable_TF2[ Name ]
|
||||
if ( TranslatedName ) then
|
||||
local bone = self:LookupBone( TranslatedName )
|
||||
if ( bone ) then return bone end
|
||||
end
|
||||
---- END TF BONE LOOKUP ----------------------------------
|
||||
|
||||
---- START Zeno BONE LOOKUP ----------------------------------
|
||||
TranslatedName = TranslateTable_Zeno[ Name ]
|
||||
if ( TranslatedName ) then
|
||||
local bone = self:LookupBone( TranslatedName )
|
||||
if ( bone ) then return bone end
|
||||
end
|
||||
---- END Zeno BONE LOOKUP ----------------------------------
|
||||
|
||||
---- START DOG BONE LOOKUP ----------------------------------
|
||||
TranslatedName = TranslateTable_DOG[ Name ]
|
||||
if ( TranslatedName ) then
|
||||
local bone = self:LookupBone( TranslatedName )
|
||||
if ( bone ) then return bone end
|
||||
end
|
||||
---- END DOG BONE LOOKUP ----------------------------------
|
||||
|
||||
---- START VORT BONE LOOKUP ----------------------------------
|
||||
TranslatedName = TranslateTable_VORT[ Name ]
|
||||
if ( TranslatedName ) then
|
||||
local bone = self:LookupBone( TranslatedName )
|
||||
if ( bone ) then return bone end
|
||||
end
|
||||
---- END VORT BONE LOOKUP ----------------------------------
|
||||
|
||||
---- START Chell BONE LOOKUP ----------------------------------
|
||||
TranslatedName = TranslateTable_Chell[ Name ]
|
||||
if ( TranslatedName ) then
|
||||
local bone = self:LookupBone( TranslatedName )
|
||||
if ( bone ) then return bone end
|
||||
end
|
||||
---- END Chell BONE LOOKUP ----------------------------------
|
||||
|
||||
---- START EggBot ( Portal 2 ) BONE LOOKUP ----------------------------------
|
||||
TranslatedName = TranslateTable_EggBot[ Name ]
|
||||
if ( TranslatedName ) then
|
||||
local bone = self:LookupBone( TranslatedName )
|
||||
if ( bone ) then return bone end
|
||||
end
|
||||
---- END EggBot BONE LOOKUP ----------------------------------
|
||||
|
||||
---- START Portal 2 ( Ball Bot ) BONE LOOKUP ----------------------------------
|
||||
TranslatedName = TranslateTable_Poral2[ Name ]
|
||||
if ( TranslatedName ) then
|
||||
local bone = self:LookupBone( TranslatedName )
|
||||
if ( bone ) then return bone end
|
||||
end
|
||||
---- END Portal 2 BONE LOOKUP ----------------------------------
|
||||
|
||||
---- START Ins BONE LOOKUP ----------------------------------
|
||||
TranslatedName = TranslateTable_INS[ Name ]
|
||||
if ( TranslatedName ) then
|
||||
local bone = self:LookupBone( TranslatedName )
|
||||
if ( bone ) then return bone end
|
||||
end
|
||||
---- END Insurgency BONE LOOKUP ----------------------------------
|
||||
|
||||
end
|
||||
|
||||
-- Cache the finger bone numbers for faster access
|
||||
local function SetupFingers( self )
|
||||
|
||||
if ( self.FingerIndex ) then return end
|
||||
|
||||
self.FingerIndex = {}
|
||||
|
||||
local i = 1
|
||||
|
||||
for hand = 0, 1 do
|
||||
for finger = 0, 4 do
|
||||
for part = 0, 2 do
|
||||
|
||||
self.FingerIndex[ i ] = GetFingerBone( self, finger, part, hand )
|
||||
|
||||
i = i + 1
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Apply the current tool values to entity's hand
|
||||
function TOOL:ApplyValues( pEntity, iHand )
|
||||
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
SetupFingers( pEntity )
|
||||
|
||||
local bTF2 = HasTF2Hands( pEntity )
|
||||
local bP2 = HasP2Hands( pEntity )
|
||||
|
||||
for i = 0, VarsOnHand - 1 do
|
||||
|
||||
local Var = self:GetClientInfo( i )
|
||||
local VecComp = string.Explode( " ", Var )
|
||||
|
||||
local Ang = nil
|
||||
|
||||
if ( bP2 ) then
|
||||
if ( i < 3 ) then
|
||||
Ang = Angle( tonumber( VecComp[1] ), tonumber( VecComp[2] ), 0 )
|
||||
else
|
||||
Ang = Angle( -tonumber( VecComp[2] ), tonumber( VecComp[1] ), 0 )
|
||||
end
|
||||
|
||||
elseif ( bTF2 ) then
|
||||
|
||||
if ( i < 3 ) then
|
||||
Ang = Angle( 0, tonumber( VecComp[2] ), tonumber( VecComp[1] ) )
|
||||
else
|
||||
Ang = Angle( 0, tonumber( VecComp[1] ), -tonumber( VecComp[2] ) )
|
||||
end
|
||||
|
||||
else
|
||||
if ( i < 3 ) then
|
||||
Ang = Angle( tonumber( VecComp[2] ), tonumber( VecComp[1] ), 0 )
|
||||
else
|
||||
Ang = Angle( tonumber( VecComp[1] ), tonumber( VecComp[2] ), 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local bone = pEntity.FingerIndex[ i + iHand * VarsOnHand + 1 ]
|
||||
if ( bone ) then
|
||||
pEntity:ManipulateBoneAngles( bone, Ang )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Hope we don't have any one armed models
|
||||
function TOOL:GetHandPositions( pEntity )
|
||||
|
||||
local LeftHand = pEntity:LookupBone( "ValveBiped.Bip01_L_Hand" )
|
||||
if ( !LeftHand ) then LeftHand = pEntity:LookupBone( "bip_hand_L" ) end
|
||||
if ( !LeftHand ) then LeftHand = pEntity:LookupBone( "Bip01_L_Hand" ) end
|
||||
if ( !LeftHand ) then LeftHand = pEntity:LookupBone( "Dog_Model.Hand_L" ) end -- DOG
|
||||
if ( !LeftHand ) then LeftHand = pEntity:LookupBone( "ValveBiped.Hand1_L" ) end -- Vortigaunt
|
||||
if ( !LeftHand ) then LeftHand = pEntity:LookupBone( "wrist_L" ) end -- Chell
|
||||
if ( !LeftHand ) then LeftHand = pEntity:LookupBone( "L Hand" ) end -- Insurgency
|
||||
if ( !LeftHand ) then LeftHand = pEntity:LookupBone( "wrist_A_L" ) end -- Portal 2 Egg bot
|
||||
|
||||
local RightHand = pEntity:LookupBone( "ValveBiped.Bip01_R_Hand" )
|
||||
if ( !RightHand ) then RightHand = pEntity:LookupBone( "bip_hand_R" ) end
|
||||
if ( !RightHand ) then RightHand = pEntity:LookupBone( "Bip01_R_Hand" ) end
|
||||
if ( !RightHand ) then RightHand = pEntity:LookupBone( "Bip01_R_Hand" ) end
|
||||
if ( !RightHand ) then RightHand = pEntity:LookupBone( "Dog_Model.Hand_R" ) end
|
||||
if ( !RightHand ) then RightHand = pEntity:LookupBone( "ValveBiped.Hand1_R" ) end
|
||||
if ( !RightHand ) then RightHand = pEntity:LookupBone( "wrist_R" ) end
|
||||
if ( !RightHand ) then RightHand = pEntity:LookupBone( "R Hand" ) end
|
||||
if ( !RightHand ) then RightHand = pEntity:LookupBone( "wrist_A_R" ) end
|
||||
|
||||
if ( !LeftHand || !RightHand ) then return false end
|
||||
|
||||
local LeftHandMatrix = pEntity:GetBoneMatrix( LeftHand )
|
||||
local RightHandMatrix = pEntity:GetBoneMatrix( RightHand )
|
||||
if ( !LeftHandMatrix || !RightHandMatrix ) then return false end
|
||||
|
||||
return LeftHandMatrix, RightHandMatrix
|
||||
|
||||
end
|
||||
|
||||
-- Applies current convar hand to picked hand
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return false end
|
||||
--if ( trace.Entity:GetClass() != "prop_ragdoll" && !trace.Entity:IsNPC() ) then return false end
|
||||
|
||||
local LeftHandMatrix, RightHandMatrix = self:GetHandPositions( trace.Entity )
|
||||
|
||||
if ( !LeftHandMatrix ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local LeftHand = ( LeftHandMatrix:GetTranslation() - trace.HitPos ):Length()
|
||||
local RightHand = ( RightHandMatrix:GetTranslation() - trace.HitPos ):Length()
|
||||
|
||||
if ( LeftHand < RightHand ) then
|
||||
|
||||
self:ApplyValues( trace.Entity, 0 )
|
||||
|
||||
else
|
||||
|
||||
self:ApplyValues( trace.Entity, 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Selects picked hand and sucks off convars
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent ) && ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
||||
|
||||
if ( !IsValid( ent ) || ent:IsPlayer() ) then self:SetHand( NULL, 0 ) return true end
|
||||
--if ( ent:GetClass() != "prop_ragdoll" && ent:GetClass() != "prop_dynamic" && !ent:IsNPC() ) then return false end
|
||||
|
||||
if ( CLIENT ) then return false end
|
||||
|
||||
local LeftHandMatrix, RightHandMatrix = self:GetHandPositions( ent )
|
||||
if ( !LeftHandMatrix ) then return false end
|
||||
|
||||
local LeftHand = ( LeftHandMatrix:GetTranslation() - trace.HitPos ):Length()
|
||||
local RightHand = ( RightHandMatrix:GetTranslation() - trace.HitPos ):Length()
|
||||
|
||||
local Hand = 0
|
||||
if ( LeftHand < RightHand ) then
|
||||
|
||||
self:SetHand( ent, 0 )
|
||||
|
||||
else
|
||||
|
||||
self:SetHand( ent, 1 )
|
||||
Hand = 1
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Make sure entity has fingers set up!
|
||||
--
|
||||
SetupFingers( ent )
|
||||
|
||||
local bTF2 = HasTF2Hands( ent )
|
||||
|
||||
--
|
||||
-- Rwead the variables from the angles of the fingers, into our convars
|
||||
--
|
||||
for i = 0, VarsOnHand-1 do
|
||||
|
||||
local bone = ent.FingerIndex[ i + Hand * VarsOnHand + 1 ]
|
||||
if ( bone ) then
|
||||
|
||||
local Ang = ent:GetManipulateBoneAngles( bone )
|
||||
|
||||
if ( bTF2 ) then
|
||||
|
||||
if ( i < 3 ) then
|
||||
self:GetOwner():ConCommand( Format( "finger_%s %.1f %.1f", i, Ang.Roll, Ang.Yaw ) )
|
||||
else
|
||||
self:GetOwner():ConCommand( Format( "finger_%s %.1f %.1f", i, Ang.Yaw, -Ang.Roll ) )
|
||||
end
|
||||
else
|
||||
if ( i < 3 ) then
|
||||
self:GetOwner():ConCommand( Format( "finger_%s %.1f %.1f", i, Ang.Yaw, Ang.Pitch ) )
|
||||
else
|
||||
self:GetOwner():ConCommand( Format( "finger_%s %.1f %.1f", i, Ang.Pitch, Ang.Yaw ) )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- We don't want to send the finger poses to the client straight away
|
||||
-- because they will get the old poses that are currently in their convars
|
||||
-- We need to wait until they convars get updated with the sucked pose
|
||||
self.NextUpdate = CurTime() + 0.5
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
local OldHand = nil
|
||||
local OldEntity = nil
|
||||
local OldEntityValid = false
|
||||
|
||||
--[[
|
||||
Updates the selected entity with the values from the convars
|
||||
Also, on the client it rebuilds the control panel if we have
|
||||
selected a new entity or hand
|
||||
]]
|
||||
function TOOL:Think()
|
||||
|
||||
local selected = self:HandEntity()
|
||||
local hand = self:HandNum()
|
||||
|
||||
if ( self.NextUpdate && self.NextUpdate > CurTime() ) then return end
|
||||
|
||||
if ( CLIENT && ( OldHand != hand || OldEntity != selected || IsValid( selected ) != OldEntityValid ) ) then
|
||||
|
||||
OldHand = hand
|
||||
OldEntity = selected
|
||||
OldEntityValid = IsValid( selected )
|
||||
|
||||
self:RebuildControlPanel( self:HandEntity(), self:HandNum() )
|
||||
|
||||
end
|
||||
|
||||
if ( !IsValid( selected ) ) then return end
|
||||
if ( selected:IsWorld() ) then return end
|
||||
|
||||
self:ApplyValues( selected, hand )
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then return end
|
||||
-- Notice the return above.
|
||||
-- The rest of this file CLIENT ONLY.
|
||||
|
||||
for i = 0, VarsOnHand do
|
||||
TOOL.ClientConVar[ "" .. i ] = "0 0"
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel, ent, hand )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.finger.desc" } )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "finger", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
SetupFingers( ent )
|
||||
|
||||
if ( !ent.FingerIndex ) then return end
|
||||
|
||||
-- Detect mitten hands
|
||||
local NumVars = table.Count( ent.FingerIndex )
|
||||
|
||||
CPanel:AddControl( "fingerposer", { hand = hand, numvars = NumVars } )
|
||||
|
||||
CPanel:AddControl( "Checkbox", { Label = "#tool.finger.restrict_axis", Command = "finger_restrict" } )
|
||||
|
||||
end
|
||||
|
||||
local FacePoser = surface.GetTextureID( "gui/faceposer_indicator" )
|
||||
|
||||
-- Draw a circle around the selected hand
|
||||
function TOOL:DrawHUD()
|
||||
|
||||
if ( GetConVarNumber( "gmod_drawtooleffects" ) == 0 ) then return end
|
||||
|
||||
local selected = self:HandEntity()
|
||||
local hand = self:HandNum()
|
||||
|
||||
if ( !IsValid( selected ) ) then return end
|
||||
if ( selected:IsWorld() ) then return end
|
||||
|
||||
local lefthand, righthand = self:GetHandPositions( selected )
|
||||
|
||||
local BoneMatrix = lefthand
|
||||
if ( hand == 1 ) then BoneMatrix = righthand end
|
||||
if ( !BoneMatrix ) then return end
|
||||
|
||||
local vPos = BoneMatrix:GetTranslation()
|
||||
|
||||
local scrpos = vPos:ToScreen()
|
||||
if ( !scrpos.visible ) then return end
|
||||
|
||||
-- Work out the side distance to give a rough headsize box..
|
||||
local player_eyes = LocalPlayer():EyeAngles()
|
||||
local side = ( vPos + player_eyes:Right() * 20 ):ToScreen()
|
||||
local size = math.abs( side.x - scrpos.x )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetTexture( FacePoser )
|
||||
surface.DrawTexturedRect( scrpos.x - size, scrpos.y - size, size * 2, size * 2 )
|
||||
|
||||
end
|
||||
@@ -0,0 +1,251 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.hoverball.name"
|
||||
|
||||
TOOL.ClientConVar[ "keyup" ] = "46"
|
||||
TOOL.ClientConVar[ "keydn" ] = "43"
|
||||
TOOL.ClientConVar[ "keyon" ] = "40"
|
||||
TOOL.ClientConVar[ "speed" ] = "5"
|
||||
TOOL.ClientConVar[ "resistance" ] = "5"
|
||||
TOOL.ClientConVar[ "strength" ] = "10"
|
||||
TOOL.ClientConVar[ "model" ] = "models/dav0r/hoverball.mdl"
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
cleanup.Register( "hoverballs" )
|
||||
|
||||
local function IsValidHoverballModel( model )
|
||||
for mdl, _ in pairs( list.Get( "HoverballModels" ) ) do
|
||||
if ( mdl:lower() == model:lower() ) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( trace.Entity && trace.Entity:IsPlayer() ) then return false end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local model = self:GetClientInfo( "model" )
|
||||
local key_d = self:GetClientNumber( "keydn" )
|
||||
local key_u = self:GetClientNumber( "keyup" )
|
||||
local key_o = self:GetClientNumber( "keyon" )
|
||||
local speed = self:GetClientNumber( "speed" )
|
||||
local strength = math.Clamp( self:GetClientNumber( "strength" ), 0.1, 20 )
|
||||
local resistance = math.Clamp( self:GetClientNumber( "resistance" ), 0, 20 )
|
||||
|
||||
-- We shot an existing hoverball - just change its values
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:GetClass() == "gmod_hoverball" && trace.Entity:GetPlayer() == ply ) then
|
||||
|
||||
trace.Entity:SetSpeed( speed )
|
||||
trace.Entity:SetAirResistance( resistance )
|
||||
trace.Entity:SetStrength( strength )
|
||||
|
||||
numpad.Remove( trace.Entity.NumDown )
|
||||
numpad.Remove( trace.Entity.NumUp )
|
||||
numpad.Remove( trace.Entity.NumBackDown )
|
||||
numpad.Remove( trace.Entity.NumBackUp )
|
||||
numpad.Remove( trace.Entity.NumToggle )
|
||||
|
||||
trace.Entity.NumDown = numpad.OnDown( ply, key_u, "Hoverball_Up", trace.Entity, true )
|
||||
trace.Entity.NumUp = numpad.OnUp( ply, key_u, "Hoverball_Up", trace.Entity, false )
|
||||
|
||||
trace.Entity.NumBackDown = numpad.OnDown( ply, key_d, "Hoverball_Down", trace.Entity, true )
|
||||
trace.Entity.NumBackUp = numpad.OnUp( ply, key_d, "Hoverball_Down", trace.Entity, false )
|
||||
|
||||
trace.Entity.NumToggle = numpad.OnDown( ply, key_o, "Hoverball_Toggle", trace.Entity )
|
||||
|
||||
trace.Entity.key_u = key_u
|
||||
trace.Entity.key_d = key_d
|
||||
trace.Entity.key_o = key_o
|
||||
trace.Entity.speed = speed
|
||||
trace.Entity.strength = strength
|
||||
trace.Entity.resistance = resistance
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( !util.IsValidModel( model ) || !util.IsValidProp( model ) || !IsValidHoverballModel( model ) ) then return false end
|
||||
if ( !self:GetWeapon():CheckLimit( "hoverballs" ) ) then return false end
|
||||
|
||||
local ball = MakeHoverBall( ply, trace.HitPos, key_d, key_u, speed, resistance, strength, model, nil, nil, nil, nil, key_o )
|
||||
if ( !IsValid( ball ) ) then return false end
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch + 90
|
||||
ball:SetAngles( ang )
|
||||
|
||||
local CurPos = ball:GetPos()
|
||||
local NearestPoint = ball:NearestPoint( CurPos - ( trace.HitNormal * 512 ) )
|
||||
local Offset = CurPos - NearestPoint
|
||||
ball:SetPos( trace.HitPos + Offset )
|
||||
|
||||
undo.Create( "HoverBall" )
|
||||
undo.AddEntity( ball )
|
||||
|
||||
-- Don't weld to world
|
||||
if ( IsValid( trace.Entity ) ) then
|
||||
|
||||
local weld = constraint.Weld( ball, trace.Entity, 0, trace.PhysicsBone, 0, 0, true )
|
||||
if ( IsValid( weld ) ) then
|
||||
ply:AddCleanup( "hoverballs", weld )
|
||||
undo.AddEntity( weld )
|
||||
end
|
||||
|
||||
if ( IsValid( ball:GetPhysicsObject() ) ) then ball:GetPhysicsObject():EnableCollisions( false ) end
|
||||
ball:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
ball.nocollide = true
|
||||
|
||||
end
|
||||
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function MakeHoverBall( ply, Pos, key_d, key_u, speed, resistance, strength, model, Vel, aVel, frozen, nocollide, key_o, Data )
|
||||
|
||||
if ( IsValid( ply ) && !ply:CheckLimit( "hoverballs" ) ) then return false end
|
||||
if ( !IsValidHoverballModel( model ) ) then return false end
|
||||
|
||||
local ball = ents.Create( "gmod_hoverball" )
|
||||
if ( !IsValid( ball ) ) then return false end
|
||||
|
||||
duplicator.DoGeneric( ball, Data )
|
||||
ball:SetPos( Pos ) -- Backwards compatible for addons directly calling this function
|
||||
ball:SetModel( model )
|
||||
ball:Spawn()
|
||||
|
||||
DoPropSpawnedEffect( ball )
|
||||
duplicator.DoGenericPhysics( ball, ply, Data )
|
||||
|
||||
ball:SetSpeed( speed )
|
||||
ball:SetAirResistance( resistance )
|
||||
ball:SetStrength( strength )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ball:SetPlayer( ply )
|
||||
end
|
||||
|
||||
ball.NumDown = numpad.OnDown( ply, key_u, "Hoverball_Up", ball, true )
|
||||
ball.NumUp = numpad.OnUp( ply, key_u, "Hoverball_Up", ball, false )
|
||||
|
||||
ball.NumBackDown = numpad.OnDown( ply, key_d, "Hoverball_Down", ball, true )
|
||||
ball.NumBackUp = numpad.OnUp( ply, key_d, "Hoverball_Down", ball, false )
|
||||
|
||||
if ( key_o ) then ball.NumToggle = numpad.OnDown( ply, key_o, "Hoverball_Toggle", ball ) end
|
||||
|
||||
if ( nocollide == true ) then
|
||||
if ( IsValid( ball:GetPhysicsObject() ) ) then ball:GetPhysicsObject():EnableCollisions( false ) end
|
||||
ball:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
end
|
||||
|
||||
local ttable = {
|
||||
key_d = key_d,
|
||||
key_u = key_u,
|
||||
key_o = key_o,
|
||||
pl = ply,
|
||||
nocollide = nocollide,
|
||||
speed = speed,
|
||||
strength = strength,
|
||||
resistance = resistance,
|
||||
model = model
|
||||
}
|
||||
|
||||
table.Merge( ball:GetTable(), ttable )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "hoverballs", ball )
|
||||
ply:AddCleanup( "hoverballs", ball )
|
||||
end
|
||||
|
||||
return ball
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityClass( "gmod_hoverball", MakeHoverBall, "Pos", "key_d", "key_u", "speed", "resistance", "strength", "model", "Vel", "aVel", "frozen", "nocollide", "key_o", "Data" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostHoverball( ent, ply )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
if ( !trace.Hit || IsValid( trace.Entity ) && ( trace.Entity:GetClass() == "gmod_hoverball" || trace.Entity:IsPlayer() ) ) then
|
||||
|
||||
ent:SetNoDraw( true )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch + 90
|
||||
ent:SetAngles( ang )
|
||||
|
||||
local CurPos = ent:GetPos()
|
||||
local NearestPoint = ent:NearestPoint( CurPos - ( trace.HitNormal * 512 ) )
|
||||
local Offset = CurPos - NearestPoint
|
||||
ent:SetPos( trace.HitPos + Offset )
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
local mdl = self:GetClientInfo( "model" )
|
||||
if ( !IsValidHoverballModel( mdl ) ) then self:ReleaseGhostEntity() return end
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) || self.GhostEntity:GetModel() != mdl ) then
|
||||
self:MakeGhostEntity( mdl, vector_origin, angle_zero )
|
||||
end
|
||||
|
||||
self:UpdateGhostHoverball( self.GhostEntity, self:GetOwner() )
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.hoverball.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "hoverball", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.hoverball.up", Command = "hoverball_keyup", Label2 = "#tool.hoverball.down", Command2 = "hoverball_keydn" } )
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.toggle", Command = "hoverball_keyon" } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.hoverball.speed", Command = "hoverball_speed", Type = "Float", Min = 0, Max = 20, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.hoverball.resistance", Command = "hoverball_resistance", Type = "Float", Min = 0, Max = 10, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.hoverball.strength", Command = "hoverball_strength", Type = "Float", Min = 0.1, Max = 10, Help = true } )
|
||||
|
||||
CPanel:AddControl( "PropSelect", { Label = "#tool.hoverball.model", ConVar = "hoverball_model", Models = list.Get( "HoverballModels" ), Height = 0 } )
|
||||
|
||||
end
|
||||
|
||||
list.Set( "HoverballModels", "models/dav0r/hoverball.mdl", {} )
|
||||
list.Set( "HoverballModels", "models/maxofs2d/hover_basic.mdl", {} )
|
||||
list.Set( "HoverballModels", "models/maxofs2d/hover_classic.mdl", {} )
|
||||
list.Set( "HoverballModels", "models/maxofs2d/hover_plate.mdl", {} )
|
||||
list.Set( "HoverballModels", "models/maxofs2d/hover_propeller.mdl", {} )
|
||||
list.Set( "HoverballModels", "models/maxofs2d/hover_rings.mdl", {} )
|
||||
@@ -0,0 +1,241 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.hydraulic.name"
|
||||
|
||||
TOOL.ClientConVar[ "group" ] = "37"
|
||||
TOOL.ClientConVar[ "width" ] = "3"
|
||||
TOOL.ClientConVar[ "addlength" ] = "100"
|
||||
TOOL.ClientConVar[ "fixed" ] = "1"
|
||||
TOOL.ClientConVar[ "speed" ] = "64"
|
||||
TOOL.ClientConVar[ "toggle" ] = "1"
|
||||
TOOL.ClientConVar[ "material" ] = "cable/rope"
|
||||
TOOL.ClientConVar[ "color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "color_g" ] = "255"
|
||||
TOOL.ClientConVar[ "color_b" ] = "255"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1, op = 1 },
|
||||
{ name = "right", stage = 0 },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return false end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
self:SetOperation( 1 )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
if ( ( !IsValid( self:GetEnt( 1 ) ) && !IsValid( self:GetEnt( 2 ) ) ) || iNum > 1 ) then
|
||||
|
||||
self:ClearObjects()
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local width = self:GetClientNumber( "width", 3 )
|
||||
local bind = self:GetClientNumber( "group", 1 )
|
||||
local AddLength = self:GetClientNumber( "addlength", 0 )
|
||||
local fixed = self:GetClientNumber( "fixed", 1 )
|
||||
local speed = self:GetClientNumber( "speed", 64 )
|
||||
local material = self:GetClientInfo( "material" )
|
||||
local toggle = self:GetClientNumber( "toggle" ) != 0
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
local WPos1, WPos2 = self:GetPos( 1 ), self:GetPos( 2 )
|
||||
|
||||
local Length1 = ( WPos1 - WPos2 ):Length()
|
||||
local Length2 = Length1 + AddLength
|
||||
|
||||
local constr, rope, controller, slider = constraint.Hydraulic( self:GetOwner(), Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, Length1, Length2, width, bind, fixed, speed, material, toggle, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Hydraulic" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope ) ) then undo.AddEntity( rope ) end
|
||||
if ( IsValid( slider ) ) then undo.AddEntity( slider ) end
|
||||
if ( IsValid( controller ) ) then undo.AddEntity( controller ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope ) end
|
||||
if ( IsValid( slider ) ) then self:GetOwner():AddCleanup( "ropeconstraints", slider ) end
|
||||
if ( IsValid( controller ) ) then self:GetOwner():AddCleanup( "ropeconstraints", controller ) end
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( self:GetOperation() == 1 ) then return false end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
local tr_new = {}
|
||||
tr_new.start = trace.HitPos
|
||||
tr_new.endpos = trace.HitPos + ( trace.HitNormal * 16384 )
|
||||
tr_new.filter = { self:GetOwner() }
|
||||
if ( IsValid( trace.Entity ) ) then
|
||||
table.insert( tr_new.filter, trace.Entity )
|
||||
end
|
||||
|
||||
local tr = util.TraceLine( tr_new )
|
||||
if ( !tr.Hit ) then
|
||||
self:ClearObjects()
|
||||
return
|
||||
end
|
||||
|
||||
-- Don't try to constrain world to world
|
||||
if ( trace.HitWorld && tr.HitWorld ) then
|
||||
self:ClearObjects()
|
||||
return
|
||||
end
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then
|
||||
self:ClearObjects()
|
||||
return
|
||||
end
|
||||
|
||||
if ( IsValid( tr.Entity ) && tr.Entity:IsPlayer() ) then
|
||||
self:ClearObjects()
|
||||
return
|
||||
end
|
||||
|
||||
-- Check to see if the player can create a hydraulic constraint with the entity in the trace
|
||||
if ( !hook.Run( "CanTool", self:GetOwner(), tr, "hydraulic", self, 2 ) ) then
|
||||
self:ClearObjects()
|
||||
return
|
||||
end
|
||||
|
||||
local Phys2 = tr.Entity:GetPhysicsObjectNum( tr.PhysicsBone )
|
||||
self:SetObject( 2, tr.Entity, tr.HitPos, Phys2, tr.PhysicsBone, tr.HitNormal )
|
||||
|
||||
if ( CLIENT ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local width = self:GetClientNumber( "width", 3 )
|
||||
local bind = self:GetClientNumber( "group", 1 )
|
||||
local AddLength = self:GetClientNumber( "addlength", 0 )
|
||||
local fixed = self:GetClientNumber( "fixed", 1 )
|
||||
local speed = self:GetClientNumber( "speed", 64 )
|
||||
local material = self:GetClientInfo( "material" )
|
||||
local toggle = self:GetClientNumber( "toggle" ) != 0
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
local WPos1, WPos2 = self:GetPos( 1 ), self:GetPos( 2 )
|
||||
|
||||
local Length1 = ( WPos1 - WPos2 ):Length()
|
||||
local Length2 = Length1 + AddLength
|
||||
|
||||
local constr, rope, controller, slider = constraint.Hydraulic( self:GetOwner(), Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, Length1, Length2, width, bind, fixed, speed, material, toggle, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Hydraulic" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope ) ) then undo.AddEntity( rope ) end
|
||||
if ( IsValid( slider ) ) then undo.AddEntity( slider ) end
|
||||
if ( IsValid( controller ) ) then undo.AddEntity( controller ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope ) end
|
||||
if ( IsValid( slider ) ) then self:GetOwner():AddCleanup( "ropeconstraints", slider ) end
|
||||
if ( IsValid( controller ) ) then self:GetOwner():AddCleanup( "ropeconstraints", controller ) end
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Hydraulic" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.hydraulic.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "hydraulic", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.hydraulic.controls", Command = "hydraulic_group" } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.hydraulic.addlength", Command = "hydraulic_addlength", Type = "Float", Min = -1000, Max = 1000, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.hydraulic.speed", Command = "hydraulic_speed", Type = "Float", Min = 0, Max = 50, Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.hydraulic.fixed", Command = "hydraulic_fixed", Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.toggle", Command = "hydraulic_toggle", Help = true } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.hydraulic.width", Command = "hydraulic_width", Type = "Float", Min = 0, Max = 5 } )
|
||||
CPanel:AddControl( "RopeMaterial", { Label = "#tool.hydraulic.material", ConVar = "hydraulic_material" } )
|
||||
CPanel:AddControl( "Color", { Label = "#tool.hydraulic.color", Red = "hydraulic_color_r", Green = "hydraulic_color_g", Blue = "hydraulic_color_b" } )
|
||||
|
||||
end
|
||||
157
gamemodes/sandbox/entities/weapons/gmod_tool/stools/inflator.lua
Normal file
157
gamemodes/sandbox/entities/weapons/gmod_tool/stools/inflator.lua
Normal file
@@ -0,0 +1,157 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Poser"
|
||||
TOOL.Name = "#tool.inflator.name"
|
||||
|
||||
TOOL.LeftClickAutomatic = true
|
||||
TOOL.RightClickAutomatic = true
|
||||
TOOL.RequiresTraceHit = true
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
local ScaleYZ = {
|
||||
"ValveBiped.Bip01_L_UpperArm",
|
||||
"ValveBiped.Bip01_L_Forearm",
|
||||
"ValveBiped.Bip01_L_Thigh",
|
||||
"ValveBiped.Bip01_L_Calf",
|
||||
"ValveBiped.Bip01_R_UpperArm",
|
||||
"ValveBiped.Bip01_R_Forearm",
|
||||
"ValveBiped.Bip01_R_Thigh",
|
||||
"ValveBiped.Bip01_R_Calf",
|
||||
"ValveBiped.Bip01_Spine2",
|
||||
"ValveBiped.Bip01_Spine1",
|
||||
"ValveBiped.Bip01_Spine",
|
||||
"ValveBiped.Bip01_Spinebut",
|
||||
|
||||
-- Vortigaunt
|
||||
"ValveBiped.spine4",
|
||||
"ValveBiped.spine3",
|
||||
"ValveBiped.spine2",
|
||||
"ValveBiped.spine1",
|
||||
"ValveBiped.hlp_ulna_R",
|
||||
"ValveBiped.hlp_ulna_L",
|
||||
"ValveBiped.arm1_L",
|
||||
"ValveBiped.arm1_R",
|
||||
"ValveBiped.arm2_L",
|
||||
"ValveBiped.arm2_R",
|
||||
"ValveBiped.leg_bone1_L",
|
||||
"ValveBiped.leg_bone1_R",
|
||||
"ValveBiped.leg_bone2_L",
|
||||
"ValveBiped.leg_bone2_R",
|
||||
"ValveBiped.leg_bone3_L",
|
||||
"ValveBiped.leg_bone3_R",
|
||||
|
||||
-- Team Fortress 2
|
||||
"bip_knee_L",
|
||||
"bip_knee_R",
|
||||
"bip_hip_R",
|
||||
"bip_hip_L",
|
||||
}
|
||||
|
||||
local ScaleXZ = {
|
||||
"ValveBiped.Bip01_pelvis",
|
||||
|
||||
-- Team Fortress 2
|
||||
"bip_upperArm_L",
|
||||
"bip_upperArm_R",
|
||||
"bip_lowerArm_L",
|
||||
"bip_lowerArm_R",
|
||||
"bip_forearm_L",
|
||||
"bip_forearm_R",
|
||||
}
|
||||
|
||||
local function GetNiceBoneScale( name, scale )
|
||||
|
||||
if ( table.HasValue( ScaleYZ, name ) or string.find( name:lower(), "leg" ) or string.find( name:lower(), "arm" ) ) then
|
||||
return Vector( 0, scale, scale )
|
||||
end
|
||||
|
||||
if ( table.HasValue( ScaleXZ, name ) ) then
|
||||
return Vector( scale, 0, scale )
|
||||
end
|
||||
|
||||
return Vector( scale, scale, scale )
|
||||
|
||||
end
|
||||
|
||||
--Scale the specified bone by Scale
|
||||
local function ScaleBone( ent, bone, scale )
|
||||
|
||||
if ( !bone or CLIENT ) then return false end
|
||||
|
||||
local physBone = ent:TranslateBoneToPhysBone( bone )
|
||||
for i = 0, ent:GetBoneCount() do
|
||||
if ( ent:TranslateBoneToPhysBone( i ) != physBone ) then continue end
|
||||
|
||||
-- Some bones are scaled only in certain directions (like legs don't scale on length)
|
||||
local v = GetNiceBoneScale( ent:GetBoneName( i ), scale ) * 0.1
|
||||
local TargetScale = ent:GetManipulateBoneScale( i ) + v * 0.1
|
||||
|
||||
if ( TargetScale.x < 0 ) then TargetScale.x = 0 end
|
||||
if ( TargetScale.y < 0 ) then TargetScale.y = 0 end
|
||||
if ( TargetScale.z < 0 ) then TargetScale.z = 0 end
|
||||
|
||||
ent:ManipulateBoneScale( i, TargetScale )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--Scale UP
|
||||
function TOOL:LeftClick( trace, scale )
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return false end
|
||||
if ( !trace.Entity:IsNPC() and trace.Entity:GetClass() != "prop_ragdoll" /*&& !trace.Entity:IsPlayer()*/ ) then return false end
|
||||
|
||||
local bone = trace.Entity:TranslatePhysBoneToBone( trace.PhysicsBone )
|
||||
ScaleBone( trace.Entity, bone, scale or 1 )
|
||||
self:GetWeapon():SetNextPrimaryFire( CurTime() + 0.01 )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( trace.HitPos )
|
||||
util.Effect( "inflator_magic", effectdata )
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
-- Scale DOWN
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
return self:LeftClick( trace, -1 )
|
||||
|
||||
end
|
||||
|
||||
-- Reset scaling
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return false end
|
||||
if ( !trace.Entity:IsNPC() and trace.Entity:GetClass() != "prop_ragdoll" /*&& !trace.Entity:IsPlayer()*/ ) then return false end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
for i = 0, trace.Entity:GetBoneCount() do
|
||||
trace.Entity:ManipulateBoneScale( i, Vector( 1, 1, 1 ) )
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.inflator.desc" } )
|
||||
|
||||
end
|
||||
299
gamemodes/sandbox/entities/weapons/gmod_tool/stools/lamp.lua
Normal file
299
gamemodes/sandbox/entities/weapons/gmod_tool/stools/lamp.lua
Normal file
@@ -0,0 +1,299 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.lamp.name"
|
||||
|
||||
TOOL.ClientConVar[ "r" ] = "255"
|
||||
TOOL.ClientConVar[ "g" ] = "255"
|
||||
TOOL.ClientConVar[ "b" ] = "255"
|
||||
TOOL.ClientConVar[ "key" ] = "37"
|
||||
TOOL.ClientConVar[ "fov" ] = "90"
|
||||
TOOL.ClientConVar[ "distance" ] = "1024"
|
||||
TOOL.ClientConVar[ "brightness" ] = "4"
|
||||
TOOL.ClientConVar[ "texture" ] = "effects/flashlight001"
|
||||
TOOL.ClientConVar[ "model" ] = "models/lamps/torch.mdl"
|
||||
TOOL.ClientConVar[ "toggle" ] = "1"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" },
|
||||
}
|
||||
|
||||
cleanup.Register( "lamps" )
|
||||
|
||||
local function IsValidLampModel( model )
|
||||
for mdl, _ in pairs( list.Get( "LampModels" ) ) do
|
||||
if ( mdl:lower() == model:lower() ) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) and trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local pos = trace.HitPos
|
||||
|
||||
local r = math.Clamp( self:GetClientNumber( "r" ), 0, 255 )
|
||||
local g = math.Clamp( self:GetClientNumber( "g" ), 0, 255 )
|
||||
local b = math.Clamp( self:GetClientNumber( "b" ), 0, 255 )
|
||||
local key = self:GetClientNumber( "key" )
|
||||
local mdl = self:GetClientInfo( "model" )
|
||||
local fov = self:GetClientNumber( "fov" )
|
||||
local distance = self:GetClientNumber( "distance" )
|
||||
local bright = self:GetClientNumber( "brightness" )
|
||||
local toggle = self:GetClientNumber( "toggle" ) != 1
|
||||
|
||||
local tex = self:GetClientInfo( "texture" )
|
||||
local mat = Material( tex )
|
||||
local texture = mat:GetString( "$basetexture" )
|
||||
|
||||
if ( IsValid( trace.Entity ) and trace.Entity:GetClass() == "gmod_lamp" and trace.Entity:GetPlayer() == ply ) then
|
||||
|
||||
trace.Entity:SetColor( Color( r, g, b, 255 ) )
|
||||
trace.Entity:SetFlashlightTexture( texture )
|
||||
trace.Entity:SetLightFOV( fov )
|
||||
trace.Entity:SetDistance( distance )
|
||||
trace.Entity:SetBrightness( bright )
|
||||
trace.Entity:SetToggle( !toggle )
|
||||
trace.Entity:UpdateLight()
|
||||
|
||||
numpad.Remove( trace.Entity.NumDown )
|
||||
numpad.Remove( trace.Entity.NumUp )
|
||||
|
||||
trace.Entity.NumDown = numpad.OnDown( ply, key, "LampToggle", trace.Entity, 1 )
|
||||
trace.Entity.NumUp = numpad.OnUp( ply, key, "LampToggle", trace.Entity, 0 )
|
||||
|
||||
-- For duplicator
|
||||
trace.Entity.Texture = texture
|
||||
trace.Entity.fov = fov
|
||||
trace.Entity.distance = distance
|
||||
trace.Entity.r = r
|
||||
trace.Entity.g = g
|
||||
trace.Entity.b = b
|
||||
trace.Entity.brightness = bright
|
||||
trace.Entity.KeyDown = key
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( !util.IsValidModel( mdl ) or !util.IsValidProp( mdl ) or !IsValidLampModel( mdl ) ) then return false end
|
||||
if ( !self:GetWeapon():CheckLimit( "lamps" ) ) then return false end
|
||||
|
||||
local lamp = MakeLamp( ply, r, g, b, key, toggle, texture, mdl, fov, distance, bright, !toggle, { Pos = pos, Angle = angle_zero } )
|
||||
if ( !IsValid( lamp ) ) then return false end
|
||||
|
||||
local CurPos = lamp:GetPos()
|
||||
local NearestPoint = lamp:NearestPoint( CurPos - ( trace.HitNormal * 512 ) )
|
||||
local LampOffset = CurPos - NearestPoint
|
||||
|
||||
lamp:SetPos( trace.HitPos + LampOffset )
|
||||
|
||||
undo.Create( "Lamp" )
|
||||
undo.AddEntity( lamp )
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) or trace.Entity:GetClass() != "gmod_lamp" ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ent = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
|
||||
ply:ConCommand( "lamp_fov " .. ent:GetLightFOV() )
|
||||
ply:ConCommand( "lamp_distance " .. ent:GetDistance() )
|
||||
ply:ConCommand( "lamp_brightness " .. ent:GetBrightness() )
|
||||
ply:ConCommand( "lamp_texture " .. ent:GetFlashlightTexture() )
|
||||
|
||||
if ( ent:GetToggle() ) then
|
||||
ply:ConCommand( "lamp_toggle 1" )
|
||||
else
|
||||
ply:ConCommand( "lamp_toggle 0" )
|
||||
end
|
||||
|
||||
local clr = ent:GetColor()
|
||||
ply:ConCommand( "lamp_r " .. clr.r )
|
||||
ply:ConCommand( "lamp_g " .. clr.g )
|
||||
ply:ConCommand( "lamp_b " .. clr.b )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function MakeLamp( ply, r, g, b, KeyDown, toggle, texture, model, fov, distance, brightness, on, Data )
|
||||
|
||||
if ( IsValid( ply ) and !ply:CheckLimit( "lamps" ) ) then return false end
|
||||
if ( !IsValidLampModel( model ) ) then return false end
|
||||
|
||||
local lamp = ents.Create( "gmod_lamp" )
|
||||
if ( !IsValid( lamp ) ) then return false end
|
||||
|
||||
duplicator.DoGeneric( lamp, Data )
|
||||
lamp:SetModel( model ) -- Backwards compatible for addons directly calling this function
|
||||
lamp:SetFlashlightTexture( texture )
|
||||
lamp:SetLightFOV( fov )
|
||||
lamp:SetColor( Color( r, g, b, 255 ) )
|
||||
lamp:SetDistance( distance )
|
||||
lamp:SetBrightness( brightness )
|
||||
lamp:Switch( on )
|
||||
lamp:SetToggle( !toggle )
|
||||
|
||||
lamp:Spawn()
|
||||
|
||||
DoPropSpawnedEffect( lamp )
|
||||
|
||||
duplicator.DoGenericPhysics( lamp, ply, Data )
|
||||
|
||||
lamp:SetPlayer( ply )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "lamps", lamp )
|
||||
ply:AddCleanup( "lamps", lamp )
|
||||
end
|
||||
|
||||
lamp.Texture = texture
|
||||
lamp.KeyDown = KeyDown
|
||||
lamp.fov = fov
|
||||
lamp.distance = distance
|
||||
lamp.r = r
|
||||
lamp.g = g
|
||||
lamp.b = b
|
||||
lamp.brightness = brightness
|
||||
|
||||
lamp.NumDown = numpad.OnDown( ply, KeyDown, "LampToggle", lamp, 1 )
|
||||
lamp.NumUp = numpad.OnUp( ply, KeyDown, "LampToggle", lamp, 0 )
|
||||
|
||||
return lamp
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityClass( "gmod_lamp", MakeLamp, "r", "g", "b", "KeyDown", "Toggle", "Texture", "Model", "fov", "distance", "brightness", "on", "Data" )
|
||||
|
||||
numpad.Register( "LampToggle", function( ply, ent, onoff )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
if ( !ent:GetToggle() ) then ent:Switch( onoff == 1 ) return end
|
||||
|
||||
if ( numpad.FromButton() ) then
|
||||
|
||||
ent:Switch( onoff == 1 )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
if ( onoff == 0 ) then return end
|
||||
|
||||
return ent:Toggle()
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostLamp( ent, ply )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
if ( !trace.Hit or IsValid( trace.Entity ) and ( trace.Entity:IsPlayer() or trace.Entity:GetClass() == "gmod_lamp" ) ) then
|
||||
|
||||
ent:SetNoDraw( true )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
local CurPos = ent:GetPos()
|
||||
local NearestPoint = ent:NearestPoint( CurPos - ( trace.HitNormal * 512 ) )
|
||||
local LampOffset = CurPos - NearestPoint
|
||||
|
||||
ent:SetPos( trace.HitPos + LampOffset )
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
local mdl = self:GetClientInfo( "model" )
|
||||
if ( !IsValidLampModel( mdl ) ) then self:ReleaseGhostEntity() return end
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) or self.GhostEntity:GetModel() != mdl ) then
|
||||
self:MakeGhostEntity( mdl, vector_origin, angle_zero )
|
||||
end
|
||||
|
||||
self:UpdateGhostLamp( self.GhostEntity, self:GetOwner() )
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.lamp.desc" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "lamp", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.lamp.key", Command = "lamp_key" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.lamp.fov", Command = "lamp_fov", Type = "Float", Min = 10, Max = 170 } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.lamp.distance", Command = "lamp_distance", Min = 64, Max = 2048 } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.lamp.brightness", Command = "lamp_brightness", Type = "Float", Min = 0, Max = 8 } )
|
||||
|
||||
CPanel:AddControl( "Checkbox", { Label = "#tool.lamp.toggle", Command = "lamp_toggle" } )
|
||||
|
||||
CPanel:AddControl( "Color", { Label = "#tool.lamp.color", Red = "lamp_r", Green = "lamp_g", Blue = "lamp_b" } )
|
||||
|
||||
local MatSelect = CPanel:MatSelect( "lamp_texture", nil, false, 0.33, 0.33 )
|
||||
MatSelect.Height = 4
|
||||
|
||||
for k, v in pairs( list.Get( "LampTextures" ) ) do
|
||||
MatSelect:AddMaterial( v.Name or k, k )
|
||||
end
|
||||
|
||||
CPanel:AddControl( "PropSelect", { Label = "#tool.lamp.model", ConVar = "lamp_model", Height = 0, Models = list.Get( "LampModels" ) } )
|
||||
|
||||
end
|
||||
|
||||
list.Set( "LampTextures", "effects/flashlight001", { Name = "#lamptexture.default" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/slit", { Name = "#lamptexture.slit" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/circles", { Name = "#lamptexture.circles" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/window", { Name = "#lamptexture.window" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/logo", { Name = "#lamptexture.logo" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/gradient", { Name = "#lamptexture.gradient" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/bars", { Name = "#lamptexture.bars" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/tech", { Name = "#lamptexture.techdemo" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/soft", { Name = "#lamptexture.soft" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/hard", { Name = "#lamptexture.hard" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/caustics", { Name = "#lamptexture.caustics" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/square", { Name = "#lamptexture.square" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/camera", { Name = "#lamptexture.camera" } )
|
||||
list.Set( "LampTextures", "effects/flashlight/view", { Name = "#lamptexture.view" } )
|
||||
|
||||
list.Set( "LampModels", "models/lamps/torch.mdl", {} )
|
||||
list.Set( "LampModels", "models/maxofs2d/lamp_flashlight.mdl", { Offset = Vector( 8.5, 0, 0 ) } )
|
||||
list.Set( "LampModels", "models/maxofs2d/lamp_projector.mdl", { Offset = Vector( 8.5, 0, 0 ) } )
|
||||
list.Set( "LampModels", "models/props_wasteland/light_spotlight01_lamp.mdl", { Offset = Vector( 9, 0, 4 ), Skin = 1, Scale = 3 } )
|
||||
list.Set( "LampModels", "models/props_wasteland/light_spotlight02_lamp.mdl", { Offset = Vector( 5.5, 0, 0 ), Skin = 1 } )
|
||||
list.Set( "LampModels", "models/props_c17/light_decklight01_off.mdl", { Offset = Vector( 3, 0, 0 ), Skin = 1, Scale = 3 } )
|
||||
list.Set( "LampModels", "models/props_wasteland/prison_lamp001c.mdl", { Offset = Vector( 0, 0, -5 ), Angle = Angle( 90, 0, 0 ) } )
|
||||
|
||||
-- This works, but the ghost entity is invisible due to $alphatest...
|
||||
--list.Set( "LampModels", "models/props_c17/lamp_standard_off01.mdl", { Offset = Vector( 5.20, 0.25, 8 ), Angle = Angle( 90, 0, 0 ), NearZ = 6 } )
|
||||
@@ -0,0 +1,47 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.AddToMenu = false
|
||||
|
||||
--
|
||||
-- This tool is the most important aspect of Garry's Mod
|
||||
--
|
||||
|
||||
TOOL.LeftClickAutomatic = true
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
util.PrecacheSound( "ambient/wind/wind_hit2.wav" )
|
||||
self:GetOwner():EmitSound( "ambient/wind/wind_hit2.wav" )
|
||||
|
||||
if ( IsValid( trace.Entity ) and IsValid( trace.Entity:GetPhysicsObject() ) ) then
|
||||
|
||||
local phys = trace.Entity:GetPhysicsObject() -- The physics object
|
||||
local direction = trace.StartPos - trace.HitPos -- The direction of the force
|
||||
local force = 32 -- The ideal amount of force
|
||||
local distance = direction:Length() -- The distance the phys object is from the gun
|
||||
local maxdistance = 512 -- The max distance the gun should reach
|
||||
|
||||
-- Lessen the force from a distance
|
||||
local ratio = math.Clamp( 1 - ( distance / maxdistance ), 0, 1 )
|
||||
|
||||
-- Set up the 'real' force and the offset of the force
|
||||
local vForce = -direction * ( force * ratio )
|
||||
local vOffset = trace.HitPos
|
||||
|
||||
-- Apply it!
|
||||
phys:ApplyForceOffset( vForce, vOffset )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
243
gamemodes/sandbox/entities/weapons/gmod_tool/stools/light.lua
Normal file
243
gamemodes/sandbox/entities/weapons/gmod_tool/stools/light.lua
Normal file
@@ -0,0 +1,243 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.light.name"
|
||||
|
||||
TOOL.ClientConVar[ "ropelength" ] = "64"
|
||||
TOOL.ClientConVar[ "ropematerial" ] = "cable/rope"
|
||||
TOOL.ClientConVar[ "r" ] = "255"
|
||||
TOOL.ClientConVar[ "g" ] = "255"
|
||||
TOOL.ClientConVar[ "b" ] = "255"
|
||||
TOOL.ClientConVar[ "brightness" ] = "2"
|
||||
TOOL.ClientConVar[ "size" ] = "256"
|
||||
TOOL.ClientConVar[ "key" ] = "37"
|
||||
TOOL.ClientConVar[ "toggle" ] = "1"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" }
|
||||
}
|
||||
|
||||
cleanup.Register( "lights" )
|
||||
|
||||
function TOOL:LeftClick( trace, attach )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
if ( attach == nil ) then attach = true end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && attach && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local pos, ang = trace.HitPos + trace.HitNormal * 8, trace.HitNormal:Angle() - Angle( 90, 0, 0 )
|
||||
|
||||
local r = math.Clamp( self:GetClientNumber( "r" ), 0, 255 )
|
||||
local g = math.Clamp( self:GetClientNumber( "g" ), 0, 255 )
|
||||
local b = math.Clamp( self:GetClientNumber( "b" ), 0, 255 )
|
||||
local brght = math.Clamp( self:GetClientNumber( "brightness" ), -10, 20 )
|
||||
local size = self:GetClientNumber( "size" )
|
||||
local toggle = self:GetClientNumber( "toggle" ) != 1
|
||||
|
||||
local key = self:GetClientNumber( "key" )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:GetClass() == "gmod_light" && trace.Entity:GetPlayer() == ply ) then
|
||||
|
||||
trace.Entity:SetColor( Color( r, g, b, 255 ) )
|
||||
trace.Entity.r = r
|
||||
trace.Entity.g = g
|
||||
trace.Entity.b = b
|
||||
trace.Entity.Brightness = brght
|
||||
trace.Entity.Size = size
|
||||
|
||||
trace.Entity:SetBrightness( brght )
|
||||
trace.Entity:SetLightSize( size )
|
||||
trace.Entity:SetToggle( !toggle )
|
||||
|
||||
trace.Entity.KeyDown = key
|
||||
|
||||
numpad.Remove( trace.Entity.NumDown )
|
||||
numpad.Remove( trace.Entity.NumUp )
|
||||
|
||||
trace.Entity.NumDown = numpad.OnDown( ply, key, "LightToggle", trace.Entity, 1 )
|
||||
trace.Entity.NumUp = numpad.OnUp( ply, key, "LightToggle", trace.Entity, 0 )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( !self:GetWeapon():CheckLimit( "lights" ) ) then return false end
|
||||
|
||||
local light = MakeLight( ply, r, g, b, brght, size, toggle, !toggle, key, { Pos = pos, Angle = ang } )
|
||||
if ( !IsValid( light ) ) then return false end
|
||||
|
||||
undo.Create( "Light" )
|
||||
undo.AddEntity( light )
|
||||
|
||||
if ( attach ) then
|
||||
|
||||
local length = math.Clamp( self:GetClientNumber( "ropelength" ), 4, 1024 )
|
||||
local material = self:GetClientInfo( "ropematerial" )
|
||||
|
||||
local LPos1 = Vector( 0, 0, 6.5 )
|
||||
local LPos2 = trace.Entity:WorldToLocal( trace.HitPos )
|
||||
|
||||
if ( IsValid( trace.Entity ) ) then
|
||||
|
||||
local phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
if ( IsValid( phys ) ) then
|
||||
LPos2 = phys:WorldToLocal( trace.HitPos )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local constr, rope = constraint.Rope( light, trace.Entity, 0, trace.PhysicsBone, LPos1, LPos2, 0, length, 0, 1, material )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.AddEntity( constr )
|
||||
ply:AddCleanup( "lights", constr )
|
||||
end
|
||||
if ( IsValid( rope ) ) then
|
||||
undo.AddEntity( rope )
|
||||
ply:AddCleanup( "lights", rope )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
return self:LeftClick( trace, false )
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function MakeLight( ply, r, g, b, brght, size, toggle, on, KeyDown, Data )
|
||||
|
||||
if ( IsValid( ply ) && !ply:CheckLimit( "lights" ) ) then return false end
|
||||
|
||||
local light = ents.Create( "gmod_light" )
|
||||
if ( !IsValid( light ) ) then return end
|
||||
|
||||
duplicator.DoGeneric( light, Data )
|
||||
|
||||
light:SetColor( Color( r, g, b, 255 ) )
|
||||
light:SetBrightness( brght )
|
||||
light:SetLightSize( size )
|
||||
light:SetToggle( !toggle )
|
||||
light:SetOn( on )
|
||||
|
||||
light:Spawn()
|
||||
|
||||
DoPropSpawnedEffect( light )
|
||||
|
||||
duplicator.DoGenericPhysics( light, ply, Data )
|
||||
|
||||
light:SetPlayer( ply )
|
||||
|
||||
light.lightr = r
|
||||
light.lightg = g
|
||||
light.lightb = b
|
||||
light.Brightness = brght
|
||||
light.Size = size
|
||||
light.KeyDown = KeyDown
|
||||
light.on = on
|
||||
|
||||
light.NumDown = numpad.OnDown( ply, KeyDown, "LightToggle", light, 1 )
|
||||
light.NumUp = numpad.OnUp( ply, KeyDown, "LightToggle", light, 0 )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "lights", light )
|
||||
ply:AddCleanup( "lights", light )
|
||||
end
|
||||
|
||||
return light
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityClass( "gmod_light", MakeLight, "lightr", "lightg", "lightb", "Brightness", "Size", "Toggle", "on", "KeyDown", "Data" )
|
||||
|
||||
local function Toggle( ply, ent, onoff )
|
||||
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
if ( !ent:GetToggle() ) then ent:SetOn( onoff == 1 ) return end
|
||||
|
||||
if ( numpad.FromButton() ) then
|
||||
|
||||
ent:SetOn( onoff == 1 )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
if ( onoff == 0 ) then return end
|
||||
|
||||
return ent:Toggle()
|
||||
|
||||
end
|
||||
numpad.Register( "LightToggle", Toggle )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostLight( ent, ply )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
if ( !trace.Hit || IsValid( trace.Entity ) && ( trace.Entity:IsPlayer() || trace.Entity:GetClass() == "gmod_light" ) ) then
|
||||
|
||||
ent:SetNoDraw( true )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
ent:SetPos( trace.HitPos + trace.HitNormal * 8 )
|
||||
ent:SetAngles( trace.HitNormal:Angle() - Angle( 90, 0, 0 ) )
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) || self.GhostEntity:GetModel() != "models/maxofs2d/light_tubular.mdl" ) then
|
||||
self:MakeGhostEntity( "models/maxofs2d/light_tubular.mdl", vector_origin, angle_zero )
|
||||
end
|
||||
|
||||
self:UpdateGhostLight( self.GhostEntity, self:GetOwner() )
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.light.desc" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "light", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.light.key", Command = "light_key", ButtonSize = 22 } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.light.ropelength", Command = "light_ropelength", Type = "Float", Min = 0, Max = 256 } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.light.brightness", Command = "light_brightness", Type = "Int", Min = -6, Max = 6 } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.light.size", Command = "light_size", Type = "Float", Min = 0, Max = 1024 } )
|
||||
|
||||
CPanel:AddControl( "Checkbox", { Label = "#tool.light.toggle", Command = "light_toggle" } )
|
||||
|
||||
CPanel:AddControl( "Color", { Label = "#tool.light.color", Red = "light_r", Green = "light_g", Blue = "light_b" } )
|
||||
|
||||
end
|
||||
@@ -0,0 +1,70 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "LVS"
|
||||
TOOL.Name = "#AI Enabler"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar[ "team" ] = "-1"
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.lvsaienabler.name", "AI Enabler" )
|
||||
language.Add( "tool.lvsaienabler.desc", "A tool used to enable/disable AI on LVS-Vehicles" )
|
||||
language.Add( "tool.lvsaienabler.0", "Left click on a LVS-Vehicle to enable AI, Right click to disable." )
|
||||
language.Add( "tool.lvsaienabler.1", "Left click on a LVS-Vehicle to enable AI, Right click to disable." )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not IsValid( ent ) then return false end
|
||||
|
||||
if not ent.LVS and not ent.LFS then return end
|
||||
|
||||
if isfunction( ent.SetAI ) then
|
||||
ent:SetAI( true )
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
local Team = self:GetClientNumber( "team" )
|
||||
|
||||
if Team ~= -1 then
|
||||
ent:SetAITEAM( math.Clamp( Team, 0, 3 ) )
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not IsValid( ent ) then return false end
|
||||
|
||||
if not ent.LVS and not ent.LFS then return end
|
||||
|
||||
if isfunction( ent.SetAI ) then
|
||||
ent:SetAI( false )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
CPanel:AddControl( "Header", { Text = "#tool.lvsaienabler.name", Description = "#tool.lvsaienabler.desc" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "TeamOverride", Type = "Int", Min = -1, Max = 3, Command = "lvsaienabler_team" } )
|
||||
end
|
||||
@@ -0,0 +1,127 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "LVS"
|
||||
TOOL.Name = "#tool.lvshealthshieldeditor.name"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar[ "maxshield" ] = 0
|
||||
TOOL.ClientConVar[ "maxhealth" ] = 5000
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.lvshealthshieldeditor.name", "Max Health & Shield Editor" )
|
||||
language.Add( "tool.lvshealthshieldeditor.desc", "A tool used to edit Max Health & Shield on LVS-Vehicles" )
|
||||
language.Add( "tool.lvshealthshieldeditor.0", "Left click on a LVS-Vehicle to set Max Health, Right click to set Max Shield, Reload to reset." )
|
||||
language.Add( "tool.lvshealthshieldeditor.1", "Left click on a LVS-Vehicle to set Max Health, Right click to set Max Shield, Reload to reset." )
|
||||
language.Add( "tool.lvshealthshieldeditor.maxshield", "Max Shield" )
|
||||
language.Add( "tool.lvshealthshieldeditor.maxhealth", "Max Health" )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not IsValid( ent ) then return false end
|
||||
|
||||
if not ent.LVS and not ent.LFS then return end
|
||||
|
||||
if not ent.OGMaxHealth then
|
||||
ent.OGMaxHealth = ent.MaxHealth
|
||||
end
|
||||
|
||||
ent.MaxHealth = self:GetClientNumber( "maxhealth" )
|
||||
ent:SetHP( ent.MaxHealth )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not IsValid( ent ) then return false end
|
||||
|
||||
if not ent.LVS and not ent.LFS then return end
|
||||
|
||||
if not ent.OGMaxShield then
|
||||
ent.OGMaxShield = ent.MaxShield
|
||||
end
|
||||
|
||||
ent.MaxShield = self:GetClientNumber( "maxshield" )
|
||||
ent:SetShield( ent.MaxShield )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not IsValid( ent ) then return false end
|
||||
|
||||
if not ent.LVS and not ent.LFS then return end
|
||||
|
||||
if ent.OGMaxHealth then
|
||||
ent.MaxHealth = ent.OGMaxHealth
|
||||
end
|
||||
|
||||
if ent.OGMaxShield then
|
||||
ent.MaxShield = ent.OGMaxShield
|
||||
end
|
||||
|
||||
ent:SetHP( ent.MaxHealth )
|
||||
ent:SetShield( ent.MaxShield )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
if SERVER then return end
|
||||
|
||||
local ply = LocalPlayer()
|
||||
local tr = ply:GetEyeTrace()
|
||||
|
||||
local ent = tr.Entity
|
||||
if not IsValid( ent ) then return end
|
||||
|
||||
if not ent.LVS and not ent.LFS then return end
|
||||
|
||||
local Text = "Health: "..tostring( math.Round( ent:GetHP(), 0 ) ).."/"..tostring( ent.MaxHealth )
|
||||
if ent:GetShield() > 0 then
|
||||
Text = Text.."\nShield: "..tostring( math.Round( ent:GetShield(), 0 ) ).."/"..tostring( ent.MaxShield )
|
||||
end
|
||||
|
||||
AddWorldTip( ent:EntIndex(), Text, SysTime() + 0.05, ent:GetPos(), ent )
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "Header", { Text = "#tool.lvshealthshieldeditor.name", Description = "#tool.lvshealthshieldeditor.desc" } )
|
||||
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "#tool.lvshealthshieldeditor.maxhealth",
|
||||
Type = "Int",
|
||||
Min = "1",
|
||||
Max = "50000",
|
||||
Command = "lvshealthshieldeditor_maxhealth",
|
||||
Help = false
|
||||
})
|
||||
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "#tool.lvshealthshieldeditor.maxshield",
|
||||
Type = "Int",
|
||||
Min = "0",
|
||||
Max = "50000",
|
||||
Command = "lvshealthshieldeditor_maxshield",
|
||||
Help = false
|
||||
})
|
||||
|
||||
panel:AddControl( "Label", { Text = "NOTE: Value in Edit-Properties menu will still be the same, because they can not be updated after the vehicle is spawned!" } )
|
||||
end
|
||||
@@ -0,0 +1,154 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "LVS"
|
||||
TOOL.Name = "#tool.lvsturret.name"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
cleanup.Register( "lvsturret" )
|
||||
CreateConVar("sbox_maxlvsturret", 1, "FCVAR_NOTIFY")
|
||||
|
||||
TOOL.ClientConVar[ "delay" ] = "0.05"
|
||||
TOOL.ClientConVar[ "damage" ] = "15"
|
||||
TOOL.ClientConVar[ "speed" ] = "30000"
|
||||
TOOL.ClientConVar[ "size" ] = "1"
|
||||
TOOL.ClientConVar[ "spread" ] = "0"
|
||||
TOOL.ClientConVar[ "penetration" ] = "10"
|
||||
TOOL.ClientConVar[ "splashdamage" ] = "0"
|
||||
TOOL.ClientConVar[ "splashradius" ] = "0"
|
||||
TOOL.ClientConVar[ "tracer" ] = "lvs_tracer_orange"
|
||||
TOOL.ClientConVar[ "splasheffect" ] = "lvs_bullet_impact"
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.lvsturret.name", "Projectile Turret" )
|
||||
language.Add( "tool.lvsturret.desc", "A Tool used to spawn Turrets" )
|
||||
language.Add( "tool.lvsturret.0", "Left click to spawn or update a turret" )
|
||||
language.Add( "tool.lvsturret.1", "Left click to spawn or update a turret" )
|
||||
|
||||
language.Add( "Cleanup_lvsturret", "[LVS] Projectile Turret" )
|
||||
language.Add( "Cleaned_lvsturret", "Cleaned up all [LVS] Projectile Turrets" )
|
||||
|
||||
language.Add( "SBoxLimit_lvsturret", "You've reached the Projectile Turret limit!" )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if CLIENT then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not istable( WireLib ) then
|
||||
ply:PrintMessage( HUD_PRINTTALK, "[LVS]: WIREMOD REQUIRED" )
|
||||
ply:SendLua( "gui.OpenURL( 'https://steamcommunity.com/sharedfiles/filedetails/?id=160250458' )")
|
||||
end
|
||||
|
||||
if IsValid( trace.Entity ) and trace.Entity:GetClass():lower() == "lvs_turret" then
|
||||
self:UpdateTurret( trace.Entity )
|
||||
else
|
||||
local turret = self:MakeTurret( ply, trace.HitPos + trace.HitNormal * 5 )
|
||||
|
||||
undo.Create("Turret")
|
||||
undo.AddEntity( turret )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function TOOL:UpdateTurret( ent )
|
||||
if not IsValid( ent ) then return end
|
||||
|
||||
ent:SetShootDelay( self:GetClientNumber( "delay" ) )
|
||||
ent:SetDamage( math.Clamp( self:GetClientNumber( "damage" ), 0, 1000 ) )
|
||||
ent:SetSpeed( math.Clamp( self:GetClientNumber( "speed" ), 10000, 100000 ) )
|
||||
ent:SetSize( math.Clamp( self:GetClientNumber( "size" ), 0, 50 ) )
|
||||
ent:SetSpread( math.Clamp( self:GetClientNumber( "spread" ), 0, 1 ) )
|
||||
ent:SetPenetration( math.Clamp( self:GetClientNumber( "penetration" ), 0, 500 ) )
|
||||
ent:SetSplashDamage( math.Clamp( self:GetClientNumber( "splashdamage" ), 0, 1000 ) )
|
||||
ent:SetSplashDamageRadius( math.Clamp( self:GetClientNumber( "splashradius" ), 0, 750 ) )
|
||||
ent:SetTracer( self:GetClientInfo( "tracer" ) )
|
||||
ent:SetSplashDamageType( self:GetClientInfo( "splasheffect" ) )
|
||||
end
|
||||
|
||||
function TOOL:MakeTurret( ply, Pos, Ang )
|
||||
|
||||
if not ply:CheckLimit( "lvsturret" ) then return NULL end
|
||||
|
||||
local turret = ents.Create( "lvs_turret" )
|
||||
|
||||
if not IsValid( turret ) then return NULL end
|
||||
|
||||
turret:SetPos( Pos )
|
||||
turret:SetAngles( Angle(0,0,0) )
|
||||
turret:Spawn()
|
||||
|
||||
turret.Attacker = ply
|
||||
|
||||
self:UpdateTurret( turret )
|
||||
|
||||
ply:AddCount( "lvsturret", turret )
|
||||
ply:AddCleanup( "lvsturret", turret )
|
||||
|
||||
return turret
|
||||
end
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "lvs_turrets", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Header", { Text = "#tool.lvsturret.name", Description = "#tool.lvsturret.desc" } )
|
||||
|
||||
local TracerEffect = {Label = "Tracer Effect", MenuButton = 0, Options={}, CVars = {}}
|
||||
local TracerOptions = {
|
||||
["LaserBlue"] = "lvs_laser_blue",
|
||||
["LaserRed"] = "lvs_laser_red",
|
||||
["LaserGreen"] = "lvs_laser_green",
|
||||
["TracerGreen"] = "lvs_tracer_green",
|
||||
["TracerOrange"] = "lvs_tracer_orange",
|
||||
["TracerWhite"] = "lvs_tracer_white",
|
||||
["TracerYellow"] = "lvs_tracer_yellow",
|
||||
["AutoCannon"] = "lvs_tracer_autocannon",
|
||||
["Cannon"] = "lvs_tracer_cannon",
|
||||
}
|
||||
for id, name in pairs( TracerOptions ) do
|
||||
if not file.Exists( "effects/"..name..".lua", "LUA" ) then continue end
|
||||
TracerEffect["Options"][id] = { lvsturret_tracer = name }
|
||||
end
|
||||
CPanel:AddControl("ComboBox", TracerEffect )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Shoot Delay", Type = "Float", Min = 0, Max = 2.0, Command = "lvsturret_delay" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Damage", Type = "Float", Min = 0, Max = 1000, Command = "lvsturret_damage" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Bullet Speed", Type = "Float", Min = 10000, Max = 100000, Command = "lvsturret_speed" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Bullet Spread", Type = "Float", Min = 0, Max = 1, Command = "lvsturret_spread" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Hull Size", Type = "Float", Min = 0, Max = 50, Command = "lvsturret_size" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Armor Penetration (mm)", Type = "Float", Min = 0, Max = 500, Command = "lvsturret_penetration" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Splash Damage", Type = "Float", Min = 0, Max = 1000, Command = "lvsturret_splashdamage" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Splash Radius", Type = "Float", Min = 0, Max = 750, Command = "lvsturret_splashradius" } )
|
||||
|
||||
local SplashType = {Label = "Splash Type", MenuButton = 0, Options={}, CVars = {}}
|
||||
SplashType["Options"][ "Shrapnel" ] = { lvsturret_splasheffect = "lvs_bullet_impact" }
|
||||
SplashType["Options"][ "Explosive" ] = { lvsturret_splasheffect = "lvs_bullet_impact_explosive" }
|
||||
CPanel:AddControl("ComboBox", SplashType )
|
||||
end
|
||||
166
gamemodes/sandbox/entities/weapons/gmod_tool/stools/material.lua
Normal file
166
gamemodes/sandbox/entities/weapons/gmod_tool/stools/material.lua
Normal file
@@ -0,0 +1,166 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Render"
|
||||
TOOL.Name = "#tool.material.name"
|
||||
|
||||
TOOL.ClientConVar[ "override" ] = "debug/env_cubemap_model"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
--
|
||||
-- Duplicator function
|
||||
--
|
||||
local function SetMaterial( Player, Entity, Data )
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
--
|
||||
-- Make sure this is in the 'allowed' list in multiplayer - to stop people using exploits
|
||||
--
|
||||
if ( !game.SinglePlayer() && !list.Contains( "OverrideMaterials", Data.MaterialOverride ) && Data.MaterialOverride != "" ) then return end
|
||||
|
||||
Entity:SetMaterial( Data.MaterialOverride )
|
||||
duplicator.StoreEntityModifier( Entity, "material", Data )
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
if ( SERVER ) then
|
||||
duplicator.RegisterEntityModifier( "material", SetMaterial )
|
||||
end
|
||||
|
||||
-- Left click applies the current material
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
|
||||
if ( !IsValid( ent ) ) then return false end -- The entity is valid and isn't worldspawn
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local mat = self:GetClientInfo( "override" )
|
||||
SetMaterial( self:GetOwner(), ent, { MaterialOverride = mat } )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Right click copies the material
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
|
||||
if ( !IsValid( ent ) ) then return false end -- The entity is valid and isn't worldspawn
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
self:GetOwner():ConCommand( "material_override " .. ent:GetMaterial() )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Reload reverts the material
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
|
||||
if ( !IsValid( ent ) ) then return false end -- The entity is valid and isn't worldspawn
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
SetMaterial( self:GetOwner(), ent, { MaterialOverride = "" } )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
list.Add( "OverrideMaterials", "models/wireframe" )
|
||||
list.Add( "OverrideMaterials", "debug/env_cubemap_model" )
|
||||
list.Add( "OverrideMaterials", "models/shadertest/shader3" )
|
||||
list.Add( "OverrideMaterials", "models/shadertest/shader4" )
|
||||
list.Add( "OverrideMaterials", "models/shadertest/shader5" )
|
||||
list.Add( "OverrideMaterials", "models/shiny" )
|
||||
list.Add( "OverrideMaterials", "models/debug/debugwhite" )
|
||||
list.Add( "OverrideMaterials", "Models/effects/comball_sphere" )
|
||||
list.Add( "OverrideMaterials", "Models/effects/comball_tape" )
|
||||
list.Add( "OverrideMaterials", "Models/effects/splodearc_sheet" )
|
||||
list.Add( "OverrideMaterials", "Models/effects/vol_light001" )
|
||||
list.Add( "OverrideMaterials", "models/props_combine/stasisshield_sheet" )
|
||||
list.Add( "OverrideMaterials", "models/props_combine/portalball001_sheet" )
|
||||
list.Add( "OverrideMaterials", "models/props_combine/com_shield001a" )
|
||||
list.Add( "OverrideMaterials", "models/props_c17/frostedglass_01a" )
|
||||
list.Add( "OverrideMaterials", "models/props_lab/Tank_Glass001" )
|
||||
list.Add( "OverrideMaterials", "models/props_combine/tprings_globe" )
|
||||
list.Add( "OverrideMaterials", "models/rendertarget" )
|
||||
list.Add( "OverrideMaterials", "models/screenspace" )
|
||||
list.Add( "OverrideMaterials", "brick/brick_model" )
|
||||
list.Add( "OverrideMaterials", "models/props_pipes/GutterMetal01a" )
|
||||
list.Add( "OverrideMaterials", "models/props_pipes/Pipesystem01a_skin3" )
|
||||
list.Add( "OverrideMaterials", "models/props_wasteland/wood_fence01a" )
|
||||
list.Add( "OverrideMaterials", "models/props_foliage/tree_deciduous_01a_trunk" )
|
||||
list.Add( "OverrideMaterials", "models/props_c17/FurnitureFabric003a" )
|
||||
list.Add( "OverrideMaterials", "models/props_c17/FurnitureMetal001a" )
|
||||
list.Add( "OverrideMaterials", "models/props_c17/paper01" )
|
||||
list.Add( "OverrideMaterials", "models/flesh" )
|
||||
|
||||
-- phx
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/metalset_1-2" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/metalfloor_2-3" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/plastic" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/wood" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/bluemetal" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/cube" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/dome" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/gear" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/stripes" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/wire/pcb_green" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/wire/pcb_red" )
|
||||
list.Add( "OverrideMaterials", "phoenix_storms/wire/pcb_blue" )
|
||||
|
||||
list.Add( "OverrideMaterials", "hunter/myplastic" )
|
||||
list.Add( "OverrideMaterials", "models/XQM/LightLinesRed_tool" )
|
||||
|
||||
if ( IsMounted( "tf" ) ) then
|
||||
list.Add( "OverrideMaterials", "models/player/shared/gold_player" )
|
||||
list.Add( "OverrideMaterials", "models/player/shared/ice_player" )
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.material.help" } )
|
||||
|
||||
local filter = CPanel:AddControl( "TextBox", { Label = "#spawnmenu.quick_filter_tool" } )
|
||||
filter:SetUpdateOnType( true )
|
||||
|
||||
-- Remove duplicate materials. table.HasValue is used to preserve material order
|
||||
local materials = {}
|
||||
for id, str in ipairs( list.Get( "OverrideMaterials" ) ) do
|
||||
if ( !table.HasValue( materials, str ) ) then
|
||||
table.insert( materials, str )
|
||||
end
|
||||
end
|
||||
|
||||
local matlist = CPanel:MatSelect( "material_override", materials, true, 0.25, 0.25 )
|
||||
|
||||
filter.OnValueChange = function( s, txt )
|
||||
for id, pnl in ipairs( matlist.Controls ) do
|
||||
if ( !pnl.Value:lower():find( txt:lower(), nil, true ) ) then
|
||||
pnl:SetVisible( false )
|
||||
else
|
||||
pnl:SetVisible( true )
|
||||
end
|
||||
end
|
||||
matlist:InvalidateChildren()
|
||||
CPanel:InvalidateChildren()
|
||||
end
|
||||
end
|
||||
161
gamemodes/sandbox/entities/weapons/gmod_tool/stools/motor.lua
Normal file
161
gamemodes/sandbox/entities/weapons/gmod_tool/stools/motor.lua
Normal file
@@ -0,0 +1,161 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.motor.name"
|
||||
|
||||
TOOL.ClientConVar[ "torque" ] = "500"
|
||||
TOOL.ClientConVar[ "friction" ] = "1"
|
||||
TOOL.ClientConVar[ "nocollide" ] = "1"
|
||||
TOOL.ClientConVar[ "forcetime" ] = "0"
|
||||
TOOL.ClientConVar[ "fwd" ] = "45"
|
||||
TOOL.ClientConVar[ "bwd" ] = "42"
|
||||
TOOL.ClientConVar[ "toggle" ] = "0"
|
||||
TOOL.ClientConVar[ "forcelimit" ] = "0"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1 },
|
||||
{ name = "reload"}
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
|
||||
-- Don't allow us to choose the world as the first object
|
||||
if ( iNum == 0 && !IsValid( trace.Entity ) ) then return end
|
||||
|
||||
-- Don't allow us to choose the same object
|
||||
if ( iNum == 1 && trace.Entity == self:GetEnt( 1 ) ) then return end
|
||||
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self:ClearObjects()
|
||||
self:ReleaseGhostEntity()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local torque = self:GetClientNumber( "torque" )
|
||||
local friction = self:GetClientNumber( "friction" )
|
||||
local nocollide = self:GetClientNumber( "nocollide" )
|
||||
local time = self:GetClientNumber( "forcetime" )
|
||||
local forekey = self:GetClientNumber( "fwd" )
|
||||
local backkey = self:GetClientNumber( "bwd" )
|
||||
local toggle = self:GetClientNumber( "toggle" )
|
||||
local limit = self:GetClientNumber( "forcelimit" )
|
||||
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
local Norm1, Norm2 = self:GetNormal( 1 ), self:GetNormal( 2 )
|
||||
local Phys1 = self:GetPhys( 1 )
|
||||
local WPos2 = self:GetPos( 2 )
|
||||
|
||||
-- Note: To keep stuff ragdoll friendly try to treat things as physics objects rather than entities
|
||||
local Ang1, Ang2 = Norm1:Angle(), ( -Norm2 ):Angle()
|
||||
local TargetAngle = Phys1:AlignAngles( Ang1, Ang2 )
|
||||
|
||||
Phys1:SetAngles( TargetAngle )
|
||||
|
||||
-- Move the object so that the hitpos on our object is at the second hitpos
|
||||
local TargetPos = WPos2 + ( Phys1:GetPos() - self:GetPos( 1 ) ) + ( Norm2 * 0.2 )
|
||||
|
||||
-- Set the position
|
||||
Phys1:SetPos( TargetPos )
|
||||
|
||||
-- Wake up the physics object so that the entity updates
|
||||
Phys1:Wake()
|
||||
|
||||
-- Set the hinge Axis perpendicular to the trace hit surface
|
||||
LPos1 = Phys1:WorldToLocal( WPos2 + Norm2 * 64 )
|
||||
|
||||
local constr, axis = constraint.Motor( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, friction, torque, time, nocollide, toggle, self:GetOwner(), limit, forekey, backkey, 1 )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Motor" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( axis ) ) then undo.AddEntity( axis ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "constraints", constr )
|
||||
if ( IsValid( axis ) ) then self:GetOwner():AddCleanup( "constraints", axis ) end
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
self:ReleaseGhostEntity()
|
||||
|
||||
else
|
||||
|
||||
self:StartGhostEntity( trace.Entity )
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Motor" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
if ( self:NumObjects() != 1 ) then return end
|
||||
|
||||
self:UpdateGhostEntity()
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.motor.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "motor", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.motor.numpad1", Command = "motor_fwd", Label2 = "#tool.motor.numpad2", Command2 = "motor_bwd" } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.motor.torque", Command = "motor_torque", Type = "Float", Min = 0, Max = 10000 } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.forcelimit", Command = "motor_forcelimit", Type = "Float", Min = 0, Max = 50000, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.hingefriction", Command = "motor_friction", Type = "Float", Min = 0, Max = 100, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.motor.forcetime", Command = "motor_forcetime", Type = "Float", Min = 0, Max = 120, Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.nocollide", Command = "motor_nocollide", Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.toggle", Command = "motor_toggle", Help = true } )
|
||||
|
||||
end
|
||||
251
gamemodes/sandbox/entities/weapons/gmod_tool/stools/muscle.lua
Normal file
251
gamemodes/sandbox/entities/weapons/gmod_tool/stools/muscle.lua
Normal file
@@ -0,0 +1,251 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.muscle.name"
|
||||
|
||||
TOOL.ClientConVar[ "group" ] = "37"
|
||||
TOOL.ClientConVar[ "width" ] = "2"
|
||||
TOOL.ClientConVar[ "addlength" ] = "100"
|
||||
TOOL.ClientConVar[ "fixed" ] = "1"
|
||||
TOOL.ClientConVar[ "period" ] = "1"
|
||||
TOOL.ClientConVar[ "material" ] = "cable/rope"
|
||||
TOOL.ClientConVar[ "starton" ] = "0"
|
||||
TOOL.ClientConVar[ "color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "color_g" ] = "255"
|
||||
TOOL.ClientConVar[ "color_b" ] = "255"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1, op = 1 },
|
||||
{ name = "right", stage = 0 },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
self:SetOperation( 1 )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
if ( ( !IsValid( self:GetEnt( 1 ) ) && !IsValid( self:GetEnt( 2 ) ) ) || iNum > 1 ) then
|
||||
|
||||
self:ClearObjects()
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local width = self:GetClientNumber( "width", 3 )
|
||||
local bind = self:GetClientNumber( "group", 1 )
|
||||
local AddLength = self:GetClientNumber( "addlength", 0 )
|
||||
local fixed = self:GetClientNumber( "fixed", 1 )
|
||||
local period = self:GetClientNumber( "period", 1 )
|
||||
local starton = self:GetClientNumber( "starton" ) == 1
|
||||
local material = self:GetClientInfo( "material" )
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
|
||||
-- If AddLength is 0 then what's the point.
|
||||
if ( AddLength == 0 ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
if ( period <= 0 ) then period = 0.1 end
|
||||
|
||||
AddLength = math.Clamp( AddLength, -1000, 1000 )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
local WPos1, WPos2 = self:GetPos( 1 ), self:GetPos( 2 )
|
||||
|
||||
local Length1 = ( WPos1 - WPos2 ):Length()
|
||||
local Length2 = Length1 + AddLength
|
||||
|
||||
local amp = Length2 - Length1
|
||||
|
||||
local constr, rope, controller, slider = constraint.Muscle( self:GetOwner(), Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, Length1, Length2, width, bind, fixed, period, amp, starton, material, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Muscle" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope ) ) then undo.AddEntity( rope ) end
|
||||
if ( IsValid( slider ) ) then undo.AddEntity( slider ) end
|
||||
if ( IsValid( controller ) ) then undo.AddEntity( controller ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope ) end
|
||||
if ( IsValid( slider ) ) then self:GetOwner():AddCleanup( "ropeconstraints", slider ) end
|
||||
if ( IsValid( controller ) ) then self:GetOwner():AddCleanup( "ropeconstraints", controller ) end
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( self:GetOperation() == 1 ) then return false end
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
local tr_new = {}
|
||||
tr_new.start = trace.HitPos
|
||||
tr_new.endpos = trace.HitPos + ( trace.HitNormal * 16384 )
|
||||
tr_new.filter = { self:GetOwner() }
|
||||
if ( IsValid( trace.Entity ) ) then
|
||||
table.insert( tr_new.filter, trace.Entity )
|
||||
end
|
||||
|
||||
local tr = util.TraceLine( tr_new )
|
||||
if ( !tr.Hit ) then
|
||||
self:ClearObjects()
|
||||
return false
|
||||
end
|
||||
|
||||
-- Don't try to constrain world to world
|
||||
if ( trace.HitWorld && tr.HitWorld ) then
|
||||
self:ClearObjects()
|
||||
return false
|
||||
end
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then
|
||||
self:ClearObjects()
|
||||
return false
|
||||
end
|
||||
if ( IsValid( tr.Entity ) && tr.Entity:IsPlayer() ) then
|
||||
self:ClearObjects()
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check to see if the player can create a muscle constraint with the entity in the trace
|
||||
if ( !hook.Run( "CanTool", self:GetOwner(), tr, "muscle", self, 2 ) ) then
|
||||
self:ClearObjects()
|
||||
return false
|
||||
end
|
||||
|
||||
local Phys2 = tr.Entity:GetPhysicsObjectNum( tr.PhysicsBone )
|
||||
self:SetObject( 2, tr.Entity, tr.HitPos, Phys2, tr.PhysicsBone, tr.HitNormal )
|
||||
|
||||
if ( CLIENT ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local width = self:GetClientNumber( "width", 3 )
|
||||
local bind = self:GetClientNumber( "group", 1 )
|
||||
local AddLength = self:GetClientNumber( "addlength", 0 )
|
||||
local fixed = self:GetClientNumber( "fixed", 1 )
|
||||
local period = self:GetClientNumber( "period", 64 )
|
||||
local starton = self:GetClientNumber( "starton" ) > 0
|
||||
local material = self:GetClientInfo( "material" )
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
local WPos1, WPos2 = self:GetPos( 1 ), self:GetPos( 2 )
|
||||
|
||||
local Length1 = ( WPos1 - WPos2 ):Length()
|
||||
local Length2 = Length1 + AddLength
|
||||
|
||||
local amp = Length2 - Length1
|
||||
|
||||
local constr, rope, controller, slider = constraint.Muscle( self:GetOwner(), Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, Length1, Length2, width, bind, fixed, period, amp, starton, material, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Muscle" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope ) ) then undo.AddEntity( rope ) end
|
||||
if ( IsValid( slider ) ) then undo.AddEntity( slider ) end
|
||||
if ( IsValid( controller ) ) then undo.AddEntity( controller ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope ) end
|
||||
if ( IsValid( slider ) ) then self:GetOwner():AddCleanup( "ropeconstraints", slider ) end
|
||||
if ( IsValid( controller ) ) then self:GetOwner():AddCleanup( "ropeconstraints", controller ) end
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Muscle" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.muscle.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "muscle", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.muscle.numpad", Command = "muscle_group" } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.muscle.length", Command = "muscle_addlength", Type = "Float", Min = -1000, Max = 1000, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.muscle.period", Command = "muscle_period", Type = "Float", Min = 0, Max = 10, Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.muscle.fixed", Command = "muscle_fixed", Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.muscle.starton", Command = "muscle_starton", Help = true } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.muscle.width", Command = "muscle_width", Type = "Float", Min = 0, Max = 5 } )
|
||||
CPanel:AddControl( "RopeMaterial", { Label = "#tool.muscle.material", ConVar = "muscle_material" } )
|
||||
CPanel:AddControl( "Color", { Label = "#tool.muscle.color", Red = "muscle_color_r", Green = "muscle_color_g", Blue = "muscle_color_b" } )
|
||||
|
||||
end
|
||||
@@ -0,0 +1,118 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.nocollide.name"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1 },
|
||||
{ name = "right" },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
cleanup.Register( "nocollide" )
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return end
|
||||
if ( trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
if ( iNum > 0 ) then self:ClearObjects() end
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
|
||||
local constr = constraint.NoCollide( Ent1, Ent2, Bone1, Bone2 )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "NoCollide" )
|
||||
undo.AddEntity( constr )
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "nocollide", constr )
|
||||
end
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return end
|
||||
if ( trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
if ( trace.Entity:GetCollisionGroup() == COLLISION_GROUP_WORLD ) then
|
||||
|
||||
trace.Entity:SetCollisionGroup( COLLISION_GROUP_NONE )
|
||||
|
||||
else
|
||||
|
||||
trace.Entity:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "NoCollide" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
-- This is unreliable
|
||||
hook.Add( "EntityRemoved", "nocollide_fix", function( ent )
|
||||
if ( ent:GetClass() == "logic_collision_pair" ) then
|
||||
ent:Fire( "EnableCollisions" )
|
||||
end
|
||||
end )
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.nocollide.desc" } )
|
||||
|
||||
end
|
||||
168
gamemodes/sandbox/entities/weapons/gmod_tool/stools/paint.lua
Normal file
168
gamemodes/sandbox/entities/weapons/gmod_tool/stools/paint.lua
Normal file
@@ -0,0 +1,168 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Render"
|
||||
TOOL.Name = "#tool.paint.name"
|
||||
|
||||
TOOL.LeftClickAutomatic = true
|
||||
TOOL.RightClickAutomatic = true
|
||||
TOOL.RequiresTraceHit = true
|
||||
|
||||
TOOL.ClientConVar[ "decal" ] = "Blood"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
local function PlaceDecal( ply, ent, data )
|
||||
|
||||
if ( !IsValid( ent ) && !ent:IsWorld() ) then return end
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
local bone
|
||||
if ( data.bone && data.bone < ent:GetPhysicsObjectCount() ) then bone = ent:GetPhysicsObjectNum( data.bone ) end
|
||||
if ( !IsValid( bone ) ) then bone = ent:GetPhysicsObject() end
|
||||
if ( !IsValid( bone ) ) then bone = ent end
|
||||
|
||||
util.Decal( data.decal, bone:LocalToWorld( data.Pos1 ), bone:LocalToWorld( data.Pos2 ), ply )
|
||||
|
||||
local i = ent.DecalCount or 0
|
||||
i = i + 1
|
||||
duplicator.StoreEntityModifier( ent, "decal" .. i, data )
|
||||
ent.DecalCount = i
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Register decal duplicator
|
||||
--
|
||||
if ( SERVER ) then
|
||||
for i = 1, 32 do
|
||||
|
||||
duplicator.RegisterEntityModifier( "decal" .. i, function( ply, ent, data )
|
||||
timer.Simple( i * 0.05, function() PlaceDecal( ply, ent, data ) end )
|
||||
end )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
if ( !IsValid( trace.Entity ) ) then return false end
|
||||
|
||||
trace.Entity:RemoveAllDecals()
|
||||
|
||||
if ( SERVER ) then
|
||||
for i = 1, 32 do
|
||||
duplicator.ClearEntityModifier( trace.Entity, "decal" .. i )
|
||||
end
|
||||
trace.Entity.DecalCount = nil
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
return self:RightClick( trace, true )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace, bNoDelay )
|
||||
|
||||
self:GetWeapon():EmitSound( "SprayCan.Paint" )
|
||||
local decal = self:GetClientInfo( "decal" )
|
||||
|
||||
local Pos1 = trace.HitPos + trace.HitNormal
|
||||
local Pos2 = trace.HitPos - trace.HitNormal
|
||||
|
||||
local Bone
|
||||
if ( trace.PhysicsBone && trace.PhysicsBone < trace.Entity:GetPhysicsObjectCount() ) then Bone = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone ) end
|
||||
if ( !IsValid( Bone ) ) then Bone = trace.Entity:GetPhysicsObject() end
|
||||
if ( !IsValid( Bone ) ) then Bone = trace.Entity end
|
||||
|
||||
Pos1 = Bone:WorldToLocal( Pos1 )
|
||||
Pos2 = Bone:WorldToLocal( Pos2 )
|
||||
|
||||
PlaceDecal( self:GetOwner(), trace.Entity, { Pos1 = Pos1, Pos2 = Pos2, bone = trace.PhysicsBone, decal = decal } )
|
||||
|
||||
if ( bNoDelay ) then
|
||||
self:GetWeapon():SetNextPrimaryFire( CurTime() + 0.05 )
|
||||
self:GetWeapon():SetNextSecondaryFire( CurTime() + 0.05 )
|
||||
else
|
||||
self:GetWeapon():SetNextPrimaryFire( CurTime() + 0.2 )
|
||||
self:GetWeapon():SetNextSecondaryFire( CurTime() + 0.2 )
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
game.AddDecal( "Eye", "decals/eye" )
|
||||
game.AddDecal( "Dark", "decals/dark" )
|
||||
game.AddDecal( "Smile", "decals/smile" )
|
||||
game.AddDecal( "Light", "decals/light" )
|
||||
game.AddDecal( "Cross", "decals/cross" )
|
||||
game.AddDecal( "Nought", "decals/nought" )
|
||||
game.AddDecal( "Noughtsncrosses", "decals/noughtsncrosses" )
|
||||
|
||||
list.Add( "PaintMaterials", "Eye" )
|
||||
list.Add( "PaintMaterials", "Smile" )
|
||||
list.Add( "PaintMaterials", "Light" )
|
||||
list.Add( "PaintMaterials", "Dark" )
|
||||
list.Add( "PaintMaterials", "Blood" )
|
||||
list.Add( "PaintMaterials", "YellowBlood" )
|
||||
list.Add( "PaintMaterials", "Impact.Metal" )
|
||||
list.Add( "PaintMaterials", "Scorch" )
|
||||
list.Add( "PaintMaterials", "BeerSplash" )
|
||||
list.Add( "PaintMaterials", "ExplosiveGunshot" )
|
||||
list.Add( "PaintMaterials", "BirdPoop" )
|
||||
list.Add( "PaintMaterials", "PaintSplatPink" )
|
||||
list.Add( "PaintMaterials", "PaintSplatGreen" )
|
||||
list.Add( "PaintMaterials", "PaintSplatBlue" )
|
||||
list.Add( "PaintMaterials", "ManhackCut" )
|
||||
list.Add( "PaintMaterials", "FadingScorch" )
|
||||
list.Add( "PaintMaterials", "Antlion.Splat" )
|
||||
list.Add( "PaintMaterials", "Splash.Large" )
|
||||
list.Add( "PaintMaterials", "BulletProof" )
|
||||
list.Add( "PaintMaterials", "GlassBreak" )
|
||||
list.Add( "PaintMaterials", "Impact.Sand" )
|
||||
list.Add( "PaintMaterials", "Impact.BloodyFlesh" )
|
||||
list.Add( "PaintMaterials", "Impact.Antlion" )
|
||||
list.Add( "PaintMaterials", "Impact.Glass" )
|
||||
list.Add( "PaintMaterials", "Impact.Wood" )
|
||||
list.Add( "PaintMaterials", "Impact.Concrete" )
|
||||
list.Add( "PaintMaterials", "Noughtsncrosses" )
|
||||
list.Add( "PaintMaterials", "Nought" )
|
||||
list.Add( "PaintMaterials", "Cross" )
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
-- Remove duplicates.
|
||||
local Options = {}
|
||||
for id, str in ipairs( list.Get( "PaintMaterials" ) ) do
|
||||
if ( !table.HasValue( Options, str ) ) then
|
||||
table.insert( Options, str )
|
||||
end
|
||||
end
|
||||
|
||||
table.sort( Options )
|
||||
|
||||
local listbox = CPanel:AddControl( "ListBox", { Label = "#tool.paint.texture", Height = 17 + table.Count( Options ) * 17 } )
|
||||
for k, decal in ipairs( Options ) do
|
||||
local line = listbox:AddLine( decal )
|
||||
line.data = { paint_decal = decal, gmod_tool = "paint" }
|
||||
|
||||
if ( GetConVarString( "paint_decal" ) == tostring( decal ) ) then line:SetSelected( true ) end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,73 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.physprop.name"
|
||||
|
||||
TOOL.ClientConVar[ "gravity_toggle" ] = "1"
|
||||
TOOL.ClientConVar[ "material" ] = "metal_bouncy"
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return false end
|
||||
if ( trace.Entity:IsPlayer() || trace.Entity:IsWorld() ) then return false end
|
||||
|
||||
-- Make sure there's a physics object to manipulate
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
-- Client can bail out here and assume we're going ahead
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
-- Get the entity/bone from the trace
|
||||
local ent = trace.Entity
|
||||
local Bone = trace.PhysicsBone
|
||||
|
||||
-- Get client's CVars
|
||||
local gravity = self:GetClientNumber( "gravity_toggle" ) == 1
|
||||
local material = self:GetClientInfo( "material" )
|
||||
|
||||
-- Set the properties
|
||||
|
||||
construct.SetPhysProp( self:GetOwner(), ent, Bone, nil, { GravityToggle = gravity, Material = material } )
|
||||
|
||||
DoPropSpawnedEffect( ent )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "physprop", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "ListBox", { Label = "#tool.physprop.material", Options = list.Get( "PhysicsMaterials" ) } )
|
||||
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.physprop.gravity", Command = "physprop_gravity_toggle" } )
|
||||
|
||||
end
|
||||
|
||||
list.Set( "PhysicsMaterials", "#physprop.metalbouncy", { physprop_material = "metal_bouncy" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.metal", { physprop_material = "metal" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.dirt", { physprop_material = "dirt" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.slime", { physprop_material = "slipperyslime" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.wood", { physprop_material = "wood" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.glass", { physprop_material = "glass" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.concrete", { physprop_material = "concrete_block" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.ice", { physprop_material = "ice" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.rubber", { physprop_material = "rubber" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.paper", { physprop_material = "paper" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.flesh", { physprop_material = "zombieflesh" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.superice", { physprop_material = "gmod_ice" } )
|
||||
list.Set( "PhysicsMaterials", "#physprop.superbouncy", { physprop_material = "gmod_bouncy" } )
|
||||
124
gamemodes/sandbox/entities/weapons/gmod_tool/stools/pulley.lua
Normal file
124
gamemodes/sandbox/entities/weapons/gmod_tool/stools/pulley.lua
Normal file
@@ -0,0 +1,124 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.pulley.name"
|
||||
|
||||
TOOL.ClientConVar[ "width" ] = "3"
|
||||
TOOL.ClientConVar[ "forcelimit" ] = "0"
|
||||
TOOL.ClientConVar[ "rigid" ] = "0"
|
||||
TOOL.ClientConVar[ "material" ] = "cable/cable"
|
||||
TOOL.ClientConVar[ "color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "color_g" ] = "255"
|
||||
TOOL.ClientConVar[ "color_b" ] = "255"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1 },
|
||||
{ name = "left_2", stage = 2 },
|
||||
{ name = "left_3", stage = 3 },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return false end
|
||||
if ( !IsValid( trace.Entity ) && ( iNum == nil || iNum == 0 || iNum > 2 ) ) then return false end
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
if ( iNum > 2 ) then
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local width = self:GetClientNumber( "width" )
|
||||
local forcelimit = self:GetClientNumber( "forcelimit" )
|
||||
local rigid = self:GetClientNumber( "rigid" ) == 1
|
||||
local material = self:GetClientInfo( "material" )
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1 = self:GetEnt( 1 )
|
||||
local Ent4 = self:GetEnt( 4 )
|
||||
local Bone1 = self:GetBone( 1 )
|
||||
local Bone4 = self:GetBone( 4 )
|
||||
local LPos1 = self:GetLocalPos( 1 )
|
||||
local LPos4 = self:GetLocalPos( 4 )
|
||||
local WPos2 = self:GetPos( 2 )
|
||||
local WPos3 = self:GetPos( 3 )
|
||||
|
||||
local constr, rope1, rope2, rope3 = constraint.Pulley( Ent1, Ent4, Bone1, Bone4, LPos1, LPos4, WPos2, WPos3, forcelimit, rigid, width, material, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Pulley" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope1 ) ) then undo.AddEntity( rope1 ) end
|
||||
if ( IsValid( rope2 ) ) then undo.AddEntity( rope2 ) end
|
||||
if ( IsValid( rope3 ) ) then undo.AddEntity( rope3 ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope1 ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope1 ) end
|
||||
if ( IsValid( rope2 ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope2 ) end
|
||||
if ( IsValid( rope3 ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope3 ) end
|
||||
end
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Pulley" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.pulley.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "pulley", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.forcelimit", Command = "pulley_forcelimit", Type = "Float", Min = 0, Max = 1000, Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.pulley.rigid", Command = "pulley_rigid", Help = true } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.pulley.width", Command = "pulley_width", Type = "Float", Min = 0, Max = 10 } )
|
||||
CPanel:AddControl( "RopeMaterial", { Label = "#tool.pulley.material", ConVar = "pulley_material" } )
|
||||
CPanel:AddControl( "Color", { Label = "#tool.pulley.color", Red = "pulley_color_r", Green = "pulley_color_g", Blue = "pulley_color_b" } )
|
||||
|
||||
end
|
||||
113
gamemodes/sandbox/entities/weapons/gmod_tool/stools/remover.lua
Normal file
113
gamemodes/sandbox/entities/weapons/gmod_tool/stools/remover.lua
Normal file
@@ -0,0 +1,113 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.remover.name"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
local function DoRemoveEntity( ent )
|
||||
|
||||
if ( !IsValid( ent ) || ent:IsPlayer() ) then return false end
|
||||
|
||||
-- Nothing for the client to do here
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
-- Remove all constraints (this stops ropes from hanging around)
|
||||
constraint.RemoveAll( ent )
|
||||
|
||||
-- Remove it properly in 1 second
|
||||
timer.Simple( 1, function() if ( IsValid( ent ) ) then ent:Remove() end end )
|
||||
|
||||
-- Make it non solid
|
||||
ent:SetNotSolid( true )
|
||||
ent:SetMoveType( MOVETYPE_NONE )
|
||||
ent:SetNoDraw( true )
|
||||
|
||||
-- Send Effect
|
||||
local ed = EffectData()
|
||||
ed:SetOrigin( ent:GetPos() )
|
||||
ed:SetEntity( ent )
|
||||
util.Effect( "entity_remove", ed, true, true )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Remove a single entity
|
||||
--
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( DoRemoveEntity( trace.Entity ) ) then
|
||||
|
||||
if ( !CLIENT ) then
|
||||
self:GetOwner():SendLua( "achievements.Remover()" )
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Remove this entity and everything constrained
|
||||
--
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
local entity = trace.Entity
|
||||
if ( !IsValid( entity ) || entity:IsPlayer() ) then return false end
|
||||
|
||||
-- Client can bail out now.
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ConstrainedEntities = constraint.GetAllConstrainedEntities( entity )
|
||||
local Count = 0
|
||||
|
||||
-- Loop through all the entities in the system
|
||||
for _, ent in pairs( ConstrainedEntities ) do
|
||||
|
||||
if ( DoRemoveEntity( ent ) ) then
|
||||
Count = Count + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:GetOwner():SendLua( string.format( "for i=1,%i do achievements.Remover() end", Count ) )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Reload removes all constraints on the targetted entity
|
||||
--
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveAll( trace.Entity )
|
||||
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.remover.desc" } )
|
||||
|
||||
end
|
||||
195
gamemodes/sandbox/entities/weapons/gmod_tool/stools/rope.lua
Normal file
195
gamemodes/sandbox/entities/weapons/gmod_tool/stools/rope.lua
Normal file
@@ -0,0 +1,195 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.rope.name"
|
||||
|
||||
TOOL.ClientConVar[ "forcelimit" ] = "0"
|
||||
TOOL.ClientConVar[ "addlength" ] = "0"
|
||||
TOOL.ClientConVar[ "material" ] = "cable/rope"
|
||||
TOOL.ClientConVar[ "width" ] = "2"
|
||||
TOOL.ClientConVar[ "rigid" ] = "0"
|
||||
TOOL.ClientConVar[ "color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "color_g" ] = "255"
|
||||
TOOL.ClientConVar[ "color_b" ] = "255"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1 },
|
||||
{ name = "right", stage = 1 },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self:ClearObjects()
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local forcelimit = self:GetClientNumber( "forcelimit" )
|
||||
local addlength = self:GetClientNumber( "addlength" )
|
||||
local material = self:GetClientInfo( "material" )
|
||||
local width = self:GetClientNumber( "width" )
|
||||
local rigid = self:GetClientNumber( "rigid" ) == 1
|
||||
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local WPos1, WPos2 = self:GetPos( 1 ), self:GetPos( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
local length = ( WPos1 - WPos2 ):Length()
|
||||
|
||||
local constr, rope = constraint.Rope( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, length, addlength, forcelimit, width, material, rigid, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
-- Add the constraint to the players undo table
|
||||
undo.Create( "Rope" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope ) ) then undo.AddEntity( rope ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope ) end
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self:ClearObjects()
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local forcelimit = self:GetClientNumber( "forcelimit" )
|
||||
local addlength = self:GetClientNumber( "addlength" )
|
||||
local material = self:GetClientInfo( "material" )
|
||||
local width = self:GetClientNumber( "width" )
|
||||
local rigid = self:GetClientNumber( "rigid" ) == 1
|
||||
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local WPos1, WPos2 = self:GetPos( 1 ), self:GetPos( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
local length = ( WPos1 - WPos2 ):Length()
|
||||
|
||||
local constr, rope = constraint.Rope( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, length, addlength, forcelimit, width, material, rigid, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
-- Add the constraint to the players undo table
|
||||
undo.Create( "Rope" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope ) ) then undo.AddEntity( rope ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope ) end
|
||||
end
|
||||
|
||||
-- Clear the objects and set the last object as object 1
|
||||
self:ClearObjects()
|
||||
|
||||
iNum = self:NumObjects()
|
||||
self:SetObject( iNum + 1, Ent2, trace.HitPos, Phys, Bone2, trace.HitNormal )
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Rope" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.rope.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "rope", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.forcelimit", Command = "rope_forcelimit", Type = "Float", Min = 0, Max = 1000, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.rope.addlength", Command = "rope_addlength", Type = "Float", Min = -500, Max = 500, Help = true } )
|
||||
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.rope.rigid", Command = "rope_rigid", Help = true } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.rope.width", Command = "rope_width", Type = "Float", Min = 0, Max = 10 } )
|
||||
CPanel:AddControl( "RopeMaterial", { Label = "#tool.rope.material", ConVar = "rope_material" } )
|
||||
|
||||
CPanel:AddControl( "Color", { Label = "#tool.rope.color", Red = "rope_color_r", Green = "rope_color_g", Blue = "rope_color_b" } )
|
||||
|
||||
end
|
||||
@@ -0,0 +1,854 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "simfphys"
|
||||
TOOL.Name = "#Vehicle Duplicator"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
if SERVER then
|
||||
util.AddNetworkString( "sphys_dupe" )
|
||||
|
||||
local recv_interval_start = 0 -- first second of current interval
|
||||
local recv_interval_len = 1 -- in seconds, length of interval before resetting recv_interval_(start,count)
|
||||
local recv_interval_count = 0 -- current count of messages received in interval
|
||||
local recv_max = 500 -- maximum number of messages to receive during one interval
|
||||
local recv_stop = 0 -- is the net.Receive stopped (activates short-circuit)
|
||||
local recv_delay_after_stop = 3600 -- how long to wait (in seconds) before allowing messages again
|
||||
|
||||
net.Receive("sphys_dupe", function( length, ply )
|
||||
if (recv_stop == 1) then -- if stopped,
|
||||
return -- short-circuit
|
||||
end
|
||||
-- check if a new interval has come
|
||||
if (recv_interval_start + recv_interval_len < os.time()) then
|
||||
recv_interval_start = os.time() -- reset time
|
||||
recv_interval_count = 0 -- reset message count
|
||||
end
|
||||
recv_interval_count = recv_interval_count + 1
|
||||
-- check if below threshold
|
||||
if (recv_interval_count > recv_max) then
|
||||
-- if over threshold, activate short-circuit
|
||||
recv_stop = 1
|
||||
-- and create a timer to deactivate the short-circuit in recv_delay_after_stop seconds
|
||||
timer.Simple(recv_delay_after_stop, function()
|
||||
recv_stop = 0
|
||||
end)
|
||||
-- warn server about attack
|
||||
PrintMessage(HUD_PRINTTALK, "WARNING: " .. ply:Nick() .. " [" .. ply:SteamID() .. "] is attacking sphys_dupe. simfphys duplicator is disabled for " .. tostring(recv_delay_after_stop) .. " seconds.")
|
||||
end
|
||||
|
||||
ply.TOOLMemory = net.ReadTable()
|
||||
ply:SelectWeapon( "gmod_tool" )
|
||||
end)
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.simfphysduplicator.name", "Vehicle Duplicator" )
|
||||
language.Add( "tool.simfphysduplicator.desc", "Copy, Paste or Save your Vehicles" )
|
||||
language.Add( "tool.simfphysduplicator.0", "Left click to spawn or update. Right click to copy" )
|
||||
language.Add( "tool.simfphysduplicator.1", "Left click to spawn or update. Right click to copy" )
|
||||
|
||||
local selecteditem = nil
|
||||
local TOOLMemory = {}
|
||||
|
||||
net.Receive("sphys_dupe", function( length )
|
||||
TOOLMemory = net.ReadTable()
|
||||
end)
|
||||
|
||||
local function GetSaves( panel )
|
||||
local saved_vehicles = file.Find("saved_vehicles/*.txt", "DATA")
|
||||
local index = 0
|
||||
local highlight = false
|
||||
local offset = 22
|
||||
|
||||
for k,v in pairs(saved_vehicles) do
|
||||
local printname = v
|
||||
|
||||
if not selecteditem then
|
||||
selecteditem = printname
|
||||
end
|
||||
|
||||
local Button = vgui.Create( "DButton", panel )
|
||||
Button:SetText( printname )
|
||||
Button:SetTextColor( Color( 255, 255, 255 ) )
|
||||
Button:SetPos( 0,index * offset)
|
||||
Button:SetSize( 280, offset )
|
||||
Button.highlight = highlight
|
||||
Button.printname = printname
|
||||
Button.Paint = function( self, w, h )
|
||||
|
||||
local c_selected = Color( 128, 185, 128, 255 )
|
||||
local c_normal = self.highlight and Color( 108, 111, 114, 200 ) or Color( 77, 80, 82, 200 )
|
||||
local c_hovered = Color( 41, 128, 185, 255 )
|
||||
local c_ = (selecteditem == self.printname) and c_selected or (self:IsHovered() and c_hovered or c_normal)
|
||||
|
||||
draw.RoundedBox( 5, 1, 1, w - 2, h - 1, c_ )
|
||||
end
|
||||
Button.DoClick = function( self )
|
||||
selecteditem = self.printname
|
||||
end
|
||||
|
||||
index = index + 1
|
||||
highlight = not highlight
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( panel )
|
||||
if not file.Exists( "saved_vehicles", "DATA" ) then
|
||||
file.CreateDir( "saved_vehicles" )
|
||||
end
|
||||
|
||||
local Frame = vgui.Create( "DFrame", panel )
|
||||
Frame:SetPos( 10, 30 )
|
||||
Frame:SetSize( 280, 320 )
|
||||
Frame:SetTitle( "" )
|
||||
Frame:SetVisible( true )
|
||||
Frame:ShowCloseButton( false )
|
||||
Frame:SetDraggable( false )
|
||||
Frame.Paint = function( self, w, h )
|
||||
draw.RoundedBox( 5, 0, 0, w, h, Color( 115, 115, 115, 255 ) )
|
||||
draw.RoundedBox( 5, 1, 1, w - 2, h - 2, Color( 234, 234, 234, 255 ) )
|
||||
end
|
||||
|
||||
local ScrollPanel = vgui.Create( "DScrollPanel", Frame )
|
||||
ScrollPanel:SetSize( 280, 320 )
|
||||
ScrollPanel:SetPos( 0, 0 )
|
||||
|
||||
GetSaves( ScrollPanel )
|
||||
|
||||
local Button = vgui.Create( "DButton", panel )
|
||||
Button:SetText( "Save" )
|
||||
Button:SetPos( 10, 350)
|
||||
Button:SetSize( 280, 20 )
|
||||
Button.DoClick = function( self )
|
||||
if isstring(TOOLMemory.SpawnName) then
|
||||
local Frame = vgui.Create( "DFrame" )
|
||||
Frame:SetPos( gui.MouseX() - 100, gui.MouseY() - 30 )
|
||||
Frame:SetSize( 280, 50 )
|
||||
Frame:SetTitle( "Save As..." )
|
||||
Frame:SetVisible( true )
|
||||
Frame:ShowCloseButton( true )
|
||||
Frame:MakePopup()
|
||||
Frame:SetDraggable( true )
|
||||
|
||||
local TextEntry = vgui.Create( "DTextEntry", Frame )
|
||||
TextEntry:SetPos( 5, 25 )
|
||||
TextEntry:SetSize( 270, 20 )
|
||||
|
||||
TextEntry.OnEnter = function()
|
||||
local Name = TextEntry:GetValue()
|
||||
|
||||
if Name ~= "" then
|
||||
local DataString = ""
|
||||
|
||||
for k,v in pairs(TOOLMemory) do
|
||||
if k == "SubMaterials" then
|
||||
local mats = ""
|
||||
local first = true
|
||||
for k, v in pairs( v ) do
|
||||
if first then
|
||||
first = false
|
||||
mats = mats..v
|
||||
else
|
||||
mats = mats..","..v
|
||||
end
|
||||
end
|
||||
DataString = DataString..k.."="..mats.."#"
|
||||
else
|
||||
DataString = DataString..k.."="..tostring( v ).."#"
|
||||
end
|
||||
end
|
||||
|
||||
local words = string.Explode( "", DataString )
|
||||
local shit = {}
|
||||
|
||||
for k, v in pairs( words ) do
|
||||
shit[k] = string.char( string.byte( v ) + 20 )
|
||||
end
|
||||
|
||||
file.Write("saved_vehicles/"..Name..".txt", string.Implode("",shit) )
|
||||
|
||||
ScrollPanel:Clear()
|
||||
selecteditem = Name..".txt"
|
||||
GetSaves( ScrollPanel )
|
||||
end
|
||||
|
||||
Frame:Close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local Button = vgui.Create( "DButton", panel )
|
||||
Button:SetText( "Load" )
|
||||
Button:SetPos( 10, 370)
|
||||
Button:SetSize( 280, 20 )
|
||||
Button.DoClick = function( self )
|
||||
if isstring(selecteditem) then
|
||||
if not file.Exists( "saved_vehicles/"..selecteditem, "DATA" ) then
|
||||
ScrollPanel:Clear()
|
||||
selecteditem = nil
|
||||
GetSaves( ScrollPanel )
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local DataString = file.Read( "saved_vehicles/"..selecteditem, "DATA" )
|
||||
|
||||
local words = string.Explode( "", DataString )
|
||||
local shit = {}
|
||||
|
||||
for k, v in pairs( words ) do
|
||||
shit[k] = string.char( string.byte( v ) - 20 )
|
||||
end
|
||||
|
||||
local Data = string.Explode( "#", string.Implode("",shit) )
|
||||
|
||||
table.Empty( TOOLMemory )
|
||||
|
||||
for _,v in pairs(Data) do
|
||||
local Var = string.Explode( "=", v )
|
||||
local name = Var[1]
|
||||
local variable = Var[2]
|
||||
|
||||
if name and variable then
|
||||
if name == "SubMaterials" then
|
||||
TOOLMemory[name] = {}
|
||||
|
||||
local submats = string.Explode( ",", variable )
|
||||
for i = 0, (table.Count( submats ) - 1) do
|
||||
TOOLMemory[name][i] = submats[i+1]
|
||||
end
|
||||
else
|
||||
TOOLMemory[name] = variable
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
net.Start("sphys_dupe")
|
||||
net.WriteTable( TOOLMemory )
|
||||
net.SendToServer()
|
||||
end
|
||||
end
|
||||
|
||||
local Button = vgui.Create( "DButton", panel )
|
||||
Button:SetText( "Delete" )
|
||||
Button:SetPos( 10, 430)
|
||||
Button:SetSize( 280, 20 )
|
||||
Button.DoClick = function( self )
|
||||
|
||||
if isstring(selecteditem) then
|
||||
file.Delete( "saved_vehicles/"..selecteditem )
|
||||
end
|
||||
|
||||
ScrollPanel:Clear()
|
||||
selecteditem = nil
|
||||
GetSaves( ScrollPanel )
|
||||
end
|
||||
|
||||
local Button = vgui.Create( "DButton", panel )
|
||||
Button:SetText( "Refresh" )
|
||||
Button:SetPos( 10, 390)
|
||||
Button:SetSize( 280, 20 )
|
||||
Button.DoClick = function( self )
|
||||
ScrollPanel:Clear()
|
||||
selecteditem = nil
|
||||
GetSaves( ScrollPanel )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ValidateModel( model )
|
||||
local v_list = list.Get( "simfphys_vehicles" )
|
||||
for listname, _ in pairs( v_list ) do
|
||||
if v_list[listname].Members.CustomWheels then
|
||||
local FrontWheel = v_list[listname].Members.CustomWheelModel
|
||||
local RearWheel = v_list[listname].Members.CustomWheelModel_R
|
||||
|
||||
if FrontWheel then
|
||||
FrontWheel = string.lower( FrontWheel )
|
||||
end
|
||||
|
||||
if RearWheel then
|
||||
RearWheel = string.lower( RearWheel )
|
||||
end
|
||||
|
||||
if model == FrontWheel or model == RearWheel then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local list = list.Get( "simfphys_Wheels" )[model]
|
||||
|
||||
if list then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL:GetVehicleData( ent, ply )
|
||||
if not IsValid(ent) then return end
|
||||
if not istable(ply.TOOLMemory) then ply.TOOLMemory = {} end
|
||||
|
||||
table.Empty( ply.TOOLMemory )
|
||||
|
||||
ply.TOOLMemory.SpawnName = ent:GetSpawn_List()
|
||||
ply.TOOLMemory.SteerSpeed = ent:GetSteerSpeed()
|
||||
ply.TOOLMemory.SteerFadeSpeed = ent:GetFastSteerConeFadeSpeed()
|
||||
ply.TOOLMemory.SteerAngFast = ent:GetFastSteerAngle()
|
||||
ply.TOOLMemory.SoundPreset = ent:GetEngineSoundPreset()
|
||||
ply.TOOLMemory.IdleRPM = ent:GetIdleRPM()
|
||||
ply.TOOLMemory.MaxRPM = ent:GetLimitRPM()
|
||||
ply.TOOLMemory.PowerStart = ent:GetPowerBandStart()
|
||||
ply.TOOLMemory.PowerEnd = ent:GetPowerBandEnd()
|
||||
ply.TOOLMemory.PeakTorque = ent:GetMaxTorque()
|
||||
ply.TOOLMemory.HasTurbo = ent:GetTurboCharged()
|
||||
ply.TOOLMemory.HasBlower = ent:GetSuperCharged()
|
||||
ply.TOOLMemory.HasRevLimiter = ent:GetRevlimiter()
|
||||
ply.TOOLMemory.HasBulletProofTires = ent:GetBulletProofTires()
|
||||
ply.TOOLMemory.MaxTraction = ent:GetMaxTraction()
|
||||
ply.TOOLMemory.GripOffset = ent:GetTractionBias()
|
||||
ply.TOOLMemory.BrakePower = ent:GetBrakePower()
|
||||
ply.TOOLMemory.PowerDistribution = ent:GetPowerDistribution()
|
||||
ply.TOOLMemory.Efficiency = ent:GetEfficiency()
|
||||
ply.TOOLMemory.HornSound = ent.snd_horn
|
||||
ply.TOOLMemory.HasBackfire = ent:GetBackFire()
|
||||
ply.TOOLMemory.DoesntStall = ent:GetDoNotStall()
|
||||
ply.TOOLMemory.SoundOverride = ent:GetSoundoverride()
|
||||
|
||||
ply.TOOLMemory.FrontHeight = ent:GetFrontSuspensionHeight()
|
||||
ply.TOOLMemory.RearHeight = ent:GetRearSuspensionHeight()
|
||||
|
||||
ply.TOOLMemory.Camber = ent.Camber or 0
|
||||
|
||||
if ent.FrontDampingOverride and ent.FrontConstantOverride and ent.RearDampingOverride and ent.RearConstantOverride then
|
||||
ply.TOOLMemory.FrontDampingOverride = ent.FrontDampingOverride
|
||||
ply.TOOLMemory.FrontConstantOverride = ent.FrontConstantOverride
|
||||
ply.TOOLMemory.RearDampingOverride = ent.RearDampingOverride
|
||||
ply.TOOLMemory.RearConstantOverride = ent.RearConstantOverride
|
||||
end
|
||||
|
||||
if ent.CustomWheels then
|
||||
if ent.GhostWheels then
|
||||
if IsValid(ent.GhostWheels[1]) then
|
||||
ply.TOOLMemory.FrontWheelOverride = ent.GhostWheels[1]:GetModel()
|
||||
elseif IsValid(ent.GhostWheels[2]) then
|
||||
ply.TOOLMemory.FrontWheelOverride = ent.GhostWheels[2]:GetModel()
|
||||
end
|
||||
|
||||
if IsValid(ent.GhostWheels[3]) then
|
||||
ply.TOOLMemory.RearWheelOverride = ent.GhostWheels[3]:GetModel()
|
||||
elseif IsValid(ent.GhostWheels[4]) then
|
||||
ply.TOOLMemory.RearWheelOverride = ent.GhostWheels[4]:GetModel()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local tsc = ent:GetTireSmokeColor()
|
||||
ply.TOOLMemory.TireSmokeColor = tsc.r..","..tsc.g..","..tsc.b
|
||||
|
||||
local Gears = ""
|
||||
for _,v in pairs(ent.Gears) do
|
||||
Gears = Gears..v..","
|
||||
end
|
||||
|
||||
local c = ent:GetColor()
|
||||
ply.TOOLMemory.Color = c.r..","..c.g..","..c.b..","..c.a
|
||||
|
||||
local bodygroups = {}
|
||||
for k,v in pairs(ent:GetBodyGroups()) do
|
||||
bodygroups[k] = ent:GetBodygroup( k )
|
||||
end
|
||||
|
||||
ply.TOOLMemory.BodyGroups = string.Implode( ",", bodygroups)
|
||||
|
||||
ply.TOOLMemory.Skin = ent:GetSkin()
|
||||
|
||||
ply.TOOLMemory.Gears = Gears
|
||||
ply.TOOLMemory.FinalGear = ent:GetDifferentialGear()
|
||||
|
||||
if ent.WheelTool_Foffset then
|
||||
ply.TOOLMemory.WheelTool_Foffset = ent.WheelTool_Foffset
|
||||
end
|
||||
|
||||
if ent.WheelTool_Roffset then
|
||||
ply.TOOLMemory.WheelTool_Roffset = ent.WheelTool_Roffset
|
||||
end
|
||||
|
||||
if ent.snd_blowoff then
|
||||
ply.TOOLMemory.snd_blowoff = ent.snd_blowoff
|
||||
end
|
||||
|
||||
if ent.snd_spool then
|
||||
ply.TOOLMemory.snd_spool = ent.snd_spool
|
||||
end
|
||||
|
||||
if ent.snd_bloweron then
|
||||
ply.TOOLMemory.snd_bloweron = ent.snd_bloweron
|
||||
end
|
||||
|
||||
if ent.snd_bloweroff then
|
||||
ply.TOOLMemory.snd_bloweroff = ent.snd_bloweroff
|
||||
end
|
||||
|
||||
ply.TOOLMemory.backfiresound = ent:GetBackfireSound()
|
||||
|
||||
ply.TOOLMemory.SubMaterials = {}
|
||||
for i = 0, (table.Count( ent:GetMaterials() ) - 1) do
|
||||
ply.TOOLMemory.SubMaterials[i] = ent:GetSubMaterial( i )
|
||||
end
|
||||
|
||||
if not IsValid( ply ) then return end
|
||||
|
||||
net.Start("sphys_dupe")
|
||||
net.WriteTable( ply.TOOLMemory )
|
||||
net.Send( ply )
|
||||
end
|
||||
|
||||
local function GetRight( ent, index, WheelPos )
|
||||
local Steer = ent:GetTransformedDirection()
|
||||
|
||||
local Right = ent.Right
|
||||
|
||||
if WheelPos.IsFrontWheel then
|
||||
Right = (IsValid( ent.SteerMaster ) and Steer.Right or ent.Right) * (WheelPos.IsRightWheel and 1 or -1)
|
||||
else
|
||||
Right = (IsValid( ent.SteerMaster ) and Steer.Right2 or ent.Right) * (WheelPos.IsRightWheel and 1 or -1)
|
||||
end
|
||||
|
||||
return Right
|
||||
end
|
||||
|
||||
local function SetWheelOffset( ent, offset_front, offset_rear )
|
||||
if not IsValid( ent ) then return end
|
||||
|
||||
ent.WheelTool_Foffset = offset_front
|
||||
ent.WheelTool_Roffset = offset_rear
|
||||
|
||||
if not istable( ent.Wheels ) or not istable( ent.GhostWheels ) then return end
|
||||
|
||||
for i = 1, table.Count( ent.GhostWheels ) do
|
||||
local Wheel = ent.Wheels[ i ]
|
||||
local WheelModel = ent.GhostWheels[i]
|
||||
local WheelPos = ent:LogicWheelPos( i )
|
||||
|
||||
if IsValid( Wheel ) and IsValid( WheelModel ) then
|
||||
local Pos = Wheel:GetPos()
|
||||
local Right = GetRight( ent, i, WheelPos )
|
||||
local offset = WheelPos.IsFrontWheel and offset_front or offset_rear
|
||||
|
||||
WheelModel:SetParent( nil )
|
||||
|
||||
local physObj = WheelModel:GetPhysicsObject()
|
||||
if IsValid( physObj ) then
|
||||
physObj:EnableMotion( false )
|
||||
end
|
||||
|
||||
WheelModel:SetPos( Pos + Right * offset )
|
||||
WheelModel:SetParent( Wheel )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ApplyWheel(ent, data)
|
||||
ent.CustomWheelAngleOffset = data[2]
|
||||
ent.CustomWheelAngleOffset_R = data[4]
|
||||
|
||||
timer.Simple( 0.05, function()
|
||||
if not IsValid( ent ) then return end
|
||||
for i = 1, table.Count( ent.GhostWheels ) do
|
||||
local Wheel = ent.GhostWheels[i]
|
||||
|
||||
if IsValid( Wheel ) then
|
||||
local isfrontwheel = (i == 1 or i == 2)
|
||||
local swap_y = (i == 2 or i == 4 or i == 6)
|
||||
|
||||
local angleoffset = isfrontwheel and ent.CustomWheelAngleOffset or ent.CustomWheelAngleOffset_R
|
||||
|
||||
local model = isfrontwheel and data[1] or data[3]
|
||||
|
||||
local fAng = ent:LocalToWorldAngles( ent.VehicleData.LocalAngForward )
|
||||
local rAng = ent:LocalToWorldAngles( ent.VehicleData.LocalAngRight )
|
||||
|
||||
local Forward = fAng:Forward()
|
||||
local Right = swap_y and -rAng:Forward() or rAng:Forward()
|
||||
local Up = ent:GetUp()
|
||||
|
||||
local Camber = data[5] or 0
|
||||
|
||||
local ghostAng = Right:Angle()
|
||||
local mirAng = swap_y and 1 or -1
|
||||
ghostAng:RotateAroundAxis(Forward,angleoffset.p * mirAng)
|
||||
ghostAng:RotateAroundAxis(Right,angleoffset.r * mirAng)
|
||||
ghostAng:RotateAroundAxis(Up,-angleoffset.y)
|
||||
|
||||
ghostAng:RotateAroundAxis(Forward, Camber * mirAng)
|
||||
|
||||
Wheel:SetModelScale( 1 )
|
||||
Wheel:SetModel( model )
|
||||
Wheel:SetAngles( ghostAng )
|
||||
|
||||
timer.Simple( 0.05, function()
|
||||
if not IsValid(Wheel) or not IsValid( ent ) then return end
|
||||
local wheelsize = Wheel:OBBMaxs() - Wheel:OBBMins()
|
||||
local radius = isfrontwheel and ent.FrontWheelRadius or ent.RearWheelRadius
|
||||
local size = (radius * 2) / math.max(wheelsize.x,wheelsize.y,wheelsize.z)
|
||||
|
||||
Wheel:SetModelScale( size )
|
||||
end)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function GetAngleFromSpawnlist( model )
|
||||
if not model then print("invalid model") return Angle(0,0,0) end
|
||||
|
||||
model = string.lower( model )
|
||||
|
||||
local v_list = list.Get( "simfphys_vehicles" )
|
||||
for listname, _ in pairs( v_list ) do
|
||||
if v_list[listname].Members.CustomWheels then
|
||||
local FrontWheel = v_list[listname].Members.CustomWheelModel
|
||||
local RearWheel = v_list[listname].Members.CustomWheelModel_R
|
||||
|
||||
if FrontWheel then
|
||||
FrontWheel = string.lower( FrontWheel )
|
||||
end
|
||||
|
||||
if RearWheel then
|
||||
RearWheel = string.lower( RearWheel )
|
||||
end
|
||||
|
||||
if model == FrontWheel or model == RearWheel then
|
||||
local Angleoffset = v_list[listname].Members.CustomWheelAngleOffset
|
||||
if (Angleoffset) then
|
||||
return Angleoffset
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local list = list.Get( "simfphys_Wheels" )[model]
|
||||
local output = list and list.Angle or Angle(0,0,0)
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
if CLIENT then return true end
|
||||
|
||||
local Ent = trace.Entity
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not istable(ply.TOOLMemory) then return end
|
||||
|
||||
local vname = ply.TOOLMemory.SpawnName
|
||||
local Update = false
|
||||
local VehicleList = list.Get( "simfphys_vehicles" )
|
||||
local vehicle = VehicleList[ vname ]
|
||||
|
||||
if not vehicle then return false end
|
||||
|
||||
ply.LockRightClick = true
|
||||
timer.Simple( 0.6, function() if IsValid( ply ) then ply.LockRightClick = false end end )
|
||||
|
||||
local SpawnPos = trace.HitPos + Vector(0,0,25) + (vehicle.SpawnOffset or Vector(0,0,0))
|
||||
|
||||
local SpawnAng = self:GetOwner():EyeAngles()
|
||||
SpawnAng.pitch = 0
|
||||
SpawnAng.yaw = SpawnAng.yaw + 180 + (vehicle.SpawnAngleOffset and vehicle.SpawnAngleOffset or 0)
|
||||
SpawnAng.roll = 0
|
||||
|
||||
if simfphys.IsCar( Ent ) then
|
||||
if vname ~= Ent:GetSpawn_List() then
|
||||
ply:PrintMessage( HUD_PRINTTALK, vname.." is not compatible with "..Ent:GetSpawn_List() )
|
||||
return
|
||||
end
|
||||
Update = true
|
||||
else
|
||||
Ent = simfphys.SpawnVehicle( ply, SpawnPos, SpawnAng, vehicle.Model, vehicle.Class, vname, vehicle )
|
||||
end
|
||||
|
||||
if not IsValid( Ent ) then return end
|
||||
|
||||
undo.Create( "Vehicle" )
|
||||
undo.SetPlayer( ply )
|
||||
undo.AddEntity( Ent )
|
||||
undo.SetCustomUndoText( "Undone " .. vehicle.Name )
|
||||
undo.Finish( "Vehicle (" .. tostring( vehicle.Name ) .. ")" )
|
||||
|
||||
ply:AddCleanup( "vehicles", Ent )
|
||||
|
||||
timer.Simple( 0.5, function()
|
||||
if not IsValid(Ent) then return end
|
||||
|
||||
local tsc = string.Explode( ",", ply.TOOLMemory.TireSmokeColor )
|
||||
Ent:SetTireSmokeColor( Vector( tonumber(tsc[1]), tonumber(tsc[2]), tonumber(tsc[3]) ) )
|
||||
|
||||
Ent.Turbocharged = tobool( ply.TOOLMemory.HasTurbo )
|
||||
Ent.Supercharged = tobool( ply.TOOLMemory.HasBlower )
|
||||
|
||||
Ent:SetEngineSoundPreset( math.Clamp( tonumber( ply.TOOLMemory.SoundPreset ), -1, 23) )
|
||||
Ent:SetMaxTorque( math.Clamp( tonumber( ply.TOOLMemory.PeakTorque ), 20, 1000) )
|
||||
Ent:SetDifferentialGear( math.Clamp( tonumber( ply.TOOLMemory.FinalGear ),0.2, 6 ) )
|
||||
|
||||
Ent:SetSteerSpeed( math.Clamp( tonumber( ply.TOOLMemory.SteerSpeed ), 1, 16 ) )
|
||||
Ent:SetFastSteerAngle( math.Clamp( tonumber( ply.TOOLMemory.SteerAngFast ), 0, 1) )
|
||||
Ent:SetFastSteerConeFadeSpeed( math.Clamp( tonumber( ply.TOOLMemory.SteerFadeSpeed ), 1, 5000 ) )
|
||||
|
||||
Ent:SetEfficiency( math.Clamp( tonumber( ply.TOOLMemory.Efficiency ) ,0.2,4) )
|
||||
Ent:SetMaxTraction( math.Clamp( tonumber( ply.TOOLMemory.MaxTraction ) , 5,1000) )
|
||||
Ent:SetTractionBias( math.Clamp( tonumber( ply.TOOLMemory.GripOffset ),-0.99,0.99) )
|
||||
Ent:SetPowerDistribution( math.Clamp( tonumber( ply.TOOLMemory.PowerDistribution ) ,-1,1) )
|
||||
|
||||
Ent:SetBackFire( tobool( ply.TOOLMemory.HasBackfire ) )
|
||||
Ent:SetDoNotStall( tobool( ply.TOOLMemory.DoesntStall ) )
|
||||
|
||||
Ent:SetIdleRPM( math.Clamp( tonumber( ply.TOOLMemory.IdleRPM ),1,25000) )
|
||||
Ent:SetLimitRPM( math.Clamp( tonumber( ply.TOOLMemory.MaxRPM ),4,25000) )
|
||||
Ent:SetRevlimiter( tobool( ply.TOOLMemory.HasRevLimiter ) )
|
||||
Ent:SetPowerBandEnd( math.Clamp( tonumber( ply.TOOLMemory.PowerEnd ), 3, 25000) )
|
||||
Ent:SetPowerBandStart( math.Clamp( tonumber( ply.TOOLMemory.PowerStart ) ,2 ,25000) )
|
||||
|
||||
Ent:SetTurboCharged( Ent.Turbocharged )
|
||||
Ent:SetSuperCharged( Ent.Supercharged )
|
||||
Ent:SetBrakePower( math.Clamp( tonumber( ply.TOOLMemory.BrakePower ), 0.1, 500) )
|
||||
|
||||
Ent:SetSoundoverride( ply.TOOLMemory.SoundOverride or "" )
|
||||
|
||||
Ent:SetLights_List( Ent.LightsTable or "no_lights" )
|
||||
|
||||
Ent:SetBulletProofTires( tobool( ply.TOOLMemory.HasBulletProofTires ) )
|
||||
|
||||
Ent.snd_horn = ply.TOOLMemory.HornSound
|
||||
|
||||
Ent.snd_blowoff = ply.TOOLMemory.snd_blowoff
|
||||
Ent.snd_spool = ply.TOOLMemory.snd_spool
|
||||
Ent.snd_bloweron = ply.TOOLMemory.snd_bloweron
|
||||
Ent.snd_bloweroff = ply.TOOLMemory.snd_bloweroff
|
||||
|
||||
Ent:SetBackfireSound( ply.TOOLMemory.backfiresound or "" )
|
||||
|
||||
local Gears = {}
|
||||
local Data = string.Explode( ",", ply.TOOLMemory.Gears )
|
||||
for i = 1, table.Count( Data ) do
|
||||
local gRatio = tonumber( Data[i] )
|
||||
|
||||
if isnumber( gRatio ) then
|
||||
if i == 1 then
|
||||
Gears[i] = math.Clamp( gRatio, -5, -0.001)
|
||||
|
||||
elseif i == 2 then
|
||||
Gears[i] = 0
|
||||
|
||||
else
|
||||
Gears[i] = math.Clamp( gRatio, 0.001, 5)
|
||||
end
|
||||
end
|
||||
end
|
||||
Ent.Gears = Gears
|
||||
|
||||
if istable( ply.TOOLMemory.SubMaterials ) then
|
||||
for i = 0, table.Count( ply.TOOLMemory.SubMaterials ) do
|
||||
Ent:SetSubMaterial( i, ply.TOOLMemory.SubMaterials[i] )
|
||||
end
|
||||
end
|
||||
|
||||
if ply.TOOLMemory.FrontDampingOverride and ply.TOOLMemory.FrontConstantOverride and ply.TOOLMemory.RearDampingOverride and ply.TOOLMemory.RearConstantOverride then
|
||||
Ent.FrontDampingOverride = tonumber( ply.TOOLMemory.FrontDampingOverride )
|
||||
Ent.FrontConstantOverride = tonumber( ply.TOOLMemory.FrontConstantOverride )
|
||||
Ent.RearDampingOverride = tonumber( ply.TOOLMemory.RearDampingOverride )
|
||||
Ent.RearConstantOverride = tonumber( ply.TOOLMemory.RearConstantOverride )
|
||||
|
||||
local data = {
|
||||
[1] = {Ent.FrontConstantOverride,Ent.FrontDampingOverride},
|
||||
[2] = {Ent.FrontConstantOverride,Ent.FrontDampingOverride},
|
||||
[3] = {Ent.RearConstantOverride,Ent.RearDampingOverride},
|
||||
[4] = {Ent.RearConstantOverride,Ent.RearDampingOverride},
|
||||
[5] = {Ent.RearConstantOverride,Ent.RearDampingOverride},
|
||||
[6] = {Ent.RearConstantOverride,Ent.RearDampingOverride}
|
||||
}
|
||||
|
||||
local elastics = Ent.Elastics
|
||||
if elastics then
|
||||
for i = 1, table.Count( elastics ) do
|
||||
local elastic = elastics[i]
|
||||
if Ent.StrengthenSuspension == true then
|
||||
if IsValid( elastic ) then
|
||||
elastic:Fire( "SetSpringConstant", data[i][1] * 0.5, 0 )
|
||||
elastic:Fire( "SetSpringDamping", data[i][2] * 0.5, 0 )
|
||||
end
|
||||
local elastic2 = elastics[i * 10]
|
||||
if IsValid( elastic2 ) then
|
||||
elastic2:Fire( "SetSpringConstant", data[i][1] * 0.5, 0 )
|
||||
elastic2:Fire( "SetSpringDamping", data[i][2] * 0.5, 0 )
|
||||
end
|
||||
else
|
||||
if IsValid( elastic ) then
|
||||
elastic:Fire( "SetSpringConstant", data[i][1], 0 )
|
||||
elastic:Fire( "SetSpringDamping", data[i][2], 0 )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Ent:SetFrontSuspensionHeight( tonumber( ply.TOOLMemory.FrontHeight ) )
|
||||
Ent:SetRearSuspensionHeight( tonumber( ply.TOOLMemory.RearHeight ) )
|
||||
|
||||
local groups = string.Explode( ",", ply.TOOLMemory.BodyGroups)
|
||||
for i = 1, table.Count( groups ) do
|
||||
Ent:SetBodygroup(i, tonumber(groups[i]) )
|
||||
end
|
||||
|
||||
Ent:SetSkin( ply.TOOLMemory.Skin )
|
||||
|
||||
local c = string.Explode( ",", ply.TOOLMemory.Color )
|
||||
local Color = Color( tonumber(c[1]), tonumber(c[2]), tonumber(c[3]), tonumber(c[4]) )
|
||||
|
||||
local dot = Color.r * Color.g * Color.b * Color.a
|
||||
Ent.OldColor = dot
|
||||
Ent:SetColor( Color )
|
||||
|
||||
local data = {
|
||||
Color = Color,
|
||||
RenderMode = 0,
|
||||
RenderFX = 0
|
||||
}
|
||||
duplicator.StoreEntityModifier( Ent, "colour", data )
|
||||
|
||||
if Update then
|
||||
local PhysObj = Ent:GetPhysicsObject()
|
||||
if not IsValid( PhysObj ) then return end
|
||||
|
||||
local freezeWhenDone = PhysObj:IsMotionEnabled()
|
||||
local freezeWheels = {}
|
||||
PhysObj:EnableMotion( false )
|
||||
Ent:SetNotSolid( true )
|
||||
|
||||
local ResetPos = Ent:GetPos()
|
||||
local ResetAng = Ent:GetAngles()
|
||||
|
||||
Ent:SetPos( ResetPos + Vector(0,0,30) )
|
||||
Ent:SetAngles( Angle(0,ResetAng.y,0) )
|
||||
|
||||
for i = 1, table.Count( Ent.Wheels ) do
|
||||
local Wheel = Ent.Wheels[ i ]
|
||||
if IsValid( Wheel ) then
|
||||
local wPObj = Wheel:GetPhysicsObject()
|
||||
|
||||
if IsValid( wPObj ) then
|
||||
freezeWheels[ i ] = {}
|
||||
freezeWheels[ i ].dofreeze = wPObj:IsMotionEnabled()
|
||||
freezeWheels[ i ].pos = Wheel:GetPos()
|
||||
freezeWheels[ i ].ang = Wheel:GetAngles()
|
||||
Wheel:SetNotSolid( true )
|
||||
wPObj:EnableMotion( true )
|
||||
wPObj:Wake()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
timer.Simple( 0.5, function()
|
||||
if not IsValid( Ent ) then return end
|
||||
if not IsValid( PhysObj ) then return end
|
||||
|
||||
PhysObj:EnableMotion( freezeWhenDone )
|
||||
Ent:SetNotSolid( false )
|
||||
Ent:SetPos( ResetPos )
|
||||
Ent:SetAngles( ResetAng )
|
||||
|
||||
for i = 1, table.Count( freezeWheels ) do
|
||||
local Wheel = Ent.Wheels[ i ]
|
||||
if IsValid( Wheel ) then
|
||||
local wPObj = Wheel:GetPhysicsObject()
|
||||
|
||||
Wheel:SetNotSolid( false )
|
||||
|
||||
if IsValid( wPObj ) then
|
||||
wPObj:EnableMotion( freezeWheels[i].dofreeze )
|
||||
end
|
||||
|
||||
Wheel:SetPos( freezeWheels[ i ].pos )
|
||||
Wheel:SetAngles( freezeWheels[ i ].ang )
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if Ent.CustomWheels then
|
||||
if Ent.GhostWheels then
|
||||
timer.Simple( Update and 0.25 or 0, function()
|
||||
if not IsValid( Ent ) then return end
|
||||
if ply.TOOLMemory.WheelTool_Foffset and ply.TOOLMemory.WheelTool_Roffset then
|
||||
SetWheelOffset( Ent, ply.TOOLMemory.WheelTool_Foffset, ply.TOOLMemory.WheelTool_Roffset )
|
||||
end
|
||||
|
||||
if not ply.TOOLMemory.FrontWheelOverride and not ply.TOOLMemory.RearWheelOverride then return end
|
||||
|
||||
local front_model = ply.TOOLMemory.FrontWheelOverride or vehicle.Members.CustomWheelModel
|
||||
local front_angle = GetAngleFromSpawnlist(front_model)
|
||||
|
||||
local camber = ply.TOOLMemory.Camber or 0
|
||||
local rear_model = ply.TOOLMemory.RearWheelOverride or (vehicle.Members.CustomWheelModel_R and vehicle.Members.CustomWheelModel_R or front_model)
|
||||
local rear_angle = GetAngleFromSpawnlist(rear_model)
|
||||
|
||||
if not front_model or not rear_model or not front_angle or not rear_angle then return end
|
||||
|
||||
if ValidateModel( front_model ) and ValidateModel( rear_model ) then
|
||||
Ent.Camber = camber
|
||||
ApplyWheel(Ent, {front_model,front_angle,rear_model,rear_angle,camber})
|
||||
else
|
||||
ply:PrintMessage( HUD_PRINTTALK, "selected wheel does not exist on the server")
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
if CLIENT then return true end
|
||||
|
||||
local ent = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if ply.LockRightClick then ply:PrintMessage( HUD_PRINTTALK, "Duplicator is busy") return end
|
||||
|
||||
if not istable(ply.TOOLMemory) then
|
||||
ply.TOOLMemory = {}
|
||||
end
|
||||
|
||||
if not IsValid(ent) then
|
||||
table.Empty( ply.TOOLMemory )
|
||||
|
||||
net.Start("sphys_dupe")
|
||||
net.WriteTable( ply.TOOLMemory )
|
||||
net.Send( ply )
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
self:GetVehicleData( ent, ply )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
return false
|
||||
end
|
||||
@@ -0,0 +1,335 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "simfphys"
|
||||
TOOL.Name = "#Vehicle Editor"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar[ "steerspeed" ] = 8
|
||||
TOOL.ClientConVar[ "fadespeed" ] = 535
|
||||
TOOL.ClientConVar[ "faststeerangle" ] = 0.3
|
||||
TOOL.ClientConVar[ "soundpreset" ] = 0
|
||||
TOOL.ClientConVar[ "idlerpm" ] = 800
|
||||
TOOL.ClientConVar[ "maxrpm" ] = 6200
|
||||
TOOL.ClientConVar[ "powerbandstart" ] = 2000
|
||||
TOOL.ClientConVar[ "powerbandend" ] = 6000
|
||||
TOOL.ClientConVar[ "maxtorque" ] = 280
|
||||
TOOL.ClientConVar[ "turbocharged" ] = "0"
|
||||
TOOL.ClientConVar[ "supercharged" ] = "0"
|
||||
TOOL.ClientConVar[ "revlimiter" ] = "0"
|
||||
TOOL.ClientConVar[ "diffgear" ] = 0.65
|
||||
TOOL.ClientConVar[ "traction" ] = 43
|
||||
TOOL.ClientConVar[ "tractionbias" ] = -0.02
|
||||
TOOL.ClientConVar[ "brakepower" ] = 45
|
||||
TOOL.ClientConVar[ "powerdistribution" ] = 1
|
||||
TOOL.ClientConVar[ "efficiency" ] = 1.25
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.simfphyseditor.name", "simfphys vehicle editor" )
|
||||
language.Add( "tool.simfphyseditor.desc", "A tool used to edit simfphys vehicles" )
|
||||
language.Add( "tool.simfphyseditor.0", "Left click apply settings. Right click copy settings. Reload to reset" )
|
||||
language.Add( "tool.simfphyseditor.1", "Left click apply settings. Right click copy settings. Reload to reset" )
|
||||
|
||||
language.Add( "tool.simfphyseditor.steerspeed", "Steer Speed" )
|
||||
language.Add( "tool.simfphyseditor.steerspeed.help", "How fast the steering will move to its target angle" )
|
||||
language.Add( "tool.simfphyseditor.fastspeed", "Fast Steercone Fadespeed" )
|
||||
language.Add( "tool.simfphyseditor.fastspeed.help", "At wich speed (gmod units per second) we want to fade from slow steer angle to fast steer angle" )
|
||||
language.Add( "tool.simfphyseditor.faststeerang", "Fast Steer Angle" )
|
||||
language.Add( "tool.simfphyseditor.faststeerang.help", "Steering angle at high speeds." )
|
||||
language.Add( "tool.simfphyseditor.tractionbias", "Tractionbias" )
|
||||
language.Add( "tool.simfphyseditor.tractionbias.help", "A negative value will get more understeer, a positive value more oversteer. NOTE: this will not affect under/oversteer caused by engine power." )
|
||||
language.Add( "tool.simfphyseditor.powerdist", "Powerdistribution" )
|
||||
language.Add( "tool.simfphyseditor.powerdist.help", "How much power goes to the front and rear wheels, 1 = rear wheel drive -1 = front wheel drive 0 = all wheel drive with power distributed equally on front and rear wheels." )
|
||||
language.Add( "tool.simfphyseditor.efficiency", "Efficiency" )
|
||||
language.Add( "tool.simfphyseditor.efficiency.help", "This defines how good the wheels can put the engine power to the ground. Also may affect max torque and hand brake performance. Its a cheap way to make your car accelerate faster without having to deal with griploss." )
|
||||
language.Add( "tool.simfphyseditor.turbo", "Turbocharged" )
|
||||
language.Add( "tool.simfphyseditor.turbo.help", "Enables Turbo sounds and increases torque at high RPM" )
|
||||
language.Add( "tool.simfphyseditor.blower", "Supercharged" )
|
||||
language.Add( "tool.simfphyseditor.blower.help", "Enables Supercharger sounds and increases torque at low to mid RPM" )
|
||||
language.Add( "tool.simfphyseditor.revlimiter", "Revlimiter" )
|
||||
language.Add( "tool.simfphyseditor.revlimiter.help", "Enables bouncy revlimiter. NOTE: This does not work if Limit RPM is less than 2500!" )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if CLIENT then return true end
|
||||
|
||||
ent:SetSteerSpeed( math.Clamp( self:GetClientNumber( "steerspeed" ), 1, 16 ) )
|
||||
ent:SetFastSteerConeFadeSpeed( math.Clamp( self:GetClientNumber( "fadespeed" ), 1, 5000 ) )
|
||||
ent:SetFastSteerAngle( math.Clamp( self:GetClientNumber( "faststeerangle" ),0,1) )
|
||||
ent:SetEngineSoundPreset( math.Clamp( self:GetClientNumber( "soundpreset" ), -1, 14) )
|
||||
ent:SetIdleRPM( math.Clamp( self:GetClientNumber( "idlerpm" ),1,25000) )
|
||||
ent:SetLimitRPM( math.Clamp( self:GetClientNumber( "maxrpm" ),4,25000) )
|
||||
ent:SetPowerBandStart( math.Clamp( self:GetClientNumber( "powerbandstart" ),2,25000) )
|
||||
ent:SetPowerBandEnd( math.Clamp( self:GetClientNumber( "powerbandend" ),3,25000) )
|
||||
ent:SetMaxTorque( math.Clamp( self:GetClientNumber( "maxtorque" ),20,1000) )
|
||||
ent:SetTurboCharged( self:GetClientInfo( "turbocharged" ) == "1" )
|
||||
ent:SetSuperCharged( self:GetClientInfo( "supercharged" ) == "1" )
|
||||
ent:SetRevlimiter( self:GetClientInfo( "revlimiter" ) == "1" )
|
||||
ent:SetDifferentialGear( math.Clamp( self:GetClientNumber( "diffgear" ),0.2,6 ) )
|
||||
ent:SetMaxTraction( math.Clamp(self:GetClientNumber( "traction" ) , 5,1000) )
|
||||
ent:SetTractionBias( math.Clamp( self:GetClientNumber( "tractionbias" ),-0.99,0.99) )
|
||||
ent:SetBrakePower( math.Clamp( self:GetClientNumber( "brakepower" ),0.1,500) )
|
||||
ent:SetPowerDistribution( math.Clamp( self:GetClientNumber( "powerdistribution" ) ,-1,1) )
|
||||
ent:SetEfficiency( math.Clamp( self:GetClientNumber( "efficiency" ) ,0.2,4) )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
local ent = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if CLIENT then return true end
|
||||
|
||||
ply:ConCommand( "simfphyseditor_steerspeed " ..ent:GetSteerSpeed() )
|
||||
ply:ConCommand( "simfphyseditor_fadespeed " ..ent:GetFastSteerConeFadeSpeed() )
|
||||
ply:ConCommand( "simfphyseditor_faststeerangle " ..ent:GetFastSteerAngle() )
|
||||
ply:ConCommand( "simfphyseditor_soundpreset " ..ent:GetEngineSoundPreset() )
|
||||
ply:ConCommand( "simfphyseditor_idlerpm " ..ent:GetIdleRPM() )
|
||||
ply:ConCommand( "simfphyseditor_maxrpm " ..ent:GetLimitRPM() )
|
||||
ply:ConCommand( "simfphyseditor_powerbandstart " ..ent:GetPowerBandStart() )
|
||||
ply:ConCommand( "simfphyseditor_powerbandend " ..ent:GetPowerBandEnd() )
|
||||
ply:ConCommand( "simfphyseditor_maxtorque " ..ent:GetMaxTorque() )
|
||||
ply:ConCommand( "simfphyseditor_turbocharged " ..(ent:GetTurboCharged() and 1 or 0) )
|
||||
ply:ConCommand( "simfphyseditor_supercharged " ..(ent:GetSuperCharged() and 1 or 0) )
|
||||
ply:ConCommand( "simfphyseditor_revlimiter " ..(ent:GetRevlimiter() and 1 or 0) )
|
||||
ply:ConCommand( "simfphyseditor_diffgear " ..ent:GetDifferentialGear() )
|
||||
ply:ConCommand( "simfphyseditor_traction " ..ent:GetMaxTraction() )
|
||||
ply:ConCommand( "simfphyseditor_tractionbias " ..ent:GetTractionBias() )
|
||||
ply:ConCommand( "simfphyseditor_brakepower " ..ent:GetBrakePower() )
|
||||
ply:ConCommand( "simfphyseditor_powerdistribution " ..ent:GetPowerDistribution() )
|
||||
ply:ConCommand( "simfphyseditor_efficiency " ..ent:GetEfficiency() )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
if CLIENT then
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not IsValid( ply ) then return end
|
||||
|
||||
ply.simeditor_nextrequest = isnumber( ply.simeditor_nextrequest ) and ply.simeditor_nextrequest or 0
|
||||
|
||||
local ent = ply:GetEyeTrace().Entity
|
||||
|
||||
if not simfphys.IsCar( ent ) then return end
|
||||
|
||||
if ply.simeditor_nextrequest < CurTime() then
|
||||
net.Start( "simfphys_plyrequestinfo" )
|
||||
net.WriteEntity( ent )
|
||||
net.SendToServer()
|
||||
|
||||
ply.simeditor_nextrequest = CurTime() + 0.6
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
local ent = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if (SERVER) then
|
||||
local vname = ent:GetSpawn_List()
|
||||
local VehicleList = list.Get( "simfphys_vehicles" )[vname]
|
||||
|
||||
ent:SetSteerSpeed( VehicleList.Members.TurnSpeed )
|
||||
ent:SetFastSteerConeFadeSpeed( VehicleList.Members.SteeringFadeFastSpeed )
|
||||
ent:SetFastSteerAngle( VehicleList.Members.FastSteeringAngle / ent.VehicleData["steerangle"] )
|
||||
ent:SetEngineSoundPreset( VehicleList.Members.EngineSoundPreset )
|
||||
ent:SetIdleRPM( VehicleList.Members.IdleRPM )
|
||||
ent:SetLimitRPM( VehicleList.Members.LimitRPM )
|
||||
ent:SetPowerBandStart( VehicleList.Members.PowerbandStart )
|
||||
ent:SetPowerBandEnd( VehicleList.Members.PowerbandEnd )
|
||||
ent:SetMaxTorque( VehicleList.Members.PeakTorque )
|
||||
ent:SetTurboCharged( VehicleList.Members.Turbocharged or false )
|
||||
ent:SetSuperCharged( VehicleList.Members.Supercharged or false )
|
||||
ent:SetRevlimiter( VehicleList.Members.Revlimiter or false )
|
||||
ent:SetDifferentialGear( VehicleList.Members.DifferentialGear )
|
||||
ent:SetMaxTraction( VehicleList.Members.MaxGrip )
|
||||
ent:SetTractionBias( VehicleList.Members.GripOffset / VehicleList.Members.MaxGrip )
|
||||
ent:SetBrakePower( VehicleList.Members.BrakePower )
|
||||
ent:SetPowerDistribution( VehicleList.Members.PowerBias )
|
||||
ent:SetEfficiency( VehicleList.Members.Efficiency )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "Header", { Text = "#tool.simfphyseditor.name", Description = "#tool.simfphyseditor.desc" } )
|
||||
|
||||
panel:AddControl( "ComboBox", { MenuButton = 1, Folder = "simfphys", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "--- Steering ---" } )
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "#tool.simfphyseditor.steerspeed",
|
||||
Type = "Float",
|
||||
Min = "1",
|
||||
Max = "16",
|
||||
Command = "simfphyseditor_steerspeed",
|
||||
Help = true
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "#tool.simfphyseditor.fastspeed",
|
||||
Type = "Float",
|
||||
Min = "1",
|
||||
Max = "5000",
|
||||
Command = "simfphyseditor_fadespeed",
|
||||
Help = true
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "#tool.simfphyseditor.faststeerang",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "1",
|
||||
Command = "simfphyseditor_faststeerangle",
|
||||
Help = true
|
||||
})
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "--- Engine ---" } )
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Engine Sound Preset",
|
||||
Type = "Int",
|
||||
Min = "-1",
|
||||
Max = "14",
|
||||
Command = "simfphyseditor_soundpreset"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Idle RPM",
|
||||
Type = "Int",
|
||||
Min = "1",
|
||||
Max = "25000",
|
||||
Command = "simfphyseditor_idlerpm"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Limit RPM",
|
||||
Type = "Int",
|
||||
Min = "4",
|
||||
Max = "25000",
|
||||
Command = "simfphyseditor_maxrpm"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Powerband Start",
|
||||
Type = "Int",
|
||||
Min = "2",
|
||||
Max = "25000",
|
||||
Command = "simfphyseditor_powerbandstart"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Powerband End",
|
||||
Type = "Int",
|
||||
Min = "3",
|
||||
Max = "25000",
|
||||
Command = "simfphyseditor_powerbandend"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Max Torque",
|
||||
Type = "Float",
|
||||
Min = "20",
|
||||
Max = "1000",
|
||||
Command = "simfphyseditor_maxtorque"
|
||||
})
|
||||
panel:AddControl( "Checkbox",
|
||||
{
|
||||
Label = "#tool.simfphyseditor.revlimiter",
|
||||
Command = "simfphyseditor_revlimiter",
|
||||
Help = true
|
||||
})
|
||||
panel:AddControl( "Checkbox",
|
||||
{
|
||||
Label = "#tool.simfphyseditor.turbo",
|
||||
Command = "simfphyseditor_turbocharged",
|
||||
Help = true
|
||||
})
|
||||
panel:AddControl( "Checkbox",
|
||||
{
|
||||
Label = "#tool.simfphyseditor.blower",
|
||||
Command = "simfphyseditor_supercharged",
|
||||
Help = true
|
||||
})
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "--- Transmission ---" } )
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "DifferentialGear",
|
||||
Type = "Float",
|
||||
Min = "0.2",
|
||||
Max = "6",
|
||||
Command = "simfphyseditor_diffgear"
|
||||
})
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "--- Wheels ---" } )
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Max Traction",
|
||||
Type = "Float",
|
||||
Min = "5",
|
||||
Max = "1000",
|
||||
Command = "simfphyseditor_traction"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "#tool.simfphyseditor.tractionbias",
|
||||
Type = "Float",
|
||||
Min = "-0.99",
|
||||
Max = "0.99",
|
||||
Command = "simfphyseditor_tractionbias",
|
||||
Help = true
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Brakepower",
|
||||
Type = "Float",
|
||||
Min = "0.1",
|
||||
Max = "500",
|
||||
Command = "simfphyseditor_brakepower"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "#tool.simfphyseditor.powerdist",
|
||||
Type = "Float",
|
||||
Min = "-1",
|
||||
Max = "1",
|
||||
Command = "simfphyseditor_powerdistribution",
|
||||
Help = true
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "#tool.simfphyseditor.efficiency",
|
||||
Type = "Float",
|
||||
Min = "0.2",
|
||||
Max = "4",
|
||||
Command = "simfphyseditor_efficiency",
|
||||
Help = true
|
||||
})
|
||||
end
|
||||
@@ -0,0 +1,239 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "simfphys"
|
||||
TOOL.Name = "#Transmission Editor"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar[ "numgears" ] = 5
|
||||
TOOL.ClientConVar[ "gear_r" ] = -0.1
|
||||
TOOL.ClientConVar[ "gear_1" ] = 0.1
|
||||
TOOL.ClientConVar[ "gear_2" ] = 0.2
|
||||
TOOL.ClientConVar[ "gear_3" ] = 0.3
|
||||
TOOL.ClientConVar[ "gear_4" ] = 0.4
|
||||
TOOL.ClientConVar[ "gear_5" ] = 0.5
|
||||
TOOL.ClientConVar[ "gear_6" ] = 0.6
|
||||
TOOL.ClientConVar[ "gear_7" ] = 0.7
|
||||
TOOL.ClientConVar[ "gear_8" ] = 0.8
|
||||
TOOL.ClientConVar[ "gear_9" ] = 0.9
|
||||
TOOL.ClientConVar[ "gear_10" ] = 1
|
||||
TOOL.ClientConVar[ "gear_11" ] = 1.1
|
||||
TOOL.ClientConVar[ "gear_12" ] = 1.2
|
||||
TOOL.ClientConVar[ "gear_diff" ] = 0.5
|
||||
TOOL.ClientConVar[ "forcetype" ] = "0"
|
||||
TOOL.ClientConVar[ "type" ] = 2
|
||||
|
||||
local function SetGears( ply, ent, gears)
|
||||
if ( SERVER ) then
|
||||
ent.Gears = gears
|
||||
duplicator.StoreEntityModifier( ent, "gearmod", gears )
|
||||
end
|
||||
end
|
||||
duplicator.RegisterEntityModifier( "gearmod", SetGears )
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.simfphysgeareditor.name", "Transmission Editor" )
|
||||
language.Add( "tool.simfphysgeareditor.desc", "A tool used to edit gear ratios on simfphys vehicles" )
|
||||
language.Add( "tool.simfphysgeareditor.0", "Left click apply settings. Right click copy settings. Reload to reset" )
|
||||
language.Add( "tool.simfphysgeareditor.1", "Left click apply settings. Right click copy settings. Reload to reset" )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if (SERVER) then
|
||||
local vname = ent:GetSpawn_List()
|
||||
local VehicleList = list.Get( "simfphys_vehicles" )[vname]
|
||||
|
||||
local gears = {math.Clamp(self:GetClientNumber( "gear_r" ), -5, -0.001),0}
|
||||
for i = 1, self:GetClientNumber( "numgears" ) do
|
||||
local index = i + 2
|
||||
gears[index] = math.Clamp( self:GetClientNumber( "gear_"..i ), 0.001, 5)
|
||||
end
|
||||
|
||||
SetGears(self:GetOwner(), ent, gears )
|
||||
ent:SetDifferentialGear( math.Clamp( self:GetClientNumber( "gear_diff" ),0.2,6 ) )
|
||||
|
||||
if tobool( self:GetClientInfo( "forcetype" ) ) then
|
||||
ent.ForceTransmission = math.Clamp( self:GetClientNumber( "type" ), 1, 2 )
|
||||
else
|
||||
ent.ForceTransmission = nil
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
local ent = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if (SERVER) then
|
||||
local vname = ent:GetSpawn_List()
|
||||
local VehicleList = list.Get( "simfphys_vehicles" )[vname]
|
||||
|
||||
local gears = ent.Gears
|
||||
local diffgear = ent:GetDifferentialGear()
|
||||
local num = table.Count( gears ) - 2
|
||||
|
||||
for i = 3, 13 do
|
||||
ply:ConCommand( "simfphysgeareditor_gear_"..(i - 2).." "..(gears[i] or 0.001))
|
||||
end
|
||||
ply:ConCommand( "simfphysgeareditor_gear_r "..gears[1])
|
||||
ply:ConCommand( "simfphysgeareditor_numgears "..num)
|
||||
ply:ConCommand( "simfphysgeareditor_gear_diff "..diffgear)
|
||||
|
||||
local forcetype = isnumber( ent.ForceTransmission )
|
||||
|
||||
ply:ConCommand( "simfphysgeareditor_forcetype "..tostring(forcetype and 1 or 0) )
|
||||
|
||||
if forcetype then
|
||||
ply:ConCommand( "simfphysgeareditor_type "..ent.ForceTransmission)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
local ent = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if (SERVER) then
|
||||
local vname = ent:GetSpawn_List()
|
||||
local VehicleList = list.Get( "simfphys_vehicles" )[vname]
|
||||
|
||||
SetGears(self:GetOwner(), ent, VehicleList.Members.Gears )
|
||||
ent:SetDifferentialGear( VehicleList.Members.DifferentialGear )
|
||||
|
||||
ent.ForceTransmission = VehicleList.Members.ForceTransmission
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "Header", { Text = "#tool.simfphysgeareditor.name", Description = "#tool.simfphysgeareditor.desc" } )
|
||||
panel:AddControl( "ComboBox", { MenuButton = 1, Folder = "transeditor", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
local Frame = vgui.Create( "DPanel", panel )
|
||||
Frame:SetPos( 10, 130 )
|
||||
Frame:SetSize( 275, 700 )
|
||||
Frame.Paint = function( self, w, h )
|
||||
end
|
||||
|
||||
local Label = vgui.Create( "DLabel", panel )
|
||||
Label:SetPos( 15, 80 )
|
||||
Label:SetSize( 280, 40 )
|
||||
Label:SetText( "Amount Gears" )
|
||||
Label:SetTextColor( Color(0,0,0,255) )
|
||||
|
||||
local n_slider = vgui.Create( "DNumSlider", panel)
|
||||
n_slider:SetPos( 15, 80 )
|
||||
n_slider:SetSize( 280, 40 )
|
||||
n_slider:SetMin( 1 )
|
||||
n_slider:SetMax( 12 )
|
||||
n_slider:SetDecimals( 0 )
|
||||
n_slider:SetConVar( "simfphysgeareditor_numgears" )
|
||||
n_slider.OnValueChanged = function( self, amount )
|
||||
Frame:Clear()
|
||||
|
||||
local value = math.Round( amount, 0 )
|
||||
local yy = 0
|
||||
|
||||
for i = 1, value do
|
||||
local Label = vgui.Create( "DLabel", Frame )
|
||||
Label:SetPos( 5, yy )
|
||||
Label:SetSize( 275, 40 )
|
||||
Label:SetText( "Gear "..i )
|
||||
Label:SetTextColor( Color(0,0,0,255) )
|
||||
|
||||
local g_slider = vgui.Create( "DNumSlider", Frame)
|
||||
g_slider:SetPos( 5, yy )
|
||||
g_slider:SetSize( 275, 40 )
|
||||
g_slider:SetMin( 0.001 )
|
||||
g_slider:SetMax( 5 )
|
||||
g_slider:SetDecimals( 3 )
|
||||
g_slider:SetConVar( "simfphysgeareditor_gear_"..i )
|
||||
|
||||
yy = yy + 25
|
||||
end
|
||||
|
||||
yy = yy + 25
|
||||
|
||||
local Label = vgui.Create( "DLabel", Frame )
|
||||
Label:SetPos( 5, yy )
|
||||
Label:SetSize( 275, 40 )
|
||||
Label:SetText( "Reverse" )
|
||||
Label:SetTextColor( Color(0,0,0,255) )
|
||||
local g_slider = vgui.Create( "DNumSlider", Frame)
|
||||
g_slider:SetPos( 5, yy )
|
||||
g_slider:SetSize( 275, 40 )
|
||||
g_slider:SetMin( -5 )
|
||||
g_slider:SetMax( -0.001 )
|
||||
g_slider:SetDecimals( 3 )
|
||||
g_slider:SetConVar( "simfphysgeareditor_gear_r" )
|
||||
|
||||
yy = yy + 50
|
||||
|
||||
local Label = vgui.Create( "DLabel", Frame )
|
||||
Label:SetPos( 5, yy )
|
||||
Label:SetSize( 275, 40 )
|
||||
Label:SetText( "Final Gear (Differential)" )
|
||||
Label:SetTextColor( Color(0,0,0,255) )
|
||||
local g_slider = vgui.Create( "DNumSlider", Frame)
|
||||
g_slider:SetPos( 5, yy )
|
||||
g_slider:SetSize( 275, 40 )
|
||||
g_slider:SetMin( 0.001 )
|
||||
g_slider:SetMax( 5 )
|
||||
g_slider:SetDecimals( 3 )
|
||||
g_slider:SetConVar( "simfphysgeareditor_gear_diff" )
|
||||
|
||||
yy = yy + 50
|
||||
|
||||
local Label = vgui.Create( "DLabel", Frame )
|
||||
Label:SetPos( 30, yy )
|
||||
Label:SetSize( 280, 40 )
|
||||
Label:SetText( "Force Transmission Type" )
|
||||
Label:SetTextColor( Color(0,0,0,255) )
|
||||
|
||||
local CheckBox = vgui.Create( "DCheckBoxLabel", Frame )
|
||||
CheckBox:SetPos( 5,yy )
|
||||
CheckBox:SetText( "" )
|
||||
CheckBox:SetConVar( "simfphysgeareditor_forcetype" )
|
||||
CheckBox:SetSize( 280, 40 )
|
||||
|
||||
yy = yy + 30
|
||||
|
||||
local Label = vgui.Create( "DLabel", Frame )
|
||||
Label:SetPos( 5, yy )
|
||||
Label:SetSize( 275, 40 )
|
||||
Label:SetText( "Type \n1 = Automatic\n2 = Manual" )
|
||||
Label:SetTextColor( Color(0,0,0,255) )
|
||||
local g_slider = vgui.Create( "DNumSlider", Frame)
|
||||
g_slider:SetPos( 5, yy )
|
||||
g_slider:SetSize( 275, 40 )
|
||||
g_slider:SetMin( 1 )
|
||||
g_slider:SetMax( 2 )
|
||||
g_slider:SetDecimals( 0 )
|
||||
g_slider:SetConVar( "simfphysgeareditor_type" )
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,152 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "simfphys"
|
||||
TOOL.Name = "#Sound Editor - Misc"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar[ "TurboBlowOff" ] = "simulated_vehicles/turbo_blowoff.ogg"
|
||||
TOOL.ClientConVar[ "TurboSpin" ] = "simulated_vehicles/turbo_spin.wav"
|
||||
TOOL.ClientConVar[ "SuperChargerOn" ] = "simulated_vehicles/blower_gearwhine.wav"
|
||||
TOOL.ClientConVar[ "SuperChargerOff" ] = "simulated_vehicles/blower_spin.wav"
|
||||
TOOL.ClientConVar[ "HornSound" ] = "simulated_vehicles/horn_1.wav"
|
||||
TOOL.ClientConVar[ "BackfireSound" ] = ""
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.simfphysmiscsoundeditor.name", "Misc Sound Editor" )
|
||||
language.Add( "tool.simfphysmiscsoundeditor.desc", "A tool used to edit miscellaneous sounds on simfphys vehicles" )
|
||||
language.Add( "tool.simfphysmiscsoundeditor.0", "Left click apply settings. Right click copy settings. Reload to reset" )
|
||||
language.Add( "tool.simfphysmiscsoundeditor.1", "Left click apply settings. Right click copy settings. Reload to reset" )
|
||||
|
||||
presets.Add( "simfphys_miscsound", "Horn 0 - Out of my way", { simfphysmiscsoundeditor_HornSound = "simulated_vehicles/horn_0.wav", } )
|
||||
presets.Add( "simfphys_miscsound", "Horn 1", { simfphysmiscsoundeditor_HornSound = "simulated_vehicles/horn_1.wav", } )
|
||||
presets.Add( "simfphys_miscsound", "Horn 2", { simfphysmiscsoundeditor_HornSound = "simulated_vehicles/horn_2.wav", } )
|
||||
presets.Add( "simfphys_miscsound", "Horn 3", { simfphysmiscsoundeditor_HornSound = "simulated_vehicles/horn_3.wav", } )
|
||||
presets.Add( "simfphys_miscsound", "Horn 4", { simfphysmiscsoundeditor_HornSound = "simulated_vehicles/horn_4.wav", } )
|
||||
presets.Add( "simfphys_miscsound", "Horn 5", { simfphysmiscsoundeditor_HornSound = "simulated_vehicles/horn_5.wav", } )
|
||||
presets.Add( "simfphys_miscsound", "Horn 6 - Vote Daniels", { simfphysmiscsoundeditor_HornSound = "simulated_vehicles/horn_6.wav", } )
|
||||
presets.Add( "simfphys_miscsound", "Horn 7", { simfphysmiscsoundeditor_HornSound = "simulated_vehicles/horn_7.wav", } )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
ent.snd_blowoff = self:GetClientInfo( "TurboBlowOff" )
|
||||
ent.snd_spool = self:GetClientInfo( "TurboSpin" )
|
||||
ent.snd_bloweroff = self:GetClientInfo( "SuperChargerOff" )
|
||||
ent.snd_bloweron = self:GetClientInfo( "SuperChargerOn" )
|
||||
ent.snd_horn = self:GetClientInfo( "HornSound" )
|
||||
ent:SetBackfireSound( self:GetClientInfo( "BackfireSound" ) )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
local ent = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if SERVER then
|
||||
local Sounds = {}
|
||||
Sounds.TurboBlowOff = ent.snd_blowoff or "simulated_vehicles/turbo_blowoff.ogg"
|
||||
Sounds.TurboSpin = ent.snd_spool or "simulated_vehicles/turbo_spin.wav"
|
||||
Sounds.SuperCharger1 = ent.snd_bloweroff or "simulated_vehicles/blower_spin.wav"
|
||||
Sounds.SuperCharger2 = ent.snd_bloweron or "simulated_vehicles/blower_gearwhine.wav"
|
||||
Sounds.HornSound = ent.snd_horn or "simulated_vehicles/horn_1.wav"
|
||||
|
||||
ply:ConCommand( "simfphysmiscsoundeditor_TurboBlowOff "..Sounds.TurboBlowOff )
|
||||
ply:ConCommand( "simfphysmiscsoundeditor_TurboSpin "..Sounds.TurboSpin )
|
||||
ply:ConCommand( "simfphysmiscsoundeditor_SuperChargerOn "..Sounds.SuperCharger2 )
|
||||
ply:ConCommand( "simfphysmiscsoundeditor_SuperChargerOff "..Sounds.SuperCharger1 )
|
||||
ply:ConCommand( "simfphysmiscsoundeditor_HornSound "..Sounds.HornSound )
|
||||
|
||||
local backfiresound = ent:GetBackfireSound()
|
||||
if backfiresound == "" then
|
||||
ply:ConCommand( "simfphysmiscsoundeditor_BackfireSound simulated_vehicles/sfx/ex_backfire_1.ogg" )
|
||||
else
|
||||
ply:ConCommand( "simfphysmiscsoundeditor_BackfireSound "..backfiresound )
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if SERVER then
|
||||
local vehiclelist = list.Get( "simfphys_vehicles" )[ ent:GetSpawn_List() ]
|
||||
|
||||
ent.snd_blowoff = vehiclelist.Members.snd_blowoff or "simulated_vehicles/turbo_blowoff.ogg"
|
||||
ent.snd_spool = vehiclelist.Members.snd_spool or "simulated_vehicles/turbo_spin.wav"
|
||||
ent.snd_bloweroff = vehiclelist.Members.snd_bloweroff or "simulated_vehicles/blower_spin.wav"
|
||||
ent.snd_bloweron = vehiclelist.Members.snd_bloweron or "simulated_vehicles/blower_gearwhine.wav"
|
||||
ent.snd_horn = vehiclelist.Members.snd_horn or "simulated_vehicles/horn_1.wav"
|
||||
ent:SetBackfireSound( vehiclelist.Members.snd_backfire or "" )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "Header", { Text = "#tool.simfphysmiscsoundeditor.name", Description = "#tool.simfphysmiscsoundeditor.desc" } )
|
||||
panel:AddControl( "ComboBox", { MenuButton = 1, Folder = "simfphys_miscsound", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Textbox",
|
||||
{
|
||||
Label = "Turbo blowoff",
|
||||
Command = "simfphysmiscsoundeditor_TurboBlowOff"
|
||||
})
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Textbox",
|
||||
{
|
||||
Label = "Turbo",
|
||||
Command = "simfphysmiscsoundeditor_TurboSpin"
|
||||
})
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Textbox",
|
||||
{
|
||||
Label = "Supercharger 1",
|
||||
Command = "simfphysmiscsoundeditor_SuperChargerOn"
|
||||
})
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Textbox",
|
||||
{
|
||||
Label = "Supercharger 2",
|
||||
Command = "simfphysmiscsoundeditor_SuperChargerOff"
|
||||
})
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Textbox",
|
||||
{
|
||||
Label = "Horn",
|
||||
Command = "simfphysmiscsoundeditor_HornSound"
|
||||
})
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Textbox",
|
||||
{
|
||||
Label = "Backfire",
|
||||
Command = "simfphysmiscsoundeditor_BackfireSound"
|
||||
})
|
||||
|
||||
end
|
||||
@@ -0,0 +1,430 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "simfphys"
|
||||
TOOL.Name = "#Sound Editor - Engine"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar[ "Idle" ] = "simulated_vehicles/misc/e49_idle.wav"
|
||||
TOOL.ClientConVar[ "IdlePitch" ] = 1
|
||||
TOOL.ClientConVar[ "Mid" ] = "simulated_vehicles/misc/gto_onlow.wav"
|
||||
TOOL.ClientConVar[ "MidPitch" ] = 1
|
||||
TOOL.ClientConVar[ "MidVolume" ] = 0.75
|
||||
TOOL.ClientConVar[ "MidFadeOutRPMpercent" ] = 68
|
||||
TOOL.ClientConVar[ "MidFadeOutRate" ] = 0.4
|
||||
TOOL.ClientConVar[ "High" ] = "simulated_vehicles/misc/nv2_onlow_ex.wav"
|
||||
TOOL.ClientConVar[ "HighPitch" ] = 1
|
||||
TOOL.ClientConVar[ "HighVolume" ] = 1
|
||||
TOOL.ClientConVar[ "HighFadeInRPMpercent" ] = 26.6
|
||||
TOOL.ClientConVar[ "HighFadeInRate" ] = 0.266
|
||||
TOOL.ClientConVar[ "Throttle" ] = "simulated_vehicles/valve_noise.wav"
|
||||
TOOL.ClientConVar[ "ThrottlePitch" ] = 0.65
|
||||
TOOL.ClientConVar[ "ThrottleVolume" ] = 1
|
||||
TOOL.ClientConVar[ "Type" ] = "0"
|
||||
TOOL.ClientConVar[ "ShiftDown" ] = ""
|
||||
TOOL.ClientConVar[ "ShiftUp" ] = ""
|
||||
TOOL.ClientConVar[ "RevDown" ] = ""
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.simfphyssoundeditor.name", "Engine Sound Editor" )
|
||||
language.Add( "tool.simfphyssoundeditor.desc", "A tool used to edit engine sounds on simfphys vehicles" )
|
||||
language.Add( "tool.simfphyssoundeditor.0", "Left click apply settings. Right click copy settings. Reload to reset" )
|
||||
language.Add( "tool.simfphyssoundeditor.1", "Left click apply settings. Right click copy settings. Reload to reset" )
|
||||
|
||||
presets.Add( "simfphys_sound", "Jalopy", {
|
||||
simfphyssoundeditor_High = "simulated_vehicles/jalopy/jalopy_high.wav",
|
||||
simfphyssoundeditor_HighFadeInRate = "0.40",
|
||||
simfphyssoundeditor_HighFadeInRPMpercent = "55.00",
|
||||
simfphyssoundeditor_HighPitch = "0.75",
|
||||
simfphyssoundeditor_HighVolume = "0.90",
|
||||
simfphyssoundeditor_Idle = "simulated_vehicles/jalopy/jalopy_idle.wav",
|
||||
simfphyssoundeditor_IdlePitch = "0.95",
|
||||
simfphyssoundeditor_Mid = "simulated_vehicles/jalopy/jalopy_mid.wav",
|
||||
simfphyssoundeditor_MidFadeOutRate = "0.25",
|
||||
simfphyssoundeditor_MidFadeOutRPMpercent = "55.00",
|
||||
simfphyssoundeditor_MidPitch = "1.00",
|
||||
simfphyssoundeditor_MidVolume = "1.00",
|
||||
simfphyssoundeditor_ThrottlePitch = "0.00",
|
||||
simfphyssoundeditor_ThrottleVolume = "0.00",
|
||||
simfphyssoundeditor_Type = "0",
|
||||
simfphyssoundeditor_ShiftDown = "",
|
||||
simfphyssoundeditor_ShiftUp = "",
|
||||
simfphyssoundeditor_RevDown = ""
|
||||
} )
|
||||
|
||||
presets.Add( "simfphys_sound", "APC", {
|
||||
simfphyssoundeditor_High = "simulated_vehicles/misc/v8high2.wav",
|
||||
simfphyssoundeditor_HighFadeInRate = "0.19",
|
||||
simfphyssoundeditor_HighFadeInRPMpercent = "58.00",
|
||||
simfphyssoundeditor_HighPitch = "1.00",
|
||||
simfphyssoundeditor_HighVolume = "0.75",
|
||||
simfphyssoundeditor_Idle = "simulated_vehicles/misc/nanjing_loop.wav",
|
||||
simfphyssoundeditor_IdlePitch = "1.00",
|
||||
simfphyssoundeditor_Mid = "simulated_vehicles/misc/m50.wav",
|
||||
simfphyssoundeditor_MidFadeOutRate = "0.48",
|
||||
simfphyssoundeditor_MidFadeOutRPMpercent = "58.00",
|
||||
simfphyssoundeditor_MidPitch = "1.00",
|
||||
simfphyssoundeditor_MidVolume = "1.00",
|
||||
simfphyssoundeditor_ThrottlePitch = "0.00",
|
||||
simfphyssoundeditor_ThrottleVolume = "0.00",
|
||||
simfphyssoundeditor_Type = "0",
|
||||
simfphyssoundeditor_ShiftDown = "",
|
||||
simfphyssoundeditor_ShiftUp = "",
|
||||
simfphyssoundeditor_RevDown = ""
|
||||
} )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if SERVER then
|
||||
if self:GetClientInfo( "Type" ) == "1" then
|
||||
ent:SetEngineSoundPreset( -1 )
|
||||
|
||||
local outputstring = {}
|
||||
outputstring[1] = self:GetClientInfo( "Type" )
|
||||
outputstring[2] = self:GetClientInfo( "High" )
|
||||
outputstring[3] = self:GetClientInfo( "HighPitch" )
|
||||
outputstring[4] = self:GetClientInfo( "Idle" )
|
||||
outputstring[5] = self:GetClientInfo( "IdlePitch" )
|
||||
outputstring[6] = self:GetClientInfo( "Mid" )
|
||||
outputstring[7] = self:GetClientInfo( "MidPitch" )
|
||||
outputstring[8] = self:GetClientInfo( "RevDown" )
|
||||
outputstring[9] = self:GetClientInfo( "ShiftDown" )
|
||||
outputstring[10] = self:GetClientInfo( "ShiftUp" )
|
||||
|
||||
ent:SetSoundoverride( string.Implode(",", outputstring ) )
|
||||
else
|
||||
local outputstring = {}
|
||||
outputstring[1] = self:GetClientInfo( "Idle" )
|
||||
outputstring[2] = self:GetClientInfo( "IdlePitch" )
|
||||
outputstring[3] = self:GetClientInfo( "Mid" )
|
||||
outputstring[4] = self:GetClientInfo( "MidPitch" )
|
||||
outputstring[5] = self:GetClientInfo( "MidVolume" )
|
||||
outputstring[6] = self:GetClientInfo( "MidFadeOutRPMpercent" )
|
||||
outputstring[7] = self:GetClientInfo( "MidFadeOutRate" )
|
||||
outputstring[8] = self:GetClientInfo( "High" )
|
||||
outputstring[9] = self:GetClientInfo( "HighPitch" )
|
||||
outputstring[10] = self:GetClientInfo( "HighVolume" )
|
||||
outputstring[11] = self:GetClientInfo( "HighFadeInRPMpercent" )
|
||||
outputstring[12] = self:GetClientInfo( "HighFadeInRate" )
|
||||
outputstring[13] = self:GetClientInfo( "Throttle" )
|
||||
outputstring[14] = self:GetClientInfo( "ThrottlePitch" )
|
||||
outputstring[15] = self:GetClientInfo( "ThrottleVolume" )
|
||||
|
||||
ent:SetEngineSoundPreset( 0 )
|
||||
ent:SetSoundoverride( string.Implode(",", outputstring ) )
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
local ent = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if SERVER then
|
||||
local SoundType = ent:GetEngineSoundPreset()
|
||||
local Sounds = {}
|
||||
|
||||
local vehiclelist = list.Get( "simfphys_vehicles" )[ ent:GetSpawn_List() ]
|
||||
|
||||
if SoundType == -1 then
|
||||
Sounds.Type = 1
|
||||
|
||||
Sounds.Idle = vehiclelist.Members.snd_idle or ""
|
||||
Sounds.Low = vehiclelist.Members.snd_low or ""
|
||||
Sounds.High = vehiclelist.Members.snd_mid or ""
|
||||
Sounds.RevDown = vehiclelist.Members.snd_low_revdown or Sounds.Low
|
||||
Sounds.ShiftUp = vehiclelist.Members.snd_mid_gearup or Sounds.High
|
||||
Sounds.ShiftDown = vehiclelist.Members.snd_mid_geardown or Sounds.ShiftUp
|
||||
|
||||
Sounds.Pitch_Low = vehiclelist.Members.snd_low_pitch or 1
|
||||
Sounds.Pitch_High = vehiclelist.Members.snd_mid_pitch or 1
|
||||
Sounds.Pitch_All = vehiclelist.Members.snd_pitch or 1
|
||||
|
||||
elseif SoundType == 0 then
|
||||
Sounds.Type = 0
|
||||
|
||||
local soundoverride = ent:GetSoundoverride()
|
||||
local data = string.Explode( ",", soundoverride)
|
||||
|
||||
if soundoverride ~= "" then
|
||||
Sounds.Idle = data[1]
|
||||
Sounds.Pitch_All = data[2]
|
||||
|
||||
Sounds.Low = data[3]
|
||||
Sounds.Pitch_Low = data[4]
|
||||
Sounds.MidVolume = data[5]
|
||||
Sounds.MidFadeOutPercent = data[6]
|
||||
Sounds.MidFadeOutRate = data[7]
|
||||
|
||||
Sounds.High = data[8]
|
||||
Sounds.Pitch_High = data[9]
|
||||
Sounds.HighVolume = data[10]
|
||||
Sounds.HighFadeInPercent = data[11]
|
||||
Sounds.HighFadeInRate = data[12]
|
||||
|
||||
Sounds.ThrottleSound = data[13]
|
||||
Sounds.ThrottlePitch = data[14]
|
||||
Sounds.ThrottleVolume = data[15]
|
||||
else
|
||||
Sounds.Idle = vehiclelist and vehiclelist.Members.Sound_Idle or "simulated_vehicles/misc/e49_idle.wav"
|
||||
Sounds.Pitch_All = vehiclelist and vehiclelist.Members.Sound_IdlePitch or 1
|
||||
|
||||
Sounds.Low = vehiclelist and vehiclelist.Members.Sound_Mid or "simulated_vehicles/misc/gto_onlow.wav"
|
||||
Sounds.Pitch_Low = vehiclelist and vehiclelist.Members.Sound_MidPitch or 1
|
||||
Sounds.MidVolume = vehiclelist and vehiclelist.Members.Sound_MidVolume or 0.75
|
||||
Sounds.MidFadeOutPercent = vehiclelist and vehiclelist.Members.Sound_MidFadeOutRPMpercent or 68
|
||||
Sounds.MidFadeOutRate = vehiclelist and vehiclelist.Members.Sound_MidFadeOutRate or 0.4
|
||||
|
||||
Sounds.High = vehiclelist and vehiclelist.Members.Sound_High or "simulated_vehicles/misc/nv2_onlow_ex.wav"
|
||||
Sounds.Pitch_High = vehiclelist and vehiclelist.Members.Sound_HighPitch or 1
|
||||
Sounds.HighVolume = vehiclelist and vehiclelist.Members.Sound_HighVolume or 1
|
||||
Sounds.HighFadeInPercent = vehiclelist and vehiclelist.Members.Sound_HighFadeInRPMpercent or 26.6
|
||||
Sounds.HighFadeInRate = vehiclelist and vehiclelist.Members.Sound_HighFadeInRate or 0.266
|
||||
|
||||
Sounds.ThrottleSound = vehiclelist and vehiclelist.Members.Sound_Throttle or "simulated_vehicles/valve_noise.wav"
|
||||
Sounds.ThrottlePitch = vehiclelist and vehiclelist.Members.Sound_ThrottlePitch or 0.65
|
||||
Sounds.ThrottleVolume = vehiclelist and vehiclelist.Members.Sound_ThrottleVolume or 1
|
||||
end
|
||||
else
|
||||
local demSounds = simfphys.SoundPresets[ SoundType ]
|
||||
Sounds.Type = 1
|
||||
|
||||
Sounds.Idle = demSounds[1]
|
||||
Sounds.Low = demSounds[2]
|
||||
Sounds.High = demSounds[3]
|
||||
Sounds.RevDown = demSounds[4]
|
||||
Sounds.ShiftUp = demSounds[5]
|
||||
Sounds.ShiftDown = demSounds[6]
|
||||
|
||||
Sounds.Pitch_Low = demSounds[7]
|
||||
Sounds.Pitch_High = demSounds[8]
|
||||
Sounds.Pitch_All = demSounds[9]
|
||||
end
|
||||
|
||||
ply:ConCommand( "simfphyssoundeditor_High "..Sounds.High )
|
||||
ply:ConCommand( "simfphyssoundeditor_HighPitch "..Sounds.Pitch_High )
|
||||
ply:ConCommand( "simfphyssoundeditor_Idle "..Sounds.Idle )
|
||||
ply:ConCommand( "simfphyssoundeditor_IdlePitch "..Sounds.Pitch_All )
|
||||
ply:ConCommand( "simfphyssoundeditor_Mid "..Sounds.Low )
|
||||
ply:ConCommand( "simfphyssoundeditor_MidPitch "..Sounds.Pitch_Low )
|
||||
ply:ConCommand( "simfphyssoundeditor_Type "..Sounds.Type )
|
||||
|
||||
if Sounds.Type == 1 then
|
||||
ply:ConCommand( "simfphyssoundeditor_RevDown "..Sounds.RevDown )
|
||||
ply:ConCommand( "simfphyssoundeditor_ShiftDown "..Sounds.ShiftDown )
|
||||
ply:ConCommand( "simfphyssoundeditor_ShiftUp "..Sounds.ShiftUp )
|
||||
|
||||
ply:ConCommand( "simfphyssoundeditor_HighFadeInRate 0.2" )
|
||||
ply:ConCommand( "simfphyssoundeditor_HighFadeInRPMpercent 20" )
|
||||
ply:ConCommand( "simfphyssoundeditor_HighVolume 1" )
|
||||
ply:ConCommand( "simfphyssoundeditor_MidFadeOutRate 0.5" )
|
||||
ply:ConCommand( "simfphyssoundeditor_MidFadeOutRPMpercent 10")
|
||||
ply:ConCommand( "simfphyssoundeditor_MidVolume 1" )
|
||||
|
||||
ply:ConCommand( "simfphyssoundeditor_ThrottlePitch 0" )
|
||||
ply:ConCommand( "simfphyssoundeditor_ThrottleVolume 0" )
|
||||
else
|
||||
ply:ConCommand( "simfphyssoundeditor_HighFadeInRate "..Sounds.HighFadeInRate )
|
||||
ply:ConCommand( "simfphyssoundeditor_HighFadeInRPMpercent "..Sounds.HighFadeInPercent )
|
||||
ply:ConCommand( "simfphyssoundeditor_HighVolume "..Sounds.HighVolume )
|
||||
ply:ConCommand( "simfphyssoundeditor_MidFadeOutRate "..Sounds.MidFadeOutRate )
|
||||
ply:ConCommand( "simfphyssoundeditor_MidFadeOutRPMpercent "..Sounds.MidFadeOutPercent )
|
||||
ply:ConCommand( "simfphyssoundeditor_MidVolume "..Sounds.MidVolume )
|
||||
|
||||
ply:ConCommand( "simfphyssoundeditor_Throttle "..Sounds.ThrottleSound )
|
||||
ply:ConCommand( "simfphyssoundeditor_ThrottlePitch "..Sounds.ThrottlePitch )
|
||||
ply:ConCommand( "simfphyssoundeditor_ThrottleVolume "..Sounds.ThrottleVolume )
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if SERVER then
|
||||
local vname = ent:GetSpawn_List()
|
||||
local VehicleList = list.Get( "simfphys_vehicles" )[vname]
|
||||
|
||||
ent:SetEngineSoundPreset( VehicleList.Members.EngineSoundPreset )
|
||||
ent:SetSoundoverride( "" )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function Slider( parent, name, concommand, ypos, min, max, decimals )
|
||||
local Label = vgui.Create( "DLabel", parent )
|
||||
Label:SetPos( 50, ypos )
|
||||
Label:SetSize( 225, 40 )
|
||||
Label:SetText( name )
|
||||
Label:SetTextColor( Color(0,0,0,255) )
|
||||
|
||||
local Slider = vgui.Create( "DNumSlider", parent )
|
||||
Slider:SetPos( 50, ypos )
|
||||
Slider:SetSize( 225, 40 )
|
||||
Slider:SetMin( min )
|
||||
Slider:SetMax( max )
|
||||
Slider:SetDecimals( decimals )
|
||||
Slider:SetConVar( concommand )
|
||||
end
|
||||
|
||||
local function TextEntry( parent, name, concommand, ypos )
|
||||
local Label = vgui.Create( "DLabel", parent )
|
||||
Label:SetPos( 0, ypos )
|
||||
Label:SetSize( 275, 40 )
|
||||
Label:SetText( name )
|
||||
Label:SetTextColor( Color(0,0,0,255) )
|
||||
|
||||
local TextEntry = vgui.Create( "DTextEntry", parent )
|
||||
TextEntry:SetPos( 0, ypos + 30 )
|
||||
TextEntry:SetSize( 275, 20 )
|
||||
TextEntry:SetText( GetConVar( concommand ):GetString() )
|
||||
TextEntry:SetUpdateOnType( true )
|
||||
TextEntry.OnValueChange = function( self, value )
|
||||
RunConsoleCommand( concommand , tostring( value ) )
|
||||
end
|
||||
end
|
||||
|
||||
local refresh = false
|
||||
cvars.AddChangeCallback( "simfphyssoundeditor_Idle", function( convar, oldValue, newValue )
|
||||
if oldValue ~= newValue then refresh = true end
|
||||
end )
|
||||
cvars.AddChangeCallback( "simfphyssoundeditor_RevDown", function( convar, oldValue, newValue )
|
||||
if oldValue ~= newValue then refresh = true end
|
||||
end )
|
||||
cvars.AddChangeCallback( "simfphyssoundeditor_ShiftUp", function( convar, oldValue, newValue )
|
||||
if oldValue ~= newValue then refresh = true end
|
||||
end )
|
||||
|
||||
local function BuildMenu( Frame, panel )
|
||||
Frame:Clear()
|
||||
|
||||
local checked = GetConVar( "simfphyssoundeditor_Type" ):GetString() == "1"
|
||||
|
||||
local yy = 0
|
||||
|
||||
if not checked then
|
||||
TextEntry( Frame, "Idle Sound:", "simfphyssoundeditor_Idle", yy )
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Pitch", "simfphyssoundeditor_IdlePitch", yy, 0, 2.55, 2 )
|
||||
yy = yy + 50
|
||||
|
||||
TextEntry( Frame, "Mid Sound:", "simfphyssoundeditor_Mid", yy)
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Pitch", "simfphyssoundeditor_MidPitch", yy, 0, 2.55, 3 )
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Volume", "simfphyssoundeditor_MidVolume", yy, 0, 1, 2 )
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Fade out RPM %", "simfphyssoundeditor_MidFadeOutRPMpercent", yy, 0, 100, 0 )
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Fade out rate\n(0 = instant)", "simfphyssoundeditor_MidFadeOutRate", yy, 0, 1, 2 )
|
||||
yy = yy + 50
|
||||
|
||||
TextEntry( Frame, "High Sound:", "simfphyssoundeditor_High", yy)
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Pitch", "simfphyssoundeditor_HighPitch", yy, 0, 2.55, 3 )
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Volume", "simfphyssoundeditor_HighVolume", yy, 0, 1, 2 )
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Fade in RPM %", "simfphyssoundeditor_HighFadeInRPMpercent", yy, 0, 100, 0 )
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Fade in rate\n(0 = instant)", "simfphyssoundeditor_HighFadeInRate", yy, 0, 1, 2 )
|
||||
yy = yy + 50
|
||||
|
||||
TextEntry( Frame, "On Throttle Sound:", "simfphyssoundeditor_Throttle", yy)
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Pitch", "simfphyssoundeditor_ThrottlePitch", yy, 0, 2.55, 3 )
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Volume", "simfphyssoundeditor_ThrottleVolume", yy, 0, 1, 2 )
|
||||
yy = yy + 50
|
||||
else
|
||||
TextEntry( Frame, "Idle:", "simfphyssoundeditor_Idle", yy )
|
||||
yy = yy + 100
|
||||
|
||||
TextEntry( Frame, "Gear Up:", "simfphyssoundeditor_ShiftUp", yy )
|
||||
yy = yy + 50
|
||||
TextEntry( Frame, "Gear Down:", "simfphyssoundeditor_ShiftDown", yy )
|
||||
yy = yy + 50
|
||||
TextEntry( Frame, "Gear (continue):", "simfphyssoundeditor_High", yy )
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Pitch (Gear)", "simfphyssoundeditor_HighPitch", yy, 0, 2.55, 3 )
|
||||
yy = yy + 75
|
||||
|
||||
TextEntry( Frame, "Revdown:", "simfphyssoundeditor_RevDown", yy )
|
||||
yy = yy + 50
|
||||
TextEntry( Frame, "Revdown (continue):", "simfphyssoundeditor_Mid", yy )
|
||||
yy = yy + 50
|
||||
Slider( Frame, "Pitch (Revdown)", "simfphyssoundeditor_MidPitch", yy, 0, 2.55, 3 )
|
||||
yy = yy + 100
|
||||
|
||||
|
||||
local Label = vgui.Create( "DLabel", Frame )
|
||||
Label:SetPos( 0, yy )
|
||||
Label:SetSize( 275, 40 )
|
||||
Label:SetText( "Pitch (Master)" )
|
||||
Label:SetTextColor( Color(0,0,0,255) )
|
||||
|
||||
local Slider = vgui.Create( "DNumSlider", Frame )
|
||||
Slider:SetPos( 0, yy )
|
||||
Slider:SetSize( 275, 40 )
|
||||
Slider:SetMin( 0 )
|
||||
Slider:SetMax( 2.55 )
|
||||
Slider:SetDecimals( 3 )
|
||||
Slider:SetConVar( "simfphyssoundeditor_IdlePitch" )
|
||||
end
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
function TOOL.BuildCPanel( panel )
|
||||
local ply = LocalPlayer()
|
||||
|
||||
panel:AddControl( "Header", { Text = "#tool.simfphyssoundeditor.name", Description = "#tool.simfphyssoundeditor.desc" } )
|
||||
panel:AddControl( "ComboBox", { MenuButton = 1, Folder = "simfphys_sound", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
local Frame = vgui.Create( "DPanel", panel )
|
||||
Frame:SetPos( 10, 130 )
|
||||
Frame:SetSize( 275, 900 )
|
||||
Frame.Paint = function( self, w, h )
|
||||
end
|
||||
Frame.Think = function( self )
|
||||
if refresh then
|
||||
refresh = false
|
||||
BuildMenu( Frame, panel )
|
||||
end
|
||||
end
|
||||
|
||||
local Label = vgui.Create( "DLabel", panel )
|
||||
Label:SetPos( 35, 85 )
|
||||
Label:SetSize( 280, 40 )
|
||||
Label:SetText( "Advanced Sound" )
|
||||
Label:SetTextColor( Color(0,0,0,255) )
|
||||
|
||||
local CheckBox = vgui.Create( "DCheckBoxLabel", panel )
|
||||
CheckBox:SetPos( 15,85 )
|
||||
CheckBox:SetText( "" )
|
||||
CheckBox:SetConVar( "simfphyssoundeditor_Type" )
|
||||
CheckBox:SetSize( 280, 40 )
|
||||
CheckBox.OnChange = function( self, checked )
|
||||
BuildMenu( Frame, panel )
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,218 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "simfphys"
|
||||
TOOL.Name = "#Suspension Editor"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar[ "constant_f" ] = 25000
|
||||
TOOL.ClientConVar[ "constant_r" ] = 25000
|
||||
|
||||
TOOL.ClientConVar[ "height_f" ] = 0
|
||||
TOOL.ClientConVar[ "height_r" ] = 0
|
||||
|
||||
TOOL.ClientConVar[ "damping_f" ] = 2500
|
||||
TOOL.ClientConVar[ "damping_r" ] = 2500
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.simfphyssuspensioneditor.name", "Suspension Editor" )
|
||||
language.Add( "tool.simfphyssuspensioneditor.desc", "A tool used to edit suspension on simfphys vehicles" )
|
||||
language.Add( "tool.simfphyssuspensioneditor.0", "Left click apply settings. Right click copy settings. Reload to reset" )
|
||||
language.Add( "tool.simfphyssuspensioneditor.1", "Left click apply settings. Right click copy settings. Reload to reset" )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
local data = {
|
||||
[1] = {self:GetClientNumber( "constant_f" ),self:GetClientNumber( "damping_f" )},
|
||||
[2] = {self:GetClientNumber( "constant_f" ),self:GetClientNumber( "damping_f" )},
|
||||
[3] = {self:GetClientNumber( "constant_r" ),self:GetClientNumber( "damping_r" )},
|
||||
[4] = {self:GetClientNumber( "constant_r" ),self:GetClientNumber( "damping_r" )},
|
||||
[5] = {self:GetClientNumber( "constant_r" ),self:GetClientNumber( "damping_r" )},
|
||||
[6] = {self:GetClientNumber( "constant_r" ),self:GetClientNumber( "damping_r" )}
|
||||
}
|
||||
|
||||
local elastics = ent.Elastics
|
||||
if (elastics) then
|
||||
for i = 1, table.Count( elastics ) do
|
||||
local elastic = elastics[i]
|
||||
if (ent.StrengthenSuspension == true) then
|
||||
if (IsValid(elastic)) then
|
||||
elastic:Fire( "SetSpringConstant", data[i][1] * 0.5, 0 )
|
||||
elastic:Fire( "SetSpringDamping", data[i][2] * 0.5, 0 )
|
||||
end
|
||||
local elastic2 = elastics[i * 10]
|
||||
if (IsValid(elastic2)) then
|
||||
elastic2:Fire( "SetSpringConstant", data[i][1] * 0.5, 0 )
|
||||
elastic2:Fire( "SetSpringDamping", data[i][2] * 0.5, 0 )
|
||||
end
|
||||
else
|
||||
if (IsValid(elastic)) then
|
||||
elastic:Fire( "SetSpringConstant", data[i][1], 0 )
|
||||
elastic:Fire( "SetSpringDamping", data[i][2], 0 )
|
||||
end
|
||||
end
|
||||
|
||||
ent.FrontDampingOverride = data[1][2]
|
||||
ent.FrontConstantOverride = data[1][1]
|
||||
ent.RearDampingOverride = data[4][2]
|
||||
ent.RearConstantOverride = data[4][1]
|
||||
end
|
||||
end
|
||||
|
||||
ent:SetFrontSuspensionHeight( self:GetClientNumber( "height_f" ) )
|
||||
ent:SetRearSuspensionHeight( self:GetClientNumber( "height_r" ) )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
local ent = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if (SERVER) then
|
||||
local vname = ent:GetSpawn_List()
|
||||
local VehicleList = list.Get( "simfphys_vehicles" )[vname]
|
||||
|
||||
if ent.FrontDampingOverride and ent.FrontConstantOverride and ent.RearDampingOverride and ent.RearConstantOverride then
|
||||
ply:ConCommand( "simfphyssuspensioneditor_constant_f " ..ent.FrontConstantOverride )
|
||||
ply:ConCommand( "simfphyssuspensioneditor_constant_r " ..ent.RearConstantOverride )
|
||||
|
||||
ply:ConCommand( "simfphyssuspensioneditor_damping_f " ..ent.FrontDampingOverride )
|
||||
ply:ConCommand( "simfphyssuspensioneditor_damping_r " ..ent.RearDampingOverride )
|
||||
else
|
||||
ply:ConCommand( "simfphyssuspensioneditor_constant_f " ..VehicleList.Members.FrontConstant )
|
||||
ply:ConCommand( "simfphyssuspensioneditor_constant_r " ..VehicleList.Members.RearConstant )
|
||||
|
||||
ply:ConCommand( "simfphyssuspensioneditor_damping_f " ..VehicleList.Members.FrontDamping )
|
||||
ply:ConCommand( "simfphyssuspensioneditor_damping_r " ..VehicleList.Members.RearDamping )
|
||||
end
|
||||
|
||||
ply:ConCommand( "simfphyssuspensioneditor_height_f " ..ent:GetFrontSuspensionHeight() )
|
||||
ply:ConCommand( "simfphyssuspensioneditor_height_r " ..ent:GetRearSuspensionHeight() )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
local ent = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if (SERVER) then
|
||||
local vname = ent:GetSpawn_List()
|
||||
local VehicleList = list.Get( "simfphys_vehicles" )[vname]
|
||||
|
||||
local data = {
|
||||
[1] = {VehicleList.Members.FrontConstant,VehicleList.Members.FrontDamping,VehicleList.Members.FrontHeight},
|
||||
[2] = {VehicleList.Members.FrontConstant,VehicleList.Members.FrontDamping,VehicleList.Members.FrontHeight},
|
||||
[3] = {VehicleList.Members.RearConstant,VehicleList.Members.RearDamping,VehicleList.Members.RearHeight},
|
||||
[4] = {VehicleList.Members.RearConstant,VehicleList.Members.RearDamping,VehicleList.Members.RearHeight},
|
||||
[5] = {VehicleList.Members.RearConstant,VehicleList.Members.RearDamping,VehicleList.Members.RearHeight},
|
||||
[6] = {VehicleList.Members.RearConstant,VehicleList.Members.RearDamping,VehicleList.Members.RearHeight},
|
||||
}
|
||||
|
||||
local elastics = ent.Elastics
|
||||
if (elastics) then
|
||||
for i = 1, table.Count( elastics ) do
|
||||
local elastic = elastics[i]
|
||||
if (ent.StrengthenSuspension == true) then
|
||||
if (IsValid(elastic)) then
|
||||
elastic:Fire( "SetSpringConstant", data[i][1] * 0.5, 0 )
|
||||
elastic:Fire( "SetSpringDamping", data[i][2] * 0.5, 0 )
|
||||
end
|
||||
local elastic2 = elastics[i * 10]
|
||||
if (IsValid(elastic2)) then
|
||||
elastic2:Fire( "SetSpringConstant", data[i][1] * 0.5, 0 )
|
||||
elastic2:Fire( "SetSpringDamping", data[i][2] * 0.5, 0 )
|
||||
end
|
||||
else
|
||||
if (IsValid(elastic)) then
|
||||
elastic:Fire( "SetSpringConstant", data[i][1], 0 )
|
||||
elastic:Fire( "SetSpringDamping", data[i][2], 0 )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
ent:SetFrontSuspensionHeight( 0 )
|
||||
ent:SetRearSuspensionHeight( 0 )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "Header", { Text = "#tool.simfphyssuspensioneditor.name", Description = "#tool.simfphyssuspensioneditor.desc" } )
|
||||
panel:AddControl( "ComboBox", { MenuButton = 1, Folder = "suspensionedtior", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "--- Front ---" } )
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Front Height",
|
||||
Type = "Float",
|
||||
Min = "-1",
|
||||
Max = "1",
|
||||
Command = "simfphyssuspensioneditor_height_f"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Front Constant",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "50000",
|
||||
Command = "simfphyssuspensioneditor_constant_f"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Front Damping",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "5000",
|
||||
Command = "simfphyssuspensioneditor_damping_f"
|
||||
})
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "--- Rear ---" } )
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Rear Height",
|
||||
Type = "Float",
|
||||
Min = "-1",
|
||||
Max = "1",
|
||||
Command = "simfphyssuspensioneditor_height_r"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Rear Constant",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "50000",
|
||||
Command = "simfphyssuspensioneditor_constant_r"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Rear Damping",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "5000",
|
||||
Command = "simfphyssuspensioneditor_damping_r"
|
||||
})
|
||||
end
|
||||
@@ -0,0 +1,163 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "simfphys"
|
||||
TOOL.Name = "#tool.simfphysturret.name"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
cleanup.Register( "simfphysturrets" )
|
||||
CreateConVar("sbox_maxsimfphysturrets", 1, "FCVAR_NOTIFY")
|
||||
|
||||
TOOL.ClientConVar[ "delay" ] = "0.2"
|
||||
TOOL.ClientConVar[ "damage" ] = "100"
|
||||
TOOL.ClientConVar[ "force" ] = "50"
|
||||
TOOL.ClientConVar[ "size" ] = "3"
|
||||
TOOL.ClientConVar[ "deflectang" ] = "40"
|
||||
TOOL.ClientConVar[ "blastdamage" ] = "50"
|
||||
TOOL.ClientConVar[ "blasteffect" ] = "simfphys_tankweapon_explosion_micro"
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.simfphysturret.name", "Projectile Turret" )
|
||||
language.Add( "tool.simfphysturret.desc", "A Tool used to spawn Turrets" )
|
||||
language.Add( "tool.simfphysturret.0", "Left click to spawn or update a turret" )
|
||||
language.Add( "tool.simfphysturret.1", "Left click to spawn or update a turret" )
|
||||
|
||||
language.Add( "Cleanup_simfphysturrets", "simfphys Projectile Turret" )
|
||||
language.Add( "Cleaned_simfphysturrets", "Cleaned up all simfphys Projectile Turrets" )
|
||||
|
||||
language.Add( "SBoxLimit_simfphysturrets", "You've reached the Projectile Turret limit!" )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if (CLIENT) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if not istable( WireLib ) then
|
||||
ply:PrintMessage( HUD_PRINTTALK, "[SIMFPHYS ARMED]: WIREMOD REQUIRED" )
|
||||
ply:SendLua( "gui.OpenURL( 'https://steamcommunity.com/sharedfiles/filedetails/?id=160250458' )")
|
||||
end
|
||||
|
||||
if IsValid( trace.Entity ) and trace.Entity:GetClass():lower() == "simfphys_turret" then
|
||||
self:UpdateTurret( trace.Entity )
|
||||
else
|
||||
local turret = self:MakeTurret( ply, trace.HitPos + trace.HitNormal * 5 )
|
||||
|
||||
undo.Create("Turret")
|
||||
undo.AddEntity( turret )
|
||||
undo.AddEntity( weld )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
local ValidFX = {
|
||||
["simfphys_tankweapon_explosion"] = true,
|
||||
["simfphys_tankweapon_explosion_micro"] = true,
|
||||
["simfphys_tankweapon_explosion_small"] = true,
|
||||
}
|
||||
|
||||
function TOOL:UpdateTurret( ent )
|
||||
if not IsValid( ent ) then return end
|
||||
|
||||
ent:SetShootDelay( math.Clamp(self:GetClientNumber( "delay" ),0.2,2) )
|
||||
ent:SetDamage( math.Clamp(self:GetClientNumber( "damage" ),0,5000) )
|
||||
ent:SetForce( math.Clamp(self:GetClientNumber( "force" ),0,10000) )
|
||||
ent:SetSize( math.Clamp(self:GetClientNumber( "size" ),3,15) )
|
||||
ent:SetDeflectAng( math.Clamp(self:GetClientNumber( "deflectang" ),0,45) )
|
||||
ent:SetBlastDamage( math.Clamp(self:GetClientNumber( "blastdamage" ),0,1500) )
|
||||
|
||||
local FX = self:GetClientInfo( "blasteffect" )
|
||||
|
||||
ent:SetBlastEffect( ValidFX[ FX ] and FX or "simfphys_tankweapon_explosion_micro" )
|
||||
end
|
||||
|
||||
function TOOL:MakeTurret( ply, Pos, Ang )
|
||||
|
||||
if not ply:CheckLimit( "simfphysturrets" ) then return NULL end
|
||||
|
||||
local turret = ents.Create( "simfphys_turret" )
|
||||
|
||||
if not IsValid( turret ) then return NULL end
|
||||
|
||||
turret:SetPos( Pos )
|
||||
turret:SetAngles( Angle(0,0,0) )
|
||||
turret:Spawn()
|
||||
|
||||
turret.Attacker = ply
|
||||
|
||||
self:UpdateTurret( turret )
|
||||
|
||||
ply:AddCount( "simfphysturrets", turret )
|
||||
ply:AddCleanup( "simfphysturrets", turret )
|
||||
|
||||
return turret
|
||||
end
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "simfphys_turrets", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Header", { Text = "#tool.simfphysturret.name", Description = "#tool.simfphysturret.desc" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Shoot Delay",
|
||||
Type = "Float",
|
||||
Min = 0.2,
|
||||
Max = 2.0,
|
||||
Command = "simfphysturret_delay" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Damage",
|
||||
Type = "Float",
|
||||
Min = 0,
|
||||
Max = 5000,
|
||||
Command = "simfphysturret_damage" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Force",
|
||||
Type = "Float",
|
||||
Min = 0,
|
||||
Max = 10000,
|
||||
Command = "simfphysturret_force" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Size",
|
||||
Type = "Float",
|
||||
Min = 3,
|
||||
Max = 15,
|
||||
Command = "simfphysturret_size" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Max Deflect Angle",
|
||||
Type = "Float",
|
||||
Min = 0,
|
||||
Max = 45,
|
||||
Command = "simfphysturret_deflectang" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Blast Damage",
|
||||
Type = "Float",
|
||||
Min = 0,
|
||||
Max = 1500,
|
||||
Command = "simfphysturret_blastdamage" } )
|
||||
|
||||
|
||||
local BlastEffect = {Label = "Blast Effect", MenuButton = 0, Options={}, CVars = {}}
|
||||
BlastEffect["Options"]["Small Explosion"] = { simfphysturret_blasteffect = "simfphys_tankweapon_explosion_micro" }
|
||||
BlastEffect["Options"]["Medium Explosion"] = { simfphysturret_blasteffect = "simfphys_tankweapon_explosion_small" }
|
||||
BlastEffect["Options"]["Large Explosion"] = { simfphysturret_blasteffect = "simfphys_tankweapon_explosion" }
|
||||
|
||||
CPanel:AddControl("ComboBox", BlastEffect )
|
||||
end
|
||||
@@ -0,0 +1,528 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "simfphys"
|
||||
TOOL.Name = "#Wheel Model Editor"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar[ "frontwheelmodel" ] = "models/props_vehicles/apc_tire001.mdl"
|
||||
TOOL.ClientConVar[ "rearwheelmodel" ] = "models/props_vehicles/apc_tire001.mdl"
|
||||
TOOL.ClientConVar[ "sameasfront" ] = 1
|
||||
TOOL.ClientConVar[ "camber" ] = 0
|
||||
TOOL.ClientConVar[ "offsetfront" ] = 0
|
||||
TOOL.ClientConVar[ "offsetrear" ] = 0
|
||||
|
||||
if CLIENT then
|
||||
language.Add( "tool.simfphyswheeleditor.name", "Wheel Model Editor" )
|
||||
language.Add( "tool.simfphyswheeleditor.desc", "Changes the wheels for simfphys vehicles with CustomWheels Enabled" )
|
||||
language.Add( "tool.simfphyswheeleditor.0", "Left click apply wheel model. Reload to reset" )
|
||||
language.Add( "tool.simfphyswheeleditor.1", "Left click apply wheel model. Reload to reset" )
|
||||
end
|
||||
|
||||
local function GetRight( ent, index, WheelPos )
|
||||
local Steer = ent:GetTransformedDirection()
|
||||
|
||||
local Right = ent.Right
|
||||
|
||||
if WheelPos.IsFrontWheel then
|
||||
Right = (IsValid( ent.SteerMaster ) and Steer.Right or ent.Right) * (WheelPos.IsRightWheel and 1 or -1)
|
||||
else
|
||||
Right = (IsValid( ent.SteerMaster ) and Steer.Right2 or ent.Right) * (WheelPos.IsRightWheel and 1 or -1)
|
||||
end
|
||||
|
||||
return Right
|
||||
end
|
||||
|
||||
local function SetWheelOffset( ent, offset_front, offset_rear )
|
||||
if not IsValid( ent ) then return end
|
||||
|
||||
ent.WheelTool_Foffset = offset_front
|
||||
ent.WheelTool_Roffset = offset_rear
|
||||
|
||||
if not istable( ent.Wheels ) or not istable( ent.GhostWheels ) then return end
|
||||
|
||||
for i = 1, table.Count( ent.GhostWheels ) do
|
||||
local Wheel = ent.Wheels[ i ]
|
||||
local WheelModel = ent.GhostWheels[i]
|
||||
local WheelPos = ent:LogicWheelPos( i )
|
||||
|
||||
if IsValid( Wheel ) and IsValid( WheelModel ) then
|
||||
local Pos = Wheel:GetPos()
|
||||
local Right = GetRight( ent, i, WheelPos )
|
||||
local offset = WheelPos.IsFrontWheel and offset_front or offset_rear
|
||||
|
||||
WheelModel:SetParent( nil )
|
||||
|
||||
local physObj = WheelModel:GetPhysicsObject()
|
||||
if IsValid( physObj ) then
|
||||
physObj:EnableMotion( false )
|
||||
end
|
||||
|
||||
WheelModel:SetPos( Pos + Right * offset )
|
||||
WheelModel:SetParent( Wheel )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ApplyWheel(ply, ent, data)
|
||||
|
||||
ent.CustomWheelAngleOffset = data[2]
|
||||
ent.CustomWheelAngleOffset_R = data[4]
|
||||
|
||||
timer.Simple( 0.05, function()
|
||||
if not IsValid( ent ) then return end
|
||||
|
||||
for i = 1, table.Count( ent.GhostWheels ) do
|
||||
local Wheel = ent.GhostWheels[i]
|
||||
|
||||
if IsValid( Wheel ) then
|
||||
local isfrontwheel = (i == 1 or i == 2)
|
||||
local swap_y = (i == 2 or i == 4 or i == 6)
|
||||
|
||||
local angleoffset = isfrontwheel and ent.CustomWheelAngleOffset or ent.CustomWheelAngleOffset_R
|
||||
|
||||
local model = isfrontwheel and data[1] or data[3]
|
||||
|
||||
local fAng = ent:LocalToWorldAngles( ent.VehicleData.LocalAngForward )
|
||||
local rAng = ent:LocalToWorldAngles( ent.VehicleData.LocalAngRight )
|
||||
|
||||
local Forward = fAng:Forward()
|
||||
local Right = swap_y and -rAng:Forward() or rAng:Forward()
|
||||
local Up = ent:GetUp()
|
||||
|
||||
local Camber = data[5] or 0
|
||||
|
||||
local ghostAng = Right:Angle()
|
||||
local mirAng = swap_y and 1 or -1
|
||||
ghostAng:RotateAroundAxis(Forward,angleoffset.p * mirAng)
|
||||
ghostAng:RotateAroundAxis(Right,angleoffset.r * mirAng)
|
||||
ghostAng:RotateAroundAxis(Up,-angleoffset.y)
|
||||
|
||||
ghostAng:RotateAroundAxis(Forward, Camber * mirAng)
|
||||
|
||||
Wheel:SetModelScale( 1 )
|
||||
Wheel:SetModel( model )
|
||||
Wheel:SetAngles( ghostAng )
|
||||
|
||||
timer.Simple( 0.05, function()
|
||||
if not IsValid( Wheel ) or not IsValid( ent ) then return end
|
||||
local wheelsize = Wheel:OBBMaxs() - Wheel:OBBMins()
|
||||
local radius = isfrontwheel and ent.FrontWheelRadius or ent.RearWheelRadius
|
||||
local size = (radius * 2) / math.max(wheelsize.x,wheelsize.y,wheelsize.z)
|
||||
|
||||
Wheel:SetModelScale( size )
|
||||
end)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function ValidateModel( model )
|
||||
local v_list = list.Get( "simfphys_vehicles" )
|
||||
for listname, _ in pairs( v_list ) do
|
||||
if v_list[listname].Members.CustomWheels then
|
||||
local FrontWheel = v_list[listname].Members.CustomWheelModel
|
||||
local RearWheel = v_list[listname].Members.CustomWheelModel_R
|
||||
|
||||
if FrontWheel then
|
||||
FrontWheel = string.lower( FrontWheel )
|
||||
end
|
||||
|
||||
if RearWheel then
|
||||
RearWheel = string.lower( RearWheel )
|
||||
end
|
||||
|
||||
if model == FrontWheel or model == RearWheel then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local list = list.Get( "simfphys_Wheels" )[model]
|
||||
|
||||
if list then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function GetAngleFromSpawnlist( model )
|
||||
if not model then print("invalid model") return Angle(0,0,0) end
|
||||
|
||||
model = string.lower( model )
|
||||
|
||||
local v_list = list.Get( "simfphys_vehicles" )
|
||||
for listname, _ in pairs( v_list ) do
|
||||
if v_list[listname].Members.CustomWheels then
|
||||
local FrontWheel = v_list[listname].Members.CustomWheelModel
|
||||
local RearWheel = v_list[listname].Members.CustomWheelModel_R
|
||||
|
||||
if FrontWheel then
|
||||
FrontWheel = string.lower( FrontWheel )
|
||||
end
|
||||
|
||||
if RearWheel then
|
||||
RearWheel = string.lower( RearWheel )
|
||||
end
|
||||
|
||||
if model == FrontWheel or model == RearWheel then
|
||||
local Angleoffset = v_list[listname].Members.CustomWheelAngleOffset
|
||||
if Angleoffset then
|
||||
return Angleoffset
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local list = list.Get( "simfphys_Wheels" )[model]
|
||||
local output = list and list.Angle or Angle(0,0,0)
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if SERVER then
|
||||
if not ent.CustomWheels then return end
|
||||
|
||||
local PhysObj = ent:GetPhysicsObject()
|
||||
if not IsValid( PhysObj ) then return end
|
||||
|
||||
local freezeWhenDone = PhysObj:IsMotionEnabled()
|
||||
local freezeWheels = {}
|
||||
PhysObj:EnableMotion( false )
|
||||
ent:SetNotSolid( true )
|
||||
|
||||
local ResetPos = ent:GetPos()
|
||||
local ResetAng = ent:GetAngles()
|
||||
|
||||
ent:SetPos( ResetPos + Vector(0,0,30) )
|
||||
ent:SetAngles( Angle(0,ResetAng.y,0) )
|
||||
|
||||
for i = 1, table.Count( ent.Wheels ) do
|
||||
local Wheel = ent.Wheels[ i ]
|
||||
if IsValid( Wheel ) then
|
||||
local wPObj = Wheel:GetPhysicsObject()
|
||||
|
||||
if IsValid( wPObj ) then
|
||||
freezeWheels[ i ] = {}
|
||||
freezeWheels[ i ].dofreeze = wPObj:IsMotionEnabled()
|
||||
freezeWheels[ i ].pos = Wheel:GetPos()
|
||||
freezeWheels[ i ].ang = Wheel:GetAngles()
|
||||
Wheel:SetNotSolid( true )
|
||||
wPObj:EnableMotion( true )
|
||||
wPObj:Wake()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
timer.Simple( 0.25, function()
|
||||
if not IsValid( ent ) then return end
|
||||
|
||||
local front_model = self:GetClientInfo("frontwheelmodel")
|
||||
local front_angle = GetAngleFromSpawnlist(front_model)
|
||||
|
||||
local sameasfront = self:GetClientInfo("sameasfront") == "1"
|
||||
local camber = self:GetClientInfo("camber")
|
||||
|
||||
local rear_model = sameasfront and front_model or self:GetClientInfo("rearwheelmodel")
|
||||
local rear_angle = GetAngleFromSpawnlist(rear_model)
|
||||
|
||||
local front_offset = self:GetClientInfo("offsetfront")
|
||||
local rear_offset = self:GetClientInfo("offsetrear")
|
||||
|
||||
if not front_model or not rear_model or not front_angle or not rear_angle then print("wtf bro how did you do this") return false end
|
||||
|
||||
if not ValidateModel( front_model ) or not ValidateModel( rear_model ) then
|
||||
local ply = self:GetOwner()
|
||||
ply:PrintMessage( HUD_PRINTTALK, "selected wheel does not exist on the server")
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if ent.CustomWheels then
|
||||
if ent.GhostWheels then
|
||||
ent:SteerVehicle( 0 )
|
||||
|
||||
for i = 1, table.Count( ent.Wheels ) do
|
||||
local Wheel = ent.Wheels[ i ]
|
||||
if IsValid( Wheel ) then
|
||||
local physobj = Wheel:GetPhysicsObject()
|
||||
physobj:EnableMotion( true )
|
||||
physobj:Wake()
|
||||
end
|
||||
end
|
||||
|
||||
ent.Camber = camber
|
||||
ApplyWheel(self:GetOwner(), ent, {front_model,front_angle,rear_model,rear_angle,camber})
|
||||
SetWheelOffset( ent, front_offset, rear_offset )
|
||||
end
|
||||
end
|
||||
|
||||
timer.Simple( 0.25, function()
|
||||
if not IsValid( ent ) then return end
|
||||
if not IsValid( PhysObj ) then return end
|
||||
|
||||
PhysObj:EnableMotion( freezeWhenDone )
|
||||
ent:SetNotSolid( false )
|
||||
ent:SetPos( ResetPos )
|
||||
ent:SetAngles( ResetAng )
|
||||
|
||||
for i = 1, table.Count( freezeWheels ) do
|
||||
local Wheel = ent.Wheels[ i ]
|
||||
if IsValid( Wheel ) then
|
||||
local wPObj = Wheel:GetPhysicsObject()
|
||||
|
||||
Wheel:SetNotSolid( false )
|
||||
|
||||
if IsValid( wPObj ) then
|
||||
wPObj:EnableMotion( freezeWheels[i].dofreeze )
|
||||
end
|
||||
|
||||
Wheel:SetPos( freezeWheels[ i ].pos )
|
||||
Wheel:SetAngles( freezeWheels[ i ].ang )
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
local ent = trace.Entity
|
||||
|
||||
if not simfphys.IsCar( ent ) then return false end
|
||||
|
||||
if SERVER then
|
||||
local PhysObj = ent:GetPhysicsObject()
|
||||
if not IsValid( PhysObj ) then return end
|
||||
|
||||
local freezeWhenDone = PhysObj:IsMotionEnabled()
|
||||
local freezeWheels = {}
|
||||
PhysObj:EnableMotion( false )
|
||||
ent:SetNotSolid( true )
|
||||
|
||||
local ResetPos = ent:GetPos()
|
||||
local ResetAng = ent:GetAngles()
|
||||
|
||||
ent:SetPos( ResetPos + Vector(0,0,30) )
|
||||
ent:SetAngles( Angle(0,ResetAng.y,0) )
|
||||
|
||||
for i = 1, table.Count( ent.Wheels ) do
|
||||
local Wheel = ent.Wheels[ i ]
|
||||
if IsValid( Wheel ) then
|
||||
local wPObj = Wheel:GetPhysicsObject()
|
||||
|
||||
if IsValid( wPObj ) then
|
||||
freezeWheels[ i ] = {}
|
||||
freezeWheels[ i ].dofreeze = wPObj:IsMotionEnabled()
|
||||
freezeWheels[ i ].pos = Wheel:GetPos()
|
||||
freezeWheels[ i ].ang = Wheel:GetAngles()
|
||||
Wheel:SetNotSolid( true )
|
||||
wPObj:EnableMotion( true )
|
||||
wPObj:Wake()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
timer.Simple( 0.25, function()
|
||||
if not IsValid( ent ) then return end
|
||||
|
||||
local vname = ent:GetSpawn_List()
|
||||
local VehicleList = list.Get( "simfphys_vehicles" )[vname]
|
||||
|
||||
if ent.CustomWheels then
|
||||
if ent.GhostWheels then
|
||||
ent:SteerVehicle( 0 )
|
||||
|
||||
for i = 1, table.Count( ent.Wheels ) do
|
||||
local Wheel = ent.Wheels[ i ]
|
||||
if IsValid( Wheel ) then
|
||||
local physobj = Wheel:GetPhysicsObject()
|
||||
physobj:EnableMotion( true )
|
||||
physobj:Wake()
|
||||
end
|
||||
end
|
||||
|
||||
local front_model = VehicleList.Members.CustomWheelModel
|
||||
local front_angle = VehicleList.Members.CustomWheelAngleOffset
|
||||
local rear_model = VehicleList.Members.CustomWheelModel_R and VehicleList.Members.CustomWheelModel_R or front_model
|
||||
local rear_angle = VehicleList.Members.CustomWheelAngleOffset
|
||||
|
||||
ApplyWheel(self:GetOwner(), ent, {front_model,front_angle,rear_model,rear_angle})
|
||||
SetWheelOffset( ent, 0, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
timer.Simple( 0.25, function()
|
||||
if not IsValid( ent ) then return end
|
||||
if not IsValid( PhysObj ) then return end
|
||||
|
||||
PhysObj:EnableMotion( freezeWhenDone )
|
||||
ent:SetNotSolid( false )
|
||||
ent:SetPos( ResetPos )
|
||||
ent:SetAngles( ResetAng )
|
||||
|
||||
for i = 1, table.Count( freezeWheels ) do
|
||||
local Wheel = ent.Wheels[ i ]
|
||||
if IsValid( Wheel ) then
|
||||
local wPObj = Wheel:GetPhysicsObject()
|
||||
|
||||
Wheel:SetNotSolid( false )
|
||||
|
||||
if IsValid( wPObj ) then
|
||||
wPObj:EnableMotion( freezeWheels[i].dofreeze )
|
||||
end
|
||||
|
||||
Wheel:SetPos( freezeWheels[ i ].pos )
|
||||
Wheel:SetAngles( freezeWheels[ i ].ang )
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "Header", { Text = "#tool.simfphyswheeleditor.name", Description = "#tool.simfphyswheeleditor.desc" } )
|
||||
panel:AddControl( "ComboBox", { MenuButton = 1, Folder = "wheeleditor", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Camber",
|
||||
Type = "Float",
|
||||
Min = "-60",
|
||||
Max = "60",
|
||||
Command = "simfphyswheeleditor_camber"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Offset (Front)",
|
||||
Type = "Float",
|
||||
Min = "-50",
|
||||
Max = "50",
|
||||
Command = "simfphyswheeleditor_offsetfront"
|
||||
})
|
||||
panel:AddControl( "Slider",
|
||||
{
|
||||
Label = "Offset (Rear)",
|
||||
Type = "Float",
|
||||
Min = "-50",
|
||||
Max = "50",
|
||||
Command = "simfphyswheeleditor_offsetrear"
|
||||
})
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "Front Wheel Model" } )
|
||||
panel:AddControl( "PropSelect", { Label = "", ConVar = "simfphyswheeleditor_frontwheelmodel", Height = 0, Models = list.Get( "simfphys_Wheels" ) } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "Rear Wheel Model" } )
|
||||
panel:AddControl( "Checkbox",
|
||||
{
|
||||
Label = "same as front",
|
||||
Command = "simfphyswheeleditor_sameasfront",
|
||||
})
|
||||
panel:AddControl( "PropSelect", { Label = "", ConVar = "simfphyswheeleditor_rearwheelmodel", Height = 0, Models = list.Get( "simfphys_Wheels" ) } )
|
||||
|
||||
end
|
||||
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/wheels/magnetic_large.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/smallwheel.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/normal_tire.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/wheels/breakable_tire.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/wheels/drugster_front.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/wheels/drugster_back.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/wheels/moped_tire.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/wheels/trucktire.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/wheels/trucktire2.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/wheels/747wheel.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/props_phx/wheels/monster_truck.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/bmw.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/wheel_2.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/rim_1.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/wheel_extruded_48.mdl", {Angle = Angle(-90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/wheel_race.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/tractors.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/wheel_rounded_36.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/wheel_rounded_36s.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/wheel_rugged_24.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/wheel_rugged_24w.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/wheel_spike_24.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/mechanics/wheels/wheel_spike_48.mdl", {Angle = Angle(90,0,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/xeon133/racewheel/race-wheel-30.mdl", {Angle = Angle(0,-90,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/xeon133/racewheelskinny/race-wheel-30_s.mdl", {Angle = Angle(0,-90,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/nateswheel/nateswheel.mdl", {Angle = Angle(0,180,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/xqm/airplanewheel1medium.mdl", {Angle = Angle(0,180,0)} )
|
||||
list.Set( "simfphys_Wheels", "models/xeon133/offroad/off-road-30.mdl", {Angle = Angle(0,180,0)} )
|
||||
|
||||
local LW_Wheels = {
|
||||
"models/lonewolfie/wheels/wheel_2015chargerpolice.mdl",
|
||||
"models/lonewolfie/wheels/wheel_ametorqthrust.mdl",
|
||||
"models/lonewolfie/wheels/wheel_ametorqthrust_eaglest.mdl",
|
||||
"models/lonewolfie/wheels/wheel_com_rt_gold.mdl",
|
||||
"models/lonewolfie/wheels/wheel_com_th2.mdl",
|
||||
"models/lonewolfie/wheels/wheel_cucv_big.mdl",
|
||||
"models/lonewolfie/wheels/wheel_cucv_small.mdl",
|
||||
"models/lonewolfie/wheels/wheel_fiat595.mdl",
|
||||
"models/lonewolfie/wheels/wheel_ham_edition_race.mdl",
|
||||
"models/lonewolfie/wheels/wheel_impalapolice.mdl",
|
||||
"models/lonewolfie/wheels/wheel_laxaniltc701.mdl",
|
||||
"models/lonewolfie/wheels/wheel_miktometdrag_big.mdl",
|
||||
"models/lonewolfie/wheels/wheel_miktometdrag_highprofile.mdl",
|
||||
"models/lonewolfie/wheels/wheel_miktometdrag_lowprofile.mdl",
|
||||
"models/lonewolfie/wheels/wheel_monstertruck.mdl",
|
||||
"models/lonewolfie/wheels/wheel_oet_type_rxx.mdl",
|
||||
"models/lonewolfie/wheels/wheel_speedline22b.mdl",
|
||||
"models/lonewolfie/wheels/wheel_suvpolice.mdl",
|
||||
"models/lonewolfie/wheels/wheel_volkte37.mdl",
|
||||
"models/lonewolfie/wheels/wheel_wed_sa_97.mdl",
|
||||
"models/lonewolfie/wheels/wheel_welddrag.mdl",
|
||||
"models/lonewolfie/wheels/wheel_welddrag_big.mdl"
|
||||
}
|
||||
|
||||
for i = 1, table.Count( LW_Wheels ) do
|
||||
if file.Exists( LW_Wheels[i], "GAME" ) then
|
||||
list.Set( "simfphys_Wheels", LW_Wheels[i], {Angle = Angle(0,90,0)} )
|
||||
end
|
||||
end
|
||||
|
||||
timer.Simple( 0.1, function()
|
||||
local v_list = list.Get( "simfphys_vehicles" )
|
||||
for listname, _ in pairs( v_list ) do
|
||||
if (v_list[listname].Members.CustomWheels) then
|
||||
local FrontWheel = v_list[listname].Members.CustomWheelModel
|
||||
local RearWheel = v_list[listname].Members.CustomWheelModel_R
|
||||
if (FrontWheel) then
|
||||
if (file.Exists( FrontWheel, "GAME" )) then
|
||||
list.Set( "simfphys_Wheels", FrontWheel, {} )
|
||||
end
|
||||
end
|
||||
if (RearWheel) then
|
||||
if (file.Exists( RearWheel, "GAME" )) then
|
||||
list.Set( "simfphys_Wheels", RearWheel, {} )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
195
gamemodes/sandbox/entities/weapons/gmod_tool/stools/slider.lua
Normal file
195
gamemodes/sandbox/entities/weapons/gmod_tool/stools/slider.lua
Normal file
@@ -0,0 +1,195 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.slider.name"
|
||||
|
||||
TOOL.ClientConVar[ "width" ] = "1.5"
|
||||
TOOL.ClientConVar[ "material" ] = "cable/cable"
|
||||
TOOL.ClientConVar[ "color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "color_g" ] = "255"
|
||||
TOOL.ClientConVar[ "color_b" ] = "255"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1, op = 1 },
|
||||
{ name = "right", stage = 0 },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
self:SetOperation( 1 )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local width = self:GetClientNumber( "width", 1.5 )
|
||||
local material = self:GetClientInfo( "material" )
|
||||
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
|
||||
local constr, rope = constraint.Slider( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, width, material, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Slider" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope ) ) then undo.AddEntity( rope ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope ) end
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( self:GetOperation() == 1 ) then return false end
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
local tr_new = {}
|
||||
tr_new.start = trace.HitPos
|
||||
tr_new.endpos = trace.HitPos + ( trace.HitNormal * 16384 )
|
||||
tr_new.filter = { self:GetOwner() }
|
||||
if ( IsValid( trace.Entity ) ) then
|
||||
table.insert( tr_new.filter, trace.Entity )
|
||||
end
|
||||
|
||||
local tr = util.TraceLine( tr_new )
|
||||
if ( !tr.Hit ) then
|
||||
self:ClearObjects()
|
||||
return
|
||||
end
|
||||
|
||||
-- Don't try to constrain world to world
|
||||
if ( trace.HitWorld && tr.HitWorld ) then
|
||||
self:ClearObjects()
|
||||
return
|
||||
end
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then
|
||||
self:ClearObjects()
|
||||
return
|
||||
end
|
||||
if ( IsValid( tr.Entity ) && tr.Entity:IsPlayer() ) then
|
||||
self:ClearObjects()
|
||||
return
|
||||
end
|
||||
|
||||
-- Check to see if the player can create a slider constraint with the entity in the trace
|
||||
if ( !hook.Run( "CanTool", self:GetOwner(), tr, "slider", self, 2 ) ) then
|
||||
self:ClearObjects()
|
||||
return
|
||||
end
|
||||
|
||||
local Phys2 = tr.Entity:GetPhysicsObjectNum( tr.PhysicsBone )
|
||||
self:SetObject( 2, tr.Entity, tr.HitPos, Phys2, tr.PhysicsBone, trace.HitNormal )
|
||||
|
||||
if ( CLIENT ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
local width = self:GetClientNumber( "width", 1.5 )
|
||||
local material = self:GetClientInfo( "material" )
|
||||
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
|
||||
local constr, rope = constraint.Slider( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, width, material, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Slider" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope ) ) then undo.AddEntity( rope ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope ) end
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Slider" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.slider.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "slider", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.slider.width", Command = "slider_width", Type = "Float", Min = 0, Max = 10 } )
|
||||
CPanel:AddControl( "RopeMaterial", { Label = "#tool.slider.material", ConVar = "slider_material" } )
|
||||
|
||||
CPanel:AddControl( "Color", { Label = "#tool.slider.color", Red = "slider_color_r", Green = "slider_color_g", Blue = "slider_color_b" } )
|
||||
|
||||
end
|
||||
309
gamemodes/sandbox/entities/weapons/gmod_tool/stools/thruster.lua
Normal file
309
gamemodes/sandbox/entities/weapons/gmod_tool/stools/thruster.lua
Normal file
@@ -0,0 +1,309 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.thruster.name"
|
||||
|
||||
TOOL.ClientConVar[ "force" ] = "1500"
|
||||
TOOL.ClientConVar[ "model" ] = "models/props_phx2/garbage_metalcan001a.mdl"
|
||||
TOOL.ClientConVar[ "keygroup" ] = "45"
|
||||
TOOL.ClientConVar[ "keygroup_back" ] = "42"
|
||||
TOOL.ClientConVar[ "toggle" ] = "0"
|
||||
TOOL.ClientConVar[ "collision" ] = "0"
|
||||
TOOL.ClientConVar[ "effect" ] = "fire"
|
||||
TOOL.ClientConVar[ "damageable" ] = "0"
|
||||
TOOL.ClientConVar[ "soundname" ] = "PhysicsCannister.ThrusterLoop"
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
cleanup.Register( "thrusters" )
|
||||
|
||||
local function IsValidThrusterModel( model )
|
||||
for mdl, _ in pairs( list.Get( "ThrusterModels" ) ) do
|
||||
if ( mdl:lower() == model:lower() ) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( trace.Entity && trace.Entity:IsPlayer() ) then return false end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local force = math.Clamp( self:GetClientNumber( "force" ), 0, 1E10 )
|
||||
local model = self:GetClientInfo( "model" )
|
||||
local key = self:GetClientNumber( "keygroup" )
|
||||
local key_bk = self:GetClientNumber( "keygroup_back" )
|
||||
local toggle = self:GetClientNumber( "toggle" )
|
||||
local collision = self:GetClientNumber( "collision" ) == 0
|
||||
local effect = self:GetClientInfo( "effect" )
|
||||
local damageable = self:GetClientNumber( "damageable" )
|
||||
local soundname = self:GetClientInfo( "soundname" )
|
||||
|
||||
-- If we shot a thruster change its force
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:GetClass() == "gmod_thruster" && trace.Entity.pl == ply ) then
|
||||
|
||||
trace.Entity:SetForce( force )
|
||||
trace.Entity:SetEffect( effect )
|
||||
trace.Entity:SetToggle( toggle == 1 )
|
||||
trace.Entity.ActivateOnDamage = damageable == 1
|
||||
trace.Entity:SetSound( soundname )
|
||||
|
||||
numpad.Remove( trace.Entity.NumDown )
|
||||
numpad.Remove( trace.Entity.NumUp )
|
||||
numpad.Remove( trace.Entity.NumBackDown )
|
||||
numpad.Remove( trace.Entity.NumBackUp )
|
||||
|
||||
trace.Entity.NumDown = numpad.OnDown( ply, key, "Thruster_On", trace.Entity, 1 )
|
||||
trace.Entity.NumUp = numpad.OnUp( ply, key, "Thruster_Off", trace.Entity, 1 )
|
||||
|
||||
trace.Entity.NumBackDown = numpad.OnDown( ply, key_bk, "Thruster_On", trace.Entity, -1 )
|
||||
trace.Entity.NumBackUp = numpad.OnUp( ply, key_bk, "Thruster_Off", trace.Entity, -1 )
|
||||
|
||||
trace.Entity.key = key
|
||||
trace.Entity.key_bk = key_bk
|
||||
trace.Entity.force = force
|
||||
trace.Entity.toggle = toggle
|
||||
trace.Entity.effect = effect
|
||||
trace.Entity.damageable = damageable
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if ( !util.IsValidModel( model ) || !util.IsValidProp( model ) || !IsValidThrusterModel( model ) ) then return false end
|
||||
if ( !self:GetWeapon():CheckLimit( "thrusters" ) ) then return false end
|
||||
|
||||
local Ang = trace.HitNormal:Angle()
|
||||
Ang.pitch = Ang.pitch + 90
|
||||
|
||||
local thruster = MakeThruster( ply, model, Ang, trace.HitPos, key, key_bk, force, toggle, effect, damageable, soundname )
|
||||
if ( !IsValid( thruster ) ) then return false end
|
||||
|
||||
local min = thruster:OBBMins()
|
||||
thruster:SetPos( trace.HitPos - trace.HitNormal * min.z )
|
||||
|
||||
undo.Create( "Thruster" )
|
||||
undo.AddEntity( thruster )
|
||||
|
||||
-- Don't weld to world
|
||||
if ( IsValid( trace.Entity ) ) then
|
||||
|
||||
local weld = constraint.Weld( thruster, trace.Entity, 0, trace.PhysicsBone, 0, collision, true )
|
||||
if ( IsValid( weld ) ) then
|
||||
ply:AddCleanup( "thrusters", weld )
|
||||
undo.AddEntity( weld )
|
||||
end
|
||||
|
||||
-- Don't disable collision if it's not attached to anything
|
||||
if ( collision ) then
|
||||
|
||||
if ( IsValid( thruster:GetPhysicsObject() ) ) then thruster:GetPhysicsObject():EnableCollisions( false ) end
|
||||
thruster:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
thruster.nocollide = true
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function MakeThruster( ply, model, ang, pos, key, key_bck, force, toggle, effect, damageable, soundname, nocollide, Data )
|
||||
|
||||
if ( IsValid( ply ) && !ply:CheckLimit( "thrusters" ) ) then return false end
|
||||
if ( !IsValidThrusterModel( model ) ) then return false end
|
||||
|
||||
local thruster = ents.Create( "gmod_thruster" )
|
||||
if ( !IsValid( thruster ) ) then return false end
|
||||
|
||||
duplicator.DoGeneric( thruster, Data )
|
||||
thruster:SetModel( model ) -- Backwards compatible for addons directly calling this function
|
||||
thruster:SetAngles( ang )
|
||||
thruster:SetPos( pos )
|
||||
thruster:Spawn()
|
||||
|
||||
DoPropSpawnedEffect( thruster )
|
||||
|
||||
duplicator.DoGenericPhysics( thruster, ply, Data )
|
||||
|
||||
force = math.Clamp( force, 0, 1E10 )
|
||||
|
||||
thruster:SetEffect( effect )
|
||||
thruster:SetForce( force )
|
||||
thruster:SetToggle( toggle == 1 )
|
||||
thruster.ActivateOnDamage = ( damageable == 1 )
|
||||
thruster:SetPlayer( ply )
|
||||
thruster:SetSound( soundname )
|
||||
|
||||
thruster.NumDown = numpad.OnDown( ply, key, "Thruster_On", thruster, 1 )
|
||||
thruster.NumUp = numpad.OnUp( ply, key, "Thruster_Off", thruster, 1 )
|
||||
|
||||
thruster.NumBackDown = numpad.OnDown( ply, key_bck, "Thruster_On", thruster, -1 )
|
||||
thruster.NumBackUp = numpad.OnUp( ply, key_bck, "Thruster_Off", thruster, -1 )
|
||||
|
||||
if ( nocollide == true ) then
|
||||
if ( IsValid( thruster:GetPhysicsObject() ) ) then thruster:GetPhysicsObject():EnableCollisions( false ) end
|
||||
thruster:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
end
|
||||
|
||||
table.Merge( thruster:GetTable(), {
|
||||
key = key,
|
||||
key_bck = key_bck,
|
||||
force = force,
|
||||
toggle = toggle,
|
||||
pl = ply,
|
||||
effect = effect,
|
||||
nocollide = nocollide,
|
||||
damageable = damageable,
|
||||
soundname = soundname
|
||||
} )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "thrusters", thruster )
|
||||
ply:AddCleanup( "thrusters", thruster )
|
||||
end
|
||||
|
||||
|
||||
return thruster
|
||||
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass( "gmod_thruster", MakeThruster, "Model", "Ang", "Pos", "key", "key_bck", "force", "toggle", "effect", "damageable", "soundname", "nocollide", "Data" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostThruster( ent, ply )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
if ( !trace.Hit || IsValid( trace.Entity ) && ( trace.Entity:GetClass() == "gmod_thruster" || trace.Entity:IsPlayer() ) ) then
|
||||
|
||||
ent:SetNoDraw( true )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch + 90
|
||||
|
||||
local min = ent:OBBMins()
|
||||
ent:SetPos( trace.HitPos - trace.HitNormal * min.z )
|
||||
ent:SetAngles( ang )
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
local mdl = self:GetClientInfo( "model" )
|
||||
if ( !IsValidThrusterModel( mdl ) ) then self:ReleaseGhostEntity() return end
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) || self.GhostEntity:GetModel() != mdl ) then
|
||||
self:MakeGhostEntity( mdl, vector_origin, angle_zero )
|
||||
end
|
||||
|
||||
self:UpdateGhostThruster( self.GhostEntity, self:GetOwner() )
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.thruster.desc" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "thruster", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.thruster.forward", Command = "thruster_keygroup", Label2 = "#tool.thruster.back", Command2 = "thruster_keygroup_back" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.thruster.force", Command = "thruster_force", Type = "Float", Min = 1, Max = 10000 } )
|
||||
|
||||
local combo = CPanel:AddControl( "ListBox", { Label = "#tool.thruster.effect" } )
|
||||
for k, v in pairs( list.Get( "ThrusterEffects" ) ) do
|
||||
combo:AddOption( k, { thruster_effect = v.thruster_effect } )
|
||||
end
|
||||
|
||||
CPanel:AddControl( "ListBox", { Label = "#tool.thruster.sound", Options = list.Get( "ThrusterSounds" ) } )
|
||||
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.thruster.toggle", Command = "thruster_toggle" } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.thruster.collision", Command = "thruster_collision" } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.thruster.damagable", Command = "thruster_damageable" } )
|
||||
|
||||
CPanel:AddControl( "PropSelect", { Label = "#tool.thruster.model", ConVar = "thruster_model", Height = 0, Models = list.Get( "ThrusterModels" ) } )
|
||||
|
||||
end
|
||||
|
||||
list.Set( "ThrusterSounds", "#thrustersounds.none", { thruster_soundname = "" } )
|
||||
list.Set( "ThrusterSounds", "#thrustersounds.steam", { thruster_soundname = "PhysicsCannister.ThrusterLoop" } )
|
||||
list.Set( "ThrusterSounds", "#thrustersounds.zap", { thruster_soundname = "WeaponDissolve.Charge" } )
|
||||
list.Set( "ThrusterSounds", "#thrustersounds.beam", { thruster_soundname = "WeaponDissolve.Beam" } )
|
||||
list.Set( "ThrusterSounds", "#thrustersounds.elevator", { thruster_soundname = "eli_lab.elevator_move" } )
|
||||
list.Set( "ThrusterSounds", "#thrustersounds.energy", { thruster_soundname = "combine.sheild_loop" } )
|
||||
list.Set( "ThrusterSounds", "#thrustersounds.ring", { thruster_soundname = "k_lab.ringsrotating" } )
|
||||
list.Set( "ThrusterSounds", "#thrustersounds.resonance", { thruster_soundname = "k_lab.teleport_rings_high" } )
|
||||
list.Set( "ThrusterSounds", "#thrustersounds.dropship", { thruster_soundname = "k_lab2.DropshipRotorLoop" } )
|
||||
list.Set( "ThrusterSounds", "#thrustersounds.machine", { thruster_soundname = "Town.d1_town_01_spin_loop" } )
|
||||
|
||||
list.Set( "ThrusterModels", "models/dav0r/thruster.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/MaxOfS2D/thruster_projector.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/MaxOfS2D/thruster_propeller.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/thrusters/jetpack.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_junk/plasticbucket001a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_junk/PropaneCanister001a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_junk/propane_tank001a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_junk/PopCan01a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_junk/MetalBucket01a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_lab/jar01a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_c17/lampShade001a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_c17/canister_propane01a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_c17/canister01a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_c17/canister02a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_trainstation/trainstation_ornament002.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_junk/TrafficCone001a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_c17/clock01.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_junk/terracotta01.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_c17/TrapPropeller_Engine.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_c17/FurnitureSink001a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_trainstation/trainstation_ornament001.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_trainstation/trashcan_indoor001b.mdl", {} )
|
||||
|
||||
if ( IsMounted( "cstrike" ) ) then
|
||||
list.Set( "ThrusterModels", "models/props_c17/pottery02a.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/props_c17/pottery03a.mdl", {} )
|
||||
end
|
||||
|
||||
--PHX
|
||||
list.Set( "ThrusterModels", "models/props_phx2/garbage_metalcan001a.mdl", {} )
|
||||
|
||||
--Tile Model Pack Thrusters
|
||||
list.Set( "ThrusterModels", "models/hunter/plates/plate.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/hunter/blocks/cube025x025x025.mdl", {} )
|
||||
|
||||
--XQM Model Pack Thrusters
|
||||
list.Set( "ThrusterModels", "models/XQM/AfterBurner1.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/XQM/AfterBurner1Medium.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/XQM/AfterBurner1Big.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/XQM/AfterBurner1Huge.mdl", {} )
|
||||
list.Set( "ThrusterModels", "models/XQM/AfterBurner1Large.mdl", {} )
|
||||
171
gamemodes/sandbox/entities/weapons/gmod_tool/stools/trails.lua
Normal file
171
gamemodes/sandbox/entities/weapons/gmod_tool/stools/trails.lua
Normal file
@@ -0,0 +1,171 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Render"
|
||||
TOOL.Name = "#tool.trails.name"
|
||||
|
||||
TOOL.ClientConVar[ "r" ] = 255
|
||||
TOOL.ClientConVar[ "g" ] = 255
|
||||
TOOL.ClientConVar[ "b" ] = 255
|
||||
TOOL.ClientConVar[ "a" ] = 255
|
||||
|
||||
TOOL.ClientConVar[ "length" ] = 5
|
||||
TOOL.ClientConVar[ "startsize" ] = 32
|
||||
TOOL.ClientConVar[ "endsize" ] = 0
|
||||
|
||||
TOOL.ClientConVar[ "material" ] = "trails/lol"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" }
|
||||
}
|
||||
|
||||
cleanup.Register( "trails" )
|
||||
|
||||
local function SetTrails( ply, ent, data )
|
||||
|
||||
if ( IsValid( ent.SToolTrail ) ) then
|
||||
|
||||
ent.SToolTrail:Remove()
|
||||
ent.SToolTrail = nil
|
||||
|
||||
end
|
||||
|
||||
if ( !data ) then
|
||||
|
||||
duplicator.ClearEntityModifier( ent, "trail" )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
-- Just don't even bother with invisible trails
|
||||
if ( data.StartSize <= 0 && data.EndSize <= 0 ) then return end
|
||||
|
||||
-- This is here to fix crash exploits
|
||||
if ( !game.SinglePlayer() ) then
|
||||
|
||||
-- Lock down the trail material - only allow what the server allows
|
||||
if ( !list.Contains( "trail_materials", data.Material ) ) then return end
|
||||
|
||||
-- Clamp sizes in multiplayer
|
||||
data.Length = math.Clamp( data.Length, 0.1, 10 )
|
||||
data.EndSize = math.Clamp( data.EndSize, 0, 128 )
|
||||
data.StartSize = math.Clamp( data.StartSize, 0, 128 )
|
||||
|
||||
end
|
||||
|
||||
data.StartSize = math.max( 0.0001, data.StartSize )
|
||||
|
||||
local trail_entity = util.SpriteTrail( ent, 0, data.Color, false, data.StartSize, data.EndSize, data.Length, 1 / ( ( data.StartSize + data.EndSize ) * 0.5 ), data.Material .. ".vmt" )
|
||||
|
||||
ent.SToolTrail = trail_entity
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCleanup( "trails", trail_entity )
|
||||
end
|
||||
|
||||
duplicator.StoreEntityModifier( ent, "trail", data )
|
||||
|
||||
return trail_entity
|
||||
|
||||
end
|
||||
if ( SERVER ) then
|
||||
duplicator.RegisterEntityModifier( "trail", SetTrails )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return false end
|
||||
if ( trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local r = math.Clamp( self:GetClientNumber( "r", 255 ), 0, 255 )
|
||||
local g = math.Clamp( self:GetClientNumber( "g", 255 ), 0, 255 )
|
||||
local b = math.Clamp( self:GetClientNumber( "b", 255 ), 0, 255 )
|
||||
local a = math.Clamp( self:GetClientNumber( "a", 255 ), 0, 255 )
|
||||
|
||||
local length = self:GetClientNumber( "length", 5 )
|
||||
local endsize = self:GetClientNumber( "endsize", 0 )
|
||||
local startsize = self:GetClientNumber( "startsize", 32 )
|
||||
local mat = self:GetClientInfo( "material" )
|
||||
|
||||
local trail = SetTrails( self:GetOwner(), trace.Entity, {
|
||||
Color = Color( r, g, b, a ),
|
||||
Length = length,
|
||||
StartSize = startsize,
|
||||
EndSize = endsize,
|
||||
Material = mat
|
||||
} )
|
||||
|
||||
if ( IsValid( trail ) ) then
|
||||
undo.Create( "Trail" )
|
||||
undo.AddEntity( trail )
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return false end
|
||||
if ( trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
SetTrails( self:GetOwner(), trace.Entity, nil )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Add default materials to list
|
||||
-- Note: Addons can easily add to this list in their -- own file placed in autorun or something.
|
||||
--
|
||||
list.Set( "trail_materials", "#trail.plasma", "trails/plasma" )
|
||||
list.Set( "trail_materials", "#trail.tube", "trails/tube" )
|
||||
list.Set( "trail_materials", "#trail.electric", "trails/electric" )
|
||||
list.Set( "trail_materials", "#trail.smoke", "trails/smoke" )
|
||||
list.Set( "trail_materials", "#trail.laser", "trails/laser" )
|
||||
list.Set( "trail_materials", "#trail.physbeam", "trails/physbeam" )
|
||||
list.Set( "trail_materials", "#trail.love", "trails/love" )
|
||||
list.Set( "trail_materials", "#trail.lol", "trails/lol" )
|
||||
|
||||
if ( IsMounted( "tf" ) ) then
|
||||
list.Set( "trail_materials", "#trail.beam001_blu", "effects/beam001_blu" )
|
||||
list.Set( "trail_materials", "#trail.beam001_red", "effects/beam001_red" )
|
||||
list.Set( "trail_materials", "#trail.beam001_white", "effects/beam001_white" )
|
||||
list.Set( "trail_materials", "#trail.arrowtrail_blu", "effects/arrowtrail_blu" )
|
||||
list.Set( "trail_materials", "#trail.arrowtrail_red", "effects/arrowtrail_red" )
|
||||
list.Set( "trail_materials", "#trail.repair_claw_trail_blue", "effects/repair_claw_trail_blue" )
|
||||
list.Set( "trail_materials", "#trail.repair_claw_trail_red", "effects/repair_claw_trail_red" )
|
||||
list.Set( "trail_materials", "#trail.australiumtrail_red", "effects/australiumtrail_red" )
|
||||
list.Set( "trail_materials", "#trail.beam_generic01", "effects/beam_generic01" )
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.trails.desc" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "trails", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Color", { Label = "#tool.trails.color", Red = "trails_r", Green = "trails_g", Blue = "trails_b", Alpha = "trails_a" } )
|
||||
|
||||
CPanel:NumSlider( "#tool.trails.length", "trails_length", 0, 10, 2 )
|
||||
CPanel:NumSlider( "#tool.trails.startsize", "trails_startsize", 0, 128, 2 )
|
||||
CPanel:NumSlider( "#tool.trails.endsize", "trails_endsize", 0, 128, 2 )
|
||||
|
||||
CPanel:MatSelect( "trails_material", list.Get( "trail_materials" ), true, 0.25, 0.25 )
|
||||
|
||||
end
|
||||
298
gamemodes/sandbox/entities/weapons/gmod_tool/stools/weld.lua
Normal file
298
gamemodes/sandbox/entities/weapons/gmod_tool/stools/weld.lua
Normal file
@@ -0,0 +1,298 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.weld.name"
|
||||
|
||||
TOOL.ClientConVar[ "forcelimit" ] = "0"
|
||||
TOOL.ClientConVar[ "nocollide" ] = "0"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1, op = 2 },
|
||||
{ name = "right", stage = 0 },
|
||||
{ name = "right_1", stage = 1, op = 1 },
|
||||
{ name = "right_2", stage = 2, op = 1 },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( self:GetOperation() == 1 ) then return false end
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return false end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
if ( iNum > 0 ) then self:ClearObjects() end
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
self:SetOperation( 2 )
|
||||
|
||||
if ( iNum == 0 ) then
|
||||
|
||||
self:SetStage( 1 )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( iNum == 1 ) then
|
||||
|
||||
-- Get client's CVars
|
||||
local forcelimit = self:GetClientNumber( "forcelimit" )
|
||||
local nocollide = self:GetClientNumber( "nocollide", 0 ) != 0
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
|
||||
local constr = constraint.Weld( Ent1, Ent2, Bone1, Bone2, forcelimit, nocollide )
|
||||
if ( IsValid( constr ) ) then
|
||||
|
||||
undo.Create( "Weld" )
|
||||
undo.AddEntity( constr )
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "constraints", constr )
|
||||
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( self:GetOperation() == 2 ) then return false end
|
||||
|
||||
-- Make sure the object we're about to use is valid
|
||||
local iNum = self:NumObjects()
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
|
||||
-- You can click anywhere on the 3rd pass
|
||||
if ( iNum < 2 ) then
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
-- Don't weld players, or to players
|
||||
if ( trace.Entity:IsPlayer() ) then return false end
|
||||
|
||||
-- Don't do anything with stuff without any physics..
|
||||
if ( SERVER && !IsValid( Phys ) ) then return false end
|
||||
|
||||
end
|
||||
|
||||
if ( iNum == 0 ) then
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return false end
|
||||
if ( trace.Entity:GetClass() == "prop_vehicle_jeep" ) then return false end
|
||||
|
||||
end
|
||||
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
self:SetOperation( 1 )
|
||||
|
||||
--
|
||||
-- Stage 0 - grab an object, make a ghost entity
|
||||
--
|
||||
if ( iNum == 0 ) then
|
||||
|
||||
self:StartGhostEntity( trace.Entity )
|
||||
self:SetStage( 1 )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Stage 1 - choose the spot and object to weld it to
|
||||
--
|
||||
if ( iNum == 1 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
self:ReleaseGhostEntity()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Get information we're about to use
|
||||
local Norm1, Norm2 = self:GetNormal( 1 ), self:GetNormal( 2 )
|
||||
local Phys1 = self:GetPhys( 1 )
|
||||
local WPos2 = self:GetPos( 2 )
|
||||
|
||||
-- Note: To keep stuff ragdoll friendly try to treat things as physics objects rather than entities
|
||||
local Ang1, Ang2 = Norm1:Angle(), ( -Norm2 ):Angle()
|
||||
local TargetAngle = Phys1:AlignAngles( Ang1, Ang2 )
|
||||
|
||||
Phys1:SetAngles( TargetAngle )
|
||||
|
||||
-- Move the object so that the hitpos on our object is at the second hitpos
|
||||
local TargetPos = WPos2 + ( Phys1:GetPos() - self:GetPos( 1 ) )
|
||||
|
||||
-- Set the position
|
||||
Phys1:SetPos( TargetPos )
|
||||
Phys1:EnableMotion( false )
|
||||
|
||||
-- Wake up the physics object so that the entity updates
|
||||
Phys1:Wake()
|
||||
|
||||
self.RotAxis = Norm2
|
||||
|
||||
self:ReleaseGhostEntity()
|
||||
|
||||
self:SetStage( 2 )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Stage 2 - Weld it in place.
|
||||
--
|
||||
if ( iNum == 2 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
self:ClearObjects()
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local forcelimit = self:GetClientNumber( "forcelimit" )
|
||||
local nocollide = self:GetClientNumber( "nocollide", 0 ) != 0
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local Phys1 = self:GetPhys( 1 )
|
||||
|
||||
-- The entity became invalid half way through
|
||||
if ( !IsValid( Ent1 ) ) then
|
||||
|
||||
self:ClearObjects()
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
local constr = constraint.Weld( Ent1, Ent2, Bone1, Bone2, forcelimit, nocollide )
|
||||
if ( IsValid( constr ) ) then
|
||||
|
||||
Phys1:EnableMotion( true )
|
||||
|
||||
undo.Create( "Weld" )
|
||||
undo.AddEntity( constr )
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "constraints", constr )
|
||||
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
if ( self:NumObjects() < 1 ) then return end
|
||||
|
||||
if ( self:GetOperation() == 1 ) then
|
||||
|
||||
if ( SERVER && !IsValid( self:GetEnt( 1 ) ) ) then
|
||||
|
||||
self:ClearObjects()
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
if ( self:NumObjects() == 1 ) then
|
||||
|
||||
self:UpdateGhostEntity()
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER && self:NumObjects() == 2 ) then
|
||||
|
||||
local Phys1 = self:GetPhys( 1 )
|
||||
|
||||
local cmd = self:GetOwner():GetCurrentCommand()
|
||||
|
||||
local degrees = cmd:GetMouseX() * 0.05
|
||||
|
||||
local angle = Phys1:RotateAroundAxis( self.RotAxis, degrees )
|
||||
|
||||
Phys1:SetAngles( angle )
|
||||
|
||||
-- Move so spots join up
|
||||
local TargetPos = self:GetPos( 2 ) + ( Phys1:GetPos() - self:GetPos( 1 ) )
|
||||
Phys1:SetPos( TargetPos )
|
||||
Phys1:Wake()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Weld" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:FreezeMovement()
|
||||
|
||||
return self:GetOperation() == 1 && self:GetStage() == 2
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
|
||||
self:ClearObjects()
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.weld.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "weld", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.forcelimit", Command = "weld_forcelimit", Type = "Float", Min = 0, Max = 1000, Help = true } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.nocollide", Command = "weld_nocollide" } )
|
||||
|
||||
end
|
||||
458
gamemodes/sandbox/entities/weapons/gmod_tool/stools/wheel.lua
Normal file
458
gamemodes/sandbox/entities/weapons/gmod_tool/stools/wheel.lua
Normal file
@@ -0,0 +1,458 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.wheel.name"
|
||||
|
||||
TOOL.ClientConVar[ "torque" ] = "3000"
|
||||
TOOL.ClientConVar[ "friction" ] = "1"
|
||||
TOOL.ClientConVar[ "nocollide" ] = "1"
|
||||
TOOL.ClientConVar[ "forcelimit" ] = "0"
|
||||
TOOL.ClientConVar[ "fwd" ] = "45"
|
||||
TOOL.ClientConVar[ "bck" ] = "42"
|
||||
TOOL.ClientConVar[ "toggle" ] = "0"
|
||||
TOOL.ClientConVar[ "model" ] = "models/props_vehicles/carparts_wheel01a.mdl"
|
||||
TOOL.ClientConVar[ "rx" ] = "90"
|
||||
TOOL.ClientConVar[ "ry" ] = "0"
|
||||
TOOL.ClientConVar[ "rz" ] = "90"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" },
|
||||
{ name = "use" }
|
||||
}
|
||||
|
||||
cleanup.Register( "wheels" )
|
||||
|
||||
local function IsValidWheelModel( model )
|
||||
for mdl, _ in pairs( list.Get( "WheelModels" ) ) do
|
||||
if ( mdl:lower() == model:lower() ) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Places a wheel
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( trace.Entity and trace.Entity:IsPlayer() ) then return false end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER and !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
if ( !self:GetWeapon():CheckLimit( "wheels" ) ) then return false end
|
||||
|
||||
-- Check the model's validity
|
||||
local model = self:GetClientInfo( "model" )
|
||||
if ( !util.IsValidModel( model ) or !util.IsValidProp( model ) or !IsValidWheelModel( model ) ) then return false end
|
||||
|
||||
-- Get client's CVars
|
||||
local torque = self:GetClientNumber( "torque" )
|
||||
local friction = self:GetClientNumber( "friction" )
|
||||
local nocollide = self:GetClientNumber( "nocollide" )
|
||||
local limit = self:GetClientNumber( "forcelimit" )
|
||||
local toggle = self:GetClientNumber( "toggle" ) != 0
|
||||
|
||||
local fwd = self:GetClientNumber( "fwd" )
|
||||
local bck = self:GetClientNumber( "bck" )
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
-- Make sure we have our wheel angle
|
||||
self.wheelAngle = Angle( math.NormalizeAngle( self:GetClientNumber( "rx" ) ), math.NormalizeAngle( self:GetClientNumber( "ry" ) ), math.NormalizeAngle( self:GetClientNumber( "rz" ) ) )
|
||||
|
||||
-- Create the wheel
|
||||
local wheelEnt = MakeWheel( ply, trace.HitPos, trace.HitNormal:Angle() + self.wheelAngle, model, fwd, bck, nil, nil, toggle, torque )
|
||||
if ( !IsValid( wheelEnt ) ) then return false end
|
||||
|
||||
-- Position
|
||||
local CurPos = wheelEnt:GetPos()
|
||||
local NearestPoint = wheelEnt:NearestPoint( CurPos - ( trace.HitNormal * 512 ) )
|
||||
local wheelOffset = CurPos - NearestPoint
|
||||
|
||||
wheelEnt:SetPos( trace.HitPos + wheelOffset )
|
||||
|
||||
-- Wake up the physics object so that the entity updates
|
||||
if ( IsValid( wheelEnt:GetPhysicsObject() ) ) then wheelEnt:GetPhysicsObject():Wake() end
|
||||
|
||||
-- Set the hinge Axis perpendicular to the trace hit surface
|
||||
local targetPhys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
local LPos1 = wheelEnt:GetPhysicsObject():WorldToLocal( wheelEnt:GetPos() + trace.HitNormal )
|
||||
local LPos2 = targetPhys:WorldToLocal( trace.HitPos )
|
||||
|
||||
local constr, axis = constraint.Motor( wheelEnt, trace.Entity, 0, trace.PhysicsBone, LPos1, LPos2, friction, torque, 0, nocollide, toggle, ply, limit )
|
||||
|
||||
undo.Create( "Wheel" )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.AddEntity( constr )
|
||||
ply:AddCleanup( "wheels", constr )
|
||||
end
|
||||
if ( IsValid( axis ) ) then
|
||||
undo.AddEntity( axis )
|
||||
ply:AddCleanup( "wheels", axis )
|
||||
end
|
||||
undo.AddEntity( wheelEnt )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
wheelEnt:SetMotor( constr )
|
||||
wheelEnt:SetDirection( constr.direction )
|
||||
wheelEnt:SetAxis( trace.HitNormal )
|
||||
wheelEnt:DoDirectionEffect()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
-- Apply new values to the wheel
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( trace.Entity and trace.Entity:GetClass() != "gmod_wheel" ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local wheelEnt = trace.Entity
|
||||
|
||||
-- Only change your own wheels..
|
||||
if ( IsValid( wheelEnt:GetPlayer() ) and wheelEnt:GetPlayer() != self:GetOwner() ) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local torque = self:GetClientNumber( "torque" )
|
||||
local toggle = self:GetClientNumber( "toggle" ) != 0
|
||||
local fwd = self:GetClientNumber( "fwd" )
|
||||
local bck = self:GetClientNumber( "bck" )
|
||||
|
||||
wheelEnt.BaseTorque = torque
|
||||
wheelEnt:SetTorque( torque )
|
||||
wheelEnt:SetToggle( toggle )
|
||||
|
||||
-- Make sure the table exists!
|
||||
wheelEnt.KeyBinds = wheelEnt.KeyBinds or {}
|
||||
|
||||
wheelEnt.key_f = fwd
|
||||
wheelEnt.key_r = bck
|
||||
|
||||
-- Remove old binds
|
||||
numpad.Remove( wheelEnt.KeyBinds[ 1 ] )
|
||||
numpad.Remove( wheelEnt.KeyBinds[ 2 ] )
|
||||
numpad.Remove( wheelEnt.KeyBinds[ 3 ] )
|
||||
numpad.Remove( wheelEnt.KeyBinds[ 4 ] )
|
||||
|
||||
-- Add new binds
|
||||
wheelEnt.KeyBinds[ 1 ] = numpad.OnDown( self:GetOwner(), fwd, "WheelForward", wheelEnt, true )
|
||||
wheelEnt.KeyBinds[ 2 ] = numpad.OnUp( self:GetOwner(), fwd, "WheelForward", wheelEnt, false )
|
||||
wheelEnt.KeyBinds[ 3 ] = numpad.OnDown( self:GetOwner(), bck, "WheelReverse", wheelEnt, true )
|
||||
wheelEnt.KeyBinds[ 4 ] = numpad.OnUp( self:GetOwner(), bck, "WheelReverse", wheelEnt, false )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
-- For duplicator, creates the wheel.
|
||||
function MakeWheel( ply, pos, ang, model, key_f, key_r, axis, direction, toggle, baseTorque, Data )
|
||||
|
||||
if ( IsValid( ply ) and !ply:CheckLimit( "wheels" ) ) then return false end
|
||||
if ( !IsValidWheelModel( model ) ) then return false end
|
||||
|
||||
local wheel = ents.Create( "gmod_wheel" )
|
||||
if ( !IsValid( wheel ) ) then return end
|
||||
|
||||
duplicator.DoGeneric( wheel, Data )
|
||||
wheel:SetModel( model ) -- Backwards compatible for addons directly calling this function
|
||||
wheel:SetPos( pos )
|
||||
wheel:SetAngles( ang )
|
||||
wheel:Spawn()
|
||||
|
||||
DoPropSpawnedEffect( wheel )
|
||||
|
||||
wheel:SetPlayer( ply )
|
||||
|
||||
duplicator.DoGenericPhysics( wheel, ply, Data )
|
||||
|
||||
wheel.key_f = key_f
|
||||
wheel.key_r = key_r
|
||||
|
||||
if ( axis ) then
|
||||
wheel.Axis = axis
|
||||
end
|
||||
|
||||
wheel:SetDirection( direction or 1 )
|
||||
wheel:SetToggle( toggle or false )
|
||||
|
||||
wheel:SetBaseTorque( baseTorque )
|
||||
wheel:UpdateOverlayText()
|
||||
|
||||
wheel.KeyBinds = {}
|
||||
|
||||
-- Bind to keypad
|
||||
wheel.KeyBinds[ 1 ] = numpad.OnDown( ply, key_f, "WheelForward", wheel, true )
|
||||
wheel.KeyBinds[ 2 ] = numpad.OnUp( ply, key_f, "WheelForward", wheel, false )
|
||||
wheel.KeyBinds[ 3 ] = numpad.OnDown( ply, key_r, "WheelReverse", wheel, true )
|
||||
wheel.KeyBinds[ 4 ] = numpad.OnUp( ply, key_r, "WheelReverse", wheel, false )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "wheels", wheel )
|
||||
ply:AddCleanup( "wheels", wheel )
|
||||
end
|
||||
|
||||
return wheel
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityClass( "gmod_wheel", MakeWheel, "Pos", "Ang", "Model", "key_f", "key_r", "Axis", "Direction", "Toggle", "BaseTorque", "Data" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostWheel( ent, ply )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
if ( !trace.Hit or IsValid( trace.Entity ) and ( trace.Entity:IsPlayer() /*|| trace.Entity:GetClass() == "gmod_wheel"*/ ) ) then
|
||||
|
||||
ent:SetNoDraw( true )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
local Ang = trace.HitNormal:Angle() + self.wheelAngle
|
||||
ent:SetAngles( Ang )
|
||||
|
||||
local CurPos = ent:GetPos()
|
||||
local NearestPoint = ent:NearestPoint( CurPos - ( trace.HitNormal * 512 ) )
|
||||
local WheelOffset = CurPos - NearestPoint
|
||||
ent:SetPos( trace.HitPos + WheelOffset )
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
-- Maintains the ghost wheel
|
||||
function TOOL:Think()
|
||||
|
||||
local mdl = self:GetClientInfo( "model" )
|
||||
if ( !IsValidWheelModel( mdl ) ) then self:ReleaseGhostEntity() return end
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) or self.GhostEntity:GetModel() != mdl ) then
|
||||
self.wheelAngle = Angle( math.NormalizeAngle( self:GetClientNumber( "rx" ) ), math.NormalizeAngle( self:GetClientNumber( "ry" ) ), math.NormalizeAngle( self:GetClientNumber( "rz" ) ) )
|
||||
self:MakeGhostEntity( mdl, vector_origin, angle_zero )
|
||||
end
|
||||
|
||||
self:UpdateGhostWheel( self.GhostEntity, self:GetOwner() )
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.wheel.desc" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "wheel", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.wheel.forward", Command = "wheel_fwd", Label2 = "#tool.wheel.reverse", Command2 = "wheel_bck" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.wheel.torque", Command = "wheel_torque", Type = "Float", Min = 10, Max = 10000 } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.wheel.forcelimit", Command = "wheel_forcelimit", Type = "Float", Min = 0, Max = 50000 } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.wheel.friction", Command = "wheel_friction", Type = "Float", Min = 0, Max = 100 } )
|
||||
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.wheel.nocollide", Command = "wheel_nocollide" } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "#tool.wheel.toggle", Command = "wheel_toggle" } )
|
||||
|
||||
CPanel:AddControl( "PropSelect", { Label = "#tool.wheel.model", ConVar = "wheel_model", Height = 0, Models = list.Get( "WheelModels" ) } )
|
||||
|
||||
end
|
||||
|
||||
-- Don't copy paste all of those ridiculous angles, just use one variable for all of them
|
||||
local zero = { wheel_rx = 0, wheel_ry = 0, wheel_rz = 0 }
|
||||
local one = { wheel_rx = 90, wheel_ry = 0, wheel_rz = 0 }
|
||||
local two = { wheel_rx = 90, wheel_ry = 0, wheel_rz = 90 }
|
||||
|
||||
list.Set( "WheelModels", "models/props_junk/sawblade001a.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_vehicles/carparts_wheel01a.mdl", two )
|
||||
list.Set( "WheelModels", "models/props_vehicles/apc_tire001.mdl", zero )
|
||||
list.Set( "WheelModels", "models/props_vehicles/tire001a_tractor.mdl", zero )
|
||||
list.Set( "WheelModels", "models/props_vehicles/tire001b_truck.mdl", zero )
|
||||
list.Set( "WheelModels", "models/props_vehicles/tire001c_car.mdl", zero )
|
||||
list.Set( "WheelModels", "models/props_wasteland/controlroom_filecabinet002a.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_borealis/bluebarrel001.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_c17/oildrum001.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_c17/playground_carousel01.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_c17/chair_office01a.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_c17/TrapPropeller_Blade.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_wasteland/wheel01.mdl", two )
|
||||
list.Set( "WheelModels", "models/props_trainstation/trainstation_clock001.mdl", zero )
|
||||
list.Set( "WheelModels", "models/props_junk/metal_paintcan001a.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_c17/pulleywheels_large01.mdl", zero )
|
||||
|
||||
list.Set( "WheelModels", "models/props_phx/oildrum001_explosive.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/breakable_tire.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/gibs/tire1_gib.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/normal_tire.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/mechanics/medgear.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/mechanics/biggear.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/gears/bevel9.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/gears/bevel90_24.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/gears/bevel12.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/gears/bevel24.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/gears/bevel36.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/gears/spur9.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/gears/spur12.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/gears/spur24.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/gears/spur36.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/smallwheel.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/747wheel.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/trucktire.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/trucktire2.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/metal_wheel1.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/metal_wheel2.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/wooden_wheel1.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/wooden_wheel2.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/construct/metal_plate_curve360.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/construct/metal_plate_curve360x2.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/construct/wood/wood_curve360x1.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/construct/wood/wood_curve360x2.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/construct/windows/window_curve360x1.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/construct/windows/window_curve360x2.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/trains/wheel_medium.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/trains/medium_wheel_2.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/trains/double_wheels.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/trains/double_wheels2.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/drugster_back.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/drugster_front.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/monster_truck.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/misc/propeller2x_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/misc/propeller3x_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/misc/paddle_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/misc/paddle_small2.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/magnetic_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/magnetic_small_base.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/magnetic_medium.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/magnetic_med_base.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/magnetic_large.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/magnetic_large_base.mdl", one )
|
||||
list.Set( "WheelModels", "models/props_phx/wheels/moped_tire.mdl", one )
|
||||
|
||||
--Tile Model Pack Wheels
|
||||
list.Set( "WheelModels", "models/hunter/misc/cone1x05.mdl", one )
|
||||
list.Set( "WheelModels", "models/hunter/tubes/circle2x2.mdl", one )
|
||||
list.Set( "WheelModels", "models/hunter/tubes/circle4x4.mdl", one )
|
||||
|
||||
--Primitive Mechanics
|
||||
list.Set( "WheelModels", "models/mechanics/wheels/bmw.mdl", one )
|
||||
list.Set( "WheelModels", "models/mechanics/wheels/bmwl.mdl", one )
|
||||
list.Set( "WheelModels", "models/mechanics/wheels/rim_1.mdl", one )
|
||||
list.Set( "WheelModels", "models/mechanics/wheels/tractor.mdl", one )
|
||||
list.Set( "WheelModels", "models/mechanics/wheels/wheel_2.mdl", one )
|
||||
list.Set( "WheelModels", "models/mechanics/wheels/wheel_2l.mdl", one )
|
||||
list.Set( "WheelModels", "models/mechanics/wheels/wheel_extruded_48.mdl", one )
|
||||
list.Set( "WheelModels", "models/mechanics/wheels/wheel_race.mdl", one )
|
||||
list.Set( "WheelModels", "models/mechanics/wheels/wheel_smooth2.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear12x12.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear12x12_large.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear12x12_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear12x24.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear12x24_large.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear12x24_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear12x6.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear12x6_large.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear12x6_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear16x12.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear16x12_large.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear16x12_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear16x24.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear16x24_large.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear16x24_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear16x6.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear16x6_large.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear16x6_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear24x12.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear24x12_large.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear24x12_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear24x24.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear24x24_large.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear24x24_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear24x6.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear24x6_large.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears/gear24x6_small.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_12t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_18t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_24t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_36t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_48t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_60t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_12t2.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_18t2.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_24t2.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_36t2.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_48t2.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_60t2.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_12t3.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_18t3.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_24t3.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_36t3.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_48t3.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/gear_60t3.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/bevel_12t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/bevel_18t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/bevel_24t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/bevel_36t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/bevel_48t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/bevel_60t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/vert_12t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/vert_18t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/vert_24t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/vert_36t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/pinion_20t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/pinion_40t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/pinion_80t1.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/pinion_20t2.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/pinion_40t2.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/pinion_80t2.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/pinion_20t3.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/pinion_40t3.mdl", one )
|
||||
list.Set( "WheelModels", "models/Mechanics/gears2/pinion_80t3.mdl", one )
|
||||
|
||||
--XQM Model Pack Wheels
|
||||
list.Set( "WheelModels", "models/NatesWheel/nateswheel.mdl", zero )
|
||||
list.Set( "WheelModels", "models/NatesWheel/nateswheelwide.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/JetEnginePropeller.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/JetEnginePropellerMedium.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/JetEnginePropellerBig.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/JetEnginePropellerHuge.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/JetEnginePropellerLarge.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/HelicopterRotor.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/HelicopterRotorMedium.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/HelicopterRotorBig.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/HelicopterRotorHuge.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/HelicopterRotorLarge.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/Propeller1.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/Propeller1Medium.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/Propeller1Big.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/Propeller1Huge.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/Propeller1Large.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/AirPlaneWheel1.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/AirPlaneWheel1Medium.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/AirPlaneWheel1Big.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/AirPlaneWheel1Huge.mdl", zero )
|
||||
list.Set( "WheelModels", "models/XQM/AirPlaneWheel1Large.mdl", zero )
|
||||
|
||||
--Xeon133's Wheels
|
||||
list.Set( "WheelModels", "models/xeon133/offroad/Off-road-20.mdl", zero )
|
||||
list.Set( "WheelModels", "models/xeon133/offroad/Off-road-30.mdl", zero )
|
||||
list.Set( "WheelModels", "models/xeon133/offroad/Off-road-40.mdl", zero )
|
||||
list.Set( "WheelModels", "models/xeon133/offroad/Off-road-50.mdl", zero )
|
||||
list.Set( "WheelModels", "models/xeon133/offroad/Off-road-60.mdl", zero )
|
||||
list.Set( "WheelModels", "models/xeon133/offroad/Off-road-70.mdl", zero )
|
||||
list.Set( "WheelModels", "models/xeon133/offroad/Off-road-80.mdl", zero )
|
||||
213
gamemodes/sandbox/entities/weapons/gmod_tool/stools/winch.lua
Normal file
213
gamemodes/sandbox/entities/weapons/gmod_tool/stools/winch.lua
Normal file
@@ -0,0 +1,213 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "#tool.winch.name"
|
||||
|
||||
TOOL.ClientConVar[ "rope_material" ] = "cable/rope"
|
||||
TOOL.ClientConVar[ "rope_width" ] = "3"
|
||||
TOOL.ClientConVar[ "fwd_speed" ] = "64"
|
||||
TOOL.ClientConVar[ "bwd_speed" ] = "64"
|
||||
TOOL.ClientConVar[ "fwd_group" ] = "44"
|
||||
TOOL.ClientConVar[ "bwd_group" ] = "41"
|
||||
TOOL.ClientConVar[ "color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "color_g" ] = "255"
|
||||
TOOL.ClientConVar[ "color_b" ] = "255"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left", stage = 0 },
|
||||
{ name = "left_1", stage = 1, op = 1 },
|
||||
{ name = "right", stage = 0 },
|
||||
{ name = "reload" }
|
||||
}
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
self:SetOperation( 1 )
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
|
||||
if ( CLIENT ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local material = self:GetClientInfo( "rope_material" )
|
||||
local width = self:GetClientNumber( "rope_width", 3 )
|
||||
local fwd_bind = self:GetClientNumber( "fwd_group", 44 )
|
||||
local bwd_bind = self:GetClientNumber( "bwd_group", 41 )
|
||||
local fwd_speed = self:GetClientNumber( "fwd_speed", 64 )
|
||||
local bwd_speed = self:GetClientNumber( "bwd_speed", 64 )
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
local toggle = false
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
|
||||
local constr, rope, controller = constraint.Winch( self:GetOwner(), Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, width, fwd_bind, bwd_bind, fwd_speed, bwd_speed, material, toggle, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Winch" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope ) ) then undo.AddEntity( rope ) end
|
||||
if ( IsValid( controller ) ) then undo.AddEntity( controller ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope ) end
|
||||
if ( IsValid( controller ) ) then self:GetOwner():AddCleanup( "ropeconstraints", controller ) end
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
else
|
||||
|
||||
self:SetStage( iNum + 1 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( self:GetOperation() == 1 ) then return false end
|
||||
|
||||
-- If there's no physics object then we can't constraint it!
|
||||
if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
|
||||
|
||||
local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
|
||||
self:SetObject( 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
|
||||
|
||||
local tr_new = {}
|
||||
tr_new.start = trace.HitPos
|
||||
tr_new.endpos = trace.HitPos + ( trace.HitNormal * 16384 )
|
||||
tr_new.filter = { self:GetOwner() }
|
||||
if ( IsValid( trace.Entity ) ) then
|
||||
table.insert( tr_new.filter, trace.Entity )
|
||||
end
|
||||
|
||||
local tr = util.TraceLine( tr_new )
|
||||
if ( !tr.Hit ) then
|
||||
self:ClearObjects()
|
||||
return false
|
||||
end
|
||||
|
||||
-- Don't try to constrain world to world
|
||||
if ( trace.HitWorld && tr.HitWorld ) then
|
||||
self:ClearObjects()
|
||||
return false
|
||||
end
|
||||
|
||||
if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then
|
||||
self:ClearObjects()
|
||||
return false
|
||||
end
|
||||
if ( IsValid( tr.Entity ) && tr.Entity:IsPlayer() ) then
|
||||
self:ClearObjects()
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check to see if the player can create a winch constraint with the entity in the trace
|
||||
if ( !hook.Run( "CanTool", self:GetOwner(), tr, "winch", self, 2 ) ) then
|
||||
self:ClearObjects()
|
||||
return false
|
||||
end
|
||||
|
||||
local Phys2 = tr.Entity:GetPhysicsObjectNum( tr.PhysicsBone )
|
||||
self:SetObject( 2, tr.Entity, tr.HitPos, Phys2, tr.PhysicsBone, trace.HitNormal )
|
||||
|
||||
if ( CLIENT ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Get client's CVars
|
||||
local material = self:GetClientInfo( "rope_material" )
|
||||
local width = self:GetClientNumber( "rope_width", 3 )
|
||||
local fwd_bind = self:GetClientNumber( "fwd_group", 44 )
|
||||
local bwd_bind = self:GetClientNumber( "bwd_group", 41 )
|
||||
local fwd_speed = self:GetClientNumber( "fwd_speed", 64 )
|
||||
local bwd_speed = self:GetClientNumber( "bwd_speed", 64 )
|
||||
local colorR = self:GetClientNumber( "color_r" )
|
||||
local colorG = self:GetClientNumber( "color_g" )
|
||||
local colorB = self:GetClientNumber( "color_b" )
|
||||
local toggle = false
|
||||
|
||||
-- Get information we're about to use
|
||||
local Ent1, Ent2 = self:GetEnt( 1 ), self:GetEnt( 2 )
|
||||
local Bone1, Bone2 = self:GetBone( 1 ), self:GetBone( 2 )
|
||||
local LPos1, LPos2 = self:GetLocalPos( 1 ), self:GetLocalPos( 2 )
|
||||
|
||||
local constr, rope, controller = constraint.Winch( self:GetOwner(), Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, width, fwd_bind, bwd_bind, fwd_speed, bwd_speed, material, toggle, Color( colorR, colorG, colorB, 255 ) )
|
||||
if ( IsValid( constr ) ) then
|
||||
undo.Create( "Winch" )
|
||||
undo.AddEntity( constr )
|
||||
if ( IsValid( rope ) ) then undo.AddEntity( rope ) end
|
||||
if ( IsValid( controller ) ) then undo.AddEntity( controller ) end
|
||||
undo.SetPlayer( self:GetOwner() )
|
||||
undo.Finish()
|
||||
|
||||
self:GetOwner():AddCleanup( "ropeconstraints", constr )
|
||||
if ( IsValid( rope ) ) then self:GetOwner():AddCleanup( "ropeconstraints", rope ) end
|
||||
if ( IsValid( controller ) ) then self:GetOwner():AddCleanup( "ropeconstraints", controller ) end
|
||||
end
|
||||
|
||||
-- Clear the objects so we're ready to go again
|
||||
self:ClearObjects()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) || trace.Entity:IsPlayer() ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
return constraint.RemoveConstraints( trace.Entity, "Winch" )
|
||||
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Description = "#tool.winch.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "winch", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "#tool.winch.forward", Command = "winch_fwd_group", Label2 = "#tool.winch.backward", Command2 = "winch_bwd_group" } )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.winch.fspeed", Command = "winch_fwd_speed", Type = "Float", Min = 0, Max = 1000, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.winch.bspeed", Command = "winch_bwd_speed", Type = "Float", Min = 0, Max = 1000, Help = true } )
|
||||
CPanel:AddControl( "Slider", { Label = "#tool.winch.width", Command = "winch_rope_width", Type = "Float", Min = 0, Max = 10 } )
|
||||
|
||||
CPanel:AddControl( "RopeMaterial", { Label = "#tool.winch.material", ConVar = "winch_rope_material" } )
|
||||
CPanel:AddControl( "Color", { Label = "#tool.winch.color", Red = "winch_color_r", Green = "winch_color_g", Blue = "winch_color_b" } )
|
||||
|
||||
end
|
||||
179
gamemodes/sandbox/entities/weapons/manhack_welder.lua
Normal file
179
gamemodes/sandbox/entities/weapons/manhack_welder.lua
Normal file
@@ -0,0 +1,179 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Variables that are used on both client and server
|
||||
|
||||
SWEP.Instructions = "Shoot a prop to attach a Manhack.\nRight click to attach a rollermine."
|
||||
SWEP.Author = "Facepunch"
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminOnly = true
|
||||
SWEP.UseHands = true
|
||||
|
||||
SWEP.ViewModel = "models/weapons/c_pistol.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_pistol.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.Weight = 5
|
||||
SWEP.AutoSwitchTo = false
|
||||
SWEP.AutoSwitchFrom = false
|
||||
|
||||
SWEP.PrintName = "#GMOD_ManhackGun"
|
||||
SWEP.Slot = 3
|
||||
SWEP.SlotPos = 1
|
||||
SWEP.DrawAmmo = false
|
||||
SWEP.DrawCrosshair = true
|
||||
SWEP.UseHands = true
|
||||
|
||||
local ShootSound = Sound( "Metal.SawbladeStick" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Reload does nothing
|
||||
-----------------------------------------------------------]]
|
||||
function SWEP:Reload()
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Think does nothing
|
||||
-----------------------------------------------------------]]
|
||||
function SWEP:Think()
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
PrimaryAttack
|
||||
-----------------------------------------------------------]]
|
||||
function SWEP:PrimaryAttack()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
local tr = util.TraceLine( util.GetPlayerTrace( owner ) )
|
||||
--if ( tr.HitWorld ) then return end
|
||||
|
||||
if ( IsFirstTimePredicted() ) then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( tr.HitPos )
|
||||
effectdata:SetNormal( tr.HitNormal )
|
||||
effectdata:SetMagnitude( 8 )
|
||||
effectdata:SetScale( 1 )
|
||||
effectdata:SetRadius( 16 )
|
||||
util.Effect( "Sparks", effectdata )
|
||||
end
|
||||
|
||||
self:EmitSound( ShootSound )
|
||||
|
||||
self:ShootEffects()
|
||||
|
||||
-- The rest is only done on the server
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
-- Make a manhack
|
||||
local ent = ents.Create( "npc_manhack" )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
ent:SetPos( tr.HitPos + owner:GetAimVector() * -16 )
|
||||
ent:SetAngles( tr.HitNormal:Angle() )
|
||||
ent:Spawn()
|
||||
|
||||
local weld = nil
|
||||
|
||||
if ( tr.HitWorld ) then
|
||||
|
||||
-- freeze it in place
|
||||
ent:GetPhysicsObject():EnableMotion( false )
|
||||
|
||||
else
|
||||
|
||||
-- Weld it to the object that we hit
|
||||
weld = constraint.Weld( tr.Entity, ent, tr.PhysicsBone, 0, 0 )
|
||||
|
||||
end
|
||||
|
||||
if ( owner:IsPlayer() ) then
|
||||
undo.Create( "Manhack" )
|
||||
undo.AddEntity( weld )
|
||||
undo.AddEntity( ent )
|
||||
undo.SetPlayer( owner )
|
||||
undo.Finish()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
SecondaryAttack
|
||||
-----------------------------------------------------------]]
|
||||
function SWEP:SecondaryAttack()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
local tr = util.TraceLine( util.GetPlayerTrace( owner ) )
|
||||
--if ( tr.HitWorld ) then return end
|
||||
|
||||
self:EmitSound( ShootSound )
|
||||
self:ShootEffects()
|
||||
|
||||
if ( IsFirstTimePredicted() ) then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( tr.HitPos )
|
||||
effectdata:SetNormal( tr.HitNormal )
|
||||
effectdata:SetMagnitude( 8 )
|
||||
effectdata:SetScale( 1 )
|
||||
effectdata:SetRadius( 16 )
|
||||
util.Effect( "Sparks", effectdata )
|
||||
end
|
||||
|
||||
|
||||
-- The rest is only done on the server
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
-- Make a manhack
|
||||
local ent = ents.Create( "npc_rollermine" )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
ent:SetPos( tr.HitPos + owner:GetAimVector() * -16 )
|
||||
ent:SetAngles( tr.HitNormal:Angle() )
|
||||
ent:Spawn()
|
||||
|
||||
local weld = nil
|
||||
|
||||
if ( !tr.HitWorld ) then
|
||||
|
||||
-- Weld it to the object that we hit
|
||||
weld = constraint.Weld( tr.Entity, ent, tr.PhysicsBone, 0, 0 )
|
||||
|
||||
end
|
||||
|
||||
if ( owner:IsPlayer() ) then
|
||||
undo.Create( "Rollermine" )
|
||||
undo.AddEntity( weld )
|
||||
undo.AddEntity( ent )
|
||||
undo.SetPlayer( owner )
|
||||
undo.Finish()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ShouldDropOnDie
|
||||
Desc: Should this weapon be dropped when its owner dies?
|
||||
-----------------------------------------------------------]]
|
||||
function SWEP:ShouldDropOnDie()
|
||||
return false
|
||||
end
|
||||
72
gamemodes/sandbox/gamemode/cl_hints.lua
Normal file
72
gamemodes/sandbox/gamemode/cl_hints.lua
Normal file
@@ -0,0 +1,72 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
CreateClientConVar( "cl_showhints", "1", true, false, "Whether to display popup hints." )
|
||||
|
||||
-- A list of hints we've already done so we don't repeat ourselves`
|
||||
local ProcessedHints = {}
|
||||
|
||||
--
|
||||
-- Throw's a Hint to the screen
|
||||
--
|
||||
local function ThrowHint( name )
|
||||
|
||||
local show = GetConVarNumber( "cl_showhints" )
|
||||
if ( show == 0 ) then return end
|
||||
|
||||
if ( engine.IsPlayingDemo() ) then return end
|
||||
|
||||
local text = language.GetPhrase( "Hint_" .. name )
|
||||
|
||||
local s, e, group = string.find( text, "%%([^%%]+)%%" )
|
||||
while ( s ) do
|
||||
local key = input.LookupBinding( group )
|
||||
if ( !key ) then key = "<NOT BOUND>" end
|
||||
|
||||
text = string.gsub( text, "%%([^%%]+)%%", "'" .. key:upper() .. "'" )
|
||||
s, e, group = string.find( text, "%%([^%%]+)%%" )
|
||||
end
|
||||
|
||||
GAMEMODE:AddNotify( text, NOTIFY_HINT, 20 )
|
||||
|
||||
surface.PlaySound( "ambient/water/drip" .. math.random( 1, 4 ) .. ".wav" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Adds a hint to the queue
|
||||
--
|
||||
function GM:AddHint( name, delay )
|
||||
|
||||
if ( ProcessedHints[ name ] ) then return end
|
||||
|
||||
timer.Create( "HintSystem_" .. name, delay, 1, function() ThrowHint( name ) end )
|
||||
ProcessedHints[ name ] = true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Removes a hint from the queue
|
||||
--
|
||||
function GM:SuppressHint( name )
|
||||
|
||||
timer.Remove( "HintSystem_" .. name )
|
||||
|
||||
end
|
||||
|
||||
-- Show opening menu hint if they haven't opened the menu within 30 seconds
|
||||
GM:AddHint( "OpeningMenu", 30 )
|
||||
|
||||
-- Tell them how to turn the hints off after 1 minute
|
||||
GM:AddHint( "Annoy1", 5 )
|
||||
GM:AddHint( "Annoy2", 7 )
|
||||
188
gamemodes/sandbox/gamemode/cl_init.lua
Normal file
188
gamemodes/sandbox/gamemode/cl_init.lua
Normal file
@@ -0,0 +1,188 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Sandbox Gamemode
|
||||
|
||||
This is GMod's default gamemode
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
include( "shared.lua" )
|
||||
include( "cl_spawnmenu.lua" )
|
||||
include( "cl_notice.lua" )
|
||||
include( "cl_hints.lua" )
|
||||
include( "cl_worldtips.lua" )
|
||||
include( "cl_search_models.lua" )
|
||||
include( "gui/IconEditor.lua" )
|
||||
|
||||
--
|
||||
-- Make BaseClass available
|
||||
--
|
||||
DEFINE_BASECLASS( "gamemode_base" )
|
||||
|
||||
|
||||
local physgun_halo = CreateConVar( "physgun_halo", "1", { FCVAR_ARCHIVE }, "Draw the Physics Gun grab effect?" )
|
||||
|
||||
function GM:Initialize()
|
||||
|
||||
BaseClass.Initialize( self )
|
||||
|
||||
end
|
||||
|
||||
function GM:LimitHit( name )
|
||||
|
||||
local str = "#SBoxLimit_" .. name
|
||||
local translated = language.GetPhrase( str )
|
||||
if ( str == translated ) then
|
||||
-- No translation available, apply our own
|
||||
translated = string.format( language.GetPhrase( "hint.hitXlimit" ), language.GetPhrase( name ) )
|
||||
end
|
||||
|
||||
self:AddNotify( translated, NOTIFY_ERROR, 6 )
|
||||
surface.PlaySound( "buttons/button10.wav" )
|
||||
|
||||
end
|
||||
|
||||
function GM:OnUndo( name, strCustomString )
|
||||
|
||||
local text = strCustomString
|
||||
|
||||
if ( !text ) then
|
||||
local strId = "#Undone_" .. name
|
||||
text = language.GetPhrase( strId )
|
||||
if ( strId == text ) then
|
||||
-- No translation available, generate our own
|
||||
text = string.format( language.GetPhrase( "hint.undoneX" ), language.GetPhrase( name ) )
|
||||
end
|
||||
end
|
||||
|
||||
-- This is a hack for SWEPs, Tools, etc, that already have hardcoded English only translations
|
||||
-- TODO: Do this for non English languages only
|
||||
local strMatch = string.match( text, "^Undone (.*)$" )
|
||||
if ( strMatch ) then
|
||||
text = string.format( language.GetPhrase( "hint.undoneX" ), language.GetPhrase( strMatch ) )
|
||||
end
|
||||
|
||||
self:AddNotify( text, NOTIFY_UNDO, 2 )
|
||||
|
||||
-- Find a better sound :X
|
||||
surface.PlaySound( "buttons/button15.wav" )
|
||||
|
||||
end
|
||||
|
||||
function GM:OnCleanup( name )
|
||||
|
||||
local str = "#Cleaned_" .. name
|
||||
local translated = language.GetPhrase( str )
|
||||
if ( str == translated ) then
|
||||
-- No translation available, apply our own
|
||||
translated = string.format( language.GetPhrase( "hint.cleanedX" ), language.GetPhrase( name ) )
|
||||
end
|
||||
|
||||
self:AddNotify( translated, NOTIFY_CLEANUP, 5 )
|
||||
|
||||
-- Find a better sound :X
|
||||
surface.PlaySound( "buttons/button15.wav" )
|
||||
|
||||
end
|
||||
|
||||
function GM:UnfrozeObjects( num )
|
||||
|
||||
self:AddNotify( string.format( language.GetPhrase( "hint.unfrozeX" ), num ), NOTIFY_GENERIC, 3 )
|
||||
|
||||
-- Find a better sound :X
|
||||
surface.PlaySound( "npc/roller/mine/rmine_chirp_answer1.wav" )
|
||||
|
||||
end
|
||||
|
||||
function GM:HUDPaint()
|
||||
|
||||
self:PaintWorldTips()
|
||||
|
||||
-- Draw all of the default stuff
|
||||
BaseClass.HUDPaint( self )
|
||||
|
||||
self:PaintNotes()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Draws on top of VGUI..
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PostRenderVGUI()
|
||||
|
||||
BaseClass.PostRenderVGUI( self )
|
||||
|
||||
end
|
||||
|
||||
local PhysgunHalos = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:DrawPhysgunBeam()
|
||||
Desc: Return false to override completely
|
||||
-----------------------------------------------------------]]
|
||||
function GM:DrawPhysgunBeam( ply, weapon, bOn, target, boneid, pos )
|
||||
|
||||
if ( physgun_halo:GetInt() == 0 ) then return true end
|
||||
|
||||
if ( IsValid( target ) ) then
|
||||
PhysgunHalos[ ply ] = target
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "PreDrawHalos", "AddPhysgunHalos", function()
|
||||
|
||||
if ( !PhysgunHalos || table.IsEmpty( PhysgunHalos ) ) then return end
|
||||
|
||||
for k, v in pairs( PhysgunHalos ) do
|
||||
|
||||
if ( !IsValid( k ) ) then continue end
|
||||
|
||||
local size = math.random( 1, 2 )
|
||||
local colr = k:GetWeaponColor() + VectorRand() * 0.3
|
||||
|
||||
halo.Add( PhysgunHalos, Color( colr.x * 255, colr.y * 255, colr.z * 255 ), size, size, 1, true, false )
|
||||
|
||||
end
|
||||
|
||||
PhysgunHalos = {}
|
||||
|
||||
end )
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:NetworkEntityCreated()
|
||||
Desc: Entity is created over the network
|
||||
-----------------------------------------------------------]]
|
||||
function GM:NetworkEntityCreated( ent )
|
||||
|
||||
--
|
||||
-- If the entity wants to use a spawn effect
|
||||
-- then create a propspawn effect if the entity was
|
||||
-- created within the last second (this function gets called
|
||||
-- on every entity when joining a server)
|
||||
--
|
||||
|
||||
if ( ent:GetSpawnEffect() && ent:GetCreationTime() > ( CurTime() - 1.0 ) ) then
|
||||
|
||||
local ed = EffectData()
|
||||
ed:SetOrigin( ent:GetPos() )
|
||||
ed:SetEntity( ent )
|
||||
util.Effect( "propspawn", ed, true, true )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
19
gamemodes/sandbox/gamemode/cl_notice.lua
Normal file
19
gamemodes/sandbox/gamemode/cl_notice.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function GM:AddNotify( str, type, length )
|
||||
|
||||
notification.AddLegacy( str, type, length )
|
||||
|
||||
end
|
||||
|
||||
function GM:PaintNotes()
|
||||
end
|
||||
174
gamemodes/sandbox/gamemode/cl_search_models.lua
Normal file
174
gamemodes/sandbox/gamemode/cl_search_models.lua
Normal file
@@ -0,0 +1,174 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local sbox_search_maxresults = CreateClientConVar( "sbox_search_maxresults", "1024", true, false, "The maximum amount of results the spawnmenu search should show. Model amount limited to 1/2 of this value, entities are limited to 1/4", 1024 )
|
||||
|
||||
local totalCalls = 0
|
||||
local expectedCalls = 1
|
||||
|
||||
local queuedSearch = {}
|
||||
|
||||
local function GetAllFiles( tab, folder, extension, path )
|
||||
|
||||
totalCalls = totalCalls + 1
|
||||
|
||||
local files, folders = file.Find( folder .. "*", path )
|
||||
|
||||
if ( !files ) then
|
||||
MsgN( "Warning! Ignoring '" .. folder .. "' because we cannot search in it!" )
|
||||
return
|
||||
end
|
||||
|
||||
for k, v in ipairs( files ) do
|
||||
|
||||
if ( v:EndsWith( extension ) ) then
|
||||
table.insert( tab, ( folder .. v ):lower() )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
for k, v in ipairs( folders ) do
|
||||
expectedCalls = expectedCalls + 1
|
||||
table.insert( queuedSearch, { tab, folder .. v .. "/", extension, path } )
|
||||
end
|
||||
|
||||
notification.AddProgress( "SandboxSearchIndexing", "#spawnmenu.searchindex", totalCalls / expectedCalls )
|
||||
if ( totalCalls >= expectedCalls ) then notification.Kill( "SandboxSearchIndexing" ) end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "Think", "sandbox_queued_search", function()
|
||||
|
||||
if ( #queuedSearch < 1 ) then return end
|
||||
|
||||
local call = queuedSearch[ 1 ]
|
||||
GetAllFiles( unpack( call ) )
|
||||
table.remove( queuedSearch, 1 )
|
||||
|
||||
if ( !timer.Exists( "search_models_update" ) || #queuedSearch < 1 ) then
|
||||
timer.Create( "search_models_update", 1, 1, function() hook.Run( "SearchUpdate" ) end )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
--
|
||||
-- Model Search
|
||||
--
|
||||
local model_list = nil
|
||||
search.AddProvider( function( str )
|
||||
|
||||
if ( model_list == nil ) then
|
||||
|
||||
model_list = {}
|
||||
GetAllFiles( model_list, "models/", ".mdl", "GAME" )
|
||||
|
||||
end
|
||||
|
||||
local models = {}
|
||||
|
||||
for k, v in ipairs( model_list ) do
|
||||
|
||||
-- Don't search in the models/ and .mdl bit of every model, because every model has this bit, unless they are looking for direct model path
|
||||
local modelpath = v
|
||||
if ( modelpath:StartsWith( "models/" ) && modelpath:EndsWith( ".mdl" ) && !str:EndsWith( ".mdl" ) ) then modelpath = modelpath:sub( 8, modelpath:len() - 4 ) end
|
||||
|
||||
if ( modelpath:find( str, nil, true ) ) then
|
||||
|
||||
if ( IsUselessModel( v ) ) then continue end
|
||||
|
||||
local entry = {
|
||||
text = v:GetFileFromFilename(),
|
||||
func = function() RunConsoleCommand( "gm_spawn", v ) end,
|
||||
icon = spawnmenu.CreateContentIcon( "model", g_SpawnMenu.SearchPropPanel, { model = v } ),
|
||||
words = { v }
|
||||
}
|
||||
|
||||
table.insert( models, entry )
|
||||
|
||||
end
|
||||
|
||||
if ( #models >= sbox_search_maxresults:GetInt() / 2 ) then break end
|
||||
|
||||
end
|
||||
|
||||
return models
|
||||
|
||||
end, "props" )
|
||||
|
||||
hook.Add( "GameContentChanged", "ResetModelSearchCache", function()
|
||||
|
||||
-- Addons got remounted, reset the model search cache
|
||||
model_list = nil
|
||||
|
||||
-- Reset any ongoing search process
|
||||
totalCalls = 0
|
||||
expectedCalls = 1
|
||||
queuedSearch = {}
|
||||
|
||||
end )
|
||||
|
||||
|
||||
--
|
||||
-- Entity, vehicles
|
||||
--
|
||||
local function AddSearchProvider( listname, ctype, stype )
|
||||
search.AddProvider( function( str )
|
||||
|
||||
local results = {}
|
||||
local entities = {}
|
||||
|
||||
for k, v in pairs( list.Get( listname ) ) do
|
||||
if ( listname == "Weapon" && !v.Spawnable ) then continue end
|
||||
|
||||
v.ClassName = k
|
||||
v.PrintName = v.PrintName or v.Name
|
||||
v.ScriptedEntityType = ctype
|
||||
table.insert( entities, v )
|
||||
end
|
||||
|
||||
for k, v in ipairs( entities ) do
|
||||
|
||||
local name = v.PrintName
|
||||
local name_c = v.ClassName
|
||||
if ( !isstring( name ) && !isstring( name_c ) ) then continue end
|
||||
|
||||
if ( ( isstring( name ) && name:lower():find( str, nil, true ) ) || ( isstring( name_c ) && name_c:lower():find( str, nil, true ) ) ) then
|
||||
|
||||
local entry = {
|
||||
text = v.PrintName or v.ClassName,
|
||||
icon = spawnmenu.CreateContentIcon( v.ScriptedEntityType or "entity", nil, {
|
||||
nicename = v.PrintName or v.ClassName,
|
||||
spawnname = v.ClassName,
|
||||
material = "entities/" .. v.ClassName .. ".png",
|
||||
|
||||
admin = v.AdminOnly
|
||||
} ),
|
||||
words = { v }
|
||||
}
|
||||
|
||||
table.insert( results, entry )
|
||||
|
||||
end
|
||||
|
||||
if ( #results >= sbox_search_maxresults:GetInt() / 4 ) then break end
|
||||
|
||||
end
|
||||
|
||||
table.SortByMember( results, "text", true )
|
||||
return results
|
||||
|
||||
end, stype )
|
||||
end
|
||||
|
||||
AddSearchProvider( "SpawnableEntities", "entity", "entities" )
|
||||
AddSearchProvider( "Vehicles", "vehicle", "vehicles" )
|
||||
AddSearchProvider( "NPC", "npc", "npcs" )
|
||||
AddSearchProvider( "Weapon", "weapon", "weapons" )
|
||||
146
gamemodes/sandbox/gamemode/cl_spawnmenu.lua
Normal file
146
gamemodes/sandbox/gamemode/cl_spawnmenu.lua
Normal file
@@ -0,0 +1,146 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "spawnmenu/spawnmenu.lua" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
If false is returned then the spawn menu is never created.
|
||||
This saves load times if your mod doesn't actually use the
|
||||
spawn menu for any reason.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:SpawnMenuEnabled()
|
||||
return true
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Called when spawnmenu is trying to be opened.
|
||||
Return false to dissallow it.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:SpawnMenuOpen()
|
||||
return true
|
||||
end
|
||||
|
||||
function GM:SpawnMenuOpened()
|
||||
self:SuppressHint( "OpeningMenu" )
|
||||
self:AddHint( "OpeningContext", 20 )
|
||||
self:AddHint( "EditingSpawnlists", 5 )
|
||||
end
|
||||
|
||||
function GM:SpawnMenuClosed()
|
||||
end
|
||||
|
||||
function GM:SpawnMenuCreated(spawnmenu)
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
If false is returned then the context menu is never created.
|
||||
This saves load times if your mod doesn't actually use the
|
||||
context menu for any reason.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:ContextMenuEnabled()
|
||||
return true
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Called when context menu is trying to be opened.
|
||||
Return false to dissallow it.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:ContextMenuOpen()
|
||||
return true
|
||||
end
|
||||
|
||||
function GM:ContextMenuOpened()
|
||||
self:SuppressHint( "OpeningContext" )
|
||||
self:AddHint( "ContextClick", 20 )
|
||||
end
|
||||
|
||||
function GM:ContextMenuClosed()
|
||||
end
|
||||
|
||||
function GM:ContextMenuCreated()
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Backwards compatibility. Do Not Use!!!
|
||||
-----------------------------------------------------------]]
|
||||
function GM:GetSpawnmenuTools( name )
|
||||
return spawnmenu.GetToolMenu( name )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Backwards compatibility. Do Not Use!!!
|
||||
-----------------------------------------------------------]]
|
||||
function GM:AddSTOOL( category, itemname, text, command, controls, cpanelfunction )
|
||||
self:AddToolMenuOption( "Main", category, itemname, text, command, controls, cpanelfunction )
|
||||
end
|
||||
|
||||
function GM:PreReloadToolsMenu()
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Don't hook or override this function.
|
||||
Hook AddToolMenuTabs instead!
|
||||
-----------------------------------------------------------]]
|
||||
function GM:AddGamemodeToolMenuTabs()
|
||||
|
||||
-- This is named like this to force it to be the first tab
|
||||
spawnmenu.AddToolTab( "Main", "#spawnmenu.tools_tab", "icon16/wrench.png" )
|
||||
spawnmenu.AddToolTab( "Utilities", "#spawnmenu.utilities_tab", "icon16/page_white_wrench.png" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Add your custom tabs here.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:AddToolMenuTabs()
|
||||
|
||||
-- Hook me!
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Add categories to your tabs
|
||||
-----------------------------------------------------------]]
|
||||
function GM:AddGamemodeToolMenuCategories()
|
||||
|
||||
spawnmenu.AddToolCategory( "Main", "Constraints", "#spawnmenu.tools.constraints" )
|
||||
spawnmenu.AddToolCategory( "Main", "Construction", "#spawnmenu.tools.construction" )
|
||||
spawnmenu.AddToolCategory( "Main", "Poser", "#spawnmenu.tools.posing" )
|
||||
spawnmenu.AddToolCategory( "Main", "Render", "#spawnmenu.tools.render" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Add categories to your tabs
|
||||
-----------------------------------------------------------]]
|
||||
function GM:AddToolMenuCategories()
|
||||
|
||||
-- Hook this function to add custom stuff
|
||||
|
||||
end
|
||||
|
||||
function GM:PopulateToolMenu()
|
||||
end
|
||||
|
||||
function GM:PostReloadToolsMenu()
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Add categories to your tabs
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PopulatePropMenu()
|
||||
|
||||
-- This function makes the engine load the spawn menu text files.
|
||||
-- We call it here so that any gamemodes not using the default
|
||||
-- spawn menu can totally not call it.
|
||||
spawnmenu.PopulateFromEngineTextFiles()
|
||||
|
||||
end
|
||||
103
gamemodes/sandbox/gamemode/cl_worldtips.lua
Normal file
103
gamemodes/sandbox/gamemode/cl_worldtips.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
surface.CreateFont( "GModWorldtip",
|
||||
{
|
||||
font = "Helvetica",
|
||||
size = 20,
|
||||
weight = 700
|
||||
})
|
||||
|
||||
local cl_drawworldtooltips = CreateConVar( "cl_drawworldtooltips", "1", { FCVAR_ARCHIVE }, "Whether tooltips should draw when looking at certain Sandbox entities." )
|
||||
local WorldTip = nil
|
||||
|
||||
local TipColor = Color( 250, 250, 200, 255 )
|
||||
|
||||
--
|
||||
-- Adds a hint to the queue
|
||||
--
|
||||
function AddWorldTip( unused1, text, unused2, pos, ent )
|
||||
|
||||
WorldTip = {}
|
||||
|
||||
WorldTip.dietime = SysTime() + 0.05
|
||||
WorldTip.text = text
|
||||
WorldTip.pos = pos
|
||||
WorldTip.ent = ent
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function DrawWorldTip( tip )
|
||||
|
||||
if ( IsValid( tip.ent ) ) then
|
||||
tip.pos = tip.ent:GetPos()
|
||||
end
|
||||
|
||||
local pos = tip.pos:ToScreen()
|
||||
|
||||
local black = Color( 0, 0, 0, 255 )
|
||||
local tipcol = Color( TipColor.r, TipColor.g, TipColor.b, 255 )
|
||||
|
||||
local x = 0
|
||||
local y = 0
|
||||
local padding = 10
|
||||
local offset = 50
|
||||
|
||||
surface.SetFont( "GModWorldtip" )
|
||||
local w, h = surface.GetTextSize( tip.text )
|
||||
|
||||
x = pos.x - w
|
||||
y = pos.y - h
|
||||
|
||||
x = x - offset
|
||||
y = y - offset
|
||||
|
||||
draw.RoundedBox( 8, x-padding-2, y-padding-2, w+padding*2+4, h+padding*2+4, black )
|
||||
|
||||
|
||||
local verts = {}
|
||||
verts[1] = { x=x+w/1.5-2, y=y+h+2 }
|
||||
verts[2] = { x=x+w+2, y=y+h/2-1 }
|
||||
verts[3] = { x=pos.x-offset/2+2, y=pos.y-offset/2+2 }
|
||||
|
||||
draw.NoTexture()
|
||||
surface.SetDrawColor( 0, 0, 0, tipcol.a )
|
||||
surface.DrawPoly( verts )
|
||||
|
||||
|
||||
draw.RoundedBox( 8, x-padding, y-padding, w+padding*2, h+padding*2, tipcol )
|
||||
|
||||
local verts = {}
|
||||
verts[1] = { x=x+w/1.5, y=y+h }
|
||||
verts[2] = { x=x+w, y=y+h/2 }
|
||||
verts[3] = { x=pos.x-offset/2, y=pos.y-offset/2 }
|
||||
|
||||
draw.NoTexture()
|
||||
surface.SetDrawColor( tipcol.r, tipcol.g, tipcol.b, tipcol.a )
|
||||
surface.DrawPoly( verts )
|
||||
|
||||
|
||||
draw.DrawText( tip.text, "GModWorldtip", x + w/2, y, black, TEXT_ALIGN_CENTER )
|
||||
|
||||
end
|
||||
|
||||
|
||||
function GM:PaintWorldTips()
|
||||
|
||||
if ( !cl_drawworldtooltips:GetBool() ) then return end
|
||||
|
||||
if ( WorldTip && WorldTip.dietime > SysTime() ) then
|
||||
DrawWorldTip( WorldTip )
|
||||
end
|
||||
|
||||
end
|
||||
1122
gamemodes/sandbox/gamemode/commands.lua
Normal file
1122
gamemodes/sandbox/gamemode/commands.lua
Normal file
File diff suppressed because it is too large
Load Diff
307
gamemodes/sandbox/gamemode/editor_player.lua
Normal file
307
gamemodes/sandbox/gamemode/editor_player.lua
Normal file
@@ -0,0 +1,307 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
local default_animations = { "idle_all_01", "menu_walk" }
|
||||
|
||||
list.Set( "DesktopWindows", "PlayerEditor", {
|
||||
|
||||
title = "#smwidget.playermodel",
|
||||
icon = "icon64/playermodel.png",
|
||||
width = 960,
|
||||
height = 700,
|
||||
onewindow = true,
|
||||
init = function( icon, window )
|
||||
|
||||
window:SetTitle( "#smwidget.playermodel_title" )
|
||||
window:SetSize( math.min( ScrW() - 16, window:GetWide() ), math.min( ScrH() - 16, window:GetTall() ) )
|
||||
window:SetSizable( true )
|
||||
window:SetMinWidth( window:GetWide() )
|
||||
window:SetMinHeight( window:GetTall() )
|
||||
window:Center()
|
||||
|
||||
local mdl = window:Add( "DModelPanel" )
|
||||
mdl:Dock( FILL )
|
||||
mdl:SetFOV( 36 )
|
||||
mdl:SetCamPos( vector_origin )
|
||||
mdl:SetDirectionalLight( BOX_RIGHT, Color( 255, 160, 80, 255 ) )
|
||||
mdl:SetDirectionalLight( BOX_LEFT, Color( 80, 160, 255, 255 ) )
|
||||
mdl:SetAmbientLight( Vector( -64, -64, -64 ) )
|
||||
mdl:SetAnimated( true )
|
||||
mdl.Angles = angle_zero
|
||||
mdl:SetLookAt( Vector( -100, 0, -22 ) )
|
||||
|
||||
local sheet = window:Add( "DPropertySheet" )
|
||||
sheet:Dock( RIGHT )
|
||||
sheet:SetSize( 430, 0 )
|
||||
|
||||
local modelListPnl = window:Add( "DPanel" )
|
||||
modelListPnl:DockPadding( 8, 8, 8, 8 )
|
||||
|
||||
local SearchBar = modelListPnl:Add( "DTextEntry" )
|
||||
SearchBar:Dock( TOP )
|
||||
SearchBar:DockMargin( 0, 0, 0, 8 )
|
||||
SearchBar:SetUpdateOnType( true )
|
||||
SearchBar:SetPlaceholderText( "#spawnmenu.quick_filter" )
|
||||
|
||||
local PanelSelect = modelListPnl:Add( "DPanelSelect" )
|
||||
PanelSelect:Dock( FILL )
|
||||
|
||||
for name, model in SortedPairs( player_manager.AllValidModels() ) do
|
||||
|
||||
local icon = vgui.Create( "SpawnIcon" )
|
||||
icon:SetModel( model )
|
||||
icon:SetSize( 64, 64 )
|
||||
icon:SetTooltip( name )
|
||||
icon.playermodel = name
|
||||
icon.model_path = model
|
||||
icon.OpenMenu = function( button )
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.copy", function() SetClipboardText( model ) end ):SetIcon( "icon16/page_copy.png" )
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
PanelSelect:AddPanel( icon, { cl_playermodel = name } )
|
||||
|
||||
end
|
||||
|
||||
SearchBar.OnValueChange = function( s, str )
|
||||
for id, pnl in pairs( PanelSelect:GetItems() ) do
|
||||
if ( !pnl.playermodel:find( str, 1, true ) && !pnl.model_path:find( str, 1, true ) ) then
|
||||
pnl:SetVisible( false )
|
||||
else
|
||||
pnl:SetVisible( true )
|
||||
end
|
||||
end
|
||||
PanelSelect:InvalidateLayout()
|
||||
end
|
||||
|
||||
sheet:AddSheet( "#smwidget.model", modelListPnl, "icon16/user.png" )
|
||||
|
||||
local controls = window:Add( "DPanel" )
|
||||
controls:DockPadding( 8, 8, 8, 8 )
|
||||
|
||||
local lbl = controls:Add( "DLabel" )
|
||||
lbl:SetText( "#smwidget.color_plr" )
|
||||
lbl:SetTextColor( Color( 0, 0, 0, 255 ) )
|
||||
lbl:Dock( TOP )
|
||||
|
||||
local plycol = controls:Add( "DColorMixer" )
|
||||
plycol:SetAlphaBar( false )
|
||||
plycol:SetPalette( false )
|
||||
plycol:Dock( TOP )
|
||||
plycol:SetSize( 200, math.min( window:GetTall() / 3, 260 ) )
|
||||
|
||||
local lbl = controls:Add( "DLabel" )
|
||||
lbl:SetText( "#smwidget.color_wep" )
|
||||
lbl:SetTextColor( Color( 0, 0, 0, 255 ) )
|
||||
lbl:DockMargin( 0, 32, 0, 0 )
|
||||
lbl:Dock( TOP )
|
||||
|
||||
local wepcol = controls:Add( "DColorMixer" )
|
||||
wepcol:SetAlphaBar( false )
|
||||
wepcol:SetPalette( false )
|
||||
wepcol:Dock( TOP )
|
||||
wepcol:SetSize( 200, math.min( window:GetTall() / 3, 260 ) )
|
||||
wepcol:SetVector( Vector( GetConVarString( "cl_weaponcolor" ) ) )
|
||||
|
||||
sheet:AddSheet( "#smwidget.colors", controls, "icon16/color_wheel.png" )
|
||||
|
||||
local bdcontrols = window:Add( "DPanel" )
|
||||
bdcontrols:DockPadding( 8, 8, 8, 8 )
|
||||
|
||||
local bdcontrolspanel = bdcontrols:Add( "DPanelList" )
|
||||
bdcontrolspanel:EnableVerticalScrollbar()
|
||||
bdcontrolspanel:Dock( FILL )
|
||||
|
||||
local bgtab = sheet:AddSheet( "#smwidget.bodygroups", bdcontrols, "icon16/cog.png" )
|
||||
|
||||
-- Helper functions
|
||||
local function PlayPreviewAnimation( panel, playermodel )
|
||||
|
||||
if ( !panel or !IsValid( panel.Entity ) ) then return end
|
||||
|
||||
local anims = list.Get( "PlayerOptionsAnimations" )
|
||||
|
||||
local anim = default_animations[ math.random( 1, #default_animations ) ]
|
||||
if ( anims[ playermodel ] ) then
|
||||
anims = anims[ playermodel ]
|
||||
anim = anims[ math.random( 1, #anims ) ]
|
||||
end
|
||||
|
||||
local iSeq = panel.Entity:LookupSequence( anim )
|
||||
if ( iSeq > 0 ) then panel.Entity:ResetSequence( iSeq ) end
|
||||
|
||||
end
|
||||
|
||||
-- Updating
|
||||
local function UpdateBodyGroups( pnl, val )
|
||||
if ( pnl.type == "bgroup" ) then
|
||||
|
||||
mdl.Entity:SetBodygroup( pnl.typenum, math.Round( val ) )
|
||||
|
||||
local str = string.Explode( " ", GetConVarString( "cl_playerbodygroups" ) )
|
||||
if ( #str < pnl.typenum + 1 ) then for i = 1, pnl.typenum + 1 do str[ i ] = str[ i ] or 0 end end
|
||||
str[ pnl.typenum + 1 ] = math.Round( val )
|
||||
RunConsoleCommand( "cl_playerbodygroups", table.concat( str, " " ) )
|
||||
|
||||
elseif ( pnl.type == "skin" ) then
|
||||
|
||||
mdl.Entity:SetSkin( math.Round( val ) )
|
||||
RunConsoleCommand( "cl_playerskin", math.Round( val ) )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
local function RebuildBodygroupTab()
|
||||
bdcontrolspanel:Clear()
|
||||
|
||||
bgtab.Tab:SetVisible( false )
|
||||
|
||||
local nskins = mdl.Entity:SkinCount() - 1
|
||||
if ( nskins > 0 ) then
|
||||
local skins = vgui.Create( "DNumSlider" )
|
||||
skins:Dock( TOP )
|
||||
skins:SetText( "Skin" )
|
||||
skins:SetDark( true )
|
||||
skins:SetTall( 50 )
|
||||
skins:SetDecimals( 0 )
|
||||
skins:SetMax( nskins )
|
||||
skins:SetValue( GetConVarNumber( "cl_playerskin" ) )
|
||||
skins.type = "skin"
|
||||
skins.OnValueChanged = UpdateBodyGroups
|
||||
|
||||
bdcontrolspanel:AddItem( skins )
|
||||
|
||||
mdl.Entity:SetSkin( GetConVarNumber( "cl_playerskin" ) )
|
||||
|
||||
bgtab.Tab:SetVisible( true )
|
||||
end
|
||||
|
||||
local groups = string.Explode( " ", GetConVarString( "cl_playerbodygroups" ) )
|
||||
for k = 0, mdl.Entity:GetNumBodyGroups() - 1 do
|
||||
if ( mdl.Entity:GetBodygroupCount( k ) <= 1 ) then continue end
|
||||
|
||||
local bgroup = vgui.Create( "DNumSlider" )
|
||||
bgroup:Dock( TOP )
|
||||
bgroup:SetText( string.NiceName( mdl.Entity:GetBodygroupName( k ) ) )
|
||||
bgroup:SetDark( true )
|
||||
bgroup:SetTall( 50 )
|
||||
bgroup:SetDecimals( 0 )
|
||||
bgroup.type = "bgroup"
|
||||
bgroup.typenum = k
|
||||
bgroup:SetMax( mdl.Entity:GetBodygroupCount( k ) - 1 )
|
||||
bgroup:SetValue( groups[ k + 1 ] or 0 )
|
||||
bgroup.OnValueChanged = UpdateBodyGroups
|
||||
|
||||
bdcontrolspanel:AddItem( bgroup )
|
||||
|
||||
mdl.Entity:SetBodygroup( k, groups[ k + 1 ] or 0 )
|
||||
|
||||
bgtab.Tab:SetVisible( true )
|
||||
end
|
||||
|
||||
sheet.tabScroller:InvalidateLayout()
|
||||
end
|
||||
|
||||
local function UpdateFromConvars()
|
||||
|
||||
local model = LocalPlayer():GetInfo( "cl_playermodel" )
|
||||
local modelname = player_manager.TranslatePlayerModel( model )
|
||||
util.PrecacheModel( modelname )
|
||||
mdl:SetModel( modelname )
|
||||
mdl.Entity.GetPlayerColor = function() return Vector( GetConVarString( "cl_playercolor" ) ) end
|
||||
mdl.Entity:SetPos( Vector( -100, 0, -61 ) )
|
||||
|
||||
plycol:SetVector( Vector( GetConVarString( "cl_playercolor" ) ) )
|
||||
wepcol:SetVector( Vector( GetConVarString( "cl_weaponcolor" ) ) )
|
||||
|
||||
PlayPreviewAnimation( mdl, model )
|
||||
RebuildBodygroupTab()
|
||||
|
||||
end
|
||||
|
||||
local function UpdateFromControls()
|
||||
|
||||
RunConsoleCommand( "cl_playercolor", tostring( plycol:GetVector() ) )
|
||||
RunConsoleCommand( "cl_weaponcolor", tostring( wepcol:GetVector() ) )
|
||||
|
||||
end
|
||||
|
||||
plycol.ValueChanged = UpdateFromControls
|
||||
wepcol.ValueChanged = UpdateFromControls
|
||||
|
||||
UpdateFromConvars()
|
||||
|
||||
function PanelSelect:OnActivePanelChanged( old, new )
|
||||
|
||||
if ( old != new ) then -- Only reset if we changed the model
|
||||
RunConsoleCommand( "cl_playerbodygroups", "0" )
|
||||
RunConsoleCommand( "cl_playerskin", "0" )
|
||||
end
|
||||
|
||||
timer.Simple( 0.1, function() UpdateFromConvars() end )
|
||||
|
||||
end
|
||||
|
||||
-- Hold to rotate
|
||||
|
||||
function mdl:DragMousePress()
|
||||
self.PressX, self.PressY = input.GetCursorPos()
|
||||
self.Pressed = true
|
||||
end
|
||||
|
||||
function mdl:DragMouseRelease() self.Pressed = false end
|
||||
|
||||
function mdl:LayoutEntity( ent )
|
||||
if ( self.bAnimated ) then self:RunAnimation() end
|
||||
|
||||
if ( self.Pressed ) then
|
||||
local mx, my = input.GetCursorPos()
|
||||
self.Angles = self.Angles - Angle( 0, ( ( self.PressX or mx ) - mx ) / 2, 0 )
|
||||
|
||||
self.PressX, self.PressY = mx, my
|
||||
end
|
||||
|
||||
ent:SetAngles( self.Angles )
|
||||
end
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "PlayerOptionsAnimations", "gman", { "menu_gman" } )
|
||||
|
||||
list.Set( "PlayerOptionsAnimations", "hostage01", { "idle_all_scared" } )
|
||||
list.Set( "PlayerOptionsAnimations", "hostage02", { "idle_all_scared" } )
|
||||
list.Set( "PlayerOptionsAnimations", "hostage03", { "idle_all_scared" } )
|
||||
list.Set( "PlayerOptionsAnimations", "hostage04", { "idle_all_scared" } )
|
||||
|
||||
list.Set( "PlayerOptionsAnimations", "zombine", { "menu_zombie_01" } )
|
||||
list.Set( "PlayerOptionsAnimations", "corpse", { "menu_zombie_01" } )
|
||||
list.Set( "PlayerOptionsAnimations", "zombiefast", { "menu_zombie_01" } )
|
||||
list.Set( "PlayerOptionsAnimations", "zombie", { "menu_zombie_01" } )
|
||||
list.Set( "PlayerOptionsAnimations", "skeleton", { "menu_zombie_01" } )
|
||||
|
||||
list.Set( "PlayerOptionsAnimations", "combine", { "menu_combine" } )
|
||||
list.Set( "PlayerOptionsAnimations", "combineprison", { "menu_combine" } )
|
||||
list.Set( "PlayerOptionsAnimations", "combineelite", { "menu_combine" } )
|
||||
list.Set( "PlayerOptionsAnimations", "police", { "menu_combine" } )
|
||||
list.Set( "PlayerOptionsAnimations", "policefem", { "menu_combine" } )
|
||||
|
||||
list.Set( "PlayerOptionsAnimations", "css_arctic", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_gasmask", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_guerilla", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_leet", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_phoenix", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_riot", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_swat", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_urban", { "pose_standing_02", "idle_fist" } )
|
||||
654
gamemodes/sandbox/gamemode/gui/iconeditor.lua
Normal file
654
gamemodes/sandbox/gamemode/gui/iconeditor.lua
Normal file
@@ -0,0 +1,654 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_strModel", "Model" )
|
||||
AccessorFunc( PANEL, "m_pOrigin", "Origin" )
|
||||
AccessorFunc( PANEL, "m_bCustomIcon", "CustomIcon" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetSize( 762, 502 )
|
||||
self:SetTitle( "#smwidget.icon_editor" )
|
||||
|
||||
local left = self:Add( "Panel" )
|
||||
left:Dock( LEFT )
|
||||
left:SetWide( 400 )
|
||||
self.LeftPanel = left
|
||||
|
||||
local bg = left:Add( "DPanel" )
|
||||
bg:Dock( FILL )
|
||||
bg:DockMargin( 0, 0, 0, 4 )
|
||||
bg.Paint = function( s, w, h ) draw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 128 ) ) end
|
||||
|
||||
self.SpawnIcon = bg:Add( "SpawnIcon" )
|
||||
--self.SpawnIcon.DoClick = function() self:RenderIcon() end
|
||||
|
||||
self.ModelPanel = bg:Add( "DAdjustableModelPanel" )
|
||||
self.ModelPanel:Dock( FILL )
|
||||
self.ModelPanel.FarZ = 32768
|
||||
|
||||
local mat_wireframe = Material( "models/wireframe" )
|
||||
function self.ModelPanel.PostDrawModel( mdlpnl, ent )
|
||||
if ( self.ShowOriginPnl:GetChecked() ) then
|
||||
render.DrawLine( vector_origin, Vector( 0, 0, 100 ), Color( 0, 0, 255 ) )
|
||||
render.DrawLine( vector_origin, Vector( 0, 100, 0 ), Color( 0, 255, 0 ) )
|
||||
render.DrawLine( vector_origin, Vector( 100, 0, 0 ), Color( 255, 0, 0 ) )
|
||||
end
|
||||
|
||||
if ( self.ShowBBoxPnl:GetChecked() ) then
|
||||
local mins, maxs = ent:GetRenderBounds()
|
||||
local scale = 1
|
||||
mat_wireframe:SetVector( "$color", Vector( 1, 1, 1 ) )
|
||||
render.SetMaterial( mat_wireframe )
|
||||
|
||||
render.DrawBox( ent:GetPos(), ent:GetAngles(), mins * scale, maxs * scale )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local controls = left:Add( "Panel" )
|
||||
controls:SetTall( 64 )
|
||||
controls:Dock( BOTTOM )
|
||||
|
||||
local controls_anim = controls:Add( "Panel" )
|
||||
controls_anim:SetTall( 20 )
|
||||
controls_anim:Dock( TOP )
|
||||
controls_anim:DockMargin( 0, 0, 0, 4 )
|
||||
controls_anim:MoveToBack()
|
||||
|
||||
self.AnimTrack = controls_anim:Add( "DSlider" )
|
||||
self.AnimTrack:Dock( FILL )
|
||||
self.AnimTrack:SetNotches( 100 )
|
||||
self.AnimTrack:SetTrapInside( true )
|
||||
self.AnimTrack:SetLockY( 0.5 )
|
||||
|
||||
self.AnimPause = controls_anim:Add( "DImageButton" )
|
||||
self.AnimPause:SetImage( "icon16/control_pause_blue.png" )
|
||||
self.AnimPause:SetStretchToFit( false )
|
||||
self.AnimPause:SetPaintBackground( true )
|
||||
self.AnimPause:SetIsToggle( true )
|
||||
self.AnimPause:SetToggle( false )
|
||||
self.AnimPause:Dock( LEFT )
|
||||
self.AnimPause:SetWide( 32 )
|
||||
|
||||
local BestGuess = controls:Add( "DImageButton" )
|
||||
BestGuess:SetImage( "icon32/wand.png" )
|
||||
BestGuess:SetStretchToFit( false )
|
||||
BestGuess:SetPaintBackground( true )
|
||||
BestGuess.DoClick = function() self:BestGuessLayout() end
|
||||
BestGuess:Dock( LEFT )
|
||||
BestGuess:DockMargin( 0, 0, 0, 0 )
|
||||
BestGuess:SetWide( 50 )
|
||||
BestGuess:SetTooltip( "Best Guess" )
|
||||
|
||||
local FullFrontal = controls:Add( "DImageButton" )
|
||||
FullFrontal:SetImage( "icon32/hand_point_090.png" )
|
||||
FullFrontal:SetStretchToFit( false )
|
||||
FullFrontal:SetPaintBackground( true )
|
||||
FullFrontal.DoClick = function() self:FullFrontalLayout() end
|
||||
FullFrontal:Dock( LEFT )
|
||||
FullFrontal:DockMargin( 2, 0, 0, 0 )
|
||||
FullFrontal:SetWide( 50 )
|
||||
FullFrontal:SetTooltip( "Front" )
|
||||
|
||||
local Above = controls:Add( "DImageButton" )
|
||||
Above:SetImage( "icon32/hand_property.png" )
|
||||
Above:SetStretchToFit( false )
|
||||
Above:SetPaintBackground( true )
|
||||
Above.DoClick = function() self:AboveLayout() end
|
||||
Above:Dock( LEFT )
|
||||
Above:DockMargin( 2, 0, 0, 0 )
|
||||
Above:SetWide( 50 )
|
||||
Above:SetTooltip( "Above" )
|
||||
|
||||
local Right = controls:Add( "DImageButton" )
|
||||
Right:SetImage( "icon32/hand_point_180.png" )
|
||||
Right:SetStretchToFit( false )
|
||||
Right:SetPaintBackground( true )
|
||||
Right.DoClick = function() self:RightLayout() end
|
||||
Right:Dock( LEFT )
|
||||
Right:DockMargin( 2, 0, 0, 0 )
|
||||
Right:SetWide( 50 )
|
||||
Right:SetTooltip( "Right" )
|
||||
|
||||
local Origin = controls:Add( "DImageButton" )
|
||||
Origin:SetImage( "icon32/hand_point_090.png" )
|
||||
Origin:SetStretchToFit( false )
|
||||
Origin:SetPaintBackground( true )
|
||||
Origin.DoClick = function() self:OriginLayout() end
|
||||
Origin:Dock( LEFT )
|
||||
Origin:DockMargin( 2, 0, 0, 0 )
|
||||
Origin:SetWide( 50 )
|
||||
Origin:SetTooltip( "Center" )
|
||||
|
||||
local Render = controls:Add( "DButton" )
|
||||
Render:SetText( "RENDER" )
|
||||
Render.DoClick = function() self:RenderIcon() end
|
||||
Render:Dock( RIGHT )
|
||||
Render:DockMargin( 2, 0, 0, 0 )
|
||||
Render:SetWide( 50 )
|
||||
Render:SetTooltip( "Render Icon" )
|
||||
|
||||
local Picker = controls:Add( "DImageButton" )
|
||||
Picker:SetImage( "icon32/color_picker.png" )
|
||||
Picker:SetStretchToFit( false )
|
||||
Picker:SetPaintBackground( true )
|
||||
Picker:Dock( RIGHT )
|
||||
Picker:DockMargin( 2, 0, 0, 0 )
|
||||
Picker:SetWide( 50 )
|
||||
Picker:SetTooltip( "Pick a new model from an entity" )
|
||||
Picker.DoClick = function()
|
||||
|
||||
self:SetVisible( false )
|
||||
|
||||
util.worldpicker.Start( function( tr )
|
||||
|
||||
self:SetVisible( true )
|
||||
|
||||
if ( !IsValid( tr.Entity ) ) then return end
|
||||
|
||||
self:SetFromEntity( tr.Entity )
|
||||
|
||||
end )
|
||||
end
|
||||
|
||||
local right = self:Add( "DPropertySheet" )
|
||||
right:Dock( FILL )
|
||||
right:SetPadding( 0 )
|
||||
right:DockMargin( 4, 0, 0, 0 )
|
||||
self.PropertySheet = right
|
||||
|
||||
-- Animations
|
||||
|
||||
local anims = right:Add( "Panel" )
|
||||
anims:Dock( FILL )
|
||||
anims:DockPadding( 2, 0, 2, 2 )
|
||||
right:AddSheet( "#smwidget.animations", anims, "icon16/monkey.png" )
|
||||
|
||||
self.AnimList = anims:Add( "DListView" )
|
||||
self.AnimList:AddColumn( "name" )
|
||||
self.AnimList:Dock( FILL )
|
||||
self.AnimList:SetMultiSelect( false )
|
||||
self.AnimList:SetHideHeaders( true )
|
||||
|
||||
-- Bodygroups
|
||||
|
||||
local pnl = right:Add( "Panel" )
|
||||
pnl:Dock( FILL )
|
||||
pnl:DockPadding( 7, 0, 7, 7 )
|
||||
|
||||
self.BodygroupTab = right:AddSheet( "#smwidget.bodygroups", pnl, "icon16/brick.png" )
|
||||
|
||||
self.BodyList = pnl:Add( "DScrollPanel" )
|
||||
self.BodyList:Dock( FILL )
|
||||
|
||||
--This kind of works but they don't move their stupid mouths. So fuck off.
|
||||
--[[
|
||||
self.Scenes = pnl:Add( "DTree" )
|
||||
self.Scenes:Dock( BOTTOM )
|
||||
self.Scenes:SetSize( 200, 200 )
|
||||
self.Scenes.DoClick = function( _, node )
|
||||
|
||||
if ( !node.FileName ) then return end
|
||||
local ext = string.GetExtensionFromFilename( node.FileName )
|
||||
if( ext != "vcd" ) then return end
|
||||
|
||||
self.ModelPanel:StartScene( node.FileName )
|
||||
MsgN( node.FileName )
|
||||
|
||||
end
|
||||
|
||||
local materials = self.Scenes.RootNode:AddFolder( "Scenes", "scenes/", true )
|
||||
materials:SetIcon( "icon16/photos.png" )--]]
|
||||
|
||||
-- Settings
|
||||
|
||||
local settings = right:Add( "Panel" )
|
||||
settings:Dock( FILL )
|
||||
settings:DockPadding( 7, 0, 7, 7 )
|
||||
right:AddSheet( "#smwidget.settings", settings, "icon16/cog.png" )
|
||||
|
||||
local bbox = settings:Add( "DCheckBoxLabel" )
|
||||
bbox:SetText( "Show Bounding Box" )
|
||||
bbox:Dock( TOP )
|
||||
bbox:DockMargin( 0, 0, 0, 3 )
|
||||
bbox:SetDark( true )
|
||||
bbox:SetCookieName( "model_editor_bbox" )
|
||||
self.ShowBBoxPnl = bbox
|
||||
|
||||
local origin = settings:Add( "DCheckBoxLabel" )
|
||||
origin:SetText( "Show Origin" )
|
||||
origin:Dock( TOP )
|
||||
origin:SetDark( true )
|
||||
origin:SetCookieName( "model_editor_origin" )
|
||||
self.ShowOriginPnl = origin
|
||||
|
||||
local playSpeed = settings:Add( "DNumSlider" )
|
||||
playSpeed:SetText( "Playback Speed" )
|
||||
playSpeed:Dock( TOP )
|
||||
playSpeed:SetValue( 1 )
|
||||
playSpeed:SetMinMax( -1, 2 )
|
||||
playSpeed:SetDark( true )
|
||||
playSpeed.OnValueChanged = function( s, value )
|
||||
self.ModelPanel:GetEntity():SetPlaybackRate( value )
|
||||
end
|
||||
|
||||
local moveSpeed = settings:Add( "DNumSlider" )
|
||||
moveSpeed:SetText( "Move Speed" )
|
||||
moveSpeed:Dock( TOP )
|
||||
moveSpeed:SetMinMax( 0.5, 8 )
|
||||
moveSpeed:SetValue( 1 )
|
||||
moveSpeed:SetDark( true )
|
||||
moveSpeed.OnValueChanged = function( p )
|
||||
self.ModelPanel:SetMovementScale( p:GetValue() )
|
||||
end
|
||||
moveSpeed:SetCookieName( "iconeditor_movespeed" )
|
||||
|
||||
local angle = settings:Add( "DTextEntry" )
|
||||
angle:SetTooltip( "Entity Angles" )
|
||||
angle:Dock( TOP )
|
||||
angle:DockMargin( 0, 0, 0, 3 )
|
||||
angle:SetZPos( 100 )
|
||||
angle.OnChange = function( p )
|
||||
self.ModelPanel:GetEntity():SetAngles( Angle( p:GetText() ) )
|
||||
end
|
||||
self.TargetAnglePanel = angle
|
||||
|
||||
local cam_angle = settings:Add( "DTextEntry" )
|
||||
cam_angle:SetTooltip( "Camera Angles" )
|
||||
cam_angle:Dock( TOP )
|
||||
cam_angle:DockMargin( 0, 0, 0, 3 )
|
||||
cam_angle:SetZPos( 101 )
|
||||
cam_angle.OnChange = function( p )
|
||||
self.ModelPanel:SetLookAng( Angle( p:GetText() ) )
|
||||
end
|
||||
self.TargetCamAnglePanel = cam_angle
|
||||
|
||||
local cam_pos = settings:Add( "DTextEntry" )
|
||||
cam_pos:SetTooltip( "Camera Position" )
|
||||
cam_pos:Dock( TOP )
|
||||
cam_pos:DockMargin( 0, 0, 0, 3 )
|
||||
cam_pos:SetZPos( 102 )
|
||||
cam_pos.OnChange = function( p )
|
||||
self.ModelPanel:SetCamPos( Vector( p:GetText() ) )
|
||||
end
|
||||
self.TargetCamPosPanel = cam_pos
|
||||
|
||||
local cam_fov = settings:Add( "DNumSlider" )
|
||||
cam_fov:SetText( "Camera FOV" )
|
||||
cam_fov:Dock( TOP )
|
||||
cam_fov:DockMargin( 0, 0, 0, 3 )
|
||||
cam_fov:SetZPos( 103 )
|
||||
cam_fov:SetMinMax( 0.001, 179 )
|
||||
cam_fov:SetDark( true )
|
||||
cam_fov.OnValueChanged = function( p )
|
||||
self.ModelPanel:SetFOV( p:GetValue() )
|
||||
end
|
||||
self.TargetCamFOVPanel = cam_fov
|
||||
|
||||
local copypaste_cam = settings:Add( "Panel" )
|
||||
copypaste_cam:SetTall( 20 )
|
||||
copypaste_cam:Dock( TOP )
|
||||
copypaste_cam:SetZPos( 104 )
|
||||
copypaste_cam:DockMargin( 0, 0, 0, 4 )
|
||||
|
||||
local copy = copypaste_cam:Add( "DButton" )
|
||||
copy:Dock( FILL )
|
||||
copy:SetText( "Copy Camera Settings" )
|
||||
copy:DockMargin( 0, 0, 3, 0 )
|
||||
copy.DoClick = function() SetClipboardText( util.TableToJSON( {
|
||||
pos = self.ModelPanel:GetCamPos(),
|
||||
ang = self.ModelPanel:GetLookAng(),
|
||||
fov = self.ModelPanel:GetFOV(),
|
||||
mdl_ang = self.ModelPanel:GetEntity():GetAngles()
|
||||
} ) ) end
|
||||
|
||||
local paste = copypaste_cam:Add( "DTextEntry" )
|
||||
paste:SetWide( 140 ) -- Ew
|
||||
paste:Dock( RIGHT )
|
||||
paste:SetPlaceholderText( "Paste Camera Settings Here" )
|
||||
paste.OnChange = function( p )
|
||||
local tabl = util.JSONToTable( p:GetText() )
|
||||
if ( tabl ) then
|
||||
self.ModelPanel:SetCamPos( tabl.pos )
|
||||
self.ModelPanel:SetLookAng( tabl.ang )
|
||||
self.ModelPanel:SetFOV( tabl.fov )
|
||||
self.ModelPanel:GetEntity():SetAngles( tabl.mdl_ang )
|
||||
end
|
||||
p:SetText( "" )
|
||||
end
|
||||
|
||||
local labels = { "Pitch", "Yaw", "Roll" }
|
||||
for i = 1, 3 do
|
||||
local rotate45 = settings:Add( "DButton" )
|
||||
rotate45:SetText( "Rotate Entity +/-45 " .. labels[ i ] )
|
||||
rotate45:Dock( TOP )
|
||||
rotate45:DockMargin( 0, 0, 0, 3 )
|
||||
rotate45:SetZPos( 110 + i )
|
||||
rotate45.DoClick = function( p )
|
||||
local aang = self.ModelPanel:GetEntity():GetAngles()
|
||||
aang[ i ] = aang[ i ] + 45
|
||||
self.ModelPanel:GetEntity():SetAngles( aang )
|
||||
end
|
||||
rotate45.DoRightClick = function( p )
|
||||
local aang = self.ModelPanel:GetEntity():GetAngles()
|
||||
aang[ i ] = aang[ i ] - 45
|
||||
self.ModelPanel:GetEntity():SetAngles( aang )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetDefaultLighting()
|
||||
|
||||
self.ModelPanel:SetAmbientLight( Color( 255 * 0.3, 255 * 0.3, 255 * 0.3 ) )
|
||||
|
||||
self.ModelPanel:SetDirectionalLight( BOX_FRONT, Color( 255 * 1.3, 255 * 1.3, 255 * 1.3 ) )
|
||||
self.ModelPanel:SetDirectionalLight( BOX_BACK, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
|
||||
self.ModelPanel:SetDirectionalLight( BOX_RIGHT, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
|
||||
self.ModelPanel:SetDirectionalLight( BOX_LEFT, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
|
||||
self.ModelPanel:SetDirectionalLight( BOX_TOP, Color( 255 * 2.3, 255 * 2.3, 255 * 2.3 ) )
|
||||
self.ModelPanel:SetDirectionalLight( BOX_BOTTOM, Color( 255 * 0.1, 255 * 0.1, 255 * 0.1 ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:BestGuessLayout()
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local pos = ent:GetPos()
|
||||
local ang = ent:GetAngles()
|
||||
|
||||
local tab = PositionSpawnIcon( ent, pos, true )
|
||||
|
||||
ent:SetAngles( ang )
|
||||
if ( tab ) then
|
||||
self.ModelPanel:SetCamPos( tab.origin )
|
||||
self.ModelPanel:SetFOV( tab.fov )
|
||||
self.ModelPanel:SetLookAng( tab.angles )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:FullFrontalLayout()
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local pos = ent:GetPos()
|
||||
local campos = pos + Vector( -200, 0, 0 )
|
||||
|
||||
self.ModelPanel:SetCamPos( campos )
|
||||
self.ModelPanel:SetFOV( 45 )
|
||||
self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AboveLayout()
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local pos = ent:GetPos()
|
||||
local campos = pos + Vector( 0, 0, 200 )
|
||||
|
||||
self.ModelPanel:SetCamPos( campos )
|
||||
self.ModelPanel:SetFOV( 45 )
|
||||
self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RightLayout()
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local pos = ent:GetPos()
|
||||
local campos = pos + Vector( 0, 200, 0 )
|
||||
|
||||
self.ModelPanel:SetCamPos( campos )
|
||||
self.ModelPanel:SetFOV( 45 )
|
||||
self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OriginLayout()
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local pos = ent:GetPos()
|
||||
local campos = pos + vector_origin
|
||||
|
||||
self.ModelPanel:SetCamPos( campos )
|
||||
self.ModelPanel:SetFOV( 45 )
|
||||
self.ModelPanel:SetLookAng( Angle( 0, -180, 0 ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:UpdateEntity( ent )
|
||||
|
||||
ent:SetEyeTarget( self.ModelPanel:GetCamPos() )
|
||||
|
||||
if ( IsValid( self.TargetAnglePanel ) && !self.TargetAnglePanel:IsEditing() && !self.TargetAnglePanel:IsHovered() ) then
|
||||
self.TargetAnglePanel:SetText( tostring( ent:GetAngles() ) )
|
||||
end
|
||||
if ( IsValid( self.TargetCamAnglePanel ) && !self.TargetCamAnglePanel:IsEditing() && !self.TargetCamAnglePanel:IsHovered() ) then
|
||||
self.TargetCamAnglePanel:SetText( tostring( self.ModelPanel:GetLookAng() ) )
|
||||
end
|
||||
if ( IsValid( self.TargetCamPosPanel ) && !self.TargetCamPosPanel:IsEditing() && !self.TargetCamPosPanel:IsHovered() ) then
|
||||
self.TargetCamPosPanel:SetText( tostring( self.ModelPanel:GetCamPos() ) )
|
||||
end
|
||||
if ( IsValid( self.TargetCamFOVPanel ) && !self.TargetCamFOVPanel:IsEditing() && !self.TargetCamFOVPanel:IsHovered() ) then
|
||||
self.TargetCamFOVPanel:SetValue( self.ModelPanel:GetFOV() )
|
||||
end
|
||||
|
||||
if ( self.AnimTrack:GetDragging() ) then
|
||||
|
||||
ent:SetCycle( self.AnimTrack:GetSlideX() )
|
||||
self.AnimPause:SetToggle( true )
|
||||
|
||||
elseif ( ent:GetCycle() != self.AnimTrack:GetSlideX() ) then
|
||||
|
||||
local cyc = ent:GetCycle()
|
||||
if ( cyc < 0 ) then cyc = cyc + 1 end
|
||||
self.AnimTrack:SetSlideX( cyc )
|
||||
|
||||
end
|
||||
|
||||
if ( !self.AnimPause:GetToggle() ) then
|
||||
ent:FrameAdvance( FrameTime() )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RenderIcon()
|
||||
|
||||
local tab = {}
|
||||
tab.ent = self.ModelPanel:GetEntity()
|
||||
tab.cam_pos = self.ModelPanel:GetCamPos()
|
||||
tab.cam_ang = self.ModelPanel:GetLookAng()
|
||||
tab.cam_fov = self.ModelPanel:GetFOV()
|
||||
|
||||
self.SpawnIcon:RebuildSpawnIconEx( tab )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetIcon( icon )
|
||||
|
||||
if ( !IsValid( icon ) ) then return end
|
||||
|
||||
local model = icon:GetModelName()
|
||||
self:SetOrigin( icon )
|
||||
|
||||
self.SpawnIcon:SetSize( icon:GetSize() )
|
||||
self.SpawnIcon:InvalidateLayout( true )
|
||||
|
||||
local w, h = icon:GetSize()
|
||||
if ( w / h < 1 ) then
|
||||
self:SetSize( 700, 502 + 400 )
|
||||
self.LeftPanel:SetWide( 400 )
|
||||
elseif ( w / h > 1 ) then
|
||||
self:SetSize( 900, 502 - 100 )
|
||||
self.LeftPanel:SetWide( 600 )
|
||||
else
|
||||
self:SetSize( 700, 502 )
|
||||
self.LeftPanel:SetWide( 400 )
|
||||
end
|
||||
|
||||
if ( !model or model == "" ) then
|
||||
|
||||
self:SetModel( "error.mdl" )
|
||||
self.SpawnIcon:SetSpawnIcon( icon:GetIconName() )
|
||||
self:SetCustomIcon( true )
|
||||
|
||||
else
|
||||
|
||||
self:SetModel( model )
|
||||
self.SpawnIcon:SetModel( model, icon:GetSkinID(), icon:GetBodyGroup() )
|
||||
self:SetCustomIcon( false )
|
||||
|
||||
end
|
||||
|
||||
-- Keep the spawnmenu open
|
||||
g_SpawnMenu:HangOpen( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Refresh()
|
||||
|
||||
if ( !self:GetModel() ) then return end
|
||||
|
||||
self.ModelPanel:SetModel( self:GetModel() )
|
||||
self.ModelPanel.LayoutEntity = function() self:UpdateEntity( self.ModelPanel:GetEntity() ) end
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
ent:SetSkin( self.SpawnIcon:GetSkinID() )
|
||||
ent:SetBodyGroups( self.SpawnIcon:GetBodyGroup() )
|
||||
ent:SetLOD( 0 )
|
||||
|
||||
self:BestGuessLayout()
|
||||
self:FillAnimations( ent )
|
||||
self:SetDefaultLighting()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:FillAnimations( ent )
|
||||
|
||||
self.AnimList:Clear()
|
||||
|
||||
for k, v in SortedPairsByValue( ent:GetSequenceList() or {} ) do
|
||||
|
||||
local line = self.AnimList:AddLine( string.lower( v ) )
|
||||
|
||||
line.OnSelect = function()
|
||||
|
||||
local speed = ent:GetPlaybackRate()
|
||||
ent:ResetSequence( v )
|
||||
ent:SetCycle( 0 )
|
||||
ent:SetPlaybackRate( speed )
|
||||
if ( speed < 0 ) then ent:SetCycle( 1 ) end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.BodyList:Clear()
|
||||
local newItems = 0
|
||||
|
||||
if ( ent:SkinCount() > 1 ) then
|
||||
|
||||
local skinSlider = self.BodyList:Add( "DNumSlider" )
|
||||
skinSlider:Dock( TOP )
|
||||
skinSlider:DockMargin( 0, 0, 0, 3 )
|
||||
skinSlider:SetText( "Skin" )
|
||||
skinSlider:SetDark( true )
|
||||
skinSlider:SetDecimals( 0 )
|
||||
skinSlider:SetMinMax( 0, ent:SkinCount() - 1 )
|
||||
skinSlider:SetValue( ent:GetSkin() )
|
||||
skinSlider.OnValueChanged = function( s, newVal )
|
||||
newVal = math.Round( newVal )
|
||||
|
||||
ent:SetSkin( newVal )
|
||||
|
||||
if ( IsValid( self:GetOrigin() ) ) then self:GetOrigin():SkinChanged( newVal ) end
|
||||
|
||||
-- If we're not using a custom, change our spawnicon
|
||||
-- so we save the new skin in the right place...
|
||||
if ( !self:GetCustomIcon() ) then
|
||||
self.SpawnIcon:SetModel( self.SpawnIcon:GetModelName(), newVal, self.SpawnIcon:GetBodyGroup() )
|
||||
end
|
||||
end
|
||||
newItems = newItems + 1
|
||||
|
||||
end
|
||||
|
||||
for k = 0, ent:GetNumBodyGroups() - 1 do
|
||||
|
||||
if ( ent:GetBodygroupCount( k ) <= 1 ) then continue end
|
||||
|
||||
local bgSlider = self.BodyList:Add( "DNumSlider" )
|
||||
bgSlider:Dock( TOP )
|
||||
bgSlider:DockMargin( 0, 0, 0, 3 )
|
||||
bgSlider:SetDark( true )
|
||||
bgSlider:SetDecimals( 0 )
|
||||
bgSlider:SetText( ent:GetBodygroupName( k ) )
|
||||
bgSlider:SetMinMax( 0, ent:GetBodygroupCount( k ) - 1 )
|
||||
bgSlider:SetValue( ent:GetBodygroup( k ) )
|
||||
bgSlider.BodyGroupID = k
|
||||
bgSlider.OnValueChanged = function( s, newVal )
|
||||
newVal = math.Round( newVal )
|
||||
|
||||
ent:SetBodygroup( s.BodyGroupID, newVal )
|
||||
|
||||
if ( IsValid( self:GetOrigin() ) ) then self:GetOrigin():BodyGroupChanged( s.BodyGroupID, newVal ) end
|
||||
|
||||
-- If we're not using a custom, change our spawnicon
|
||||
-- so we save the new skin in the right place...
|
||||
if ( !self:GetCustomIcon() ) then
|
||||
self.SpawnIcon:SetBodyGroup( s.BodyGroupID, newVal )
|
||||
self.SpawnIcon:SetModel( self.SpawnIcon:GetModelName(), self.SpawnIcon:GetSkinID(), self.SpawnIcon:GetBodyGroup() )
|
||||
end
|
||||
end
|
||||
newItems = newItems + 1
|
||||
|
||||
end
|
||||
|
||||
if ( newItems > 0 ) then
|
||||
self.BodygroupTab.Tab:SetVisible( true )
|
||||
else
|
||||
self.BodygroupTab.Tab:SetVisible( false )
|
||||
end
|
||||
local propertySheet = self.PropertySheet
|
||||
propertySheet.tabScroller:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetFromEntity( ent )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local bodyStr = ""
|
||||
for i = 0, 8 do
|
||||
bodyStr = bodyStr .. math.min( ent:GetBodygroup( i ) or 0, 9 )
|
||||
end
|
||||
|
||||
self.SpawnIcon:SetModel( ent:GetModel(), ent:GetSkin(), bodyStr )
|
||||
self:SetModel( ent:GetModel() )
|
||||
self:Refresh()
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "IconEditor", PANEL, "DFrame" )
|
||||
185
gamemodes/sandbox/gamemode/init.lua
Normal file
185
gamemodes/sandbox/gamemode/init.lua
Normal file
@@ -0,0 +1,185 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Sandbox Gamemode
|
||||
|
||||
This is GMod's default gamemode
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
-- These files get sent to the client
|
||||
|
||||
AddCSLuaFile( "cl_hints.lua" )
|
||||
AddCSLuaFile( "cl_init.lua" )
|
||||
AddCSLuaFile( "cl_notice.lua" )
|
||||
AddCSLuaFile( "cl_search_models.lua" )
|
||||
AddCSLuaFile( "cl_spawnmenu.lua" )
|
||||
AddCSLuaFile( "cl_worldtips.lua" )
|
||||
AddCSLuaFile( "persistence.lua" )
|
||||
AddCSLuaFile( "player_extension.lua" )
|
||||
AddCSLuaFile( "save_load.lua" )
|
||||
AddCSLuaFile( "shared.lua" )
|
||||
AddCSLuaFile( "gui/IconEditor.lua" )
|
||||
|
||||
include( 'shared.lua' )
|
||||
include( 'commands.lua' )
|
||||
include( 'player.lua' )
|
||||
include( 'spawnmenu/init.lua' )
|
||||
|
||||
--
|
||||
-- Make BaseClass available
|
||||
--
|
||||
DEFINE_BASECLASS( "gamemode_base" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawn()
|
||||
Desc: Called when a player spawns
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawn( pl, transiton )
|
||||
|
||||
player_manager.SetPlayerClass( pl, "player_sandbox" )
|
||||
|
||||
BaseClass.PlayerSpawn( self, pl, transiton )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:OnPhysgunFreeze( weapon, phys, ent, player )
|
||||
Desc: The physgun wants to freeze a prop
|
||||
-----------------------------------------------------------]]
|
||||
function GM:OnPhysgunFreeze( weapon, phys, ent, ply )
|
||||
|
||||
-- Don't freeze persistent props (should already be frozen)
|
||||
if ( ent:GetPersistent() && GetConVarString( "sbox_persist" ):Trim() != "" ) then return false end
|
||||
|
||||
BaseClass.OnPhysgunFreeze( self, weapon, phys, ent, ply )
|
||||
|
||||
ply:SendHint( "PhysgunUnfreeze", 0.3 )
|
||||
ply:SuppressHint( "PhysgunFreeze" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:OnPhysgunReload( weapon, player )
|
||||
Desc: The physgun wants to unfreeze
|
||||
-----------------------------------------------------------]]
|
||||
function GM:OnPhysgunReload( weapon, ply )
|
||||
|
||||
local num = ply:PhysgunUnfreeze()
|
||||
|
||||
if ( num > 0 ) then
|
||||
ply:SendLua( string.format( "GAMEMODE:UnfrozeObjects(%d)", num ) )
|
||||
end
|
||||
|
||||
ply:SuppressHint( "PhysgunUnfreeze" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerShouldTakeDamage
|
||||
Return true if this player should take damage from this attacker
|
||||
Note: This is a shared function - the client will think they can
|
||||
damage the players even though they can't. This just means the
|
||||
prediction will show blood.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerShouldTakeDamage( ply, attacker )
|
||||
|
||||
-- Global godmode, players can't be damaged in any way
|
||||
if ( cvars.Bool( "sbox_godmode", false ) ) then return false end
|
||||
|
||||
-- No player vs player damage
|
||||
if ( attacker:IsValid() && attacker:IsPlayer() && ply != attacker ) then
|
||||
return cvars.Bool( "sbox_playershurtplayers", true )
|
||||
end
|
||||
|
||||
-- Default, let the player be hurt
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Show the search when f1 is pressed
|
||||
-----------------------------------------------------------]]
|
||||
function GM:ShowHelp( ply )
|
||||
|
||||
ply:SendLua( "hook.Run( 'StartSearch' )" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Called once on the player's first spawn
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerInitialSpawn( ply, transiton )
|
||||
|
||||
BaseClass.PlayerInitialSpawn( self, ply, transiton )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
A ragdoll of an entity has been created
|
||||
-----------------------------------------------------------]]
|
||||
function GM:CreateEntityRagdoll( entity, ragdoll )
|
||||
|
||||
-- Replace the entity with the ragdoll in cleanups etc
|
||||
undo.ReplaceEntity( entity, ragdoll )
|
||||
cleanup.ReplaceEntity( entity, ragdoll )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Player unfroze an object
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerUnfrozeObject( ply, entity, physobject )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( physobject:GetPos() )
|
||||
effectdata:SetEntity( entity )
|
||||
util.Effect( "phys_unfreeze", effectdata, true, true )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Player froze an object
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerFrozeObject( ply, entity, physobject )
|
||||
|
||||
if ( DisablePropCreateEffect ) then return end
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( physobject:GetPos() )
|
||||
effectdata:SetEntity( entity )
|
||||
util.Effect( "phys_freeze", effectdata, true, true )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Who can edit variables?
|
||||
-- If you're writing prop protection or something, you'll
|
||||
-- probably want to hook or override this function.
|
||||
--
|
||||
function GM:CanEditVariable( ent, ply, key, val, editor )
|
||||
|
||||
-- Only allow admins to edit admin only variables!
|
||||
local isAdmin = ply:IsAdmin() || game.SinglePlayer()
|
||||
if ( editor.AdminOnly && !isAdmin ) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- This entity decides who can edit its variables
|
||||
if ( isfunction( ent.CanEditVariables ) ) then
|
||||
return ent:CanEditVariables( ply )
|
||||
end
|
||||
|
||||
-- default in sandbox is.. anyone can edit anything.
|
||||
return true
|
||||
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user