add sborka

This commit is contained in:
2026-03-31 10:27:04 +03:00
commit f5e5f56c84
2345 changed files with 382127 additions and 0 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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