add sborka
This commit is contained in:
@@ -0,0 +1,548 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.DoNotDuplicate = true
|
||||
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH
|
||||
|
||||
local IgnoreDistance = 200
|
||||
local GrabDistance = 150
|
||||
local HookupDistance = 32
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar( "Entity",0, "Base" )
|
||||
self:NetworkVar( "Entity",1, "TargetBase" )
|
||||
self:NetworkVar( "Entity",2, "DragTarget" )
|
||||
self:NetworkVar( "Int",0, "HitchType" )
|
||||
|
||||
if SERVER then
|
||||
self:SetHitchType( LVS.HITCHTYPE_NONE or -1 )
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
util.AddNetworkString( "lvs_trailerhitch" )
|
||||
|
||||
net.Receive( "lvs_trailerhitch", function( len, ply )
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
if not IsValid( ent ) or not isfunction( ent.StartDrag ) then return end
|
||||
|
||||
if ent.IsLinkInProgress then return end
|
||||
|
||||
if IsValid( ent:GetTargetBase() ) then
|
||||
ent:Decouple()
|
||||
else
|
||||
ent:StartDrag( ply )
|
||||
ent._HandBrakeForceDisabled = true
|
||||
end
|
||||
end )
|
||||
|
||||
function ENT:StartDrag( ply )
|
||||
if IsValid( self.GrabEnt ) or IsValid( ply._HitchGrabEnt ) then return end
|
||||
|
||||
if self:GetHitchType() ~= LVS.HITCHTYPE_FEMALE then return end
|
||||
|
||||
local base = self:GetBase()
|
||||
|
||||
if not IsValid( ply ) or not ply:Alive() or ply:InVehicle() or ply:GetObserverMode() ~= OBS_MODE_NONE or not ply:KeyDown( IN_WALK ) or (ply:GetShootPos() - self:GetPos()):Length() > GrabDistance or not IsValid( base ) then return end
|
||||
|
||||
ply:SprintDisable()
|
||||
|
||||
self.GrabEnt = ents.Create( "prop_physics" )
|
||||
|
||||
ply._HitchGrabEnt = self.GrabEnt
|
||||
|
||||
if not IsValid( self.GrabEnt ) then return end
|
||||
|
||||
self.GrabEnt:SetModel( "models/Combine_Helicopter/helicopter_bomb01.mdl" )
|
||||
self.GrabEnt:SetPos( self:GetPos() )
|
||||
self.GrabEnt:SetAngles( self:GetAngles() )
|
||||
self.GrabEnt:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
self.GrabEnt:Spawn()
|
||||
self.GrabEnt:Activate()
|
||||
self.GrabEnt:SetNoDraw( true )
|
||||
self.GrabEnt.DoNotDuplicate = true
|
||||
self:DeleteOnRemove( self.GrabEnt )
|
||||
|
||||
self:SetDragTarget( ply )
|
||||
|
||||
local PhysObj = self.GrabEnt:GetPhysicsObject()
|
||||
|
||||
if not IsValid( PhysObj ) then return end
|
||||
|
||||
PhysObj:SetMass( 50000 )
|
||||
PhysObj:EnableMotion( false )
|
||||
|
||||
constraint.Ballsocket( base, self.GrabEnt, 0, 0, vector_origin, 0, 0, 1 )
|
||||
|
||||
self.GrabEnt:SetSolid( SOLID_NONE )
|
||||
|
||||
base:OnStartDrag( self, ply )
|
||||
base._HandBrakeForceDisabled = true
|
||||
|
||||
base._DragOriginalCollisionGroup = base:GetCollisionGroup()
|
||||
base:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
|
||||
if base.GetWheels then
|
||||
for _, wheel in pairs( base:GetWheels() ) do
|
||||
if not IsValid( wheel ) then continue end
|
||||
|
||||
wheel._DragOriginalCollisionGroup = wheel:GetCollisionGroup()
|
||||
wheel:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
end
|
||||
end
|
||||
|
||||
self:NextThink( CurTime() )
|
||||
end
|
||||
|
||||
function ENT:StopDrag()
|
||||
if IsValid( self.GrabEnt ) then
|
||||
self.GrabEnt:Remove()
|
||||
end
|
||||
|
||||
local ply = self:GetDragTarget()
|
||||
|
||||
if IsValid( ply ) then
|
||||
ply:SprintEnable()
|
||||
end
|
||||
|
||||
local base = self:GetBase()
|
||||
|
||||
if IsValid( base ) then
|
||||
|
||||
base:OnStopDrag( self, ply )
|
||||
base._HandBrakeForceDisabled = nil
|
||||
|
||||
if IsValid( ply ) then base:SetPhysicsAttacker( ply ) end
|
||||
|
||||
if base._DragOriginalCollisionGroup then
|
||||
base:SetCollisionGroup( base._DragOriginalCollisionGroup )
|
||||
base._DragOriginalCollisionGroup = nil
|
||||
end
|
||||
|
||||
if base.GetWheels then
|
||||
for _, wheel in pairs( base:GetWheels() ) do
|
||||
if not IsValid( wheel ) then continue end
|
||||
|
||||
if IsValid( ply ) then wheel:SetPhysicsAttacker( ply ) end
|
||||
|
||||
if wheel._DragOriginalCollisionGroup then
|
||||
wheel:SetCollisionGroup( wheel._DragOriginalCollisionGroup )
|
||||
wheel._DragOriginalCollisionGroup = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:SetDragTarget( NULL )
|
||||
|
||||
for _, ent in ipairs( ents.FindByClass( "lvs_wheeldrive_trailerhitch" ) ) do
|
||||
if ent:GetHitchType() ~= LVS.HITCHTYPE_MALE then continue end
|
||||
|
||||
local dist = (self:GetPos() - ent:GetPos()):Length()
|
||||
|
||||
if dist > HookupDistance then continue end
|
||||
|
||||
self:CoupleTo( ent )
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Drag( ply )
|
||||
if not IsValid( self.GrabEnt ) or ply:InVehicle() or not ply:KeyDown( IN_WALK ) or not ply:Alive() or ply:GetObserverMode() ~= OBS_MODE_NONE then
|
||||
self:StopDrag()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if not self.GrabEnt.TargetAngle then
|
||||
self.GrabEnt.TargetAngle = ply:EyeAngles().y
|
||||
end
|
||||
|
||||
local TargetAngle = ply:EyeAngles()
|
||||
|
||||
self.GrabEnt.TargetAngle = math.ApproachAngle( self.GrabEnt.TargetAngle, TargetAngle.y, FrameTime() * 500 )
|
||||
|
||||
TargetAngle.p = math.max( TargetAngle.p, -15 )
|
||||
|
||||
TargetAngle.y = self.GrabEnt.TargetAngle
|
||||
|
||||
local TargetPos = ply:GetShootPos() + TargetAngle:Forward() * 80
|
||||
|
||||
if (self:GetPos() - TargetPos):Length() > GrabDistance then self:StopDrag() return end
|
||||
|
||||
self.GrabEnt:SetPos( TargetPos )
|
||||
|
||||
local base = self:GetBase()
|
||||
|
||||
if not IsValid( base ) then return end
|
||||
|
||||
base:PhysWake()
|
||||
|
||||
if base.WheelsOnGround then
|
||||
if base:WheelsOnGround() then return end
|
||||
else
|
||||
if base:OnGround() then return end
|
||||
end
|
||||
|
||||
local PhysObj = base:GetPhysicsObject()
|
||||
|
||||
if not IsValid( PhysObj ) then return end
|
||||
|
||||
PhysObj:SetAngleVelocity( PhysObj:GetAngleVelocity() * 0.8 )
|
||||
PhysObj:SetVelocity( PhysObj:GetVelocity() * 0.8 )
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetSolid( SOLID_NONE )
|
||||
self:SetMoveType( MOVETYPE_NONE )
|
||||
self:DrawShadow( false )
|
||||
end
|
||||
|
||||
function ENT:Decouple()
|
||||
local TargetBase = self:GetTargetBase()
|
||||
|
||||
self:SetTargetBase( NULL )
|
||||
|
||||
if not IsValid( self.HitchConstraint ) then return end
|
||||
|
||||
local base = self:GetBase()
|
||||
|
||||
if IsValid( base ) then
|
||||
base:OnCoupleChanged( TargetBase, self.HitchTarget, false )
|
||||
TargetBase:OnCoupleChanged( self:GetBase(), self, false )
|
||||
end
|
||||
|
||||
self.HitchConstraint:Remove()
|
||||
|
||||
self.HitchTarget = nil
|
||||
end
|
||||
|
||||
function ENT:CoupleTo( target )
|
||||
if not IsValid( target ) or IsValid( target.HitchConstraint ) or IsValid( self.HitchConstraint ) then return end
|
||||
|
||||
local base = self:GetBase()
|
||||
|
||||
if self.IsLinkInProgress or not IsValid( base ) or IsValid( self.PosEnt ) then return end
|
||||
|
||||
self.IsLinkInProgress = true
|
||||
|
||||
if self:GetHitchType() ~= LVS.HITCHTYPE_FEMALE or target:GetHitchType() ~= LVS.HITCHTYPE_MALE then self.IsLinkInProgress = nil return end
|
||||
|
||||
self.PosEnt = ents.Create( "prop_physics" )
|
||||
|
||||
if not IsValid( self.PosEnt ) then self.IsLinkInProgress = nil return end
|
||||
|
||||
self.PosEnt:SetModel( "models/Combine_Helicopter/helicopter_bomb01.mdl" )
|
||||
self.PosEnt:SetPos( self:GetPos() )
|
||||
self.PosEnt:SetAngles( self:GetAngles() )
|
||||
self.PosEnt:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
self.PosEnt:Spawn()
|
||||
self.PosEnt:Activate()
|
||||
self.PosEnt:SetNoDraw( true )
|
||||
self.PosEnt.DoNotDuplicate = true
|
||||
self:DeleteOnRemove( self.PosEnt )
|
||||
|
||||
local PhysObj = self.PosEnt:GetPhysicsObject()
|
||||
|
||||
if not IsValid( PhysObj ) then self.IsLinkInProgress = nil return end
|
||||
|
||||
PhysObj:SetMass( 50000 )
|
||||
PhysObj:EnableMotion( false )
|
||||
|
||||
constraint.Ballsocket( base, self.PosEnt, 0, 0, vector_origin, 0, 0, 1 )
|
||||
|
||||
local targetBase = target:GetBase()
|
||||
|
||||
base:OnCoupleChanged( targetBase, target, true )
|
||||
targetBase:OnCoupleChanged( self:GetBase(), self, true )
|
||||
|
||||
self.PosEnt:SetSolid( SOLID_NONE )
|
||||
|
||||
timer.Simple( 0, function()
|
||||
if not IsValid( self.PosEnt ) then
|
||||
self.IsLinkInProgress = nil
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if not IsValid( target ) or not IsValid( targetBase ) then
|
||||
self.PosEnt:Remove()
|
||||
|
||||
self.IsLinkInProgress = nil
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self.PosEnt:SetPos( target:GetPos() )
|
||||
|
||||
constraint.Weld( self.PosEnt, targetBase, 0, 0, 0, false, false )
|
||||
|
||||
timer.Simple( 0.25, function()
|
||||
if not IsValid( base ) or not IsValid( targetBase ) or not IsValid( self.PosEnt ) then self.IsLinkInProgress = nil return end
|
||||
|
||||
self.HitchTarget = target
|
||||
self.HitchConstraint = constraint.Ballsocket( base, targetBase, 0, 0, targetBase:WorldToLocal( self.PosEnt:GetPos() ), 0, 0, 1 )
|
||||
|
||||
target.HitchConstraint = self.HitchConstraint
|
||||
|
||||
self:SetTargetBase( targetBase )
|
||||
|
||||
self.PosEnt:Remove()
|
||||
|
||||
self.IsLinkInProgress = nil
|
||||
end )
|
||||
end )
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
|
||||
local ply = self:GetDragTarget()
|
||||
|
||||
if IsValid( ply ) then
|
||||
self:Drag( ply )
|
||||
|
||||
self:NextThink( CurTime() )
|
||||
else
|
||||
self:NextThink( CurTime() + 9999 )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:StopDrag()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local HitchEnts = {}
|
||||
|
||||
function ENT:Initialize()
|
||||
table.insert( HitchEnts, self )
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
for id, e in pairs( HitchEnts ) do
|
||||
if IsValid( e ) then continue end
|
||||
|
||||
HitchEnts[ id ] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
end
|
||||
|
||||
local function DrawDiamond( X, Y, radius )
|
||||
local segmentdist = 90
|
||||
local radius2 = radius + 1
|
||||
|
||||
for a = 0, 360, segmentdist do
|
||||
surface.DrawLine( X + math.cos( math.rad( a ) ) * radius, Y - math.sin( math.rad( a ) ) * radius, X + math.cos( math.rad( a + segmentdist ) ) * radius, Y - math.sin( math.rad( a + segmentdist ) ) * radius )
|
||||
surface.DrawLine( X + math.cos( math.rad( a ) ) * radius2, Y - math.sin( math.rad( a ) ) * radius2, X + math.cos( math.rad( a + segmentdist ) ) * radius2, Y - math.sin( math.rad( a + segmentdist ) ) * radius2 )
|
||||
end
|
||||
end
|
||||
|
||||
local function DrawText( x, y, text, col )
|
||||
local font = "TargetIDSmall"
|
||||
draw.SimpleText( text, font, x + 1, y + 1, Color( 0, 0, 0, 120 ), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
|
||||
draw.SimpleText( text, font, x + 2, y + 2, Color( 0, 0, 0, 50 ), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
|
||||
draw.SimpleText( text, font, x, y, col or color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
|
||||
end
|
||||
|
||||
local circle = Material( "vgui/circle" )
|
||||
local radius = 6
|
||||
local Col = Color(255,191,0,255)
|
||||
|
||||
local boxMins = Vector(-5,-5,-5)
|
||||
local boxMaxs = Vector(5,5,5)
|
||||
|
||||
function ENT:DrawInfoCoupled( ply )
|
||||
local boxOrigin = self:GetPos()
|
||||
local scr = boxOrigin:ToScreen()
|
||||
|
||||
if not scr.visible then return end
|
||||
|
||||
local shootPos = ply:GetShootPos()
|
||||
|
||||
local boxAngles = self:GetAngles()
|
||||
|
||||
if (boxOrigin - shootPos):Length() > 250 then return end
|
||||
|
||||
local HitPos, _, _ = util.IntersectRayWithOBB( shootPos, ply:GetAimVector() * GrabDistance, boxOrigin, boxAngles, boxMins, boxMaxs )
|
||||
|
||||
local X = scr.x
|
||||
local Y = scr.y
|
||||
|
||||
cam.Start2D()
|
||||
if HitPos then
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
|
||||
local Key = input.LookupBinding( "+walk" )
|
||||
|
||||
if not isstring( Key ) then Key = "[+walk not bound]" end
|
||||
|
||||
DrawText( X, Y + 20, "press "..Key.." to decouple!",Color(255,255,255,255) )
|
||||
|
||||
local KeyUse = ply:KeyDown( IN_WALK )
|
||||
|
||||
if self.OldKeyUse ~= KeyUse then
|
||||
self.OldKeyUse = KeyUse
|
||||
|
||||
if KeyUse then
|
||||
net.Start( "lvs_trailerhitch" )
|
||||
net.WriteEntity( self )
|
||||
net.SendToServer()
|
||||
end
|
||||
end
|
||||
else
|
||||
surface.SetDrawColor( Col.r, Col.g, Col.b, Col.a )
|
||||
end
|
||||
|
||||
DrawDiamond( X, Y, radius )
|
||||
surface.SetDrawColor( 0, 0, 0, 80 )
|
||||
DrawDiamond( X + 1, Y + 1, radius )
|
||||
cam.End2D()
|
||||
end
|
||||
|
||||
function ENT:DrawInfo( ply )
|
||||
local boxOrigin = self:GetPos()
|
||||
local scr = boxOrigin:ToScreen()
|
||||
|
||||
if not scr.visible then return end
|
||||
|
||||
local shootPos = ply:GetShootPos()
|
||||
|
||||
local boxAngles = self:GetAngles()
|
||||
|
||||
if (boxOrigin - shootPos):Length() > 250 then return end
|
||||
|
||||
local HitPos, _, _ = util.IntersectRayWithOBB( shootPos, ply:GetAimVector() * GrabDistance, boxOrigin, boxAngles, boxMins, boxMaxs )
|
||||
|
||||
local X = scr.x
|
||||
local Y = scr.y
|
||||
|
||||
local DragTarget = self:GetDragTarget()
|
||||
local IsBeingDragged = IsValid( DragTarget )
|
||||
local HasTarget = false
|
||||
|
||||
if IsBeingDragged then
|
||||
cam.Start2D()
|
||||
|
||||
for id, ent in pairs( HitchEnts ) do
|
||||
if ent == self then continue end
|
||||
|
||||
if not IsValid( ent ) or ent:GetHitchType() ~= LVS.HITCHTYPE_MALE then continue end
|
||||
|
||||
local tpos = ent:GetPos()
|
||||
|
||||
local dist = (tpos - boxOrigin):Length()
|
||||
|
||||
if dist > IgnoreDistance then continue end
|
||||
|
||||
local tscr = tpos:ToScreen()
|
||||
|
||||
if not tscr.visible then continue end
|
||||
|
||||
local tX = tscr.x
|
||||
local tY = tscr.y
|
||||
|
||||
if dist < HookupDistance and IsBeingDragged then
|
||||
HasTarget = true
|
||||
end
|
||||
|
||||
surface.SetMaterial( circle )
|
||||
surface.SetDrawColor( 0, 0, 0, 80 )
|
||||
surface.DrawTexturedRect( tX - radius * 0.5 + 1, tY - radius * 0.5 + 1, radius, radius )
|
||||
|
||||
if HasTarget then
|
||||
surface.SetDrawColor( 0, 255, 0, 255 )
|
||||
else
|
||||
surface.SetDrawColor( Col.r, Col.g, Col.b, Col.a )
|
||||
end
|
||||
|
||||
surface.DrawTexturedRect( tX - radius * 0.5, tY - radius * 0.5, radius, radius )
|
||||
|
||||
if not HasTarget then continue end
|
||||
|
||||
surface.DrawLine( X, Y, tX, tY )
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
local radiusB = 25 + math.cos( CurTime() * 10 ) * 2
|
||||
|
||||
if HasTarget then
|
||||
surface.SetDrawColor( 0, 255, 0, 255 )
|
||||
else
|
||||
surface.SetDrawColor( 255, 0, 0, 255 )
|
||||
end
|
||||
|
||||
DrawDiamond( X, Y, radiusB )
|
||||
surface.SetDrawColor( 0, 0, 0, 80 )
|
||||
DrawDiamond( X + 1, Y + 1, radiusB )
|
||||
|
||||
if HasTarget then
|
||||
DrawText( X, Y + 35, "release to couple",Color(0,255,0,255) )
|
||||
else
|
||||
DrawText( X, Y + 35, "in use by "..DragTarget:GetName(),Color(255,0,0,255) )
|
||||
end
|
||||
|
||||
cam.End2D()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
cam.Start2D()
|
||||
if HitPos then
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
|
||||
local Key = input.LookupBinding( "+walk" )
|
||||
|
||||
if not isstring( Key ) then Key = "[+walk not bound]" end
|
||||
|
||||
DrawText( X, Y + 20, "hold "..Key.." to drag!",Color(255,255,255,255) )
|
||||
|
||||
local KeyUse = ply:KeyDown( IN_WALK )
|
||||
|
||||
if self.OldKeyUse ~= KeyUse then
|
||||
self.OldKeyUse = KeyUse
|
||||
|
||||
if KeyUse then
|
||||
surface.PlaySound("common/wpn_select.wav")
|
||||
|
||||
net.Start( "lvs_trailerhitch" )
|
||||
net.WriteEntity( self )
|
||||
net.SendToServer()
|
||||
end
|
||||
end
|
||||
else
|
||||
surface.SetDrawColor( Col.r, Col.g, Col.b, Col.a )
|
||||
end
|
||||
|
||||
DrawDiamond( X, Y, radius )
|
||||
surface.SetDrawColor( 0, 0, 0, 80 )
|
||||
DrawDiamond( X + 1, Y + 1, radius )
|
||||
cam.End2D()
|
||||
end
|
||||
|
||||
function ENT:DrawTranslucent()
|
||||
local ply = LocalPlayer()
|
||||
|
||||
if not IsValid( ply ) or IsValid( ply:lvsGetVehicle() ) or self:GetHitchType() ~= LVS.HITCHTYPE_FEMALE then return end
|
||||
|
||||
local wep = ply:GetActiveWeapon()
|
||||
|
||||
if IsValid( wep ) and wep:GetClass() == "gmod_camera" then return end
|
||||
|
||||
if IsValid( self:GetTargetBase() ) then
|
||||
self:DrawInfoCoupled( ply )
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:DrawInfo( ply )
|
||||
end
|
||||
Reference in New Issue
Block a user