add sborka
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
|
||||
ENT._lvsSmoothFreeLook = 0
|
||||
|
||||
function ENT:CalcViewDirectInput( ply, pos, angles, fov, pod )
|
||||
local ViewPosL = pod:WorldToLocal( pos )
|
||||
|
||||
local view = {}
|
||||
view.fov = fov
|
||||
view.drawviewer = true
|
||||
view.angles = self:GetAngles()
|
||||
|
||||
local FreeLook = ply:lvsKeyDown( "FREELOOK" )
|
||||
local Zoom = ply:lvsKeyDown( "ZOOM" )
|
||||
|
||||
if not pod:GetThirdPersonMode() then
|
||||
|
||||
if FreeLook then
|
||||
view.angles = pod:LocalToWorldAngles( ply:EyeAngles() )
|
||||
|
||||
self._lvsSmoothFreeLook = 1
|
||||
self._lvsSmoothFreeLookAngles = self:WorldToLocalAngles( view.angles )
|
||||
else
|
||||
if self._lvsSmoothFreeLook and self._lvsSmoothFreeLookAngles then
|
||||
|
||||
view.angles = self:LocalToWorldAngles( self._lvsSmoothFreeLookAngles * self._lvsSmoothFreeLook )
|
||||
|
||||
if self._lvsSmoothFreeLook <= 0 then
|
||||
self._lvsSmoothFreeLookAngles = nil
|
||||
self._lvsSmoothFreeLook = nil
|
||||
else
|
||||
self._lvsSmoothFreeLook = self._lvsSmoothFreeLook - self._lvsSmoothFreeLook * RealFrameTime() * 8
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local velL = self:WorldToLocal( self:GetPos() + self:GetVelocity() )
|
||||
|
||||
local Dividor = math.abs( velL.x )
|
||||
local SideForce = math.Clamp( velL.y / Dividor, -1, 1)
|
||||
local UpForce = math.Clamp( velL.z / Dividor, -1, 1)
|
||||
|
||||
local ViewPunch = Vector(0,math.Clamp(SideForce * 10,-1,1),math.Clamp(UpForce * 10,-1,1))
|
||||
if Zoom then
|
||||
ViewPunch = Vector(0,0,0)
|
||||
end
|
||||
|
||||
pod._lerpPosOffset = pod._lerpPosOffset and pod._lerpPosOffset + (ViewPunch - pod._lerpPosOffset) * RealFrameTime() * 5 or Vector(0,0,0)
|
||||
pod._lerpPos = pos
|
||||
|
||||
view.origin = pos + pod:GetForward() * -pod._lerpPosOffset.y * 0.5 + pod:GetUp() * pod._lerpPosOffset.z * 0.5
|
||||
view.angles.p = view.angles.p - pod._lerpPosOffset.z * 0.1
|
||||
view.angles.y = view.angles.y + pod._lerpPosOffset.y * 0.1
|
||||
view.drawviewer = false
|
||||
|
||||
return view
|
||||
end
|
||||
|
||||
pod._lerpPos = pod._lerpPos or self:GetPos()
|
||||
|
||||
local radius = 550
|
||||
radius = radius + radius * pod:GetCameraDistance()
|
||||
|
||||
if FreeLook then
|
||||
local velL = self:WorldToLocal( self:GetPos() + self:GetVelocity() )
|
||||
|
||||
local SideForce = math.Clamp(velL.y / 10,-250,250)
|
||||
local UpForce = math.Clamp(velL.z / 10,-250,250)
|
||||
|
||||
pod._lerpPosL = pod._lerpPosL and (pod._lerpPosL + (Vector(radius, SideForce,150 + radius * 0.1 + radius * pod:GetCameraHeight() + UpForce) - pod._lerpPosL) * RealFrameTime() * 12) or Vector(0,0,0)
|
||||
pod._lerpPos = self:LocalToWorld( pod._lerpPosL )
|
||||
|
||||
view.origin = pod._lerpPos
|
||||
view.angles = self:LocalToWorldAngles( Angle(0,180,0) )
|
||||
else
|
||||
local TargetPos = self:LocalToWorld( Vector(500,0,150 + radius * 0.1 + radius * pod:GetCameraHeight()) )
|
||||
|
||||
local Sub = TargetPos - pod._lerpPos
|
||||
local Dir = Sub:GetNormalized()
|
||||
local Dist = Sub:Length()
|
||||
|
||||
local DesiredPos = TargetPos - self:GetForward() * (300 + radius) - Dir * 100
|
||||
|
||||
pod._lerpPos = pod._lerpPos + (DesiredPos - pod._lerpPos) * RealFrameTime() * (Zoom and 30 or 12)
|
||||
pod._lerpPosL = self:WorldToLocal( pod._lerpPos )
|
||||
|
||||
local vel = self:GetVelocity()
|
||||
|
||||
view.origin = pod._lerpPos
|
||||
view.angles = self:GetAngles()
|
||||
end
|
||||
|
||||
view.origin = view.origin + ViewPosL
|
||||
|
||||
return view
|
||||
end
|
||||
|
||||
function ENT:CalcViewMouseAim( ply, pos, angles, fov, pod )
|
||||
local cvarFocus = math.Clamp( LVS.cvarCamFocus:GetFloat() , -1, 1 )
|
||||
|
||||
self._lvsSmoothFreeLook = self._lvsSmoothFreeLook + ((ply:lvsKeyDown( "FREELOOK" ) and 0 or 1) - self._lvsSmoothFreeLook) * RealFrameTime() * 10
|
||||
|
||||
local Zoom = ply:lvsKeyDown( "ZOOM" )
|
||||
|
||||
local velL = self:WorldToLocal( self:GetPos() + self:GetVelocity() )
|
||||
|
||||
local Dividor = math.abs( velL.x )
|
||||
local SideForce = math.Clamp( velL.y / Dividor, -1, 1)
|
||||
local UpForce = math.Clamp( velL.z / Dividor, -1, 1)
|
||||
|
||||
local ViewPunch = Vector(0,math.Clamp(SideForce * 10,-1,1),math.Clamp(UpForce * 10,-1,1))
|
||||
if Zoom then
|
||||
ViewPunch = Vector(0,0,0)
|
||||
end
|
||||
|
||||
pod._lerpPosOffset = pod._lerpPosOffset and pod._lerpPosOffset + (ViewPunch - pod._lerpPosOffset) * RealFrameTime() * 5 or Vector(0,0,0)
|
||||
pod._lerpPos = pos
|
||||
|
||||
local view = {}
|
||||
view.origin = pos + pod:GetForward() * -pod._lerpPosOffset.y * 0.5 + pod:GetUp() * pod._lerpPosOffset.z * 0.5
|
||||
view.fov = fov
|
||||
view.drawviewer = true
|
||||
view.angles = (self:GetForward() * (1 + cvarFocus) * self._lvsSmoothFreeLook * 0.8 + ply:EyeAngles():Forward() * math.max(1 - cvarFocus, 1 - self._lvsSmoothFreeLook)):Angle()
|
||||
|
||||
if cvarFocus >= 1 then
|
||||
view.angles = LerpAngle( self._lvsSmoothFreeLook, ply:EyeAngles(), self:GetAngles() )
|
||||
else
|
||||
view.angles.r = 0
|
||||
end
|
||||
|
||||
if not pod:GetThirdPersonMode() then
|
||||
|
||||
view.drawviewer = false
|
||||
|
||||
return view
|
||||
end
|
||||
|
||||
local radius = 550
|
||||
radius = radius + radius * pod:GetCameraDistance()
|
||||
|
||||
local TargetOrigin = view.origin - view.angles:Forward() * radius + view.angles:Up() * (radius * 0.2 + radius * pod:GetCameraHeight())
|
||||
local WallOffset = 4
|
||||
|
||||
local tr = util.TraceHull( {
|
||||
start = view.origin,
|
||||
endpos = TargetOrigin,
|
||||
filter = function( e )
|
||||
local c = e:GetClass()
|
||||
local collide = not c:StartWith( "prop_physics" ) and not c:StartWith( "prop_dynamic" ) and not c:StartWith( "prop_ragdoll" ) and not e:IsVehicle() and not c:StartWith( "gmod_" ) and not c:StartWith( "lvs_" ) and not c:StartWith( "player" ) and not e.LVS
|
||||
|
||||
return collide
|
||||
end,
|
||||
mins = Vector( -WallOffset, -WallOffset, -WallOffset ),
|
||||
maxs = Vector( WallOffset, WallOffset, WallOffset ),
|
||||
} )
|
||||
|
||||
view.origin = tr.HitPos
|
||||
|
||||
if tr.Hit and not tr.StartSolid then
|
||||
view.origin = view.origin + tr.HitNormal * WallOffset
|
||||
end
|
||||
|
||||
return view
|
||||
end
|
||||
|
||||
function ENT:CalcViewOverride( ply, pos, angles, fov, pod )
|
||||
return pos, angles, fov
|
||||
end
|
||||
|
||||
function ENT:CalcViewDriver( ply, pos, angles, fov, pod )
|
||||
if ply:lvsMouseAim() then
|
||||
return self:CalcViewMouseAim( ply, pos, angles, fov, pod )
|
||||
else
|
||||
return self:CalcViewDirectInput( ply, pos, angles, fov, pod )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:CalcViewPassenger( ply, pos, angles, fov, pod )
|
||||
return LVS:CalcView( self, ply, pos, angles, fov, pod )
|
||||
end
|
||||
|
||||
function ENT:LVSCalcView( ply, original_pos, original_angles, original_fov, pod )
|
||||
local pos, angles, fov = self:CalcViewOverride( ply, original_pos, original_angles, original_fov, pod )
|
||||
|
||||
if self:GetDriverSeat() == pod then
|
||||
return self:CalcViewDriver( ply, pos, angles, fov, pod )
|
||||
else
|
||||
return self:CalcViewPassenger( ply, pos, angles, fov, pod )
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
function ENT:OnDestroyed()
|
||||
if not self.DeathSound then return end
|
||||
|
||||
if self:GetVelocity():Length() <= self.MaxVelocity * 0.5 then return end
|
||||
|
||||
self._sndDeath = CreateSound( self, self.DeathSound )
|
||||
self._sndDeath:SetSoundLevel( 125 )
|
||||
self._sndDeath:PlayEx( 1, 50 + 50 * self:CalcDoppler( LocalPlayer() ) )
|
||||
end
|
||||
|
||||
function ENT:StopDeathSound()
|
||||
if not self._sndDeath then return end
|
||||
|
||||
self._sndDeath:Stop()
|
||||
end
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
ENT.FlyByAdvance = 0
|
||||
|
||||
function ENT:FlyByThink()
|
||||
local ply = LocalPlayer()
|
||||
|
||||
if not IsValid( ply ) then return end
|
||||
|
||||
local EntTable = self:GetTable()
|
||||
|
||||
if ply:lvsGetVehicle() == self then EntTable.OldApproaching = false return end
|
||||
|
||||
local ViewEnt = ply:GetViewEntity()
|
||||
|
||||
if not IsValid( ViewEnt ) then return end
|
||||
|
||||
local Time = CurTime()
|
||||
|
||||
if (EntTable._nextflyby or 0) > Time then return end
|
||||
|
||||
EntTable._nextflyby = Time + 0.1
|
||||
|
||||
local Vel = self:GetVelocity()
|
||||
|
||||
if self:GetThrottle() <= 0.75 or Vel:Length() <= EntTable.MaxVelocity * 0.75 then return end
|
||||
|
||||
local Sub = ViewEnt:GetPos() - self:GetPos() - Vel * EntTable.FlyByAdvance
|
||||
local ToPlayer = Sub:GetNormalized()
|
||||
local VelDir = Vel:GetNormalized()
|
||||
|
||||
local ApproachAngle = math.deg( math.acos( math.Clamp( ToPlayer:Dot( VelDir ) ,-1,1) ) )
|
||||
|
||||
local Approaching = ApproachAngle < 80
|
||||
|
||||
if Approaching ~= EntTable.OldApproaching then
|
||||
EntTable.OldApproaching = Approaching
|
||||
|
||||
if Approaching then
|
||||
self:StopFlyBy()
|
||||
else
|
||||
self:OnFlyBy( 60 + 80 * math.min(ApproachAngle / 140,1) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnFlyBy( Pitch )
|
||||
if not self.FlyBySound then return end
|
||||
|
||||
local EntTable = self:GetTable()
|
||||
|
||||
EntTable.flybysnd = CreateSound( self, EntTable.FlyBySound )
|
||||
EntTable.flybysnd:SetSoundLevel( 95 )
|
||||
EntTable.flybysnd:PlayEx( 1, Pitch )
|
||||
end
|
||||
|
||||
function ENT:StopFlyBy()
|
||||
local EntTable = self:GetTable()
|
||||
|
||||
if not EntTable.flybysnd then return end
|
||||
|
||||
EntTable.flybysnd:Stop()
|
||||
EntTable.flybysnd = nil
|
||||
end
|
||||
@@ -0,0 +1,98 @@
|
||||
ENT.IconEngine = Material( "lvs/engine.png" )
|
||||
|
||||
function ENT:LVSHudPaintInfoText( X, Y, W, H, ScrX, ScrY, ply )
|
||||
local speed = math.Round( LVS:GetUnitValue( self:GetVelocity():Length() ) ,0)
|
||||
draw.DrawText( LVS:GetUnitName().." ", "LVS_FONT", X + 72, Y + 35, color_white, TEXT_ALIGN_RIGHT )
|
||||
draw.DrawText( speed, "LVS_FONT_HUD_LARGE", X + 72, Y + 20, color_white, TEXT_ALIGN_LEFT )
|
||||
|
||||
if ply ~= self:GetDriver() then return end
|
||||
|
||||
local Throttle = self:GetThrottle()
|
||||
local Col = Throttle <= 1 and color_white or Color(0,0,0,255)
|
||||
local hX = X + W - H * 0.5
|
||||
local hY = Y + H * 0.25 + H * 0.25
|
||||
|
||||
surface.SetMaterial( self.IconEngine )
|
||||
surface.SetDrawColor( 0, 0, 0, 200 )
|
||||
surface.DrawTexturedRectRotated( hX + 4, hY + 1, H * 0.5, H * 0.5, 0 )
|
||||
surface.SetDrawColor( color_white )
|
||||
surface.DrawTexturedRectRotated( hX + 2, hY - 1, H * 0.5, H * 0.5, 0 )
|
||||
|
||||
if not self:GetEngineActive() then
|
||||
draw.SimpleText( "X" , "LVS_FONT", hX, hY, Color(0,0,0,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
|
||||
end
|
||||
|
||||
self:LVSDrawCircle( hX, hY, H * 0.35, math.min( Throttle, 1 ) )
|
||||
|
||||
if Throttle > 1 then
|
||||
draw.SimpleText( "+"..math.Round((Throttle - 1) * 100,0).."%" , "LVS_FONT", hX, hY, Col, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:LVSPreHudPaint( X, Y, ply )
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:LVSHudPaint( X, Y, ply )
|
||||
if not self:LVSPreHudPaint( X, Y, ply ) then return end
|
||||
|
||||
if ply ~= self:GetDriver() then return end
|
||||
|
||||
local HitPlane = self:GetEyeTrace( true ).HitPos:ToScreen()
|
||||
local HitPilot = self:GetEyeTrace().HitPos:ToScreen()
|
||||
|
||||
local MouseAim = ply:lvsMouseAim()
|
||||
|
||||
if self:IsDrawingReflectorSight() then
|
||||
self:DrawReflectorSight( HitPlane )
|
||||
|
||||
if MouseAim then
|
||||
local LineVisible = false
|
||||
|
||||
if not ply:lvsKeyDown( "FREELOOK" ) then
|
||||
LineVisible = self:LVSHudPaintMouseAim( HitPlane, HitPilot )
|
||||
end
|
||||
|
||||
if LineVisible then
|
||||
self:PaintCrosshairOuter( HitPilot )
|
||||
end
|
||||
end
|
||||
|
||||
self:LVSPaintHitMarker( HitPilot )
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:PaintCrosshairCenter( HitPlane )
|
||||
self:PaintCrosshairOuter( HitPilot )
|
||||
|
||||
if MouseAim and not ply:lvsKeyDown( "FREELOOK" ) then
|
||||
self:LVSHudPaintMouseAim( HitPlane, HitPilot )
|
||||
end
|
||||
|
||||
self:LVSPaintHitMarker( HitPilot )
|
||||
end
|
||||
|
||||
function ENT:LVSHudPaintDirectInput( Pos2D )
|
||||
self:PaintCrosshairCenter( Pos2D )
|
||||
self:PaintCrosshairOuter( Pos2D )
|
||||
end
|
||||
|
||||
function ENT:LVSHudPaintMouseAim( HitPlane, HitPilot )
|
||||
local Sub = Vector(HitPilot.x,HitPilot.y,0) - Vector(HitPlane.x,HitPlane.y,0)
|
||||
local Len = Sub:Length()
|
||||
|
||||
if Len <= 20 then return false end
|
||||
|
||||
local Dir = Sub:GetNormalized()
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 100 )
|
||||
surface.DrawLine( HitPlane.x + Dir.x * 5, HitPlane.y + Dir.y * 5, HitPilot.x - Dir.x * 20, HitPilot.y- Dir.y * 20 )
|
||||
|
||||
-- shadow
|
||||
surface.SetDrawColor( 0, 0, 0, 50 )
|
||||
surface.DrawLine( HitPlane.x + Dir.x * 5 + 1, HitPlane.y + Dir.y * 5 + 1, HitPilot.x - Dir.x * 20+ 1, HitPilot.y- Dir.y * 20 + 1 )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
include("shared.lua")
|
||||
include("cl_camera.lua")
|
||||
include("sh_camera_eyetrace.lua")
|
||||
include("cl_hud.lua")
|
||||
include("cl_flyby.lua")
|
||||
include("cl_deathsound.lua")
|
||||
include("cl_reflectorsight.lua")
|
||||
|
||||
local ExhaustSprite = Material( "effects/muzzleflash2" )
|
||||
|
||||
function ENT:DoExhaustFX()
|
||||
local EntTable = self:GetTable()
|
||||
|
||||
local Throttle = self:GetThrottle()
|
||||
|
||||
local OffsetMagnitude = (8 + 4 * Throttle)
|
||||
|
||||
local T = CurTime()
|
||||
local FT = RealFrameTime()
|
||||
|
||||
local HP = self:GetHP()
|
||||
local MaxHP = self:GetMaxHP()
|
||||
|
||||
if HP <= 0 then return end
|
||||
|
||||
render.SetMaterial( ExhaustSprite )
|
||||
|
||||
local ShouldDoEffect = false
|
||||
|
||||
if (EntTable.NextFX or 0) < T then
|
||||
EntTable.NextFX = T + 0.05 + (1 - Throttle) / 10
|
||||
|
||||
ShouldDoEffect = true
|
||||
end
|
||||
|
||||
for id, data in pairs( EntTable.ExhaustPositions ) do
|
||||
if not EntTable.ExhaustPositions[ id ].PosOffset then
|
||||
EntTable.ExhaustPositions[ id ].PosOffset = 0
|
||||
end
|
||||
|
||||
if not EntTable.ExhaustPositions[ id ].NextFX then
|
||||
EntTable.ExhaustPositions[ id ].NextFX = 0
|
||||
end
|
||||
|
||||
local Pos = self:LocalToWorld( data.pos )
|
||||
local Dir = self:LocalToWorldAngles( data.ang ):Up()
|
||||
|
||||
self.ExhaustPositions[ id ].PosOffset = EntTable.ExhaustPositions[ id ].PosOffset + FT * (8 + 4 * Throttle)
|
||||
|
||||
if ShouldDoEffect then
|
||||
if math.random(0,1) == 1 then
|
||||
EntTable.ExhaustPositions[ id ].PosOffset = 0
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos )
|
||||
effectdata:SetNormal( Dir )
|
||||
effectdata:SetMagnitude( Throttle )
|
||||
effectdata:SetEntity( self )
|
||||
if HP > MaxHP * 0.25 then
|
||||
util.Effect( "lvs_exhaust", effectdata )
|
||||
else
|
||||
util.Effect( "lvs_exhaust_fire", effectdata )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if EntTable.ExhaustPositions[ id ].PosOffset > 1 or Throttle < 0.5 then continue end
|
||||
|
||||
local Size = math.min( 10 * (1 - EntTable.ExhaustPositions[ id ].PosOffset ) ^ 2, 5 + 5 * Throttle )
|
||||
|
||||
render.SetMaterial( ExhaustSprite )
|
||||
render.DrawSprite( Pos + Dir * EntTable.ExhaustPositions[ id ].PosOffset * (5 + 5 * Throttle), Size, Size, color_white )
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,95 @@
|
||||
|
||||
ENT.ReflectorSight = false
|
||||
ENT.ReflectorSightPos = vector_origin
|
||||
ENT.ReflectorSightColor = color_white
|
||||
ENT.ReflectorSightColorBG = color_black
|
||||
ENT.ReflectorSightMaterial = Material("lvs/sights/german.png")
|
||||
ENT.ReflectorSightMaterialRes = 128
|
||||
ENT.ReflectorSightHeight = 3
|
||||
ENT.ReflectorSightWidth = 1.5
|
||||
ENT.ReflectorSightGlow = false
|
||||
ENT.ReflectorSightGlowMaterial = Material( "sprites/light_glow02_add" )
|
||||
ENT.ReflectorSightGlowMaterialRes = 600
|
||||
ENT.ReflectorSightGlowColor = color_white
|
||||
|
||||
function ENT:PaintReflectorSight( Pos2D, Ang, Origin2D )
|
||||
if self.ReflectorSightGlow then
|
||||
surface.SetDrawColor( self.ReflectorSightGlowColor )
|
||||
surface.SetMaterial( self.ReflectorSightGlowMaterial )
|
||||
surface.DrawTexturedRectRotated( Pos2D.x, Pos2D.y, self.ReflectorSightGlowMaterialRes, self.ReflectorSightGlowMaterialRes, -Ang )
|
||||
end
|
||||
|
||||
surface.SetDrawColor( self.ReflectorSightColor )
|
||||
surface.SetMaterial( self.ReflectorSightMaterial )
|
||||
surface.DrawTexturedRectRotated( Pos2D.x, Pos2D.y, self.ReflectorSightMaterialRes, self.ReflectorSightMaterialRes, -Ang )
|
||||
end
|
||||
|
||||
function ENT:IsDrawingReflectorSight()
|
||||
if not self.ReflectorSight then return false end
|
||||
|
||||
local Pod = self:GetDriverSeat()
|
||||
|
||||
if not IsValid( Pod ) then return false end
|
||||
|
||||
return not Pod:GetThirdPersonMode()
|
||||
end
|
||||
|
||||
function ENT:DrawReflectorSight( Pos2D )
|
||||
local Pos = self:LocalToWorld( self.ReflectorSightPos )
|
||||
local Up = self:GetUp()
|
||||
local Right = self:GetRight()
|
||||
|
||||
local Width = self.ReflectorSightWidth
|
||||
local Height = self.ReflectorSightHeight
|
||||
|
||||
local TopLeft = (Pos + Up * Height - Right * Width):ToScreen()
|
||||
local TopRight = (Pos + Up * Height + Right * Width):ToScreen()
|
||||
local BottomLeft = (Pos - Right * Width):ToScreen()
|
||||
local BottomRight = (Pos + Right * Width):ToScreen()
|
||||
|
||||
Pos = Pos:ToScreen()
|
||||
|
||||
if not Pos.visible then return end
|
||||
|
||||
local poly = {
|
||||
{ x = TopLeft.x, y = TopLeft.y },
|
||||
{ x = TopRight.x, y = TopRight.y },
|
||||
{ x = BottomRight.x, y = BottomRight.y },
|
||||
{ x = BottomLeft.x, y = BottomLeft.y },
|
||||
}
|
||||
|
||||
local Ang = 0
|
||||
|
||||
if TopLeft.x < TopRight.x then
|
||||
Ang = (Vector( TopLeft.x, 0, TopLeft.y ) - Vector( TopRight.x, 0, TopRight.y )):Angle().p
|
||||
else
|
||||
Ang = (Vector( TopRight.x, 0, TopRight.y ) - Vector( TopLeft.x, 0, TopLeft.y )):Angle().p - 180
|
||||
end
|
||||
|
||||
draw.NoTexture()
|
||||
surface.SetDrawColor( self.ReflectorSightColorBG )
|
||||
surface.DrawPoly( poly )
|
||||
|
||||
render.SetStencilWriteMask( 0xFF )
|
||||
render.SetStencilTestMask( 0xFF )
|
||||
render.SetStencilReferenceValue( 0 )
|
||||
render.SetStencilPassOperation( STENCIL_KEEP )
|
||||
render.SetStencilZFailOperation( STENCIL_KEEP )
|
||||
render.ClearStencil()
|
||||
|
||||
render.SetStencilEnable( true )
|
||||
render.SetStencilReferenceValue( 1 )
|
||||
render.SetStencilCompareFunction( STENCIL_NEVER )
|
||||
render.SetStencilFailOperation( STENCIL_REPLACE )
|
||||
|
||||
draw.NoTexture()
|
||||
surface.SetDrawColor( color_white )
|
||||
surface.DrawPoly( poly )
|
||||
|
||||
render.SetStencilCompareFunction( STENCIL_EQUAL )
|
||||
render.SetStencilFailOperation( STENCIL_KEEP )
|
||||
|
||||
self:PaintReflectorSight( Pos2D, Ang, Pos )
|
||||
|
||||
render.SetStencilEnable( false )
|
||||
end
|
||||
@@ -0,0 +1,189 @@
|
||||
AddCSLuaFile( "shared.lua" )
|
||||
AddCSLuaFile( "cl_init.lua" )
|
||||
AddCSLuaFile( "cl_camera.lua" )
|
||||
AddCSLuaFile( "sh_camera_eyetrace.lua" )
|
||||
AddCSLuaFile( "cl_hud.lua" )
|
||||
AddCSLuaFile( "cl_flyby.lua" )
|
||||
AddCSLuaFile( "cl_deathsound.lua" )
|
||||
AddCSLuaFile( "cl_reflectorsight.lua" )
|
||||
include("shared.lua")
|
||||
include("sv_wheels.lua")
|
||||
include("sv_landinggear.lua")
|
||||
include("sv_components.lua")
|
||||
include("sv_ai.lua")
|
||||
include("sv_mouseaim.lua")
|
||||
include("sh_camera_eyetrace.lua")
|
||||
|
||||
function ENT:OnCreateAI()
|
||||
self:StartEngine()
|
||||
self.COL_GROUP_OLD = self:GetCollisionGroup()
|
||||
self:SetCollisionGroup( COLLISION_GROUP_INTERACTIVE_DEBRIS )
|
||||
end
|
||||
|
||||
function ENT:OnRemoveAI()
|
||||
self:StopEngine()
|
||||
self:SetCollisionGroup( self.COL_GROUP_OLD or COLLISION_GROUP_NONE )
|
||||
end
|
||||
|
||||
function ENT:ApproachTargetAngle( TargetAngle, OverridePitch, OverrideYaw, OverrideRoll, FreeMovement )
|
||||
local LocalAngles = self:WorldToLocalAngles( TargetAngle )
|
||||
|
||||
if self:GetAI() then self:SetAIAimVector( LocalAngles:Forward() ) end
|
||||
|
||||
local LocalAngPitch = LocalAngles.p
|
||||
local LocalAngYaw = LocalAngles.y
|
||||
local LocalAngRoll = LocalAngles.r
|
||||
|
||||
local TargetForward = TargetAngle:Forward()
|
||||
local Forward = self:GetForward()
|
||||
|
||||
local AngDiff = math.deg( math.acos( math.Clamp( Forward:Dot( TargetForward ) ,-1,1) ) )
|
||||
|
||||
local WingFinFadeOut = math.max( (90 - AngDiff ) / 90, 0 )
|
||||
local RudderFadeOut = math.min( math.max( (120 - AngDiff ) / 120, 0 ) * 3, 1 )
|
||||
|
||||
local AngVel = self:GetPhysicsObject():GetAngleVelocity()
|
||||
|
||||
local SmoothPitch = math.Clamp( math.Clamp(AngVel.y / 100,-0.25,0.25) / math.abs( LocalAngPitch ), -1, 1 )
|
||||
local SmoothYaw = math.Clamp( math.Clamp(AngVel.z / 100,-0.25,0.25) / math.abs( LocalAngYaw ), -1, 1 )
|
||||
|
||||
local Pitch = math.Clamp( -LocalAngPitch / 10 + SmoothPitch, -1, 1 )
|
||||
local Yaw = math.Clamp( -LocalAngYaw / 2 + SmoothYaw,-1,1) * RudderFadeOut
|
||||
local Roll = math.Clamp( (-math.Clamp(LocalAngYaw * 16,-90,90) + LocalAngRoll * RudderFadeOut * 0.75) * WingFinFadeOut / 180 , -1 , 1 )
|
||||
|
||||
if FreeMovement then
|
||||
Roll = math.Clamp( -LocalAngYaw * WingFinFadeOut / 180 , -1 , 1 )
|
||||
end
|
||||
|
||||
if OverridePitch and OverridePitch ~= 0 then
|
||||
Pitch = OverridePitch
|
||||
end
|
||||
|
||||
if OverrideYaw and OverrideYaw ~= 0 then
|
||||
Yaw = OverrideYaw
|
||||
end
|
||||
|
||||
if OverrideRoll and OverrideRoll ~= 0 then
|
||||
Roll = OverrideRoll
|
||||
end
|
||||
|
||||
self:SetSteer( Vector( math.Clamp(Roll * 1.25,-1,1), math.Clamp(-Pitch * 1.25,-1,1), -Yaw) )
|
||||
end
|
||||
|
||||
function ENT:CalcAero( phys, deltatime, EntTable )
|
||||
if not EntTable then
|
||||
EntTable = self:GetTable()
|
||||
end
|
||||
|
||||
-- mouse aim needs to run at high speed.
|
||||
if self:GetAI() then
|
||||
if EntTable._lvsAITargetAng then
|
||||
self:ApproachTargetAngle( EntTable._lvsAITargetAng )
|
||||
end
|
||||
else
|
||||
local ply = self:GetDriver()
|
||||
if IsValid( ply ) and ply:lvsMouseAim() then
|
||||
self:PlayerMouseAim( ply )
|
||||
end
|
||||
end
|
||||
|
||||
local WorldGravity = self:GetWorldGravity()
|
||||
local WorldUp = self:GetWorldUp()
|
||||
local Steer = self:GetSteer()
|
||||
|
||||
local Stability, InvStability, ForwardVelocity = self:GetStability()
|
||||
|
||||
local Forward = self:GetForward()
|
||||
local Left = -self:GetRight()
|
||||
local Up = self:GetUp()
|
||||
|
||||
local Vel = self:GetVelocity()
|
||||
local VelForward = Vel:GetNormalized()
|
||||
|
||||
local PitchPull = math.max( (math.deg( math.acos( math.Clamp( WorldUp:Dot( Up ) ,-1,1) ) ) - 90) / 90, 0 )
|
||||
local YawPull = (math.deg( math.acos( math.Clamp( WorldUp:Dot( Left ) ,-1,1) ) ) - 90) / 90
|
||||
|
||||
local GravMul = (WorldGravity / 600) * 0.25
|
||||
|
||||
-- crash behavior
|
||||
if self:IsDestroyed() then
|
||||
Steer = phys:GetAngleVelocity() / 200
|
||||
|
||||
PitchPull = (math.deg( math.acos( math.Clamp( WorldUp:Dot( Up ) ,-1,1) ) ) - 90) / 90
|
||||
|
||||
GravMul = WorldGravity / 600
|
||||
end
|
||||
|
||||
local GravityPitch = math.abs( PitchPull ) ^ 1.25 * self:Sign( PitchPull ) * GravMul * EntTable.GravityTurnRatePitch
|
||||
local GravityYaw = math.abs( YawPull ) ^ 1.25 * self:Sign( YawPull ) * GravMul * EntTable.GravityTurnRateYaw
|
||||
|
||||
local StallMul = math.min( (-math.min(Vel.z + EntTable.StallVelocity,0) / 100) * EntTable.StallForceMultiplier, EntTable.StallForceMax )
|
||||
|
||||
local StallPitch = 0
|
||||
local StallYaw = 0
|
||||
|
||||
if StallMul > 0 then
|
||||
if InvStability < 1 then
|
||||
StallPitch = PitchPull* GravMul * StallMul
|
||||
StallYaw = YawPull * GravMul * StallMul
|
||||
else
|
||||
local StallPitchDir = self:Sign( math.deg( math.acos( math.Clamp( -VelForward:Dot( self:LocalToWorldAngles( Angle(-10,0,0) ):Up() ) ,-1,1) ) ) - 90 )
|
||||
local StallYawDir = self:Sign( math.deg( math.acos( math.Clamp( -VelForward:Dot( Left ) ,-1,1) ) ) - 90 )
|
||||
|
||||
local StallPitchPull = ((90 - math.abs( math.deg( math.acos( math.Clamp( -WorldUp:Dot( Up ) ,-1,1) ) ) - 90 )) / 90) * StallPitchDir
|
||||
local StallYawPull = ((90 - math.abs( math.deg( math.acos( math.Clamp( -WorldUp:Dot( Left ) ,-1,1) ) ) - 90 )) / 90) * StallYawDir * 0.5
|
||||
|
||||
StallPitch = StallPitchPull * GravMul * StallMul
|
||||
StallYaw = StallYawPull * GravMul * StallMul
|
||||
end
|
||||
end
|
||||
|
||||
local Pitch = math.Clamp(Steer.y - GravityPitch,-1,1) * EntTable.TurnRatePitch * 3 * Stability - StallPitch * InvStability
|
||||
local Yaw = math.Clamp(Steer.z * 4 + GravityYaw,-1,1) * EntTable.TurnRateYaw * Stability + StallYaw * InvStability
|
||||
local Roll = math.Clamp(Steer.x * 1.5,-1,1) * EntTable.TurnRateRoll * 12 * Stability
|
||||
|
||||
self:HandleLandingGear( deltatime )
|
||||
self:SetWheelSteer( Steer.z * EntTable.WheelSteerAngle )
|
||||
|
||||
local VelL = self:WorldToLocal( self:GetPos() + Vel )
|
||||
|
||||
local SlipMul = 1 - math.Clamp( math.max( math.abs( VelL.x ) - EntTable.MaxPerfVelocity, 0 ) / math.max(EntTable.MaxVelocity - EntTable.MaxPerfVelocity, 0 ),0,1)
|
||||
|
||||
local MulZ = (math.max( math.deg( math.acos( math.Clamp( VelForward:Dot( Forward ) ,-1,1) ) ) - EntTable.MaxSlipAnglePitch * SlipMul * math.abs( Steer.y ), 0 ) / 90) * 0.3
|
||||
local MulY = (math.max( math.abs( math.deg( math.acos( math.Clamp( VelForward:Dot( Left ) ,-1,1) ) ) - 90 ) - EntTable.MaxSlipAngleYaw * SlipMul * math.abs( Steer.z ), 0 ) / 90) * 0.15
|
||||
|
||||
local Lift = -math.min( (math.deg( math.acos( math.Clamp( WorldUp:Dot( Up ) ,-1,1) ) ) - 90) / 180,0) * (WorldGravity / (1 / deltatime))
|
||||
|
||||
return Vector(0, -VelL.y * MulY, Lift - VelL.z * MulZ ) * Stability, Vector( Roll, Pitch, Yaw )
|
||||
end
|
||||
|
||||
function ENT:OnSkyCollide( data, PhysObj )
|
||||
|
||||
local NewVelocity = self:VectorSubtractNormal( data.HitNormal, data.OurOldVelocity ) - data.HitNormal * math.Clamp(self:GetThrustStrenght() * self.MaxThrust,250,800)
|
||||
|
||||
PhysObj:SetVelocityInstantaneous( NewVelocity )
|
||||
PhysObj:SetAngleVelocityInstantaneous( data.OurOldAngularVelocity )
|
||||
|
||||
self:FreezeStability()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate( phys, deltatime )
|
||||
local EntTable = self:GetTable()
|
||||
|
||||
local Aero, Torque = self:CalcAero( phys, deltatime, EntTable )
|
||||
|
||||
if self:GetEngineActive() then phys:Wake() end
|
||||
|
||||
local Thrust = math.max( self:GetThrustStrenght(), 0 ) * EntTable.MaxThrust * 100
|
||||
|
||||
local ForceLinear = (Aero * 10000 * EntTable.ForceLinearMultiplier + Vector(Thrust,0,0)) * deltatime
|
||||
local ForceAngle = (Torque * 25 * EntTable.ForceAngleMultiplier - phys:GetAngleVelocity() * 1.5 * EntTable.ForceAngleDampingMultiplier) * deltatime * 250
|
||||
|
||||
return self:PhysicsSimulateOverride( ForceAngle, ForceLinear, phys, deltatime, SIM_LOCAL_ACCELERATION )
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulateOverride( ForceAngle, ForceLinear, phys, deltatime, simulate )
|
||||
return ForceAngle, ForceLinear, simulate
|
||||
end
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
function ENT:GetEyeTrace( trace_forward )
|
||||
local startpos = self:LocalToWorld( self:OBBCenter() )
|
||||
|
||||
local pod = self:GetDriverSeat()
|
||||
|
||||
if IsValid( pod ) then
|
||||
startpos = pod:LocalToWorld( pod:OBBCenter() )
|
||||
end
|
||||
|
||||
local AimVector = trace_forward and self:GetForward() or self:GetAimVector()
|
||||
|
||||
local data = {
|
||||
start = startpos,
|
||||
endpos = (startpos + AimVector * 50000),
|
||||
filter = self:GetCrosshairFilterEnts(),
|
||||
}
|
||||
|
||||
local trace = util.TraceLine( data )
|
||||
|
||||
return trace
|
||||
end
|
||||
|
||||
function ENT:GetAimVector()
|
||||
if self:GetAI() then
|
||||
return self:GetAIAimVector()
|
||||
end
|
||||
|
||||
local Driver = self:GetDriver()
|
||||
|
||||
if not IsValid( Driver ) then return self:GetForward() end
|
||||
|
||||
if not Driver:lvsMouseAim() then
|
||||
if Driver:lvsKeyDown( "FREELOOK" ) then
|
||||
local pod = self:GetDriverSeat()
|
||||
|
||||
if not IsValid( pod ) then return Driver:EyeAngles():Forward() end
|
||||
|
||||
if pod:GetThirdPersonMode() then
|
||||
return -self:GetForward()
|
||||
else
|
||||
return Driver:GetAimVector()
|
||||
end
|
||||
else
|
||||
return self:GetForward()
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
local pod = self:GetDriverSeat()
|
||||
|
||||
if not IsValid( pod ) then return Driver:EyeAngles():Forward() end
|
||||
|
||||
return pod:WorldToLocalAngles( Driver:EyeAngles() ):Forward()
|
||||
else
|
||||
return Driver:EyeAngles():Forward()
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,182 @@
|
||||
|
||||
ENT.Base = "lvs_base"
|
||||
|
||||
ENT.PrintName = "[LVS] Base Fighter Plane"
|
||||
ENT.Author = "Luna"
|
||||
ENT.Information = "Luna's Vehicle Script"
|
||||
ENT.Category = "[LVS]"
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
|
||||
ENT.MaxVelocity = 2500
|
||||
ENT.MaxPerfVelocity = 1500
|
||||
ENT.MaxThrust = 250
|
||||
|
||||
ENT.ThrottleRateUp = 0.6
|
||||
ENT.ThrottleRateDown = 0.3
|
||||
|
||||
ENT.TurnRatePitch = 1
|
||||
ENT.TurnRateYaw = 1
|
||||
ENT.TurnRateRoll = 1
|
||||
|
||||
ENT.GravityTurnRatePitch = 1
|
||||
ENT.GravityTurnRateYaw = 1
|
||||
|
||||
ENT.ForceLinearMultiplier = 1
|
||||
|
||||
ENT.ForceAngleMultiplier = 1
|
||||
ENT.ForceAngleDampingMultiplier = 1
|
||||
|
||||
ENT.MaxSlipAnglePitch = 20
|
||||
ENT.MaxSlipAngleYaw = 10
|
||||
|
||||
ENT.StallVelocity = 150
|
||||
ENT.StallForceMultiplier = 4
|
||||
ENT.StallForceMax = 40
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:CreateBaseDT()
|
||||
|
||||
self:AddDT( "Vector", "Steer" )
|
||||
self:AddDT( "Vector", "AIAimVector" )
|
||||
self:AddDT( "Float", "NWThrottle" )
|
||||
self:AddDT( "Float", "MaxThrottle" )
|
||||
self:AddDT( "Float", "LandingGear" )
|
||||
|
||||
if SERVER then
|
||||
self:SetLandingGear( 1 )
|
||||
self:SetMaxThrottle( 1 )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PlayerDirectInput( ply, cmd )
|
||||
local Pod = self:GetDriverSeat()
|
||||
|
||||
local Delta = FrameTime()
|
||||
|
||||
local KeyLeft = ply:lvsKeyDown( "-ROLL" )
|
||||
local KeyRight = ply:lvsKeyDown( "+ROLL" )
|
||||
local KeyPitchUp = ply:lvsKeyDown( "+PITCH" )
|
||||
local KeyPitchDown = ply:lvsKeyDown( "-PITCH" )
|
||||
local KeyRollRight = ply:lvsKeyDown( "+YAW" )
|
||||
local KeyRollLeft = ply:lvsKeyDown( "-YAW" )
|
||||
|
||||
local MouseX = cmd:GetMouseX()
|
||||
local MouseY = cmd:GetMouseY()
|
||||
|
||||
if ply:lvsKeyDown( "FREELOOK" ) and not Pod:GetThirdPersonMode() then
|
||||
MouseX = 0
|
||||
MouseY = 0
|
||||
else
|
||||
ply:SetEyeAngles( Angle(0,90,0) )
|
||||
end
|
||||
|
||||
local SensX, SensY, ReturnDelta = ply:lvsMouseSensitivity()
|
||||
|
||||
if KeyPitchDown then MouseY = (10 / SensY) * ReturnDelta end
|
||||
if KeyPitchUp then MouseY = -(10 / SensY) * ReturnDelta end
|
||||
if KeyRollRight or KeyRollLeft then
|
||||
local NewX = (KeyRollRight and 10 or 0) - (KeyRollLeft and 10 or 0)
|
||||
|
||||
MouseX = (NewX / SensX) * ReturnDelta
|
||||
end
|
||||
|
||||
local Input = Vector( MouseX * 0.4 * SensX, MouseY * SensY, 0 )
|
||||
|
||||
local Cur = self:GetSteer()
|
||||
|
||||
local Rate = Delta * 3 * ReturnDelta
|
||||
|
||||
local New = Vector(Cur.x, Cur.y, 0) - Vector( math.Clamp(Cur.x * Delta * 5 * ReturnDelta,-Rate,Rate), math.Clamp(Cur.y * Delta * 5 * ReturnDelta,-Rate,Rate), 0)
|
||||
|
||||
local Target = New + Input * Delta * 0.8
|
||||
|
||||
local Fx = math.Clamp( Target.x, -1, 1 )
|
||||
local Fy = math.Clamp( Target.y, -1, 1 )
|
||||
|
||||
local TargetFz = (KeyLeft and 1 or 0) - (KeyRight and 1 or 0)
|
||||
local Fz = Cur.z + math.Clamp(TargetFz - Cur.z,-Rate * 3,Rate * 3)
|
||||
|
||||
local F = Cur + (Vector( Fx, Fy, Fz ) - Cur) * math.min(Delta * 100,1)
|
||||
|
||||
self:SetSteer( F )
|
||||
end
|
||||
|
||||
function ENT:CalcThrottle( ply, cmd )
|
||||
if CLIENT then return end
|
||||
|
||||
local Delta = FrameTime()
|
||||
|
||||
local ThrottleUp = ply:lvsKeyDown( "+THROTTLE" ) and self.ThrottleRateUp or 0
|
||||
local ThrottleDown = ply:lvsKeyDown( "-THROTTLE" ) and -self.ThrottleRateDown or 0
|
||||
|
||||
local Throttle = (ThrottleUp + ThrottleDown) * Delta
|
||||
|
||||
self:SetThrottle( self:GetThrottle() + Throttle )
|
||||
end
|
||||
|
||||
function ENT:SetThrottle( NewThrottle )
|
||||
if self:GetEngineActive() then
|
||||
self:SetNWThrottle( math.Clamp(NewThrottle,0,self:GetMaxThrottle()) )
|
||||
else
|
||||
self:SetNWThrottle( 0 )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetThrottle()
|
||||
if self:GetEngineActive() then
|
||||
return self:GetNWThrottle()
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:StartCommand( ply, cmd )
|
||||
if self:GetDriver() ~= ply then return end
|
||||
|
||||
if SERVER and not self.WheelAutoRetract then
|
||||
local KeyJump = ply:lvsKeyDown( "VSPEC" )
|
||||
|
||||
if self._lvsOldKeyJump ~= KeyJump then
|
||||
self._lvsOldKeyJump = KeyJump
|
||||
if KeyJump then
|
||||
self:ToggleLandingGear()
|
||||
self:PhysWake()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not ply:lvsMouseAim() then
|
||||
self:PlayerDirectInput( ply, cmd )
|
||||
end
|
||||
|
||||
self:CalcThrottle( ply, cmd )
|
||||
end
|
||||
|
||||
function ENT:FreezeStability()
|
||||
self._StabilityFrozen = CurTime() + 2
|
||||
end
|
||||
|
||||
function ENT:GetStability()
|
||||
if (self._StabilityFrozen or 0) > CurTime() then
|
||||
return 1, 0, self.MaxPerfVelocity
|
||||
end
|
||||
|
||||
local ForwardVelocity = self:WorldToLocal( self:GetPos() + self:GetVelocity() ).x
|
||||
|
||||
local Stability = math.Clamp(ForwardVelocity / self.MaxPerfVelocity,0,1) ^ 2
|
||||
local InvStability = 1 - Stability
|
||||
|
||||
return Stability, InvStability, ForwardVelocity
|
||||
end
|
||||
|
||||
function ENT:GetThrustStrenght()
|
||||
local ForwardVelocity = self:WorldToLocal( self:GetPos() + self:GetVelocity() ).x
|
||||
|
||||
return (self.MaxVelocity - ForwardVelocity) * self:GetThrottle() / self.MaxVelocity
|
||||
end
|
||||
|
||||
function ENT:GetVehicleType()
|
||||
return "plane"
|
||||
end
|
||||
@@ -0,0 +1,203 @@
|
||||
|
||||
function ENT:OnCreateAI()
|
||||
self:StartEngine()
|
||||
end
|
||||
|
||||
function ENT:OnRemoveAI()
|
||||
self:StopEngine()
|
||||
end
|
||||
|
||||
function ENT:RunAI()
|
||||
local RangerLength = 15000
|
||||
local mySpeed = self:GetVelocity():Length()
|
||||
local MinDist = 600 + mySpeed
|
||||
|
||||
local StartPos = self:LocalToWorld( self:OBBCenter() )
|
||||
|
||||
local TraceFilter = self:GetCrosshairFilterEnts()
|
||||
|
||||
local FrontLeft = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + self:LocalToWorldAngles( Angle(0,20,0) ):Forward() * RangerLength } )
|
||||
local FrontRight = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + self:LocalToWorldAngles( Angle(0,-20,0) ):Forward() * RangerLength } )
|
||||
|
||||
local FrontLeft2 = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + self:LocalToWorldAngles( Angle(25,65,0) ):Forward() * RangerLength } )
|
||||
local FrontRight2 = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + self:LocalToWorldAngles( Angle(25,-65,0) ):Forward() * RangerLength } )
|
||||
|
||||
local FrontLeft3 = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + self:LocalToWorldAngles( Angle(-25,65,0) ):Forward() * RangerLength } )
|
||||
local FrontRight3 = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + self:LocalToWorldAngles( Angle(-25,-65,0) ):Forward() * RangerLength } )
|
||||
|
||||
local FrontUp = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + self:LocalToWorldAngles( Angle(-20,0,0) ):Forward() * RangerLength } )
|
||||
local FrontDown = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + self:LocalToWorldAngles( Angle(20,0,0) ):Forward() * RangerLength } )
|
||||
|
||||
local TraceForward = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + self:GetForward() * RangerLength } )
|
||||
local TraceDown = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + Vector(0,0,-RangerLength) } )
|
||||
local TraceUp = util.TraceLine( { start = StartPos, filter = TraceFilter, endpos = StartPos + Vector(0,0,RangerLength) } )
|
||||
|
||||
local cAvoid = Vector(0,0,0)
|
||||
|
||||
local myRadius = self:BoundingRadius()
|
||||
local myPos = self:GetPos()
|
||||
local myDir = self:GetForward()
|
||||
for _, v in pairs( LVS:GetVehicles() ) do
|
||||
if v == self then continue end
|
||||
|
||||
local theirRadius = v:BoundingRadius()
|
||||
local Sub = (myPos - v:GetPos())
|
||||
local Dir = Sub:GetNormalized()
|
||||
local Dist = Sub:Length()
|
||||
|
||||
if Dist < (theirRadius + myRadius + 200) then
|
||||
if math.deg( math.acos( math.Clamp( myDir:Dot( -Dir ) ,-1,1) ) ) < 90 then
|
||||
cAvoid = cAvoid + Dir * (theirRadius + myRadius + 500)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local FLp = FrontLeft.HitPos + FrontLeft.HitNormal * MinDist + cAvoid * 8
|
||||
local FRp = FrontRight.HitPos + FrontRight.HitNormal * MinDist + cAvoid * 8
|
||||
|
||||
local FL2p = FrontLeft2.HitPos + FrontLeft2.HitNormal * MinDist
|
||||
local FR2p = FrontRight2.HitPos + FrontRight2.HitNormal * MinDist
|
||||
|
||||
local FL3p = FrontLeft3.HitPos + FrontLeft3.HitNormal * MinDist
|
||||
local FR3p = FrontRight3.HitPos + FrontRight3.HitNormal * MinDist
|
||||
|
||||
local FUp = FrontUp.HitPos + FrontUp.HitNormal * MinDist
|
||||
local FDp = FrontDown.HitPos + FrontDown.HitNormal * MinDist
|
||||
|
||||
local Up = TraceUp.HitPos + TraceUp.HitNormal * MinDist
|
||||
local Dp = TraceDown.HitPos + TraceDown.HitNormal * MinDist
|
||||
|
||||
local TargetPos = (FLp+FRp+FL2p+FR2p+FL3p+FR3p+FUp+FDp+Up+Dp) / 10
|
||||
|
||||
local alt = (StartPos - TraceDown.HitPos):Length()
|
||||
local ceiling = (StartPos - TraceUp.HitPos):Length()
|
||||
|
||||
local WallDist = (StartPos - TraceForward.HitPos):Length()
|
||||
|
||||
local Throttle = math.min( WallDist / mySpeed, 1 )
|
||||
|
||||
self._AIFireInput = false
|
||||
|
||||
if alt < 600 or ceiling < 600 or WallDist < (MinDist * 3 * (math.deg( math.acos( math.Clamp( Vector(0,0,1):Dot( myDir ) ,-1,1) ) ) / 180) ^ 2) then
|
||||
if ceiling < 600 then
|
||||
Throttle = 0
|
||||
else
|
||||
Throttle = 1
|
||||
|
||||
if self:HitGround() then
|
||||
TargetPos.z = StartPos.z + 750
|
||||
else
|
||||
if self:GetStability() < 0.5 then
|
||||
TargetPos.z = StartPos.z + 1500
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if self:GetStability() < 0.5 then
|
||||
TargetPos.z = StartPos.z + 600
|
||||
else
|
||||
if IsValid( self:GetHardLockTarget() ) then
|
||||
TargetPos = self:GetHardLockTarget():GetPos() + cAvoid * 8
|
||||
else
|
||||
if alt > mySpeed then
|
||||
local Target = self._LastAITarget
|
||||
|
||||
if not IsValid( self._LastAITarget ) or not self:AITargetInFront( self._LastAITarget, 135 ) or not self:AICanSee( self._LastAITarget ) then
|
||||
Target = self:AIGetTarget()
|
||||
end
|
||||
|
||||
if IsValid( Target ) then
|
||||
if self:AITargetInFront( Target, 65 ) then
|
||||
local T = CurTime() + self:EntIndex() * 1337
|
||||
TargetPos = Target:GetPos() + cAvoid * 8 + Vector(0,0, math.sin( T * 5 ) * 500 ) + Target:GetVelocity() * math.abs( math.cos( T * 13.37 ) ) * 5
|
||||
|
||||
Throttle = math.min( (StartPos - TargetPos):Length() / mySpeed, 1 )
|
||||
|
||||
local tr = util.TraceHull( {
|
||||
start = StartPos,
|
||||
endpos = (StartPos + self:GetForward() * 50000),
|
||||
mins = Vector( -50, -50, -50 ),
|
||||
maxs = Vector( 50, 50, 50 ),
|
||||
filter = TraceFilter
|
||||
} )
|
||||
|
||||
local CanShoot = (IsValid( tr.Entity ) and tr.Entity.LVS and tr.Entity.GetAITEAM) and (tr.Entity:GetAITEAM() ~= self:GetAITEAM() or tr.Entity:GetAITEAM() == 0) or true
|
||||
|
||||
if CanShoot and self:AITargetInFront( Target, 22 ) then
|
||||
local CurHeat = self:GetNWHeat()
|
||||
local CurWeapon = self:GetSelectedWeapon()
|
||||
|
||||
if CurWeapon > 2 then
|
||||
self:AISelectWeapon( 1 )
|
||||
else
|
||||
if CurHeat > 0.9 then
|
||||
if CurWeapon == 1 and self:AIHasWeapon( 2 ) then
|
||||
self:AISelectWeapon( 2 )
|
||||
|
||||
elseif CurWeapon == 2 then
|
||||
self:AISelectWeapon( 1 )
|
||||
end
|
||||
else
|
||||
if CurHeat == 0 and math.cos( T ) > 0 then
|
||||
self:AISelectWeapon( 1 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self._AIFireInput = true
|
||||
end
|
||||
else
|
||||
self:AISelectWeapon( 1 )
|
||||
|
||||
if alt > 6000 and self:AITargetInFront( Target, 90 ) then
|
||||
TargetPos = Target:GetPos()
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
TargetPos.z = StartPos.z + 2000
|
||||
end
|
||||
end
|
||||
end
|
||||
self:RaiseLandingGear()
|
||||
end
|
||||
|
||||
self:SetThrottle( Throttle )
|
||||
|
||||
self.smTargetPos = self.smTargetPos and self.smTargetPos + (TargetPos - self.smTargetPos) * FrameTime() or self:GetPos()
|
||||
|
||||
self._lvsAITargetAng = (self.smTargetPos - self:GetPos()):GetNormalized():Angle()
|
||||
end
|
||||
|
||||
function ENT:AISelectWeapon( ID )
|
||||
if ID == self:GetSelectedWeapon() then return end
|
||||
|
||||
local T = CurTime()
|
||||
|
||||
if (self._nextAISwitchWeapon or 0) > T then return end
|
||||
|
||||
self._nextAISwitchWeapon = T + math.random(3,6)
|
||||
|
||||
self:SelectWeapon( ID )
|
||||
end
|
||||
|
||||
function ENT:OnAITakeDamage( dmginfo )
|
||||
local attacker = dmginfo:GetAttacker()
|
||||
|
||||
if not IsValid( attacker ) then return end
|
||||
|
||||
if not self:AITargetInFront( attacker, IsValid( self:AIGetTarget() ) and 120 or 45 ) then
|
||||
self:SetHardLockTarget( attacker )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:SetHardLockTarget( target )
|
||||
self._HardLockTarget = target
|
||||
self._HardLockTime = CurTime() + 4
|
||||
end
|
||||
|
||||
function ENT:GetHardLockTarget()
|
||||
if (self._HardLockTime or 0) < CurTime() then return NULL end
|
||||
|
||||
return self._HardLockTarget
|
||||
end
|
||||
@@ -0,0 +1,100 @@
|
||||
function ENT:AddThruster( pos )
|
||||
local Thruster = ents.Create( "lvs_fighterplane_thruster" )
|
||||
|
||||
if not IsValid( Thruster ) then
|
||||
self:Remove()
|
||||
|
||||
print("LVS: Failed to create thruster entity. Vehicle terminated.")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
Thruster:SetPos( self:LocalToWorld( pos ) )
|
||||
Thruster:SetAngles( self:GetAngles() )
|
||||
Thruster:Spawn()
|
||||
Thruster:Activate()
|
||||
Thruster:SetParent( self )
|
||||
Thruster:SetBase( self )
|
||||
|
||||
self:DeleteOnRemove( Thruster )
|
||||
|
||||
self:TransferCPPI( Thruster )
|
||||
|
||||
return Thruster
|
||||
end
|
||||
|
||||
function ENT:AddEngine( pos )
|
||||
local Engine = ents.Create( "lvs_fighterplane_engine" )
|
||||
|
||||
if not IsValid( Engine ) then
|
||||
self:Remove()
|
||||
|
||||
print("LVS: Failed to create engine entity. Vehicle terminated.")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
Engine:SetPos( self:LocalToWorld( pos ) )
|
||||
Engine:SetAngles( self:GetAngles() )
|
||||
Engine:Spawn()
|
||||
Engine:Activate()
|
||||
Engine:SetParent( self )
|
||||
Engine:SetBase( self )
|
||||
|
||||
self:DeleteOnRemove( Engine )
|
||||
|
||||
self:TransferCPPI( Engine )
|
||||
|
||||
self:AddDS( {
|
||||
pos = pos,
|
||||
ang = Angle(0,0,0),
|
||||
mins = Vector(-40,-20,-30),
|
||||
maxs = Vector(40,20,30),
|
||||
Callback = function( tbl, ent, dmginfo )
|
||||
dmginfo:ScaleDamage( 2.5 )
|
||||
end
|
||||
} )
|
||||
|
||||
return Engine
|
||||
end
|
||||
|
||||
function ENT:AddRotor( pos )
|
||||
local Rotor = ents.Create( "lvs_fighterplane_rotor" )
|
||||
|
||||
if not IsValid( Rotor ) then
|
||||
self:Remove()
|
||||
|
||||
print("LVS: Failed to create rotor entity. Vehicle terminated.")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
Rotor:SetPos( self:LocalToWorld( pos ) )
|
||||
Rotor:SetAngles( self:GetAngles() )
|
||||
Rotor:Spawn()
|
||||
Rotor:Activate()
|
||||
Rotor:SetParent( self )
|
||||
Rotor:SetBase( self )
|
||||
|
||||
if self:BoundingRadius() >= 600 then
|
||||
Rotor:SetSound("lvs/vehicles/generic/bomber_propeller.wav")
|
||||
Rotor:SetSoundStrain("lvs/vehicles/generic/bomber_propeller_strain.wav")
|
||||
end
|
||||
|
||||
self:DeleteOnRemove( Rotor )
|
||||
|
||||
self:TransferCPPI( Rotor )
|
||||
|
||||
return Rotor
|
||||
end
|
||||
|
||||
function ENT:AddExhaust( pos, ang )
|
||||
if not istable( self.ExhaustPositions ) then self.ExhaustPositions = {} end
|
||||
|
||||
local Exhaust = {
|
||||
pos = pos,
|
||||
ang = ang,
|
||||
}
|
||||
|
||||
table.insert( self.ExhaustPositions, Exhaust )
|
||||
end
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
function ENT:HandleLandingGear( Rate )
|
||||
local EnableBrakes = self:GetThrottle() <= 0
|
||||
|
||||
local Cur = self:GetLandingGear()
|
||||
|
||||
if self.WheelAutoRetract then
|
||||
if self:HitGround() then
|
||||
self.LandingGearUp = false
|
||||
else
|
||||
self.LandingGearUp = self:GetStability() > 0.4
|
||||
end
|
||||
end
|
||||
|
||||
local New = Cur + math.Clamp((self.LandingGearUp and 0 or 1) - Cur,-Rate,Rate)
|
||||
|
||||
local SetValue = Cur ~= New
|
||||
|
||||
if SetValue then
|
||||
self:SetLandingGear( New )
|
||||
end
|
||||
|
||||
for _, data in pairs( self:GetWheels() ) do
|
||||
local wheel = data.entity
|
||||
local mass = data.mass
|
||||
local physobj = data.physobj
|
||||
|
||||
if not IsValid( wheel ) or not IsValid( physobj ) then continue end
|
||||
|
||||
wheel:SetBrakes( EnableBrakes )
|
||||
|
||||
if not SetValue then continue end
|
||||
|
||||
physobj:SetMass( 1 + (mass - 1) * New ^ 4 )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ToggleLandingGear()
|
||||
if self.WheelAutoRetract then return end
|
||||
|
||||
self.LandingGearUp = not self.LandingGearUp
|
||||
|
||||
self:OnLandingGearToggled( self.LandingGearUp )
|
||||
end
|
||||
|
||||
function ENT:RaiseLandingGear()
|
||||
if self.WheelAutoRetract then return end
|
||||
|
||||
if not self.LandingGearUp then
|
||||
self.LandingGearUp = true
|
||||
|
||||
self:OnLandingGearToggled( self.LandingGearUp )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DeployLandingGear()
|
||||
if self.WheelAutoRetract then return end
|
||||
|
||||
if self.LandingGearUp then
|
||||
self.LandingGearUp = false
|
||||
|
||||
self:OnLandingGearToggled( self.LandingGearUp )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnLandingGearToggled( IsDeployed )
|
||||
end
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
function ENT:PlayerMouseAim( ply )
|
||||
local Pod = self:GetDriverSeat()
|
||||
|
||||
local PitchUp = ply:lvsKeyDown( "+PITCH" )
|
||||
local PitchDown = ply:lvsKeyDown( "-PITCH" )
|
||||
local YawRight = ply:lvsKeyDown( "+YAW" )
|
||||
local YawLeft = ply:lvsKeyDown( "-YAW" )
|
||||
local RollRight = ply:lvsKeyDown( "+ROLL" )
|
||||
local RollLeft = ply:lvsKeyDown( "-ROLL" )
|
||||
|
||||
local FreeLook = ply:lvsKeyDown( "FREELOOK" )
|
||||
|
||||
local EyeAngles = Pod:WorldToLocalAngles( ply:EyeAngles() )
|
||||
|
||||
if FreeLook then
|
||||
if isangle( self.StoredEyeAngles ) then
|
||||
EyeAngles = self.StoredEyeAngles
|
||||
end
|
||||
else
|
||||
self.StoredEyeAngles = EyeAngles
|
||||
end
|
||||
|
||||
local OverridePitch = 0
|
||||
local OverrideYaw = 0
|
||||
local OverrideRoll = (RollRight and 1 or 0) - (RollLeft and 1 or 0)
|
||||
|
||||
if PitchUp or PitchDown then
|
||||
EyeAngles = self:GetAngles()
|
||||
|
||||
self.StoredEyeAngles = Angle(EyeAngles.p,EyeAngles.y,0)
|
||||
|
||||
OverridePitch = (PitchUp and 1 or 0) - (PitchDown and 1 or 0)
|
||||
end
|
||||
|
||||
if YawRight or YawLeft then
|
||||
EyeAngles = self:GetAngles()
|
||||
|
||||
self.StoredEyeAngles = Angle(EyeAngles.p,EyeAngles.y,0)
|
||||
|
||||
OverrideYaw = (YawRight and 1 or 0) - (YawLeft and 1 or 0)
|
||||
end
|
||||
|
||||
self:ApproachTargetAngle( EyeAngles, OverridePitch, OverrideYaw, OverrideRoll, FreeLook )
|
||||
end
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
ENT.WheelSteerAngle = 45
|
||||
|
||||
function ENT:AddWheelSteeringPlate( rear )
|
||||
if rear then
|
||||
if IsValid( self._lvsSteerPlateRear ) then
|
||||
return self._lvsSteerPlateRear
|
||||
end
|
||||
else
|
||||
if IsValid( self._lvsSteerPlate ) then
|
||||
return self._lvsSteerPlate
|
||||
end
|
||||
end
|
||||
|
||||
local SteerMaster = ents.Create( "prop_physics" )
|
||||
|
||||
if not IsValid( SteerMaster ) then
|
||||
self:Remove()
|
||||
|
||||
print("LVS: Failed to initialize steering plate. Vehicle terminated.")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
SteerMaster:SetModel( "models/hunter/plates/plate025x025.mdl" )
|
||||
SteerMaster:SetPos( self:GetPos() )
|
||||
SteerMaster:SetAngles( Angle(0,90,0) )
|
||||
SteerMaster:Spawn()
|
||||
SteerMaster:Activate()
|
||||
|
||||
local PhysObj = SteerMaster:GetPhysicsObject()
|
||||
if IsValid( PhysObj ) then
|
||||
PhysObj:EnableMotion( false )
|
||||
else
|
||||
self:Remove()
|
||||
|
||||
print("LVS: Failed to initialize steering plate. Vehicle terminated.")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
SteerMaster:SetOwner( self )
|
||||
SteerMaster:DrawShadow( false )
|
||||
SteerMaster:SetNotSolid( true )
|
||||
SteerMaster:SetNoDraw( true )
|
||||
SteerMaster.DoNotDuplicate = true
|
||||
self:DeleteOnRemove( SteerMaster )
|
||||
self:TransferCPPI( SteerMaster )
|
||||
|
||||
if rear then
|
||||
self._lvsSteerPlateRear = SteerMaster
|
||||
else
|
||||
self._lvsSteerPlate = SteerMaster
|
||||
end
|
||||
|
||||
return SteerMaster
|
||||
end
|
||||
|
||||
function ENT:SetWheelSteer( SteerAngle )
|
||||
if IsValid( self._lvsSteerPlate ) then
|
||||
local PhysObj = self._lvsSteerPlate:GetPhysicsObject()
|
||||
|
||||
if IsValid( PhysObj ) then
|
||||
if PhysObj:IsMotionEnabled() then
|
||||
PhysObj:EnableMotion( false )
|
||||
end
|
||||
end
|
||||
|
||||
self._lvsSteerPlate:SetAngles( self:LocalToWorldAngles( Angle(0,math.Clamp(SteerAngle,-self.WheelSteerAngle,self.WheelSteerAngle),0) ) )
|
||||
end
|
||||
|
||||
if not IsValid( self._lvsSteerPlateRear ) then return end
|
||||
|
||||
local PhysObj = self._lvsSteerPlateRear:GetPhysicsObject()
|
||||
|
||||
if not IsValid( PhysObj ) then return end
|
||||
|
||||
if PhysObj:IsMotionEnabled() then
|
||||
PhysObj:EnableMotion( false )
|
||||
end
|
||||
|
||||
self._lvsSteerPlateRear:SetAngles( self:LocalToWorldAngles( Angle(0,math.Clamp(-SteerAngle,-self.WheelSteerAngle,self.WheelSteerAngle),0) ) )
|
||||
end
|
||||
|
||||
function ENT:GetWheels()
|
||||
if not istable( self._lvsWheels ) then self._lvsWheels = {} end
|
||||
|
||||
return self._lvsWheels
|
||||
end
|
||||
|
||||
function ENT:AddWheel( pos, radius, mass, type )
|
||||
if not isvector( pos ) or not isnumber( radius ) or not isnumber( mass ) then return end
|
||||
|
||||
if not type then
|
||||
type = LVS.WHEEL_BRAKE
|
||||
end
|
||||
|
||||
local wheel = ents.Create( "lvs_fighterplane_wheel" )
|
||||
|
||||
if not IsValid( wheel ) then
|
||||
self:Remove()
|
||||
|
||||
print("LVS: Failed to initialize wheel. Vehicle terminated.")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local WheelPos = self:LocalToWorld( pos )
|
||||
local CenterPos = self:LocalToWorld( self:OBBCenter() )
|
||||
|
||||
debugoverlay.Sphere( WheelPos, radius, 5, Color(150,150,150), true )
|
||||
debugoverlay.Line( CenterPos, WheelPos, 5, Color(150,150,150), true )
|
||||
|
||||
wheel:SetPos( WheelPos )
|
||||
wheel:SetAngles( self:LocalToWorldAngles( Angle(0,90,0) ) )
|
||||
wheel:Spawn()
|
||||
wheel:Activate()
|
||||
wheel:SetBase( self )
|
||||
wheel:Define(
|
||||
{
|
||||
physmat = "jeeptire",
|
||||
radius = radius,
|
||||
mass = mass,
|
||||
brake = type == LVS.WHEEL_BRAKE,
|
||||
}
|
||||
)
|
||||
|
||||
local PhysObj = wheel:GetPhysicsObject()
|
||||
if not IsValid( PhysObj ) then
|
||||
self:Remove()
|
||||
|
||||
print("LVS: Failed to initialize wheel phys model. Vehicle terminated.")
|
||||
return
|
||||
end
|
||||
|
||||
PhysObj:EnableMotion( false )
|
||||
|
||||
self:DeleteOnRemove( wheel )
|
||||
self:TransferCPPI( wheel )
|
||||
|
||||
if type == LVS.WHEEL_STEER_NONE then
|
||||
local ballsocket = constraint.AdvBallsocket(wheel, self,0,0,Vector(0,0,0),Vector(0,0,0),0,0, -180, -180, -180, 180, 180, 180, 0, 0, 0, 0, 1)
|
||||
ballsocket.DoNotDuplicate = true
|
||||
self:TransferCPPI( ballsocket )
|
||||
end
|
||||
|
||||
if type == LVS.WHEEL_BRAKE then
|
||||
local axis = constraint.Axis( wheel, self, 0, 0, PhysObj:GetMassCenter(), wheel:GetPos(), 0, 0, 0, 0, Vector(1,0,0) , false )
|
||||
axis.DoNotDuplicate = true
|
||||
self:TransferCPPI( axis )
|
||||
|
||||
wheel:SetBrakes( true )
|
||||
end
|
||||
|
||||
if type == LVS.WHEEL_STEER_FRONT then
|
||||
wheel:SetAngles( Angle(0,0,0) )
|
||||
|
||||
local SteerMaster = self:AddWheelSteeringPlate( false )
|
||||
|
||||
local ballsocket1 = constraint.AdvBallsocket(wheel, SteerMaster,0,0,Vector(0,0,0),Vector(0,0,0),0,0, -180, -0.01, -0.01, 180, 0.01, 0.01, 0, 0, 0, 1, 0)
|
||||
ballsocket1.DoNotDuplicate = true
|
||||
self:TransferCPPI( ballsocket1 )
|
||||
|
||||
local ballsocket2 = constraint.AdvBallsocket(wheel,self,0,0,Vector(0,0,0),Vector(0,0,0),0,0, -180, -180, -180, 180, 180, 180, 0, 0, 0, 0, 0)
|
||||
ballsocket2.DoNotDuplicate = true
|
||||
self:TransferCPPI( ballsocket2 )
|
||||
end
|
||||
|
||||
if type == LVS.WHEEL_STEER_REAR then
|
||||
wheel:SetAngles( Angle(0,0,0) )
|
||||
|
||||
local SteerMaster = self:AddWheelSteeringPlate( true )
|
||||
|
||||
|
||||
local ballsocket1 = constraint.AdvBallsocket(wheel, SteerMaster,0,0,Vector(0,0,0),Vector(0,0,0),0,0, -180, -0.01, -0.01, 180, 0.01, 0.01, 0, 0, 0, 1, 0)
|
||||
ballsocket1.DoNotDuplicate = true
|
||||
self:TransferCPPI( ballsocket1 )
|
||||
|
||||
local ballsocket2 = constraint.AdvBallsocket(wheel,self,0,0,Vector(0,0,0),Vector(0,0,0),0,0, -180, -180, -180, 180, 180, 180, 0, 0, 0, 0, 0)
|
||||
ballsocket2.DoNotDuplicate = true
|
||||
self:TransferCPPI( ballsocket2 )
|
||||
end
|
||||
|
||||
local nocollide = constraint.NoCollide( wheel, self, 0, 0 )
|
||||
nocollide.DoNotDuplicate = true
|
||||
self:TransferCPPI( nocollide )
|
||||
|
||||
PhysObj:EnableMotion( true )
|
||||
PhysObj:EnableDrag( false )
|
||||
|
||||
local WheelData = {
|
||||
entity = wheel,
|
||||
physobj = PhysObj,
|
||||
mass = mass,
|
||||
}
|
||||
|
||||
if not istable( self._lvsWheels ) then self._lvsWheels = {} end
|
||||
|
||||
table.insert( self._lvsWheels, WheelData )
|
||||
|
||||
return wheel
|
||||
end
|
||||
Reference in New Issue
Block a user