add sborka
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
|
||||
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() )
|
||||
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 view = {}
|
||||
view.origin = pos
|
||||
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,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,168 @@
|
||||
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 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, self:GetThrustPercent() )
|
||||
end
|
||||
|
||||
function ENT:LVSPreHudPaint( X, Y, ply )
|
||||
return true
|
||||
end
|
||||
|
||||
ENT.Hud = true
|
||||
ENT.HudThirdPerson = false
|
||||
ENT.HudGradient = Material("gui/center_gradient")
|
||||
ENT.HudColor = Color(255,255,255)
|
||||
|
||||
function ENT:PaintHeliFlightInfo( X, Y, ply, Pos2D )
|
||||
local Roll = self:GetAngles().r
|
||||
|
||||
surface.SetDrawColor(0,0,0,40)
|
||||
surface.SetMaterial( self.HudGradient )
|
||||
surface.DrawTexturedRect( Pos2D.x - 270, Pos2D.y - 10, 140, 20 )
|
||||
surface.DrawTexturedRect( Pos2D.x + 130, Pos2D.y - 10, 140, 20 )
|
||||
|
||||
local X = math.cos( math.rad( Roll ) )
|
||||
local Y = math.sin( math.rad( Roll ) )
|
||||
|
||||
surface.SetDrawColor( self.HudColor.r, self.HudColor.g, self.HudColor.b, 255 )
|
||||
surface.DrawLine( Pos2D.x + X * 50, Pos2D.y + Y * 50, Pos2D.x + X * 125, Pos2D.y + Y * 125 )
|
||||
surface.DrawLine( Pos2D.x - X * 50, Pos2D.y - Y * 50, Pos2D.x - X * 125, Pos2D.y - Y * 125 )
|
||||
|
||||
surface.DrawLine( Pos2D.x + 125, Pos2D.y, Pos2D.x + 130, Pos2D.y + 5 )
|
||||
surface.DrawLine( Pos2D.x + 125, Pos2D.y, Pos2D.x + 130, Pos2D.y - 5 )
|
||||
surface.DrawLine( Pos2D.x - 125, Pos2D.y, Pos2D.x - 130, Pos2D.y + 5 )
|
||||
surface.DrawLine( Pos2D.x - 125, Pos2D.y, Pos2D.x - 130, Pos2D.y - 5 )
|
||||
|
||||
surface.SetDrawColor( 0, 0, 0, 80 )
|
||||
surface.DrawLine( Pos2D.x + X * 50 + 1, Pos2D.y + Y * 50 + 1, Pos2D.x + X * 125 + 1, Pos2D.y + Y * 125 + 1 )
|
||||
surface.DrawLine( Pos2D.x - X * 50 + 1, Pos2D.y - Y * 50 + 1, Pos2D.x - X * 125 + 1, Pos2D.y - Y * 125 + 1 )
|
||||
|
||||
surface.DrawLine( Pos2D.x + 126, Pos2D.y + 1, Pos2D.x + 131, Pos2D.y + 6 )
|
||||
surface.DrawLine( Pos2D.x + 126, Pos2D.y + 1, Pos2D.x + 131, Pos2D.y - 4 )
|
||||
surface.DrawLine( Pos2D.x - 126, Pos2D.y + 1, Pos2D.x - 129, Pos2D.y + 6 )
|
||||
surface.DrawLine( Pos2D.x - 126, Pos2D.y + 1, Pos2D.x - 129, Pos2D.y - 4 )
|
||||
|
||||
local X = math.cos( math.rad( Roll + 45 ) )
|
||||
local Y = math.sin( math.rad( Roll + 45 ) )
|
||||
surface.DrawLine( Pos2D.x + X * 30 - 1, Pos2D.y + Y * 30 + 1, Pos2D.x + X * 60 - 1, Pos2D.y + Y * 60 + 1 )
|
||||
local X = math.cos( math.rad( Roll + 135 ) )
|
||||
local Y = math.sin( math.rad( Roll + 135 ) )
|
||||
surface.DrawLine( Pos2D.x + X * 30 + 1, Pos2D.y + Y * 30 + 1, Pos2D.x + X * 60 + 1, Pos2D.y + Y * 60 + 1 )
|
||||
|
||||
surface.SetDrawColor( self.HudColor.r, self.HudColor.g, self.HudColor.b, 255 )
|
||||
local X = math.cos( math.rad( Roll + 45 ) )
|
||||
local Y = math.sin( math.rad( Roll + 45 ) )
|
||||
surface.DrawLine( Pos2D.x + X * 30, Pos2D.y + Y * 30, Pos2D.x + X * 60, Pos2D.y + Y * 60 )
|
||||
local X = math.cos( math.rad( Roll + 135 ) )
|
||||
local Y = math.sin( math.rad( Roll + 135 ) )
|
||||
surface.DrawLine( Pos2D.x + X * 30, Pos2D.y + Y * 30, Pos2D.x + X * 60, Pos2D.y + Y * 60 )
|
||||
|
||||
local Pitch = -self:GetAngles().p
|
||||
|
||||
surface.DrawLine( Pos2D.x - 220, Pos2D.y, Pos2D.x - 180, Pos2D.y )
|
||||
surface.DrawLine( Pos2D.x + 220, Pos2D.y, Pos2D.x + 180, Pos2D.y )
|
||||
surface.SetDrawColor( 0, 0, 0, 80 )
|
||||
surface.DrawLine( Pos2D.x - 220, Pos2D.y + 1, Pos2D.x - 180, Pos2D.y + 1 )
|
||||
surface.DrawLine( Pos2D.x + 220, Pos2D.y + 1, Pos2D.x + 180, Pos2D.y + 1 )
|
||||
|
||||
draw.DrawText( math.Round( Pitch, 2 ), "LVS_FONT_PANEL", Pos2D.x - 175, Pos2D.y - 7, Color( self.HudColor.r, self.HudColor.g, self.HudColor.b, 255 ), TEXT_ALIGN_LEFT )
|
||||
draw.DrawText( math.Round( Pitch, 2 ), "LVS_FONT_PANEL", Pos2D.x + 175, Pos2D.y - 7, Color( self.HudColor.r, self.HudColor.g, self.HudColor.b, 255 ), TEXT_ALIGN_RIGHT )
|
||||
|
||||
for i = -180, 180 do
|
||||
local Y = -i * 10 + Pitch * 10
|
||||
|
||||
local absN = math.abs( i )
|
||||
|
||||
local IsTen = absN == math.Round( absN / 10, 0 ) * 10
|
||||
|
||||
local SizeX = IsTen and 20 or 10
|
||||
|
||||
local Alpha = 255 - (math.min( math.abs( Y ) / 200,1) ^ 2) * 255
|
||||
|
||||
if Alpha <= 0 then continue end
|
||||
|
||||
surface.SetDrawColor( self.HudColor.r, self.HudColor.g, self.HudColor.b, Alpha * 0.75 )
|
||||
surface.DrawLine(Pos2D.x - 200 - SizeX, Pos2D.y + Y, Pos2D.x - 200, Pos2D.y + Y )
|
||||
surface.DrawLine(Pos2D.x + 200 + SizeX, Pos2D.y + Y, Pos2D.x + 200, Pos2D.y + Y )
|
||||
surface.SetDrawColor( 0, 0, 0, Alpha * 0.25 )
|
||||
surface.DrawLine(Pos2D.x - 200 - SizeX, Pos2D.y + Y + 1, Pos2D.x - 200, Pos2D.y + Y + 1 )
|
||||
surface.DrawLine(Pos2D.x + 200 + SizeX, Pos2D.y + Y + 1, Pos2D.x + 200, Pos2D.y + Y + 1)
|
||||
|
||||
if not IsTen then continue end
|
||||
|
||||
draw.DrawText( i, "LVS_FONT_HUD", Pos2D.x - 225, Pos2D.y + Y - 10, Color( self.HudColor.r, self.HudColor.g, self.HudColor.b, Alpha * 0.5 ), TEXT_ALIGN_RIGHT )
|
||||
draw.DrawText( i, "LVS_FONT_HUD", Pos2D.x + 225, Pos2D.y + Y - 10, Color( self.HudColor.r, self.HudColor.g, self.HudColor.b, Alpha * 0.5 ), TEXT_ALIGN_LEFT )
|
||||
end
|
||||
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 pod = ply:GetVehicle()
|
||||
|
||||
if self.Hud then
|
||||
if not pod:GetThirdPersonMode() then
|
||||
self:PaintHeliFlightInfo( X, Y, ply, HitPilot )
|
||||
end
|
||||
end
|
||||
|
||||
if self.HudThirdPerson then
|
||||
if pod:GetThirdPersonMode() then
|
||||
self:PaintHeliFlightInfo( X, Y, ply, HitPilot )
|
||||
end
|
||||
end
|
||||
|
||||
self:PaintCrosshairCenter( HitPlane )
|
||||
self:PaintCrosshairOuter( HitPilot )
|
||||
|
||||
if ply:lvsMouseAim() 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()
|
||||
local Dir = Sub:GetNormalized()
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 100 )
|
||||
if Len > 20 then
|
||||
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 )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
include("shared.lua")
|
||||
include("cl_camera.lua")
|
||||
include("sh_camera_eyetrace.lua")
|
||||
include("cl_hud.lua")
|
||||
include("cl_flyby.lua")
|
||||
@@ -0,0 +1,210 @@
|
||||
AddCSLuaFile( "shared.lua" )
|
||||
AddCSLuaFile( "cl_init.lua" )
|
||||
AddCSLuaFile( "cl_camera.lua" )
|
||||
AddCSLuaFile( "sh_camera_eyetrace.lua" )
|
||||
AddCSLuaFile( "cl_hud.lua" )
|
||||
AddCSLuaFile( "cl_flyby.lua" )
|
||||
include("shared.lua")
|
||||
include("sv_ai.lua")
|
||||
include("sv_mouseaim.lua")
|
||||
include("sv_components.lua")
|
||||
include("sv_engine.lua")
|
||||
include("sv_vehiclespecific.lua")
|
||||
include("sv_damage_extension.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, phys, deltatime )
|
||||
if not IsValid( phys ) then
|
||||
phys = self:GetPhysicsObject()
|
||||
end
|
||||
|
||||
if not deltatime then
|
||||
deltatime = FrameTime()
|
||||
end
|
||||
|
||||
local LocalAngles = self:WorldToLocalAngles( TargetAngle )
|
||||
|
||||
local LocalAngPitch = LocalAngles.p
|
||||
local LocalAngYaw = LocalAngles.y
|
||||
local LocalAngRoll = LocalAngles.r
|
||||
|
||||
local TargetForward = TargetAngle:Forward()
|
||||
local Forward = self:GetForward()
|
||||
|
||||
local Ang = self:GetAngles()
|
||||
local AngVel = phys:GetAngleVelocity()
|
||||
|
||||
local SmoothPitch = math.Clamp( math.Clamp(AngVel.y / 50,-0.25,0.25) / math.abs( LocalAngPitch ), -1, 1 )
|
||||
local SmoothYaw = math.Clamp( math.Clamp(AngVel.z / 50,-0.25,0.25) / math.abs( LocalAngYaw ), -1, 1 )
|
||||
|
||||
local VelL = self:WorldToLocal( self:GetPos() + self:GetVelocity() )
|
||||
|
||||
local Pitch = math.Clamp(-LocalAngPitch / 10 + SmoothPitch,-1,1)
|
||||
local Yaw = math.Clamp(-LocalAngYaw + SmoothYaw,-1,1)
|
||||
local Roll = math.Clamp(LocalAngRoll / 100 + Yaw * 0.25 + math.Clamp(VelL.y / math.abs( VelL.x ) / 10,-0.25,0.25),-1,1)
|
||||
|
||||
if OverrideRoll ~= 0 then
|
||||
Roll = math.Clamp( self:WorldToLocalAngles( Angle( Ang.p, Ang.y, OverrideRoll * 60 ) ).r / 40,-1,1)
|
||||
end
|
||||
|
||||
self.Roll = Roll
|
||||
|
||||
if OverridePitch and OverridePitch ~= 0 then
|
||||
Pitch = OverridePitch
|
||||
end
|
||||
|
||||
if OverrideYaw and OverrideYaw ~= 0 then
|
||||
Yaw = OverrideYaw
|
||||
end
|
||||
|
||||
self:SetSteer( Vector( Roll, -Pitch, -Yaw) )
|
||||
end
|
||||
|
||||
function ENT:OnSkyCollide( data, PhysObj )
|
||||
|
||||
local NewVelocity = self:VectorSubtractNormal( data.HitNormal, data.OurOldVelocity ) - data.HitNormal * 50
|
||||
|
||||
PhysObj:SetVelocityInstantaneous( NewVelocity )
|
||||
PhysObj:SetAngleVelocityInstantaneous( data.OurOldAngularVelocity )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate( phys, deltatime )
|
||||
if self:GetEngineActive() then phys:Wake() end
|
||||
|
||||
local EntTable = self:GetTable()
|
||||
|
||||
local WorldGravity = self:GetWorldGravity()
|
||||
local WorldUp = self:GetWorldUp()
|
||||
|
||||
local Up = self:GetUp()
|
||||
local Left = -self:GetRight()
|
||||
|
||||
local Mul = self:GetThrottle()
|
||||
local InputThrust = math.min( self:GetThrust() , 0 ) * EntTable.ThrustDown + math.max( self:GetThrust(), 0 ) * EntTable.ThrustUp
|
||||
|
||||
if self:HitGround() and InputThrust <= 0 then
|
||||
Mul = 0
|
||||
end
|
||||
|
||||
-- mouse aim needs to run at high speed.
|
||||
if self:GetAI() then
|
||||
self:CalcAIMove( phys, deltatime )
|
||||
else
|
||||
local ply = self:GetDriver()
|
||||
if IsValid( ply ) and ply:lvsMouseAim() then
|
||||
self:PlayerMouseAim( ply, phys, deltatime )
|
||||
end
|
||||
end
|
||||
|
||||
local Steer = self:GetSteer()
|
||||
|
||||
local Vel = phys:GetVelocity()
|
||||
local VelL = phys:WorldToLocal( phys:GetPos() + Vel )
|
||||
|
||||
local YawPull = (math.deg( math.acos( math.Clamp( WorldUp:Dot( Left ) ,-1,1) ) ) - 90) / 90
|
||||
|
||||
local GravityYaw = math.abs( YawPull ) ^ 1.25 * self:Sign( YawPull ) * (WorldGravity / 100) * (math.min( Vector(VelL.x,VelL.y,0):Length() / EntTable.MaxVelocity,1) ^ 2)
|
||||
|
||||
local Pitch = math.Clamp(Steer.y,-1,1) * EntTable.TurnRatePitch
|
||||
local Yaw = math.Clamp(Steer.z + GravityYaw * 0.25 * EntTable.GravityTurnRateYaw,-1,1) * EntTable.TurnRateYaw * 60
|
||||
local Roll = math.Clamp(Steer.x,-1,1) * 1.5 * EntTable.TurnRateRoll
|
||||
|
||||
local Ang = self:GetAngles()
|
||||
|
||||
local FadeMul = (1 - math.max( (45 - self:AngleBetweenNormal( WorldUp, Up )) / 45,0)) ^ 2
|
||||
local ThrustMul = math.Clamp( 1 - (Vel:Length() / EntTable.MaxVelocity) * FadeMul, 0, 1 )
|
||||
|
||||
local Thrust = self:LocalToWorldAngles( Angle(Pitch,0,Roll) ):Up() * (WorldGravity + InputThrust * 500 * ThrustMul) * Mul
|
||||
|
||||
local Force, ForceAng = phys:CalculateForceOffset( Thrust, phys:LocalToWorld( phys:GetMassCenter() ) + self:GetUp() * 1000 )
|
||||
|
||||
local ForceLinear = (Force - Vel * 0.15 * EntTable.ForceLinearDampingMultiplier) * Mul
|
||||
local ForceAngle = (ForceAng + (Vector(0,0,Yaw) - phys:GetAngleVelocity() * 1.5 * EntTable.ForceAngleDampingMultiplier) * deltatime * 250) * Mul
|
||||
|
||||
if EntTable._SteerOverride then
|
||||
ForceAngle.z = (EntTable._SteerOverrideMove * math.max( self:GetThrust() * 2, 1 ) * 100 - phys:GetAngleVelocity().z) * Mul
|
||||
end
|
||||
|
||||
return self:PhysicsSimulateOverride( ForceAngle, ForceLinear, phys, deltatime, SIM_GLOBAL_ACCELERATION )
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulateOverride( ForceAngle, ForceLinear, phys, deltatime, simulate )
|
||||
return ForceAngle, ForceLinear, simulate
|
||||
end
|
||||
|
||||
function ENT:ApproachThrust( New, Delta )
|
||||
if not Delta then
|
||||
Delta = FrameTime()
|
||||
end
|
||||
|
||||
local Cur = self:GetThrust()
|
||||
|
||||
self:SetThrust( Cur + (New - Cur) * Delta * self.ThrustRate * 2.5 )
|
||||
end
|
||||
|
||||
function ENT:CalcThrust( KeyUp, KeyDown, Delta )
|
||||
if self:HitGround() and not KeyUp then
|
||||
self:ApproachThrust( -1, Delta )
|
||||
self.Roll = self:GetAngles().r
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local Up = KeyUp and 1 or 0
|
||||
local Down = KeyDown and -1 or 0
|
||||
|
||||
self:ApproachThrust( Up + Down, Delta )
|
||||
end
|
||||
|
||||
function ENT:CalcHover( InputLeft, InputRight, InputUp, InputDown, ThrustUp, ThrustDown, PhysObj, deltatime )
|
||||
if not IsValid( PhysObj ) then
|
||||
PhysObj = self:GetPhysicsObject()
|
||||
end
|
||||
|
||||
local VelL = PhysObj:WorldToLocal( PhysObj:GetPos() + PhysObj:GetVelocity() )
|
||||
local AngVel = PhysObj:GetAngleVelocity()
|
||||
|
||||
local KeyLeft = InputLeft and 60 or 0
|
||||
local KeyRight = InputRight and 60 or 0
|
||||
local KeyPitchUp = InputUp and 60 or 0
|
||||
local KeyPitchDown = InputDown and 60 or 0
|
||||
|
||||
local Pitch = KeyPitchDown - KeyPitchUp
|
||||
local Roll = KeyRight - KeyLeft
|
||||
|
||||
if (Pitch + Roll) == 0 then
|
||||
Pitch = math.Clamp(-VelL.x / 200,-1,1) * 60
|
||||
Roll = math.Clamp(VelL.y / 250,-1,1) * 60
|
||||
end
|
||||
|
||||
local Ang = self:GetAngles()
|
||||
|
||||
local Steer = self:GetSteer()
|
||||
Steer.x = math.Clamp( Roll - Ang.r - AngVel.x,-1,1)
|
||||
Steer.y = math.Clamp( Pitch - Ang.p - AngVel.y,-1,1)
|
||||
|
||||
self:SetSteer( Steer )
|
||||
|
||||
self.Roll = Ang.r
|
||||
|
||||
if ThrustUp or ThrustDown then
|
||||
self:CalcThrust( ThrustUp, ThrustDown, deltatime )
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:ApproachThrust( math.Clamp(-VelL.z / 100,-1,1), deltatime )
|
||||
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,153 @@
|
||||
|
||||
ENT.Base = "lvs_base"
|
||||
|
||||
ENT.PrintName = "[LVS] Base Helicopter"
|
||||
ENT.Author = "Luna"
|
||||
ENT.Information = "Luna's Vehicle Script"
|
||||
ENT.Category = "[LVS]"
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
|
||||
ENT.MaxVelocity = 2150
|
||||
|
||||
ENT.ThrustUp = 1
|
||||
ENT.ThrustDown = 0.8
|
||||
ENT.ThrustRate = 1
|
||||
|
||||
ENT.ThrottleRateUp = 0.2
|
||||
ENT.ThrottleRateDown = 0.2
|
||||
|
||||
ENT.TurnRatePitch = 1
|
||||
ENT.TurnRateYaw = 1
|
||||
ENT.TurnRateRoll = 1
|
||||
|
||||
ENT.GravityTurnRateYaw = 1
|
||||
|
||||
ENT.ForceLinearDampingMultiplier = 1.5
|
||||
|
||||
ENT.ForceAngleMultiplier = 1
|
||||
ENT.ForceAngleDampingMultiplier = 1
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:CreateBaseDT()
|
||||
|
||||
self:AddDT( "Vector", "Steer" )
|
||||
self:AddDT( "Vector", "AIAimVector" )
|
||||
self:AddDT( "Float", "Throttle" )
|
||||
self:AddDT( "Float", "NWThrust" )
|
||||
end
|
||||
|
||||
function ENT:PlayerDirectInput( ply, cmd )
|
||||
local Pod = self:GetDriverSeat()
|
||||
|
||||
local Delta = FrameTime()
|
||||
|
||||
local KeyLeft = ply:lvsKeyDown( "-ROLL_HELI" )
|
||||
local KeyRight = ply:lvsKeyDown( "+ROLL_HELI" )
|
||||
local KeyPitchUp = ply:lvsKeyDown( "+PITCH_HELI" )
|
||||
local KeyPitchDown = ply:lvsKeyDown( "-PITCH_HELI" )
|
||||
local KeyRollRight = ply:lvsKeyDown( "+YAW_HELI" )
|
||||
local KeyRollLeft = ply:lvsKeyDown( "-YAW_HELI" )
|
||||
|
||||
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 )
|
||||
|
||||
if CLIENT then return end
|
||||
|
||||
if ply:lvsKeyDown( "HELI_HOVER" ) then
|
||||
self:CalcHover( ply:lvsKeyDown( "-YAW_HELI" ), ply:lvsKeyDown( "+YAW_HELI" ), KeyPitchUp, KeyPitchDown, ply:lvsKeyDown( "+THRUST_HELI" ), ply:lvsKeyDown( "-THRUST_HELI" ) )
|
||||
|
||||
self.ResetSteer = true
|
||||
|
||||
else
|
||||
if self.ResetSteer then
|
||||
self.ResetSteer = nil
|
||||
|
||||
self:SetSteer( Vector(0,0,0) )
|
||||
end
|
||||
|
||||
self:CalcThrust( ply:lvsKeyDown( "+THRUST_HELI" ), ply:lvsKeyDown( "-THRUST_HELI" ) )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:StartCommand( ply, cmd )
|
||||
if self:GetDriver() ~= ply then return end
|
||||
|
||||
if SERVER then
|
||||
local KeyJump = ply:lvsKeyDown( "VSPEC" )
|
||||
|
||||
if self._lvsOldKeyJump ~= KeyJump then
|
||||
self._lvsOldKeyJump = KeyJump
|
||||
|
||||
if KeyJump then
|
||||
self:ToggleVehicleSpecific()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not ply:lvsMouseAim() then
|
||||
self:PlayerDirectInput( ply, cmd )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:SetThrust( New )
|
||||
if self:GetEngineActive() then
|
||||
self:SetNWThrust( math.Clamp(New,-1,1) )
|
||||
else
|
||||
self:SetNWThrust( 0 )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetThrust()
|
||||
return self:GetNWThrust()
|
||||
end
|
||||
|
||||
function ENT:GetThrustPercent()
|
||||
return math.Clamp(0.5 * self:GetThrottle() + self:GetThrust() * 0.5,0,1)
|
||||
end
|
||||
|
||||
function ENT:GetThrustStrenght()
|
||||
return (1 - (self:GetVelocity():Length() / self.MaxVelocity)) * self:GetThrustPercent()
|
||||
end
|
||||
|
||||
function ENT:GetVehicleType()
|
||||
return "helicopter"
|
||||
end
|
||||
@@ -0,0 +1,200 @@
|
||||
|
||||
function ENT:OnCreateAI()
|
||||
self:StartEngine()
|
||||
end
|
||||
|
||||
function ENT:OnRemoveAI()
|
||||
self:StopEngine()
|
||||
end
|
||||
|
||||
function ENT:RunAI()
|
||||
local RangerLength = 15000
|
||||
|
||||
local mySpeed = self:GetVelocity():Length()
|
||||
local myRadius = self:BoundingRadius()
|
||||
local myPos = self:GetPos()
|
||||
local myDir = self:GetForward()
|
||||
|
||||
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)
|
||||
|
||||
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()
|
||||
|
||||
self._AIFireInput = false
|
||||
|
||||
local Target = self:AIGetTarget()
|
||||
|
||||
if alt < 600 or ceiling < 600 then
|
||||
if ceiling < 600 then
|
||||
TargetPos.z = StartPos.z - 2000
|
||||
else
|
||||
TargetPos.z = StartPos.z + 2000
|
||||
end
|
||||
else
|
||||
if IsValid( self:GetHardLockTarget() ) then
|
||||
TargetPos = self:GetHardLockTarget():GetPos() + cAvoid * 8
|
||||
else
|
||||
if IsValid( Target ) then
|
||||
local HisRadius = Target:BoundingRadius()
|
||||
local HisPos = Target:GetPos() + Vector(0,0,600)
|
||||
|
||||
TargetPos = HisPos + (myPos - HisPos):GetNormalized() * (myRadius + HisRadius + 500) + cAvoid * 8
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self._lvsTargetPos = TargetPos
|
||||
|
||||
if IsValid( Target ) then
|
||||
TargetPos = Target:LocalToWorld( Target:OBBCenter() )
|
||||
|
||||
if self:AITargetInFront( Target, 65 ) then
|
||||
local tr = self:GetEyeTrace()
|
||||
|
||||
if (IsValid( tr.Entity ) and tr.Entity.LVS and tr.Entity.GetAITEAM) and (tr.Entity:GetAITEAM() ~= self:GetAITEAM() or tr.Entity:GetAITEAM() == 0) or true 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( CurTime() ) > 0 then
|
||||
self:AISelectWeapon( 1 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self._AIFireInput = true
|
||||
end
|
||||
else
|
||||
self:AISelectWeapon( 1 )
|
||||
end
|
||||
end
|
||||
|
||||
self:SetAIAimVector( (TargetPos - myPos):GetNormalized() )
|
||||
end
|
||||
|
||||
function ENT:CalcAIMove( PhysObj, deltatime )
|
||||
if not self._lvsTargetPos then return end
|
||||
|
||||
local StartPos = self:LocalToWorld( self:OBBCenter() )
|
||||
|
||||
local Target = self:AIGetTarget()
|
||||
|
||||
local TargetPos = self._lvsTargetPos
|
||||
|
||||
local VelL = PhysObj:WorldToLocal( PhysObj:GetPos() + PhysObj:GetVelocity() )
|
||||
local AngVel = PhysObj:GetAngleVelocity()
|
||||
|
||||
local LPos = self:WorldToLocal( TargetPos )
|
||||
|
||||
local Pitch = math.Clamp(LPos.x * 0.01 - VelL.x * 0.01,-1,1) * 40
|
||||
local Yaw = ((IsValid( Target ) and Target:GetPos() or TargetPos) - StartPos):Angle().y
|
||||
local Roll = math.Clamp(VelL.y * 0.01,-1,1) * 40
|
||||
|
||||
local Ang = self:GetAngles()
|
||||
|
||||
local Steer = self:GetSteer()
|
||||
Steer.x = math.Clamp( Roll - Ang.r - AngVel.x,-1,1)
|
||||
Steer.y = math.Clamp( Pitch - Ang.p - AngVel.y,-1,1)
|
||||
Steer.z = math.Clamp( self:WorldToLocalAngles( Angle(0,Yaw,0) ).y / 10,-1,1)
|
||||
|
||||
self:SetSteer( Steer )
|
||||
self:SetThrust( math.Clamp( LPos.z - VelL.z,-1,1) )
|
||||
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 )
|
||||
if not self:IsEnemy( target ) then return end
|
||||
|
||||
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,54 @@
|
||||
|
||||
function ENT:AddEngineSound( pos )
|
||||
local Engine = ents.Create( "lvs_helicopter_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 )
|
||||
|
||||
return Engine
|
||||
end
|
||||
|
||||
function ENT:AddRotor( pos, ang, radius, speed )
|
||||
if not pos or not ang or not radius or not speed then return end
|
||||
|
||||
local Rotor = ents.Create( "lvs_helicopter_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:LocalToWorldAngles( ang ) )
|
||||
Rotor:Spawn()
|
||||
Rotor:Activate()
|
||||
Rotor:SetParent( self )
|
||||
Rotor:SetBase( self )
|
||||
Rotor:SetRadius( radius )
|
||||
Rotor:SetSpeed( speed )
|
||||
|
||||
self:DeleteOnRemove( Rotor )
|
||||
|
||||
self:TransferCPPI( Rotor )
|
||||
|
||||
return Rotor
|
||||
end
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
function ENT:StartDestroyTimer()
|
||||
if self._DestroyTimerStarted then return end
|
||||
|
||||
self._DestroyTimerStarted = true
|
||||
|
||||
timer.Simple( self:GetAI() and 5 or 60, function()
|
||||
if not IsValid( self ) then return end
|
||||
|
||||
self.MarkForDestruction = true
|
||||
end )
|
||||
end
|
||||
|
||||
function ENT:DestroySteering( movevalue )
|
||||
if self._SteerOverride then return end
|
||||
|
||||
self._SteerOverride = true
|
||||
self._SteerOverrideMove = (movevalue or 1)
|
||||
self:StartDestroyTimer()
|
||||
end
|
||||
|
||||
function ENT:DestroyEngine()
|
||||
if self._EngineDestroyed then return end
|
||||
|
||||
self._EngineDestroyed = true
|
||||
|
||||
self:TurnOffEngine()
|
||||
|
||||
self:SetThrottle( 0 )
|
||||
self:SetThrust( 0 )
|
||||
|
||||
self:StartDestroyTimer()
|
||||
end
|
||||
|
||||
function ENT:IsSteeringDestroyed()
|
||||
return self._SteerOverride == true
|
||||
end
|
||||
|
||||
function ENT:IsEngineDestroyed()
|
||||
return self._EngineDestroyed == true
|
||||
end
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
function ENT:CalcThrottle()
|
||||
if not self:GetEngineActive() then
|
||||
|
||||
if self:GetThrottle() ~= 0 then self:SetThrottle( 0 ) end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local Delta = FrameTime()
|
||||
|
||||
local Cur = self:GetThrottle()
|
||||
local New = self._StopEngine and 0 or 1
|
||||
|
||||
if self:IsDestroyed() then New = 0 end
|
||||
|
||||
if Cur == New and New == 0 then self:TurnOffEngine() return end
|
||||
|
||||
self:SetThrottle( Cur + math.Clamp( (New - Cur), -self.ThrottleRateDown * Delta, self.ThrottleRateUp * Delta ) )
|
||||
end
|
||||
|
||||
function ENT:HandleStart()
|
||||
local Driver = self:GetDriver()
|
||||
|
||||
if IsValid( Driver ) then
|
||||
local KeyReload = Driver:lvsKeyDown( "ENGINE" )
|
||||
|
||||
if self.OldKeyReload ~= KeyReload then
|
||||
self.OldKeyReload = KeyReload
|
||||
|
||||
if KeyReload then
|
||||
self:ToggleEngine()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:CalcThrottle()
|
||||
end
|
||||
|
||||
function ENT:ToggleEngine()
|
||||
if self:GetEngineActive() and not self._StopEngine then
|
||||
self:StopEngine()
|
||||
else
|
||||
self:StartEngine()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:StartEngine()
|
||||
if not self:IsEngineStartAllowed() then return end
|
||||
if self._EngineDestroyed then return end
|
||||
|
||||
if self:GetEngineActive() then
|
||||
self._StopEngine = nil
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:PhysWake()
|
||||
|
||||
self:SetEngineActive( true )
|
||||
self:OnEngineActiveChanged( true )
|
||||
|
||||
self._StopEngine = nil
|
||||
end
|
||||
|
||||
function ENT:StopEngine()
|
||||
if self._StopEngine then return end
|
||||
|
||||
self._StopEngine = true
|
||||
self:OnEngineActiveChanged( false )
|
||||
|
||||
if self:WaterLevel() >= self.WaterLevelAutoStop then
|
||||
self:TurnOffEngine()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:TurnOffEngine()
|
||||
if not self:GetEngineActive() then return end
|
||||
|
||||
self:SetEngineActive( false )
|
||||
|
||||
self._StopEngine = nil
|
||||
end
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
function ENT:PlayerMouseAim( ply, phys, deltatime )
|
||||
local Pod = self:GetDriverSeat()
|
||||
|
||||
local PitchUp = ply:lvsKeyDown( "+PITCH_HELI" )
|
||||
local PitchDown = ply:lvsKeyDown( "-PITCH_HELI" )
|
||||
local YawRight = ply:lvsKeyDown( "+YAW_HELI" )
|
||||
local YawLeft = ply:lvsKeyDown( "-YAW_HELI" )
|
||||
local RollRight = ply:lvsKeyDown( "+ROLL_HELI" )
|
||||
local RollLeft = ply:lvsKeyDown( "-ROLL_HELI" )
|
||||
|
||||
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, phys, deltatime )
|
||||
|
||||
if ply:lvsKeyDown( "HELI_HOVER" ) then
|
||||
self:CalcHover( RollLeft, RollRight, PitchUp, PitchDown, ply:lvsKeyDown( "+THRUST_HELI" ), ply:lvsKeyDown( "-THRUST_HELI" ), phys, deltatime )
|
||||
|
||||
self.ResetSteer = true
|
||||
|
||||
else
|
||||
if self.ResetSteer then
|
||||
self.ResetSteer = nil
|
||||
|
||||
self:SetSteer( Vector(0,0,0) )
|
||||
end
|
||||
|
||||
self:CalcThrust( ply:lvsKeyDown( "+THRUST_HELI" ), ply:lvsKeyDown( "-THRUST_HELI" ), deltatime )
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
function ENT:ToggleVehicleSpecific()
|
||||
self._VSPEC = not self._VSPEC
|
||||
|
||||
self:OnVehicleSpecificToggled( self._VSPEC )
|
||||
end
|
||||
|
||||
function ENT:EnableVehicleSpecific()
|
||||
if self._VSPEC then return end
|
||||
|
||||
self._VSPEC = true
|
||||
|
||||
self:OnVehicleSpecificToggled( self._VSPEC )
|
||||
end
|
||||
|
||||
function ENT:DisableVehicleSpecific()
|
||||
if not self._VSPEC then return end
|
||||
|
||||
self._VSPEC = false
|
||||
|
||||
self:OnVehicleSpecificToggled( self._VSPEC )
|
||||
end
|
||||
|
||||
function ENT:OnVehicleSpecificToggled( IsActive )
|
||||
end
|
||||
Reference in New Issue
Block a user