mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
677
lua/entities/gmod_sent_vehicle_fphysics_base/cl_init.lua
Normal file
677
lua/entities/gmod_sent_vehicle_fphysics_base/cl_init.lua
Normal file
@@ -0,0 +1,677 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
include("shared.lua")
|
||||
include("cl_tiresounds.lua")
|
||||
|
||||
function ENT:LVSHudPaint( X, Y, ply )
|
||||
local Pos2D = {
|
||||
visible = true,
|
||||
x = ScrW() * 0.5,
|
||||
y = ScrH() * 0.5,
|
||||
}
|
||||
|
||||
self:LVSPaintHitMarker( Pos2D )
|
||||
end
|
||||
|
||||
function ENT:GetViewOverride()
|
||||
return self.customview or vector_origin
|
||||
end
|
||||
|
||||
function ENT:LVSCalcView( ply, pos, angles, fov, pod )
|
||||
if pod:GetNWBool( "simfphys_SpecialCam" ) then return end
|
||||
|
||||
local IsDriverSeat = ply == self:GetDriver()
|
||||
|
||||
if IsDriverSeat and ply:lvsMouseAim() then
|
||||
angles = ply:EyeAngles()
|
||||
end
|
||||
|
||||
self.ZoomFov = fov
|
||||
|
||||
local view_origin = pos
|
||||
|
||||
if not pod:GetThirdPersonMode() then
|
||||
local viewoverride = self:GetViewOverride()
|
||||
|
||||
local X = viewoverride.X
|
||||
local Y = viewoverride.Y
|
||||
local Z = viewoverride.Z
|
||||
|
||||
view_origin = view_origin + (IsDriverSeat and pod:GetForward() * X + pod:GetRight() * Y + pod:GetUp() * Z or pod:GetUp() * 5)
|
||||
end
|
||||
|
||||
if not IsDriverSeat then return LVS:CalcView( self, ply, view_origin, angles, fov, pod ) end
|
||||
|
||||
return LVS:CalcView( self, ply, view_origin, angles, fov, pod )
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self.SmoothRPM = 0
|
||||
self.OldDist = 0
|
||||
self.PitchOffset = 0
|
||||
self.OldActive = false
|
||||
self.OldGear = 0
|
||||
self.OldThrottle = 0
|
||||
self.FadeThrottle = 0
|
||||
self.SoundMode = 0
|
||||
|
||||
self.DamageSnd = CreateSound(self, "simulated_vehicles/engine_damaged.wav")
|
||||
|
||||
self.EngineSounds = {}
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
local T = CurTime()
|
||||
|
||||
local Active = self:GetActive()
|
||||
local Throttle = self:GetThrottle()
|
||||
local LimitRPM = self:GetLimitRPM()
|
||||
|
||||
self:ManageSounds( Active, Throttle, LimitRPM )
|
||||
|
||||
self.RunNext = self.RunNext or 0
|
||||
if self.RunNext < T then
|
||||
self:ManageEffects( Active, Throttle, LimitRPM )
|
||||
self:CalcFlasher()
|
||||
|
||||
self.RunNext = T + 0.06
|
||||
end
|
||||
|
||||
self:SetPoseParameters( T )
|
||||
|
||||
self:TireSoundThink()
|
||||
end
|
||||
|
||||
function ENT:CalcFlasher()
|
||||
self.Flasher = self.Flasher or 0
|
||||
|
||||
local flashspeed = self.turnsignals_damaged and 0.06 or 0.0375
|
||||
|
||||
self.Flasher = self.Flasher and self.Flasher + flashspeed or 0
|
||||
if self.Flasher >= 1 then
|
||||
self.Flasher = self.Flasher - 1
|
||||
end
|
||||
|
||||
self.flashnum = math.min( math.abs( math.cos( math.rad( self.Flasher * 360 ) ) ^ 2 * 1.5 ) , 1)
|
||||
|
||||
if not self.signal_left and not self.signal_right then return end
|
||||
|
||||
if LocalPlayer() == self:GetDriver() then
|
||||
local fl_snd = self.flashnum > 0.9
|
||||
|
||||
if fl_snd ~= self.fl_snd then
|
||||
self.fl_snd = fl_snd
|
||||
if fl_snd then
|
||||
self:EmitSound( "simulated_vehicles/sfx/flasher_on.ogg" )
|
||||
else
|
||||
self:EmitSound( "simulated_vehicles/sfx/flasher_off.ogg" )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetFlasher()
|
||||
self.flashnum = self.flashnum or 0
|
||||
return self.flashnum
|
||||
end
|
||||
|
||||
function ENT:SetPoseParameters( curtime )
|
||||
self.sm_vSteer = self.sm_vSteer and self.sm_vSteer + (self:GetVehicleSteer() - self.sm_vSteer) * 0.3 or 0
|
||||
self:SetPoseParameter("vehicle_steer", self.sm_vSteer )
|
||||
|
||||
if not istable( self.pp_data ) then
|
||||
self.ppNextCheck = self.ppNextCheck or curtime + 0.5
|
||||
if self.ppNextCheck < curtime then
|
||||
self.ppNextCheck = curtime + 0.5
|
||||
|
||||
net.Start("simfphys_request_ppdata",true)
|
||||
net.WriteEntity( self )
|
||||
net.SendToServer()
|
||||
end
|
||||
else
|
||||
if not self.CustomWheels then
|
||||
for i = 1, table.Count( self.pp_data ) do
|
||||
local Wheel = self.pp_data[i].entity
|
||||
|
||||
if IsValid( Wheel ) then
|
||||
local addPos = Wheel:GetDamaged() and self.pp_data[i].dradius or 0
|
||||
|
||||
local Pose = (self.pp_data[i].pos - self:WorldToLocal( Wheel:GetPos()).z + addPos ) / self.pp_data[i].travel
|
||||
self:SetPoseParameter( self.pp_data[i].name, Pose )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:InvalidateBoneCache()
|
||||
end
|
||||
|
||||
function ENT:GetEnginePos()
|
||||
if isvector( self.EnginePos ) then return self:LocalToWorld( self.EnginePos ) end
|
||||
|
||||
local Attachment = self:GetAttachment( self:LookupAttachment( "vehicle_engine" ) )
|
||||
|
||||
if Attachment then return Attachment.Pos end
|
||||
|
||||
return self:GetPos()
|
||||
end
|
||||
|
||||
function ENT:GetRPM()
|
||||
local RPM = self.SmoothRPM and self.SmoothRPM or 0
|
||||
return RPM
|
||||
end
|
||||
|
||||
function ENT:DamageEffects()
|
||||
local Pos = self:GetEnginePos()
|
||||
local Scale = self:GetCurHealth() / self:GetMaxHealth()
|
||||
local smoke = self:OnSmoke() and Scale <= 0.5
|
||||
local fire = self:OnFire()
|
||||
|
||||
if self.wasSmoke ~= smoke then
|
||||
self.wasSmoke = smoke
|
||||
if smoke then
|
||||
self.smokesnd = CreateSound(self, "ambient/gas/steam2.wav")
|
||||
self.smokesnd:PlayEx(0.2,90)
|
||||
else
|
||||
if self.smokesnd then
|
||||
self.smokesnd:Stop()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.wasFire ~= fire then
|
||||
self.wasFire = fire
|
||||
if fire then
|
||||
self:EmitSound( "ambient/fire/mtov_flame2.wav" )
|
||||
|
||||
self.firesnd = CreateSound(self, "ambient/fire/fire_small1.wav")
|
||||
self.firesnd:Play()
|
||||
else
|
||||
if self.firesnd then
|
||||
self.firesnd:Stop()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if smoke then
|
||||
if Scale <= 0.5 then
|
||||
local HP = self:GetCurHealth()
|
||||
local MaxHP = self:GetMaxHealth()
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos )
|
||||
effectdata:SetEntity( self )
|
||||
effectdata:SetMagnitude( math.max(HP - MaxHP * 0.25,0) / (MaxHP * 0.25) )
|
||||
util.Effect( "simfphys_engine_smoke", effectdata )
|
||||
end
|
||||
end
|
||||
|
||||
if fire then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos )
|
||||
effectdata:SetEntity( self )
|
||||
util.Effect( "simfphys_engine_fire", effectdata )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ManageEffects( Active, fThrottle, LimitRPM )
|
||||
self:DamageEffects()
|
||||
|
||||
Active = Active and (self:GetFlyWheelRPM() ~= 0)
|
||||
if not Active then return end
|
||||
if not self.ExhaustPositions then return end
|
||||
|
||||
local Scale = fThrottle * (0.2 + math.min(self:GetRPM() / LimitRPM,1) * 0.8) ^ 2
|
||||
|
||||
for i = 1, table.Count( self.ExhaustPositions ) do
|
||||
if self.ExhaustPositions[i].OnBodyGroups then
|
||||
if self:BodyGroupIsValid( self.ExhaustPositions[i].OnBodyGroups ) then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self.ExhaustPositions[i].pos )
|
||||
effectdata:SetAngles( self.ExhaustPositions[i].ang )
|
||||
effectdata:SetMagnitude( Scale )
|
||||
effectdata:SetEntity( self )
|
||||
util.Effect( "simfphys_exhaust", effectdata )
|
||||
end
|
||||
else
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self.ExhaustPositions[i].pos )
|
||||
effectdata:SetAngles( self.ExhaustPositions[i].ang )
|
||||
effectdata:SetMagnitude( Scale )
|
||||
effectdata:SetEntity( self )
|
||||
util.Effect( "simfphys_exhaust", effectdata )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ManageSounds( Active, fThrottle, LimitRPM )
|
||||
local EngineVolume = LVS.EngineVolume
|
||||
|
||||
local FlyWheelRPM = self:GetFlyWheelRPM()
|
||||
local Active = Active and (FlyWheelRPM ~= 0)
|
||||
local IdleRPM = self:GetIdleRPM()
|
||||
|
||||
local IsCruise = self:GetIsCruiseModeOn()
|
||||
|
||||
local CurDist = (LocalPlayer():GetPos() - self:GetPos()):Length()
|
||||
local Throttle = IsCruise and math.Clamp(self:GetThrottle() ^ 3,0.01,0.7) or fThrottle
|
||||
local Gear = self:GetGear()
|
||||
local Clutch = self:GetClutch()
|
||||
local FadeRPM = LimitRPM * 0.5
|
||||
|
||||
local FT = FrameTime()
|
||||
local Rate = 3.33 * FT
|
||||
|
||||
self.FadeThrottle = self.FadeThrottle + math.Clamp(Throttle - self.FadeThrottle,-Rate,Rate)
|
||||
self.PitchOffset = self.PitchOffset + ((CurDist - self.OldDist) * 0.23 - self.PitchOffset) * 0.5
|
||||
self.OldDist = CurDist
|
||||
self.SmoothRPM = self.SmoothRPM + math.Clamp(FlyWheelRPM - self.SmoothRPM,-0.972 * FT * LimitRPM,1.66 * FT * LimitRPM)
|
||||
|
||||
self.OldThrottle2 = self.OldThrottle2 or 0
|
||||
if Throttle ~= self.OldThrottle2 then
|
||||
self.OldThrottle2 = Throttle
|
||||
if Throttle == 0 then
|
||||
if self.SmoothRPM > LimitRPM * 0.6 then
|
||||
self:Backfire()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetRevlimiter() and LimitRPM > 2500 then
|
||||
if (self.SmoothRPM >= LimitRPM - 200) and self.FadeThrottle > 0 then
|
||||
self.SmoothRPM = self.SmoothRPM - 0.2 * LimitRPM
|
||||
self.FadeThrottle = 0.2
|
||||
self:Backfire()
|
||||
end
|
||||
end
|
||||
|
||||
if Active ~= self.OldActive then
|
||||
local preset = self:GetEngineSoundPreset()
|
||||
local UseGearResetter = self:SetSoundPreset( preset )
|
||||
|
||||
self.SoundMode = UseGearResetter and 2 or 1
|
||||
|
||||
self.OldActive = Active
|
||||
|
||||
if Active then
|
||||
local MaxHealth = self:GetMaxHealth()
|
||||
local Health = self:GetCurHealth()
|
||||
|
||||
if Health <= (MaxHealth * 0.6) then
|
||||
self.DamageSnd:PlayEx(0,0)
|
||||
end
|
||||
|
||||
if self.SoundMode == 2 then
|
||||
self.HighRPM = CreateSound(self, self.EngineSounds[ "HighRPM" ] )
|
||||
self.LowRPM = CreateSound(self, self.EngineSounds[ "LowRPM" ])
|
||||
self.Idle = CreateSound(self, self.EngineSounds[ "Idle" ])
|
||||
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
self.LowRPM:PlayEx(0,0)
|
||||
self.Idle:PlayEx(0,0)
|
||||
else
|
||||
local IdleSound = self.EngineSounds[ "IdleSound" ]
|
||||
local LowSound = self.EngineSounds[ "LowSound" ]
|
||||
local HighSound = self.EngineSounds[ "HighSound" ]
|
||||
local ThrottleSound = self.EngineSounds[ "ThrottleSound" ]
|
||||
|
||||
if IdleSound then
|
||||
self.Idle = CreateSound(self, IdleSound)
|
||||
self.Idle:PlayEx(0,0)
|
||||
end
|
||||
|
||||
if LowSound then
|
||||
self.LowRPM = CreateSound(self, LowSound)
|
||||
self.LowRPM:PlayEx(0,0)
|
||||
end
|
||||
|
||||
if HighSound then
|
||||
self.HighRPM = CreateSound(self, HighSound)
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
end
|
||||
|
||||
if ThrottleSound then
|
||||
self.Valves = CreateSound(self, ThrottleSound)
|
||||
self.Valves:PlayEx(0,0)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:SaveStopSounds()
|
||||
end
|
||||
end
|
||||
|
||||
if Active then
|
||||
local Volume = 0.25 + 0.25 * ((self.SmoothRPM / LimitRPM) ^ 1.5) + self.FadeThrottle * 0.5
|
||||
local Pitch = math.Clamp( (20 + self.SmoothRPM / 50 - self.PitchOffset) * self.PitchMulAll,0,255)
|
||||
|
||||
if self.DamageSnd then
|
||||
self.DamageSnd:ChangeVolume( ((self.SmoothRPM / LimitRPM) * 0.6 ^ 1.5) * EngineVolume )
|
||||
self.DamageSnd:ChangePitch( 100 )
|
||||
end
|
||||
|
||||
if self.SoundMode == 2 then
|
||||
if self.FadeThrottle ~= self.OldThrottle then
|
||||
self.OldThrottle = self.FadeThrottle
|
||||
if self.FadeThrottle == 0 and Clutch == 0 then
|
||||
if self.SmoothRPM >= FadeRPM then
|
||||
if IsCruise ~= true then
|
||||
if self.LowRPM then
|
||||
self.LowRPM:Stop()
|
||||
end
|
||||
self.LowRPM = CreateSound(self, self.EngineSounds[ "RevDown" ] )
|
||||
self.LowRPM:PlayEx(0,0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Gear ~= self.OldGear then
|
||||
if self.SmoothRPM >= FadeRPM and Gear > 3 then
|
||||
if Clutch ~= 1 then
|
||||
if self.OldGear < Gear then
|
||||
if self.HighRPM then
|
||||
self.HighRPM:Stop()
|
||||
end
|
||||
|
||||
self.HighRPM = CreateSound(self, self.EngineSounds[ "ShiftUpToHigh" ] )
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
|
||||
if self.SmoothRPM > LimitRPM * 0.6 then
|
||||
if math.random(0,4) >= 3 then
|
||||
timer.Simple(0.4, function()
|
||||
if not IsValid( self ) then return end
|
||||
self:Backfire()
|
||||
end)
|
||||
end
|
||||
end
|
||||
else
|
||||
if self.FadeThrottle > 0 then
|
||||
if self.HighRPM then
|
||||
self.HighRPM:Stop()
|
||||
end
|
||||
|
||||
self.HighRPM = CreateSound(self, self.EngineSounds[ "ShiftDownToHigh" ] )
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if Clutch ~= 1 then
|
||||
if self.OldGear > Gear and self.FadeThrottle > 0 and Gear >= 3 then
|
||||
if self.HighRPM then
|
||||
self.HighRPM:Stop()
|
||||
end
|
||||
|
||||
self.HighRPM = CreateSound(self, self.EngineSounds[ "ShiftDownToHigh" ] )
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
else
|
||||
if self.HighRPM then
|
||||
self.HighRPM:Stop()
|
||||
end
|
||||
|
||||
if self.LowRPM then
|
||||
self.LowRPM:Stop()
|
||||
end
|
||||
|
||||
self.HighRPM = CreateSound(self, self.EngineSounds[ "HighRPM" ] )
|
||||
self.LowRPM = CreateSound(self, self.EngineSounds[ "LowRPM" ])
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
self.LowRPM:PlayEx(0,0)
|
||||
end
|
||||
end
|
||||
end
|
||||
self.OldGear = Gear
|
||||
end
|
||||
|
||||
self.Idle:ChangeVolume( math.Clamp( math.min((self.SmoothRPM / IdleRPM) * 3,1.5 + self.FadeThrottle * 0.5) * 0.7 - self.SmoothRPM / 2000 ,0,1) * EngineVolume )
|
||||
self.Idle:ChangePitch( math.Clamp( Pitch * 3,0,255) )
|
||||
|
||||
self.LowRPM:ChangeVolume( math.Clamp(Volume - (self.SmoothRPM - 2000) / 2000 * self.FadeThrottle,0,1) * EngineVolume )
|
||||
self.LowRPM:ChangePitch( math.Clamp( Pitch * self.PitchMulLow,0,255) )
|
||||
|
||||
local hivol = math.max((self.SmoothRPM - 2000) / 2000,0) * Volume
|
||||
self.HighRPM:ChangeVolume( (self.FadeThrottle < 0.4 and hivol * self.FadeThrottle or hivol * self.FadeThrottle * 2.5) * EngineVolume )
|
||||
self.HighRPM:ChangePitch( math.Clamp( Pitch * self.PitchMulHigh,0,255) )
|
||||
else
|
||||
if Gear ~= self.OldGear then
|
||||
if self.SmoothRPM >= FadeRPM and Gear > 3 then
|
||||
if Clutch ~= 1 then
|
||||
if self.OldGear < Gear then
|
||||
if self.SmoothRPM > LimitRPM * 0.6 then
|
||||
if math.random(0,4) >= 3 then
|
||||
timer.Simple(0.4, function()
|
||||
if not IsValid( self ) then return end
|
||||
self:Backfire()
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self.OldGear = Gear
|
||||
end
|
||||
|
||||
|
||||
local IdlePitch = self.Idle_PitchMul
|
||||
self.Idle:ChangeVolume( math.Clamp( math.min((self.SmoothRPM / IdleRPM) * 3,1.5 + self.FadeThrottle * 0.5) * 0.7 - self.SmoothRPM / 2000,0,1) * EngineVolume )
|
||||
self.Idle:ChangePitch( math.Clamp( Pitch * 3 * IdlePitch,0,255) )
|
||||
|
||||
local LowPitch = self.Mid_PitchMul
|
||||
local LowVolume = self.Mid_VolumeMul
|
||||
local LowFadeOutRPM = LimitRPM * (self.Mid_FadeOutRPMpercent / 100)
|
||||
local LowFadeOutRate = LimitRPM * self.Mid_FadeOutRate
|
||||
self.LowRPM:ChangeVolume( math.Clamp( (Volume - math.Clamp((self.SmoothRPM - LowFadeOutRPM) / LowFadeOutRate,0,1)) * LowVolume,0,1) * EngineVolume )
|
||||
self.LowRPM:ChangePitch( math.Clamp(Pitch * LowPitch,0,255) )
|
||||
|
||||
local HighPitch = self.High_PitchMul
|
||||
local HighVolume = self.High_VolumeMul
|
||||
local HighFadeInRPM = LimitRPM * (self.High_FadeInRPMpercent / 100)
|
||||
local HighFadeInRate = LimitRPM * self.High_FadeInRate
|
||||
self.HighRPM:ChangeVolume( math.Clamp( math.Clamp((self.SmoothRPM - HighFadeInRPM) / HighFadeInRate,0,Volume) * HighVolume,0,1) * EngineVolume)
|
||||
self.HighRPM:ChangePitch( math.Clamp(Pitch * HighPitch,0,255) )
|
||||
|
||||
local ThrottlePitch = self.Throttle_PitchMul
|
||||
local ThrottleVolume = self.Throttle_VolumeMul
|
||||
self.Valves:ChangeVolume( math.Clamp((self.SmoothRPM - 2000) / 2000,0,Volume) * (0.2 + 0.15 * self.FadeThrottle) * ThrottleVolume * EngineVolume )
|
||||
self.Valves:ChangePitch( math.Clamp(Pitch * ThrottlePitch,0,255) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Backfire( damaged )
|
||||
if not self:GetBackFire() and not damaged then return end
|
||||
|
||||
if not self.ExhaustPositions then return end
|
||||
|
||||
local expos = self.ExhaustPositions
|
||||
|
||||
for i = 1, table.Count( expos ) do
|
||||
if math.random(1,3) >= 2 or damaged then
|
||||
local Pos = expos[i].pos
|
||||
local Ang = expos[i].ang - Angle(90,0,0)
|
||||
|
||||
if expos[i].OnBodyGroups then
|
||||
if self:BodyGroupIsValid( expos[i].OnBodyGroups ) then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos )
|
||||
effectdata:SetAngles( Ang )
|
||||
effectdata:SetEntity( self )
|
||||
effectdata:SetFlags( damaged and 1 or 0 )
|
||||
util.Effect( "simfphys_backfire", effectdata )
|
||||
end
|
||||
else
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos )
|
||||
effectdata:SetAngles( Ang )
|
||||
effectdata:SetEntity( self )
|
||||
effectdata:SetFlags( damaged and 1 or 0 )
|
||||
util.Effect( "simfphys_backfire", effectdata )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:SetSoundPreset(index)
|
||||
if index == -1 then
|
||||
local soundoverride = self:GetSoundoverride()
|
||||
local data = string.Explode( ",", soundoverride)
|
||||
|
||||
if soundoverride ~= "" and data[1] == "1" then
|
||||
|
||||
self.EngineSounds[ "Idle" ] = data[4]
|
||||
self.EngineSounds[ "LowRPM" ] = data[6]
|
||||
self.EngineSounds[ "HighRPM" ] = data[2]
|
||||
self.EngineSounds[ "RevDown" ] = data[8]
|
||||
self.EngineSounds[ "ShiftUpToHigh" ] = data[10]
|
||||
self.EngineSounds[ "ShiftDownToHigh" ] = data[9]
|
||||
|
||||
self.PitchMulLow = data[7]
|
||||
self.PitchMulHigh = data[3]
|
||||
self.PitchMulAll = data[5]
|
||||
else
|
||||
local idle = self.snd_idle or ""
|
||||
local low = self.snd_low or ""
|
||||
local mid = self.snd_mid or ""
|
||||
local revdown = self.snd_low_revdown or ""
|
||||
local gearup = self.snd_mid_gearup or ""
|
||||
local geardown = self.snd_mid_geardown or ""
|
||||
|
||||
self.EngineSounds[ "Idle" ] = idle ~= "" and idle or false
|
||||
self.EngineSounds[ "LowRPM" ] = low ~= "" and low or false
|
||||
self.EngineSounds[ "HighRPM" ] = mid ~= "" and mid or false
|
||||
self.EngineSounds[ "RevDown" ] = revdown ~= "" and revdown or low
|
||||
self.EngineSounds[ "ShiftUpToHigh" ] = gearup ~= "" and gearup or mid
|
||||
self.EngineSounds[ "ShiftDownToHigh" ] = geardown ~= "" and geardown or gearup
|
||||
|
||||
self.PitchMulLow = self.snd_low_pitch or 1
|
||||
self.PitchMulHigh = self.snd_mid_pitch or 1
|
||||
self.PitchMulAll = self.snd_pitch or 1
|
||||
end
|
||||
|
||||
if self.EngineSounds[ "Idle" ] ~= false and self.EngineSounds[ "LowRPM" ] ~= false and self.EngineSounds[ "HighRPM" ] ~= false then
|
||||
return true
|
||||
else
|
||||
self:SetSoundPreset( 0 )
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if index == 0 then
|
||||
local soundoverride = self:GetSoundoverride()
|
||||
local data = string.Explode( ",", soundoverride)
|
||||
|
||||
if soundoverride ~= "" and data[1] ~= "1" then
|
||||
self.EngineSounds[ "IdleSound" ] = data[1]
|
||||
self.Idle_PitchMul = data[2]
|
||||
|
||||
self.EngineSounds[ "LowSound" ] = data[3]
|
||||
self.Mid_PitchMul = data[4]
|
||||
self.Mid_VolumeMul = data[5]
|
||||
self.Mid_FadeOutRPMpercent = data[6]
|
||||
self.Mid_FadeOutRate = data[7]
|
||||
|
||||
self.EngineSounds[ "HighSound" ] = data[8]
|
||||
self.High_PitchMul = data[9]
|
||||
self.High_VolumeMul = data[10]
|
||||
self.High_FadeInRPMpercent = data[11]
|
||||
self.High_FadeInRate = data[12]
|
||||
|
||||
self.EngineSounds[ "ThrottleSound" ] = data[13]
|
||||
self.Throttle_PitchMul = data[14]
|
||||
self.Throttle_VolumeMul = data[15]
|
||||
else
|
||||
self.EngineSounds[ "IdleSound" ] = self.Sound_Idle or "simulated_vehicles/misc/e49_idle.wav"
|
||||
self.Idle_PitchMul = self.Sound_IdlePitch or 1
|
||||
|
||||
self.EngineSounds[ "LowSound" ] = self.Sound_Mid or "simulated_vehicles/misc/gto_onlow.wav"
|
||||
self.Mid_PitchMul = self.Sound_MidPitch or 1
|
||||
self.Mid_VolumeMul = self.Sound_MidVolume or 0.75
|
||||
self.Mid_FadeOutRPMpercent = self.Sound_MidFadeOutRPMpercent or 68
|
||||
self.Mid_FadeOutRate = self.Sound_MidFadeOutRate or 0.4
|
||||
|
||||
self.EngineSounds[ "HighSound" ] = self.Sound_High or "simulated_vehicles/misc/nv2_onlow_ex.wav"
|
||||
self.High_PitchMul = self.Sound_HighPitch or 1
|
||||
self.High_VolumeMul = self.Sound_HighVolume or 1
|
||||
self.High_FadeInRPMpercent = self.Sound_HighFadeInRPMpercent or 26.6
|
||||
self.High_FadeInRate = self.Sound_HighFadeInRate or 0.266
|
||||
|
||||
self.EngineSounds[ "ThrottleSound" ] = self.Sound_Throttle or "simulated_vehicles/valve_noise.wav"
|
||||
self.Throttle_PitchMul = self.Sound_ThrottlePitch or 0.65
|
||||
self.Throttle_VolumeMul = self.Sound_ThrottleVolume or 1
|
||||
end
|
||||
|
||||
self.PitchMulLow = 1
|
||||
self.PitchMulHigh = 1
|
||||
self.PitchMulAll = 1
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if index > 0 then
|
||||
local clampindex = math.Clamp(index,1,table.Count(simfphys.SoundPresets))
|
||||
self.EngineSounds[ "Idle" ] = simfphys.SoundPresets[clampindex][1]
|
||||
self.EngineSounds[ "LowRPM" ] = simfphys.SoundPresets[clampindex][2]
|
||||
self.EngineSounds[ "HighRPM" ] = simfphys.SoundPresets[clampindex][3]
|
||||
self.EngineSounds[ "RevDown" ] = simfphys.SoundPresets[clampindex][4]
|
||||
self.EngineSounds[ "ShiftUpToHigh" ] = simfphys.SoundPresets[clampindex][5]
|
||||
self.EngineSounds[ "ShiftDownToHigh" ] = simfphys.SoundPresets[clampindex][6]
|
||||
|
||||
self.PitchMulLow = simfphys.SoundPresets[clampindex][7]
|
||||
self.PitchMulHigh = simfphys.SoundPresets[clampindex][8]
|
||||
self.PitchMulAll = simfphys.SoundPresets[clampindex][9]
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:GetVehicleInfo()
|
||||
return self.VehicleInfo
|
||||
end
|
||||
|
||||
function ENT:SaveStopSounds()
|
||||
if self.HighRPM then
|
||||
self.HighRPM:Stop()
|
||||
end
|
||||
|
||||
if self.LowRPM then
|
||||
self.LowRPM:Stop()
|
||||
end
|
||||
|
||||
if self.Idle then
|
||||
self.Idle:Stop()
|
||||
end
|
||||
|
||||
if self.Valves then
|
||||
self.Valves:Stop()
|
||||
end
|
||||
|
||||
if self.DamageSnd then
|
||||
self.DamageSnd:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:StopFireSound()
|
||||
if self.smokesnd then
|
||||
self.smokesnd:Stop()
|
||||
end
|
||||
|
||||
if self.firesnd then
|
||||
self.firesnd:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:SaveStopSounds()
|
||||
self:StopFireSound()
|
||||
self:TireSoundRemove()
|
||||
end
|
||||
@@ -0,0 +1,91 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
ENT.TireSoundFade = 0.15
|
||||
ENT.TireSoundTypes = {
|
||||
["roll"] = "simulated_vehicles/sfx/wheel_roll.wav",
|
||||
["roll_dirt"] = "simulated_vehicles/sfx/wheel_roll_dirt.wav",
|
||||
["roll_wet"] = "simulated_vehicles/sfx/wheel_roll_wet.wav",
|
||||
["roll_damaged"] = "simulated_vehicles/sfx/tire_damaged.wav",
|
||||
["skid"] = "simulated_vehicles/sfx/wheel_skid.wav",
|
||||
["skid_dirt"] = "simulated_vehicles/sfx/wheel_skid_dirt.wav",
|
||||
["skid_wet"] = "simulated_vehicles/sfx/wheel_skid_wet.wav",
|
||||
}
|
||||
ENT.TireSoundLevelSkid = 85
|
||||
ENT.TireSoundLevelRoll = 75
|
||||
|
||||
function ENT:TireSoundRemove()
|
||||
for snd, _ in pairs( self.TireSoundTypes ) do
|
||||
self:StopTireSound( snd )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:TireSoundThink()
|
||||
for snd, _ in pairs( self.TireSoundTypes ) do
|
||||
local T = self:GetTireSoundTime( snd )
|
||||
|
||||
if T > 0 then
|
||||
local speed = self:GetVelocity():Length()
|
||||
|
||||
local sound = self:StartTireSound( snd )
|
||||
|
||||
if string.StartsWith( snd, "skid" ) then
|
||||
local vel = speed
|
||||
speed = math.max( math.abs( self:GetWheelVelocity() ) - vel, 0 ) * 5 + vel
|
||||
end
|
||||
|
||||
local volume = math.min(speed / 1000,1) ^ 2 * T
|
||||
local pitch = 100 + math.Clamp((speed - 400) / 200,0,155)
|
||||
|
||||
sound:ChangeVolume( volume, 0 )
|
||||
sound:ChangePitch( pitch, 0.5 )
|
||||
else
|
||||
self:StopTireSound( snd )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoTireSound( snd )
|
||||
if not istable( self._TireSounds ) then
|
||||
self._TireSounds = {}
|
||||
end
|
||||
|
||||
self._TireSounds[ snd ] = CurTime() + self.TireSoundFade
|
||||
end
|
||||
|
||||
function ENT:GetTireSoundTime( snd )
|
||||
if not istable( self._TireSounds ) or not self._TireSounds[ snd ] then return 0 end
|
||||
|
||||
return math.max(self._TireSounds[ snd ] - CurTime(),0) / self.TireSoundFade
|
||||
end
|
||||
|
||||
function ENT:StartTireSound( snd )
|
||||
if not self.TireSoundTypes[ snd ] or not istable( self._ActiveTireSounds ) then
|
||||
self._ActiveTireSounds = {}
|
||||
end
|
||||
|
||||
if self._ActiveTireSounds[ snd ] then return self._ActiveTireSounds[ snd ] end
|
||||
|
||||
local sound = CreateSound( self, self.TireSoundTypes[ snd ] )
|
||||
sound:SetSoundLevel( string.StartsWith( snd, "skid" ) and self.TireSoundLevelSkid or self.TireSoundLevelRoll )
|
||||
sound:PlayEx(0,100)
|
||||
|
||||
self._ActiveTireSounds[ snd ] = sound
|
||||
|
||||
return sound
|
||||
end
|
||||
|
||||
function ENT:StopTireSound( snd )
|
||||
if not istable( self._ActiveTireSounds ) or not self._ActiveTireSounds[ snd ] then return end
|
||||
|
||||
self._ActiveTireSounds[ snd ]:Stop()
|
||||
self._ActiveTireSounds[ snd ] = nil
|
||||
end
|
||||
314
lua/entities/gmod_sent_vehicle_fphysics_base/damage.lua
Normal file
314
lua/entities/gmod_sent_vehicle_fphysics_base/damage.lua
Normal file
@@ -0,0 +1,314 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
ENT.DSArmorDamageReduction = 1
|
||||
ENT.DSArmorDamageReductionType = DMG_GENERIC
|
||||
|
||||
ENT.DSArmorIgnoreDamageType = DMG_GENERIC
|
||||
|
||||
function ENT:ApplyDamage( damage, type )
|
||||
if type == DMG_BLAST then
|
||||
damage = damage * 10
|
||||
end
|
||||
|
||||
if type == DMG_BULLET then
|
||||
damage = damage * 2
|
||||
end
|
||||
|
||||
local MaxHealth = self:GetMaxHealth()
|
||||
local CurHealth = self:GetCurHealth()
|
||||
|
||||
local NewHealth = math.max( math.Round(CurHealth - damage,0) , 0 )
|
||||
|
||||
if NewHealth <= (MaxHealth * 0.6) then
|
||||
if NewHealth <= (MaxHealth * 0.3) then
|
||||
self:SetOnFire( true )
|
||||
self:SetOnSmoke( false )
|
||||
else
|
||||
self:SetOnSmoke( true )
|
||||
end
|
||||
end
|
||||
|
||||
if MaxHealth > 30 and NewHealth <= 31 then
|
||||
if self:EngineActive() then
|
||||
self:DamagedStall()
|
||||
end
|
||||
end
|
||||
|
||||
if NewHealth <= 0 then
|
||||
|
||||
self:ExplodeVehicle()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:SetCurHealth( NewHealth )
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
if not self:IsInitialized() then return end
|
||||
|
||||
if dmginfo:IsDamageType( self.DSArmorIgnoreDamageType ) then return end
|
||||
|
||||
if dmginfo:IsDamageType( self.DSArmorDamageReductionType ) then
|
||||
if dmginfo:GetDamage() ~= 0 then
|
||||
dmginfo:ScaleDamage( self.DSArmorDamageReduction )
|
||||
|
||||
dmginfo:SetDamage( math.max(dmginfo:GetDamage(),1) )
|
||||
end
|
||||
end
|
||||
|
||||
if dmginfo:IsDamageType( DMG_BLAST ) then
|
||||
local Inflictor = dmginfo:GetInflictor()
|
||||
|
||||
if IsValid( Inflictor ) and isfunction( Inflictor.GetEntityFilter ) then
|
||||
for ents, _ in pairs( Inflictor:GetEntityFilter() ) do
|
||||
if ents == self then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local dmgPartsTableOK = true
|
||||
|
||||
if istable( self._dmgParts ) then
|
||||
for _, part in pairs( self._dmgParts ) do
|
||||
if isvector( part.mins ) and isvector( part.maxs ) and isvector( part.pos ) and isangle( part.ang ) then continue end
|
||||
|
||||
dmgPartsTableOK = false
|
||||
|
||||
break
|
||||
end
|
||||
else
|
||||
dmgPartsTableOK = false
|
||||
end
|
||||
|
||||
local CriticalHit = false
|
||||
|
||||
if dmgPartsTableOK then
|
||||
CriticalHit = self:CalcComponentDamage( dmginfo )
|
||||
else
|
||||
print("[LVS] - "..self:GetSpawn_List().." is doing something it shouldn't! DS part has been detected but was registered incorrectly!")
|
||||
end
|
||||
|
||||
if hook.Run( "simfphysOnTakeDamage", self, dmginfo ) then return end
|
||||
|
||||
local Damage = dmginfo:GetDamage()
|
||||
local DamagePos = dmginfo:GetDamagePosition()
|
||||
local Type = dmginfo:GetDamageType()
|
||||
local Driver = self:GetDriver()
|
||||
|
||||
self.LastAttacker = dmginfo:GetAttacker()
|
||||
self.LastInflictor = dmginfo:GetInflictor()
|
||||
|
||||
if simfphys.DamageEnabled then
|
||||
net.Start( "simfphys_spritedamage" )
|
||||
net.WriteEntity( self )
|
||||
net.WriteVector( self:WorldToLocal( DamagePos ) )
|
||||
net.WriteBool( false )
|
||||
net.Broadcast()
|
||||
|
||||
if Type == DMG_AIRBOAT then
|
||||
Type = DMG_DIRECT
|
||||
Damage = Damage * 6
|
||||
end
|
||||
|
||||
local oldHP = self:GetCurHealth()
|
||||
|
||||
self:ApplyDamage( Damage, Type )
|
||||
|
||||
local newHP = self:GetCurHealth()
|
||||
|
||||
if oldHP ~= newHP then
|
||||
local IsFireDamage = dmginfo:IsDamageType( DMG_BURN )
|
||||
|
||||
if IsValid( self.LastAttacker ) and self.LastAttacker:IsPlayer() and not IsFireDamage then
|
||||
net.Start( "lvs_hitmarker" )
|
||||
net.WriteBool( CriticalHit )
|
||||
net.Send( self.LastAttacker )
|
||||
end
|
||||
|
||||
if Damage > 1 and not IsFireDamage then
|
||||
net.Start( "lvs_hurtmarker" )
|
||||
net.WriteFloat( math.min( Damage / 50, 1 ) )
|
||||
net.Send( self:GetEveryone() )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ExplodeVehicle()
|
||||
if not IsValid( self ) then return end
|
||||
|
||||
if self.destroyed then return end
|
||||
|
||||
self.destroyed = true
|
||||
|
||||
local Attacker = self.LastAttacker
|
||||
|
||||
if IsValid( Attacker ) and Attacker:IsPlayer() then
|
||||
net.Start( "lvs_killmarker" )
|
||||
net.Send( Attacker )
|
||||
end
|
||||
|
||||
local GibMDL = self.GibModels
|
||||
self.GibModels = nil
|
||||
|
||||
self:OnFinishExplosion()
|
||||
|
||||
self.GibModels = GibMDL
|
||||
GibMDL = nil
|
||||
|
||||
local ply = self.EntityOwner
|
||||
local skin = self:GetSkin()
|
||||
local Col = self:GetColor()
|
||||
Col.r = Col.r * 0.8
|
||||
Col.g = Col.g * 0.8
|
||||
Col.b = Col.b * 0.8
|
||||
|
||||
local Driver = self:GetDriver()
|
||||
if IsValid( Driver ) then
|
||||
if self.RemoteDriver ~= Driver then
|
||||
local dmginfo = DamageInfo()
|
||||
dmginfo:SetDamage( Driver:Health() + Driver:Armor() )
|
||||
dmginfo:SetAttacker( self.LastAttacker or game.GetWorld() )
|
||||
dmginfo:SetInflictor( self.LastInflictor or game.GetWorld() )
|
||||
dmginfo:SetDamageType( DMG_DIRECT )
|
||||
|
||||
Driver:TakeDamageInfo( dmginfo )
|
||||
end
|
||||
end
|
||||
|
||||
if self.PassengerSeats then
|
||||
for i = 1, table.Count( self.PassengerSeats ) do
|
||||
local Passenger = self.pSeat[i]:GetDriver()
|
||||
if IsValid( Passenger ) then
|
||||
local dmginfo = DamageInfo()
|
||||
dmginfo:SetDamage( Passenger:Health() + Passenger:Armor() )
|
||||
dmginfo:SetAttacker( self.LastAttacker or game.GetWorld() )
|
||||
dmginfo:SetInflictor( self.LastInflictor or game.GetWorld() )
|
||||
dmginfo:SetDamageType( DMG_DIRECT )
|
||||
|
||||
Passenger:TakeDamageInfo( dmginfo )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.GibModels then
|
||||
local bprop = ents.Create( "gmod_sent_vehicle_fphysics_gib" )
|
||||
bprop:SetModel( self.GibModels[1] )
|
||||
bprop:SetPos( self:GetPos() )
|
||||
bprop:SetAngles( self:GetAngles() )
|
||||
bprop.MakeSound = true
|
||||
bprop:Spawn()
|
||||
bprop:Activate()
|
||||
bprop:GetPhysicsObject():SetVelocity( self:GetVelocity() + Vector(math.random(-5,5),math.random(-5,5),math.random(150,250)) )
|
||||
bprop:GetPhysicsObject():SetMass( self.Mass * 0.75 )
|
||||
bprop.DoNotDuplicate = true
|
||||
bprop:SetColor( Col )
|
||||
bprop:SetSkin( skin )
|
||||
|
||||
self.Gib = bprop
|
||||
|
||||
simfphys.SetOwner( ply , bprop )
|
||||
|
||||
if IsValid( ply ) then
|
||||
undo.Create( "Gib" )
|
||||
undo.SetPlayer( ply )
|
||||
undo.AddEntity( bprop )
|
||||
undo.SetCustomUndoText( "Undone Gib" )
|
||||
undo.Finish( "Gib" )
|
||||
ply:AddCleanup( "Gibs", bprop )
|
||||
end
|
||||
|
||||
bprop.Gibs = {}
|
||||
for i = 2, table.Count( self.GibModels ) do
|
||||
local prop = ents.Create( "gmod_sent_vehicle_fphysics_gib" )
|
||||
prop:SetModel( self.GibModels[i] )
|
||||
prop:SetPos( self:GetPos() )
|
||||
prop:SetAngles( self:GetAngles() )
|
||||
prop:SetOwner( bprop )
|
||||
prop:Spawn()
|
||||
prop:Activate()
|
||||
prop.DoNotDuplicate = true
|
||||
bprop:DeleteOnRemove( prop )
|
||||
bprop.Gibs[i-1] = prop
|
||||
|
||||
local PhysObj = prop:GetPhysicsObject()
|
||||
if IsValid( PhysObj ) then
|
||||
PhysObj:SetVelocityInstantaneous( VectorRand() * 500 + self:GetVelocity() + Vector(0,0,math.random(150,250)) )
|
||||
PhysObj:AddAngleVelocity( VectorRand() )
|
||||
end
|
||||
|
||||
|
||||
simfphys.SetOwner( ply , prop )
|
||||
end
|
||||
else
|
||||
|
||||
local bprop = ents.Create( "gmod_sent_vehicle_fphysics_gib" )
|
||||
bprop:SetModel( self:GetModel() )
|
||||
bprop:SetPos( self:GetPos() )
|
||||
bprop:SetAngles( self:GetAngles() )
|
||||
bprop.MakeSound = true
|
||||
bprop:Spawn()
|
||||
bprop:Activate()
|
||||
bprop:GetPhysicsObject():SetVelocity( self:GetVelocity() + Vector(math.random(-5,5),math.random(-5,5),math.random(150,250)) )
|
||||
bprop:GetPhysicsObject():SetMass( self.Mass * 0.75 )
|
||||
bprop.DoNotDuplicate = true
|
||||
bprop:SetColor( Col )
|
||||
bprop:SetSkin( skin )
|
||||
for i = 0, self:GetNumBodyGroups() do
|
||||
bprop:SetBodygroup(i, self:GetBodygroup(i))
|
||||
end
|
||||
|
||||
self.Gib = bprop
|
||||
|
||||
simfphys.SetOwner( ply , bprop )
|
||||
|
||||
if IsValid( ply ) then
|
||||
undo.Create( "Gib" )
|
||||
undo.SetPlayer( ply )
|
||||
undo.AddEntity( bprop )
|
||||
undo.SetCustomUndoText( "Undone Gib" )
|
||||
undo.Finish( "Gib" )
|
||||
ply:AddCleanup( "Gibs", bprop )
|
||||
end
|
||||
|
||||
if self.CustomWheels == true and not self.NoWheelGibs then
|
||||
bprop.Wheels = {}
|
||||
for i = 1, table.Count( self.GhostWheels ) do
|
||||
local Wheel = self.GhostWheels[i]
|
||||
if IsValid(Wheel) then
|
||||
local prop = ents.Create( "gmod_sent_vehicle_fphysics_gib" )
|
||||
prop:SetModel( Wheel:GetModel() )
|
||||
prop:SetPos( Wheel:LocalToWorld( Vector(0,0,0) ) )
|
||||
prop:SetAngles( Wheel:LocalToWorldAngles( Angle(0,0,0) ) )
|
||||
prop:SetOwner( bprop )
|
||||
prop:Spawn()
|
||||
prop:Activate()
|
||||
prop:GetPhysicsObject():SetVelocity( self:GetVelocity() + Vector(math.random(-5,5),math.random(-5,5),math.random(0,25)) )
|
||||
prop:GetPhysicsObject():SetMass( 20 )
|
||||
prop.DoNotDuplicate = true
|
||||
bprop:DeleteOnRemove( prop )
|
||||
bprop.Wheels[i] = prop
|
||||
|
||||
simfphys.SetOwner( ply , prop )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:Extinguish()
|
||||
|
||||
self:OnDestroyed()
|
||||
|
||||
hook.Run( "simfphysOnDestroyed", self, self.Gib )
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
1428
lua/entities/gmod_sent_vehicle_fphysics_base/init.lua
Normal file
1428
lua/entities/gmod_sent_vehicle_fphysics_base/init.lua
Normal file
File diff suppressed because it is too large
Load Diff
317
lua/entities/gmod_sent_vehicle_fphysics_base/numpads.lua
Normal file
317
lua/entities/gmod_sent_vehicle_fphysics_base/numpads.lua
Normal file
@@ -0,0 +1,317 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
numpad.Register( "k_forward", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["W"] = keydown
|
||||
end
|
||||
|
||||
if keydown and ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_reverse", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["S"] = keydown
|
||||
end
|
||||
|
||||
if keydown and ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_left", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["A"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_right", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["D"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_a_forward", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["aW"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_a_reverse", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["aS"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_a_left", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if (ent.PressedKeys) then
|
||||
ent.PressedKeys["aA"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_a_right", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["aD"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_gup", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
if not pl:lvsGetInputEnabled() then keydown = false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["M1"] = keydown
|
||||
end
|
||||
|
||||
if keydown and ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_gdn", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
if not pl:lvsGetInputEnabled() then keydown = false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["M2"] = keydown
|
||||
end
|
||||
|
||||
if keydown and ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_wot", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["Shift"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_clutch", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["Alt"] = keydown
|
||||
end
|
||||
end )
|
||||
numpad.Register( "k_hbrk", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["Space"] = keydown
|
||||
end
|
||||
|
||||
if keydown and ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_ccon", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if keydown then
|
||||
if ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
else
|
||||
ent:SetIsCruiseModeOn( true )
|
||||
ent.cc_speed = math.Round(ent:GetVelocity():Length(),0)
|
||||
end
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_hrn", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
ent.KeyPressedTime = isnumber( ent.KeyPressedTime ) and ent.KeyPressedTime or 0
|
||||
|
||||
local v_list = list.Get( "simfphys_lights" )[ent.LightsTable] or false
|
||||
|
||||
if keydown then
|
||||
ent.HornKeyIsDown = true
|
||||
|
||||
if v_list and v_list.ems_sounds then
|
||||
if not ent.emson then
|
||||
timer.Simple( 0.1, function()
|
||||
if not IsValid(ent) or not ent.HornKeyIsDown then return end
|
||||
|
||||
if not ent.horn then
|
||||
ent.horn = CreateSound(ent, ent.snd_horn or "simulated_vehicles/horn_1.wav")
|
||||
ent.horn:PlayEx(0,100)
|
||||
end
|
||||
end)
|
||||
end
|
||||
else
|
||||
if not ent.horn then
|
||||
ent.horn = CreateSound(ent, ent.snd_horn or "simulated_vehicles/horn_1.wav")
|
||||
ent.horn:PlayEx(0,100)
|
||||
end
|
||||
end
|
||||
else
|
||||
ent.HornKeyIsDown = false
|
||||
end
|
||||
|
||||
if not v_list then return end
|
||||
|
||||
if v_list.ems_sounds then
|
||||
|
||||
local Time = CurTime()
|
||||
|
||||
if keydown then
|
||||
ent.KeyPressedTime = Time
|
||||
else
|
||||
if (Time - ent.KeyPressedTime) < 0.15 then
|
||||
if not ent.emson then
|
||||
ent.emson = true
|
||||
ent.cursound = 0
|
||||
end
|
||||
end
|
||||
|
||||
if (Time - ent.KeyPressedTime) >= 0.22 then
|
||||
if ent.emson then
|
||||
ent.emson = false
|
||||
if ent.ems then
|
||||
ent.ems:Stop()
|
||||
end
|
||||
end
|
||||
else
|
||||
if ent.emson then
|
||||
if ent.ems then ent.ems:Stop() end
|
||||
local sounds = v_list.ems_sounds
|
||||
local numsounds = table.Count( sounds )
|
||||
|
||||
if numsounds <= 1 and ent.ems then
|
||||
ent.emson = false
|
||||
ent.ems = nil
|
||||
ent:SetEMSEnabled( false )
|
||||
return
|
||||
end
|
||||
|
||||
ent.cursound = ent.cursound + 1
|
||||
if ent.cursound > table.Count( sounds ) then
|
||||
ent.cursound = 1
|
||||
end
|
||||
|
||||
ent.ems = CreateSound(ent, sounds[ent.cursound])
|
||||
ent.ems:Play()
|
||||
end
|
||||
end
|
||||
ent:SetEMSEnabled( ent.emson )
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
numpad.Register( "k_eng", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if keydown then
|
||||
if ent:EngineActive() then
|
||||
ent:StopEngine()
|
||||
else
|
||||
ent:StartEngine( true )
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
numpad.Register( "k_flgts", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) or not ent.LightsTable then return false end
|
||||
|
||||
if keydown then
|
||||
ent:EmitSound( "buttons/lightswitch2.wav" )
|
||||
|
||||
if ent:GetFogLightsEnabled() then
|
||||
ent:SetFogLightsEnabled( false )
|
||||
else
|
||||
ent:SetFogLightsEnabled( true )
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
numpad.Register( "k_lgts", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) or not ent.LightsTable then return false end
|
||||
|
||||
local Time = CurTime()
|
||||
|
||||
if keydown then
|
||||
ent.KeyPressedTime = Time
|
||||
else
|
||||
if ent.KeyPressedTime and (Time - ent.KeyPressedTime) >= (ent.LightsActivated and 0.22 or 0) then
|
||||
if (ent.NextLightCheck or 0) > Time then return end
|
||||
|
||||
local vehiclelist = list.Get( "simfphys_lights" )[ent.LightsTable] or false
|
||||
if not vehiclelist then return end
|
||||
|
||||
if ent.LightsActivated then
|
||||
ent.NextLightCheck = Time + (vehiclelist.DelayOff or 0)
|
||||
ent.LightsActivated = false
|
||||
ent:SetLightsEnabled(false)
|
||||
ent:EmitSound( "buttons/lightswitch2.wav" )
|
||||
ent.LampsActivated = false
|
||||
ent:SetLampsEnabled( ent.LampsActivated )
|
||||
else
|
||||
ent.NextLightCheck = Time + (vehiclelist.DelayOn or 0)
|
||||
ent.LightsActivated = true
|
||||
ent:EmitSound( "buttons/lightswitch2.wav" )
|
||||
end
|
||||
|
||||
if ent.LightsActivated then
|
||||
if vehiclelist.BodyGroups then
|
||||
ent:SetBodygroup(vehiclelist.BodyGroups.On[1], vehiclelist.BodyGroups.On[2] )
|
||||
end
|
||||
if vehiclelist.Animation then
|
||||
ent:PlayAnimation( vehiclelist.Animation.On )
|
||||
end
|
||||
if ent.LightsPP then
|
||||
ent:PlayPP(ent.LightsActivated)
|
||||
end
|
||||
else
|
||||
if vehiclelist.BodyGroups then
|
||||
ent:SetBodygroup(vehiclelist.BodyGroups.Off[1], vehiclelist.BodyGroups.Off[2] )
|
||||
end
|
||||
if vehiclelist.Animation then
|
||||
ent:PlayAnimation( vehiclelist.Animation.Off )
|
||||
end
|
||||
if ent.LightsPP then
|
||||
ent:PlayPP(ent.LightsActivated)
|
||||
end
|
||||
end
|
||||
else
|
||||
if (ent.NextLightCheck or 0) > Time then return end
|
||||
|
||||
if ent.LampsActivated then
|
||||
ent.LampsActivated = false
|
||||
else
|
||||
ent.LampsActivated = true
|
||||
end
|
||||
|
||||
ent:SetLampsEnabled( ent.LampsActivated )
|
||||
|
||||
ent:EmitSound( "items/flashlight1.wav" )
|
||||
end
|
||||
end
|
||||
end )
|
||||
314
lua/entities/gmod_sent_vehicle_fphysics_base/shared.lua
Normal file
314
lua/entities/gmod_sent_vehicle_fphysics_base/shared.lua
Normal file
@@ -0,0 +1,314 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
ENT.Base = "lvs_base"
|
||||
|
||||
ENT.PrintName = "Comedy Effect"
|
||||
ENT.Author = "Blu"
|
||||
ENT.Information = ""
|
||||
ENT.Category = "Fun + Games"
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
|
||||
ENT.AutomaticFrameAdvance = true
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH
|
||||
|
||||
ENT.Editable = true
|
||||
|
||||
-- this needs to be here for some addons
|
||||
ENT.IsSimfphyscar = true
|
||||
|
||||
ENT.LVSsimfphys = true
|
||||
|
||||
ENT.MaxHealth = -1
|
||||
|
||||
ENT.MouseSteerAngle = 20
|
||||
ENT.MouseSteerExponent = 2
|
||||
|
||||
ENT.lvsDisableZoom = false
|
||||
|
||||
ENT.DoNotDuplicate = true
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:AddDT( "Int", "AITEAM", { KeyName = "aiteam", Edit = { type = "Int", order = 0,min = 0, max = 3, category = "AI"} } )
|
||||
|
||||
self:AddDT( "Float", "SteerSpeed", { KeyName = "steerspeed", Edit = { type = "Float", order = 1,min = 1, max = 16, category = "Steering"} } )
|
||||
self:AddDT( "Float", "FastSteerConeFadeSpeed", { KeyName = "faststeerconefadespeed", Edit = { type = "Float", order = 2,min = 1, max = 5000, category = "Steering"} } )
|
||||
self:AddDT( "Float", "FastSteerAngle", { KeyName = "faststeerangle", Edit = { type = "Float", order = 3,min = 0, max = 1, category = "Steering"} } )
|
||||
|
||||
self:AddDT( "Float", "FrontSuspensionHeight", { KeyName = "frontsuspensionheight", Edit = { type = "Float", order = 4,min = -1, max = 1, category = "Suspension" } } )
|
||||
self:AddDT( "Float", "RearSuspensionHeight", { KeyName = "rearsuspensionheight", Edit = { type = "Float", order = 5,min = -1, max = 1, category = "Suspension" } } )
|
||||
|
||||
self:AddDT( "Int", "EngineSoundPreset", { KeyName = "enginesoundpreset", Edit = { type = "Int", order = 6,min = -1, max = 23, category = "Engine"} } )
|
||||
self:AddDT( "Int", "IdleRPM", { KeyName = "idlerpm", Edit = { type = "Int", order = 7,min = 1, max = 25000, category = "Engine"} } )
|
||||
self:AddDT( "Int", "LimitRPM", { KeyName = "limitrpm", Edit = { type = "Int", order = 8,min = 4, max = 25000, category = "Engine"} } )
|
||||
self:AddDT( "Int", "PowerBandStart", { KeyName = "powerbandstart", Edit = { type = "Int", order = 9,min = 2, max = 25000, category = "Engine"} } )
|
||||
self:AddDT( "Int", "PowerBandEnd", { KeyName = "powerbandend", Edit = { type = "Int", order = 10,min = 3, max = 25000, category = "Engine"} } )
|
||||
self:AddDT( "Float", "MaxTorque", { KeyName = "maxtorque", Edit = { type = "Float", order = 11,min = 20, max = 1000, category = "Engine"} } )
|
||||
self:AddDT( "Bool", "Revlimiter", { KeyName = "revlimiter", Edit = { type = "Boolean", order = 12, category = "Engine"} } )
|
||||
self:AddDT( "Bool", "TurboCharged", { KeyName = "turbocharged", Edit = { type = "Boolean", order = 13, category = "Engine"} } )
|
||||
self:AddDT( "Bool", "SuperCharged", { KeyName = "supercharged", Edit = { type = "Boolean", order = 14, category = "Engine"} } )
|
||||
self:AddDT( "Bool", "BackFire", { KeyName = "backfire", Edit = { type = "Boolean", order = 15, category = "Engine"} } )
|
||||
self:AddDT( "Bool", "DoNotStall", { KeyName = "donotstall", Edit = { type = "Boolean", order = 16, category = "Engine"} } )
|
||||
|
||||
self:AddDT( "Float", "DifferentialGear", { KeyName = "differentialgear", Edit = { type = "Float", order = 17,min = 0.2, max = 6, category = "Transmission"} } )
|
||||
|
||||
self:AddDT( "Float", "BrakePower", { KeyName = "brakepower", Edit = { type = "Float", order = 18,min = 0.1, max = 500, category = "Wheels"} } )
|
||||
self:AddDT( "Float", "PowerDistribution", { KeyName = "powerdistribution", Edit = { type = "Float", order = 19,min = -1, max = 1, category = "Wheels"} } )
|
||||
self:AddDT( "Float", "Efficiency", { KeyName = "efficiency", Edit = { type = "Float", order = 20,min = 0.2, max = 4, category = "Wheels"} } )
|
||||
self:AddDT( "Float", "MaxTraction", { KeyName = "maxtraction", Edit = { type = "Float", order = 21,min = 5, max = 1000, category = "Wheels"} } )
|
||||
self:AddDT( "Float", "TractionBias", { KeyName = "tractionbias", Edit = { type = "Float", order = 22,min = -0.99, max = 0.99, category = "Wheels"} } )
|
||||
self:AddDT( "Bool", "BulletProofTires", { KeyName = "bulletprooftires", Edit = { type = "Boolean", order = 23, category = "Wheels"} } )
|
||||
self:AddDT( "Vector", "TireSmokeColor", { KeyName = "tiresmokecolor", Edit = { type = "VectorColor", order = 24, category = "Wheels"} } )
|
||||
|
||||
self:AddDT( "Float", "FlyWheelRPM" )
|
||||
self:AddDT( "Float", "Throttle" )
|
||||
self:AddDT( "Float", "WheelVelocity" )
|
||||
self:AddDT( "Int", "Gear" )
|
||||
self:AddDT( "Int", "Clutch" )
|
||||
self:AddDT( "Bool", "IsCruiseModeOn" )
|
||||
self:AddDT( "Bool", "IsBraking" )
|
||||
self:AddDT( "Bool", "LightsEnabled" )
|
||||
self:AddDT( "Bool", "LampsEnabled" )
|
||||
self:AddDT( "Bool", "EMSEnabled" )
|
||||
self:AddDT( "Bool", "FogLightsEnabled" )
|
||||
self:AddDT( "Bool", "HandBrakeEnabled" )
|
||||
|
||||
self:AddDT( "Bool", "lvsLockedStatus" )
|
||||
self:AddDT( "Bool", "lvsReady" )
|
||||
|
||||
self:AddDT( "Float", "VehicleSteer" )
|
||||
|
||||
self:AddDT( "Float", "CurHealth" )
|
||||
|
||||
self:AddDT( "Entity", "Driver" )
|
||||
self:AddDT( "Entity", "DriverSeat" )
|
||||
self:AddDT( "Entity", "FuelTank" )
|
||||
self:AddDT( "Bool", "Active" )
|
||||
|
||||
self:AddDT( "String", "Spawn_List")
|
||||
self:AddDT( "String", "Lights_List")
|
||||
self:AddDT( "String", "Soundoverride")
|
||||
|
||||
self:AddDT( "Vector", "FuelPortPosition" )
|
||||
|
||||
if SERVER then
|
||||
self:SetCurHealth( 1 )
|
||||
|
||||
self:NetworkVarNotify( "FrontSuspensionHeight", self.OnFrontSuspensionHeightChanged )
|
||||
self:NetworkVarNotify( "RearSuspensionHeight", self.OnRearSuspensionHeightChanged )
|
||||
self:NetworkVarNotify( "TurboCharged", self.OnTurboCharged )
|
||||
self:NetworkVarNotify( "SuperCharged", self.OnSuperCharged )
|
||||
self:NetworkVarNotify( "Active", self.OnActiveChanged )
|
||||
self:NetworkVarNotify( "Throttle", self.OnThrottleChanged )
|
||||
self:NetworkVarNotify( "CurHealth", self.OnHealthChanged )
|
||||
end
|
||||
|
||||
self:AddDataTables()
|
||||
end
|
||||
|
||||
function ENT:AddDataTables()
|
||||
end
|
||||
|
||||
local VehicleMeta = FindMetaTable("Entity")
|
||||
local OldIsVehicle = VehicleMeta.IsVehicle
|
||||
function VehicleMeta:IsVehicle()
|
||||
|
||||
if self.LVSsimfphys then
|
||||
return true
|
||||
end
|
||||
|
||||
return OldIsVehicle( self )
|
||||
end
|
||||
|
||||
function ENT:GetSelectedWeapon()
|
||||
return 0
|
||||
end
|
||||
|
||||
function ENT:GetAI()
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:SetHP( nHealth )
|
||||
self:SetCurHealth( nHealth )
|
||||
end
|
||||
|
||||
function ENT:GetShield()
|
||||
return 0
|
||||
end
|
||||
|
||||
function ENT:SetShield()
|
||||
end
|
||||
|
||||
function ENT:GetHP()
|
||||
return self:GetCurHealth()
|
||||
end
|
||||
|
||||
function ENT:GetMaxHP()
|
||||
return self:GetMaxHealth()
|
||||
end
|
||||
|
||||
function ENT:GetMaxHealth()
|
||||
return self:GetNWFloat( "MaxHealth", 2000 )
|
||||
end
|
||||
|
||||
function ENT:GetMaxFuel()
|
||||
return self:GetNWFloat( "MaxFuel", 60 )
|
||||
end
|
||||
|
||||
function ENT:GetFuel()
|
||||
return self:GetNWFloat( "Fuel", self:GetMaxFuel() )
|
||||
end
|
||||
|
||||
function ENT:GetFuelUse()
|
||||
return self:GetNWFloat( "FuelUse", 0 )
|
||||
end
|
||||
|
||||
function ENT:GetFuelType()
|
||||
return self:GetNWInt( "FuelType", 1 )
|
||||
end
|
||||
|
||||
function ENT:GetFuelPos()
|
||||
return self:LocalToWorld( self:GetFuelPortPosition() )
|
||||
end
|
||||
|
||||
function ENT:OnSmoke()
|
||||
return self:GetNWBool( "OnSmoke", false )
|
||||
end
|
||||
|
||||
function ENT:OnFire()
|
||||
return self:GetNWBool( "OnFire", false )
|
||||
end
|
||||
|
||||
function ENT:GetIsVehicleLocked()
|
||||
return self:GetlvsLockedStatus()
|
||||
end
|
||||
|
||||
function ENT:SetIsVehicleLocked( lock )
|
||||
self:SetlvsLockedStatus( lock )
|
||||
end
|
||||
|
||||
function ENT:GetBackfireSound()
|
||||
return self:GetNWString( "backfiresound" )
|
||||
end
|
||||
|
||||
function ENT:SetBackfireSound( the_sound )
|
||||
self:SetNWString( "backfiresound", the_sound )
|
||||
end
|
||||
|
||||
function ENT:BodyGroupIsValid( bodygroups )
|
||||
for index, groups in pairs( bodygroups ) do
|
||||
local mygroup = self:GetBodygroup( index )
|
||||
for g_index = 1, table.Count( groups ) do
|
||||
if mygroup == groups[g_index] then return true end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:GetVehicleClass()
|
||||
return self:GetSpawn_List()
|
||||
end
|
||||
|
||||
function ENT:CalcMainActivityPassenger( ply )
|
||||
if not istable( self.PassengerSeats ) then
|
||||
|
||||
if not self.HasCheckedpSeats then
|
||||
self.HasCheckedpSeats = true
|
||||
|
||||
self.PassengerSeats = list.Get( "simfphys_vehicles" )[ self:GetSpawn_List() ].Members.PassengerSeats
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local Pod = ply:GetVehicle()
|
||||
|
||||
local pSeatTBL = self.PassengerSeats[ Pod:GetNWInt( "pPodIndex", -1 ) - 1 ]
|
||||
|
||||
if not istable( pSeatTBL ) then return end
|
||||
|
||||
local seq = pSeatTBL.anim
|
||||
|
||||
if not isstring( seq ) then return end
|
||||
|
||||
if ply.m_bWasNoclipping then
|
||||
ply.m_bWasNoclipping = nil
|
||||
ply:AnimResetGestureSlot( GESTURE_SLOT_CUSTOM )
|
||||
|
||||
if CLIENT then
|
||||
ply:SetIK( true )
|
||||
end
|
||||
end
|
||||
|
||||
ply.CalcIdeal = ACT_STAND
|
||||
ply.CalcSeqOverride = ply:LookupSequence( seq )
|
||||
|
||||
return ply.CalcIdeal, ply.CalcSeqOverride
|
||||
end
|
||||
|
||||
function ENT:CalcMainActivity( ply )
|
||||
if ply ~= self:GetDriver() then return self:CalcMainActivityPassenger( ply ) end
|
||||
|
||||
if ply.m_bWasNoclipping then
|
||||
ply.m_bWasNoclipping = nil
|
||||
ply:AnimResetGestureSlot( GESTURE_SLOT_CUSTOM )
|
||||
|
||||
if CLIENT then
|
||||
ply:SetIK( true )
|
||||
end
|
||||
end
|
||||
|
||||
ply.CalcIdeal = ACT_STAND
|
||||
|
||||
if isstring( self.SeatAnim ) then
|
||||
ply.CalcSeqOverride = ply:LookupSequence( self.SeatAnim )
|
||||
else
|
||||
if not self.HasCheckedSeat then
|
||||
self.HasCheckedSeat = true
|
||||
|
||||
self.SeatAnim = list.Get( "simfphys_vehicles" )[ self:GetSpawn_List() ].Members.SeatAnim
|
||||
end
|
||||
|
||||
ply.CalcSeqOverride = ply:LookupSequence( "drive_jeep" )
|
||||
end
|
||||
|
||||
return ply.CalcIdeal, ply.CalcSeqOverride
|
||||
end
|
||||
|
||||
function ENT:UpdateAnimation( ply, velocity, maxseqgroundspeed )
|
||||
ply:SetPlaybackRate( 1 )
|
||||
|
||||
if CLIENT then
|
||||
if ply == self:GetDriver() then
|
||||
ply:SetPoseParameter( "vehicle_steer", self:GetVehicleSteer() )
|
||||
ply:InvalidateBoneCache()
|
||||
end
|
||||
|
||||
GAMEMODE:GrabEarAnimation( ply )
|
||||
GAMEMODE:MouthMoveAnimation( ply )
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:StartCommand( ply, cmd )
|
||||
if self:GetDriver() ~= ply then return end
|
||||
|
||||
if SERVER then
|
||||
self:SetRoadkillAttacker( ply )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetVehicleType()
|
||||
return "car"
|
||||
end
|
||||
522
lua/entities/gmod_sent_vehicle_fphysics_base/simfunc.lua
Normal file
522
lua/entities/gmod_sent_vehicle_fphysics_base/simfunc.lua
Normal file
@@ -0,0 +1,522 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
function ENT:WheelOnGround()
|
||||
self.FrontWheelPowered = self:GetPowerDistribution() ~= 1
|
||||
self.RearWheelPowered = self:GetPowerDistribution() ~= -1
|
||||
|
||||
for i = 1, table.Count( self.Wheels ) do
|
||||
local Wheel = self.Wheels[i]
|
||||
|
||||
if not IsValid( Wheel ) then continue end
|
||||
|
||||
local dmgMul = Wheel:GetDamaged() and 0.5 or 1
|
||||
local surfacemul = simfphys.TractionData[Wheel:GetSurfaceMaterial():lower()]
|
||||
|
||||
self.VehicleData[ "SurfaceMul_" .. i ] = (surfacemul and math.max(surfacemul,0.001) or 1) * dmgMul
|
||||
|
||||
local WheelPos = self:LogicWheelPos( i )
|
||||
|
||||
local WheelRadius = WheelPos.IsFrontWheel and self.FrontWheelRadius or self.RearWheelRadius
|
||||
local startpos = Wheel:GetPos()
|
||||
local dir = -self.Up
|
||||
local len = WheelRadius + math.Clamp(-self.Vel.z / 50,2.5,6)
|
||||
local HullSize = Vector(WheelRadius,WheelRadius,0)
|
||||
local tr = util.TraceHull( {
|
||||
start = startpos,
|
||||
endpos = startpos + dir * len,
|
||||
maxs = HullSize,
|
||||
mins = -HullSize,
|
||||
filter = self.VehicleData["filter"]
|
||||
} )
|
||||
|
||||
if tr.Hit then
|
||||
self.VehicleData[ "onGround_" .. i ] = 1
|
||||
Wheel:SetSpeed( Wheel.FX )
|
||||
Wheel:SetSkidSound( Wheel.skid )
|
||||
Wheel:SetSurfaceMaterial( util.GetSurfacePropName( tr.SurfaceProps ) )
|
||||
Wheel:SetOnGround(1)
|
||||
else
|
||||
self.VehicleData[ "onGround_" .. i ] = 0
|
||||
Wheel:SetOnGround(0)
|
||||
end
|
||||
end
|
||||
|
||||
local FrontOnGround = math.max(self.VehicleData[ "onGround_1" ],self.VehicleData[ "onGround_2" ])
|
||||
local RearOnGround = math.max(self.VehicleData[ "onGround_3" ],self.VehicleData[ "onGround_4" ],self.VehicleData[ "onGround_5" ],self.VehicleData[ "onGround_6" ])
|
||||
|
||||
self.DriveWheelsOnGround = math.max(self.FrontWheelPowered and FrontOnGround or 0,self.RearWheelPowered and RearOnGround or 0)
|
||||
end
|
||||
|
||||
function ENT:SimulateAirControls(tilt_forward,tilt_back,tilt_left,tilt_right)
|
||||
if self:IsDriveWheelsOnGround() then return end
|
||||
|
||||
if hook.Run( "simfphysAirControl", self, tilt_forward, tilt_back, tilt_left, tilt_right) then return end
|
||||
|
||||
local PObj = self:GetPhysicsObject()
|
||||
|
||||
local TiltForce = ((self.Right * (tilt_right - tilt_left) * 1.8) + (self.Forward * (tilt_forward - tilt_back) * 6)) * math.acos( math.Clamp( self.Up:Dot(Vector(0,0,1)) ,-1,1) ) * (180 / math.pi) * self.Mass
|
||||
PObj:ApplyForceOffset( TiltForce, PObj:GetMassCenter() + self.Up )
|
||||
PObj:ApplyForceOffset( -TiltForce, PObj:GetMassCenter() - self.Up )
|
||||
end
|
||||
|
||||
function ENT:SimulateEngine(IdleRPM,LimitRPM,Powerbandstart,Powerbandend,c_time)
|
||||
local PObj = self:GetPhysicsObject()
|
||||
|
||||
local IsRunning = self:EngineActive()
|
||||
local Throttle = self:GetThrottle()
|
||||
|
||||
if not self:IsDriveWheelsOnGround() then
|
||||
self.Clutch = 1
|
||||
end
|
||||
|
||||
if self.Gears[self.CurrentGear] == 0 then
|
||||
self.GearRatio = 1
|
||||
self.Clutch = 1
|
||||
self.HandBrake = self.HandBrake + (self.HandBrakePower - self.HandBrake) * 0.2
|
||||
else
|
||||
self.GearRatio = self.Gears[self.CurrentGear] * self:GetDiffGear()
|
||||
end
|
||||
|
||||
self:SetClutch( self.Clutch )
|
||||
local InvClutch = 1 - self.Clutch
|
||||
|
||||
local GearedRPM = self.WheelRPM / math.abs(self.GearRatio)
|
||||
|
||||
local MaxTorque = self:GetMaxTorque()
|
||||
|
||||
local DesRPM = Lerp(InvClutch, math.max(IdleRPM + (LimitRPM - IdleRPM) * Throttle,0), GearedRPM )
|
||||
local Drag = (MaxTorque * (math.max( self.EngineRPM - IdleRPM, 0) / Powerbandend) * ( 1 - Throttle) / 0.15) * InvClutch
|
||||
|
||||
local TurboCharged = self:GetTurboCharged()
|
||||
local SuperCharged = self:GetSuperCharged()
|
||||
local boost = (TurboCharged and self:SimulateTurbo(Powerbandend) or 0) * 0.3 + (SuperCharged and self:SimulateBlower(Powerbandend) or 0)
|
||||
|
||||
if self:GetCurHealth() <= self:GetMaxHealth() * 0.3 then
|
||||
MaxTorque = MaxTorque * (self:GetCurHealth() / (self:GetMaxHealth() * 0.3))
|
||||
end
|
||||
|
||||
self.EngineRPM = math.Clamp(self.EngineRPM + math.Clamp(DesRPM - self.EngineRPM,-math.max(self.EngineRPM / 15, 1 ),math.max(-self.RpmDiff / 1.5 * InvClutch + (self.Torque * 5) / 0.15 * self.Clutch, 1)) + self.RPM_DIFFERENCE * Throttle,0,LimitRPM) * self.EngineIsOn
|
||||
self.Torque = (Throttle + boost) * math.max(MaxTorque * math.min(self.EngineRPM / Powerbandstart, (LimitRPM - self.EngineRPM) / (LimitRPM - Powerbandend),1), 0)
|
||||
self:SetFlyWheelRPM( math.min(self.EngineRPM + self.exprpmdiff * 2 * InvClutch,LimitRPM) )
|
||||
|
||||
self.RpmDiff = self.EngineRPM - GearedRPM
|
||||
|
||||
local signGearRatio = ((self.GearRatio > 0) and 1 or 0) + ((self.GearRatio < 0) and -1 or 0)
|
||||
local signThrottle = (Throttle > 0) and 1 or 0
|
||||
local signSpeed = ((self.ForwardSpeed > 0) and 1 or 0) + ((self.ForwardSpeed < 0) and -1 or 0)
|
||||
|
||||
local TorqueDiff = (self.RpmDiff / LimitRPM) * 0.15 * self.Torque
|
||||
local EngineBrake = (signThrottle == 0) and math.min( self.EngineRPM * (self.EngineRPM / LimitRPM) ^ 2 / 60 * signSpeed, 100 ) or 0
|
||||
|
||||
local GearedPower = ((self.ThrottleDelay <= c_time and (self.Torque + TorqueDiff) * signThrottle * signGearRatio or 0) - EngineBrake) / math.abs(self.GearRatio) / 50
|
||||
|
||||
self.EngineTorque = IsRunning and GearedPower * InvClutch or 0
|
||||
|
||||
if not self:GetDoNotStall() then
|
||||
if IsRunning then
|
||||
if self.EngineRPM <= IdleRPM * 0.2 then
|
||||
self.CurrentGear = 2
|
||||
self:StallAndRestart()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if simfphys.Fuel then
|
||||
local FuelUse = (Throttle * 0.3 + 0.7) * ((self.EngineRPM / LimitRPM) * MaxTorque + self.Torque) / 1500000
|
||||
local Fuel = self:GetFuel()
|
||||
self:SetFuel( Fuel - FuelUse * (1 / simfphys.FuelMul) )
|
||||
|
||||
self.UsedFuel = self.UsedFuel and (self.UsedFuel + FuelUse) or 0
|
||||
self.CheckUse = self.CheckUse or 0
|
||||
if self.CheckUse < CurTime() then
|
||||
self.CheckUse = CurTime() + 1
|
||||
self:SetFuelUse( self.UsedFuel * 60 )
|
||||
self.UsedFuel = 0
|
||||
end
|
||||
|
||||
if Fuel <= 0 and IsRunning then
|
||||
self:StopEngine()
|
||||
end
|
||||
else
|
||||
self:SetFuelUse( -1 )
|
||||
end
|
||||
|
||||
local ReactionForce = (self.EngineTorque * 2 - math.Clamp(self.ForwardSpeed,-self.Brake,self.Brake)) * self.DriveWheelsOnGround
|
||||
local BaseMassCenter = PObj:GetMassCenter()
|
||||
local dt_mul = math.max( math.min(self:GetPowerDistribution() + 0.5,1),0)
|
||||
|
||||
PObj:ApplyForceOffset( -self.Forward * self.Mass * ReactionForce, BaseMassCenter + self.Up * dt_mul )
|
||||
PObj:ApplyForceOffset( self.Forward * self.Mass * ReactionForce, BaseMassCenter - self.Up * dt_mul )
|
||||
end
|
||||
|
||||
function ENT:SimulateTransmission(k_throttle,k_brake,k_fullthrottle,k_clutch,k_handbrake,k_gearup,k_geardown,isauto,IdleRPM,Powerbandstart,Powerbandend,shiftmode,cruisecontrol,curtime)
|
||||
local GearsCount = table.Count( self.Gears )
|
||||
local cruiseThrottle = math.min( math.max(self.cc_speed - math.abs(self.ForwardSpeed),0) / 10 ^ 2, 1)
|
||||
|
||||
if isnumber(self.ForceTransmission) then
|
||||
isauto = self.ForceTransmission <= 1
|
||||
end
|
||||
|
||||
if not isauto then
|
||||
self.Brake = self:GetBrakePower() * math.max( k_brake, self.PressedKeys["joystick_brake"] )
|
||||
self.HandBrake = self.HandBrakePower * k_handbrake
|
||||
self.Clutch = math.max( k_clutch, k_handbrake, self.PressedKeys["joystick_clutch"] )
|
||||
|
||||
local AutoThrottle = self:EngineActive() and ((self.EngineRPM < IdleRPM) and (IdleRPM - self.EngineRPM) / IdleRPM or 0) or 0
|
||||
local Throttle = cruisecontrol and cruiseThrottle or ( math.max( (0.5 + 0.5 * k_fullthrottle) * k_throttle, self.PressedKeys["joystick_throttle"] ) + AutoThrottle)
|
||||
self:SetThrottle( Throttle )
|
||||
|
||||
if k_gearup ~= self.GearUpPressed then
|
||||
self.GearUpPressed = k_gearup
|
||||
|
||||
if k_gearup == 1 then
|
||||
|
||||
if self.CurrentGear ~= GearsCount then
|
||||
self.ThrottleDelay = curtime + 0.4 - 0.4 * k_clutch
|
||||
end
|
||||
|
||||
self.CurrentGear = math.Clamp(self.CurrentGear + 1,1,GearsCount)
|
||||
end
|
||||
end
|
||||
|
||||
if k_geardown ~= self.GearDownPressed then
|
||||
self.GearDownPressed = k_geardown
|
||||
|
||||
if k_geardown == 1 then
|
||||
|
||||
self.CurrentGear = math.Clamp(self.CurrentGear - 1,1,GearsCount)
|
||||
|
||||
if self.CurrentGear == 1 then
|
||||
self.ThrottleDelay = curtime + 0.25
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
local throttleMod = 0.5 + 0.5 * k_fullthrottle
|
||||
local throttleForward = math.max( k_throttle * throttleMod, self.PressedKeys["joystick_throttle"] )
|
||||
local throttleReverse = math.max( k_brake * throttleMod, self.PressedKeys["joystick_brake"] )
|
||||
local throttleStanding = math.max( k_throttle * throttleMod, k_brake * throttleMod, self.PressedKeys["joystick_brake"], self.PressedKeys["joystick_throttle"] )
|
||||
local inputThrottle = self.ForwardSpeed >= 50 and throttleForward or ((self.ForwardSpeed < 50 and self.ForwardSpeed > -350) and throttleStanding or throttleReverse)
|
||||
|
||||
local Throttle = cruisecontrol and cruiseThrottle or inputThrottle
|
||||
local CalcRPM = self.EngineRPM - self.RPM_DIFFERENCE * Throttle
|
||||
self:SetThrottle( Throttle )
|
||||
|
||||
if self.CurrentGear <= 3 and Throttle > 0 and self.CurrentGear ~= 2 then
|
||||
if Throttle < 1 and not cruisecontrol then
|
||||
local autoclutch = math.Clamp((Powerbandstart / self.EngineRPM) - 0.5,0,1)
|
||||
|
||||
self.sm_autoclutch = self.sm_autoclutch and (self.sm_autoclutch + math.Clamp(autoclutch - self.sm_autoclutch,-0.2,0.1) ) or 0
|
||||
else
|
||||
self.sm_autoclutch = (self.EngineRPM < IdleRPM + (Powerbandstart - IdleRPM)) and 1 or 0
|
||||
end
|
||||
else
|
||||
self.sm_autoclutch = 0
|
||||
end
|
||||
|
||||
self.Clutch = math.max(self.sm_autoclutch,k_handbrake)
|
||||
|
||||
self.HandBrake = self.HandBrakePower * k_handbrake
|
||||
|
||||
self.Brake = self:GetBrakePower() * (self.ForwardSpeed >= 0 and math.max(k_brake,self.PressedKeys["joystick_brake"]) or math.max(k_throttle,self.PressedKeys["joystick_throttle"]))
|
||||
|
||||
if self:IsDriveWheelsOnGround() then
|
||||
if self.ForwardSpeed >= 50 then
|
||||
if self.Clutch == 0 then
|
||||
local NextGear = self.CurrentGear + 1 <= GearsCount and math.min(self.CurrentGear + 1,GearsCount) or self.CurrentGear
|
||||
local NextGearRatio = self.Gears[NextGear] * self:GetDiffGear()
|
||||
local NextGearRPM = self.WheelRPM / math.abs(NextGearRatio)
|
||||
|
||||
local PrevGear = self.CurrentGear - 1 <= GearsCount and math.max(self.CurrentGear - 1,3) or self.CurrentGear
|
||||
local PrevGearRatio = self.Gears[PrevGear] * self:GetDiffGear()
|
||||
local PrevGearRPM = self.WheelRPM / math.abs(PrevGearRatio)
|
||||
|
||||
local minThrottle = shiftmode == 1 and 1 or math.max(Throttle,0.5)
|
||||
|
||||
local ShiftUpRPM = Powerbandstart + (Powerbandend - Powerbandstart) * minThrottle
|
||||
local ShiftDownRPM = IdleRPM + (Powerbandend - Powerbandstart) * minThrottle
|
||||
|
||||
local CanShiftUp = NextGearRPM > math.max(Powerbandstart * minThrottle,Powerbandstart - IdleRPM) and CalcRPM >= ShiftUpRPM and self.CurrentGear < GearsCount
|
||||
local CanShiftDown = CalcRPM <= ShiftDownRPM and PrevGearRPM < ShiftDownRPM and self.CurrentGear > 3
|
||||
|
||||
if CanShiftUp and self.NextShift < curtime then
|
||||
self.CurrentGear = self.CurrentGear + 1
|
||||
self.NextShift = curtime + 0.5
|
||||
self.ThrottleDelay = curtime + 0.25
|
||||
end
|
||||
|
||||
if CanShiftDown and self.NextShift < curtime then
|
||||
self.CurrentGear = self.CurrentGear - 1
|
||||
self.NextShift = curtime + 0.35
|
||||
end
|
||||
|
||||
self.CurrentGear = math.Clamp(self.CurrentGear,3,GearsCount)
|
||||
end
|
||||
|
||||
elseif (self.ForwardSpeed < 50 and self.ForwardSpeed > -350) then
|
||||
|
||||
self.CurrentGear = (k_throttle == 1 and 3 or k_brake == 1 and 1 or self.PressedKeys["joystick_throttle"] > 0 and 3 or self.PressedKeys["joystick_brake"] > 0 and 1) or 3
|
||||
self.Brake = self:GetBrakePower() * math.max(k_throttle * k_brake,self.PressedKeys["joystick_throttle"] * self.PressedKeys["joystick_brake"])
|
||||
|
||||
elseif (self.ForwardSpeed >= -350) then
|
||||
|
||||
if (Throttle > 0) then
|
||||
self.Brake = 0
|
||||
end
|
||||
|
||||
self.CurrentGear = 1
|
||||
end
|
||||
|
||||
if (Throttle == 0 and math.abs(self.ForwardSpeed) <= 80) then
|
||||
self.CurrentGear = 2
|
||||
self.Brake = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
self:SetIsBraking( self.Brake > 0 )
|
||||
self:SetGear( self.CurrentGear )
|
||||
self:SetHandBrakeEnabled( self.HandBrake > 0 or self.CurrentGear == 2 )
|
||||
|
||||
if self.Clutch == 1 or self.CurrentGear == 2 then
|
||||
if math.abs(self.ForwardSpeed) <= 20 then
|
||||
|
||||
local PObj = self:GetPhysicsObject()
|
||||
local TiltForce = self.Torque * (-1 + self:GetThrottle() * 2)
|
||||
|
||||
PObj:ApplyForceOffset( self.Up * TiltForce, PObj:GetMassCenter() + self.Right * 1000 )
|
||||
PObj:ApplyForceOffset( -self.Up * TiltForce, PObj:GetMassCenter() - self.Right * 1000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetTransformedDirection()
|
||||
local SteerAngForward = self.Forward:Angle()
|
||||
local SteerAngRight = self.Right:Angle()
|
||||
local SteerAngForward2 = self.Forward:Angle()
|
||||
local SteerAngRight2 = self.Right:Angle()
|
||||
|
||||
SteerAngForward:RotateAroundAxis(-self.Up, self.VehicleData[ "Steer" ])
|
||||
SteerAngRight:RotateAroundAxis(-self.Up, self.VehicleData[ "Steer" ])
|
||||
SteerAngForward2:RotateAroundAxis(-self.Up, -self.VehicleData[ "Steer" ])
|
||||
SteerAngRight2:RotateAroundAxis(-self.Up, -self.VehicleData[ "Steer" ])
|
||||
|
||||
local SteerForward = SteerAngForward:Forward()
|
||||
local SteerRight = SteerAngRight:Forward()
|
||||
local SteerForward2 = SteerAngForward2:Forward()
|
||||
local SteerRight2 = SteerAngRight2:Forward()
|
||||
|
||||
return {Forward = SteerForward,Right = SteerRight,Forward2 = SteerForward2, Right2 = SteerRight2}
|
||||
end
|
||||
|
||||
function ENT:LogicWheelPos( index )
|
||||
local IsFront = index == 1 or index == 2
|
||||
local IsRight = index == 2 or index == 4 or index == 6
|
||||
|
||||
return {IsFrontWheel = IsFront, IsRightWheel = IsRight}
|
||||
end
|
||||
|
||||
function ENT:SimulateWheels(k_clutch,LimitRPM)
|
||||
local Steer = self:GetTransformedDirection()
|
||||
local MaxGrip = self:GetMaxTraction()
|
||||
local Efficiency = self:GetEfficiency()
|
||||
local GripOffset = self:GetTractionBias() * MaxGrip
|
||||
local wVel = 0
|
||||
|
||||
for i = 1, table.Count( self.Wheels ) do
|
||||
local Wheel = self.Wheels[i]
|
||||
|
||||
if IsValid( Wheel ) then
|
||||
local WheelPos = self:LogicWheelPos( i )
|
||||
local WheelRadius = WheelPos.IsFrontWheel and self.FrontWheelRadius or self.RearWheelRadius
|
||||
local WheelDiameter = WheelRadius * 2
|
||||
local SurfaceMultiplicator = self.VehicleData[ "SurfaceMul_" .. i ]
|
||||
local MaxTraction = (WheelPos.IsFrontWheel and (MaxGrip + GripOffset) or (MaxGrip - GripOffset)) * SurfaceMultiplicator
|
||||
|
||||
local IsPoweredWheel = (WheelPos.IsFrontWheel and self.FrontWheelPowered or not WheelPos.IsFrontWheel and self.RearWheelPowered) and 1 or 0
|
||||
|
||||
local Velocity = Wheel:GetVelocity()
|
||||
local VelForward = Velocity:GetNormalized()
|
||||
local OnGround = self.VehicleData[ "onGround_" .. i ]
|
||||
|
||||
local Forward = WheelPos.IsFrontWheel and Steer.Forward or self.Forward
|
||||
local Right = WheelPos.IsFrontWheel and Steer.Right or self.Right
|
||||
|
||||
if self.CustomWheels then
|
||||
if WheelPos.IsFrontWheel then
|
||||
Forward = IsValid(self.SteerMaster) and Steer.Forward or self.Forward
|
||||
Right = IsValid(self.SteerMaster) and Steer.Right or self.Right
|
||||
else
|
||||
if IsValid( self.SteerMaster2 ) then
|
||||
Forward = Steer.Forward2
|
||||
Right = Steer.Right2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local Ax = math.deg( math.acos( math.Clamp( Forward:Dot(VelForward) ,-1,1) ) )
|
||||
local Ay = math.deg( math.asin( math.Clamp( Right:Dot(VelForward) ,-1,1) ) )
|
||||
|
||||
local Fx = math.cos( math.rad( Ax ) ) * Velocity:Length()
|
||||
local Fy = math.sin( math.rad( Ay ) ) * Velocity:Length()
|
||||
|
||||
local absFy = math.abs(Fy)
|
||||
local absFx = math.abs(Fx)
|
||||
|
||||
local PowerBiasMul = WheelPos.IsFrontWheel and (1 - self:GetPowerDistribution()) * 0.5 or (1 + self:GetPowerDistribution()) * 0.5
|
||||
local BrakeForce = math.Clamp(-Fx,-self.Brake,self.Brake) * SurfaceMultiplicator
|
||||
|
||||
local TorqueConv = self.EngineTorque * PowerBiasMul * IsPoweredWheel
|
||||
local ForwardForce = TorqueConv + (not WheelPos.IsFrontWheel and math.Clamp(-Fx,-self.HandBrake,self.HandBrake) or 0) + BrakeForce * 0.5
|
||||
|
||||
local TractionCycle = Vector(math.min(absFy,MaxTraction),ForwardForce,0):Length()
|
||||
|
||||
local GripLoss = math.max(TractionCycle - MaxTraction,0)
|
||||
local GripRemaining = math.max(MaxTraction - GripLoss,math.min(absFy / 25,MaxTraction))
|
||||
--local GripRemaining = math.max(MaxTraction - GripLoss,math.min(absFy / 25,MaxTraction / 2))
|
||||
|
||||
local signForwardForce = ((ForwardForce > 0) and 1 or 0) + ((ForwardForce < 0) and -1 or 0)
|
||||
local signEngineTorque = ((self.EngineTorque > 0) and 1 or 0) + ((self.EngineTorque < 0) and -1 or 0)
|
||||
|
||||
local Power = ForwardForce * Efficiency - GripLoss * signForwardForce + math.Clamp(BrakeForce * 0.5,-MaxTraction,MaxTraction)
|
||||
|
||||
local Force = -Right * math.Clamp(Fy,-GripRemaining,GripRemaining) + Forward * Power
|
||||
|
||||
local wRad = Wheel:GetDamaged() and Wheel.dRadius or WheelRadius
|
||||
local wFX = (Fx + GripLoss * 35 * signEngineTorque * IsPoweredWheel)
|
||||
local TurnWheel = (wFX / wRad * 1.85) + self.EngineRPM / 80 * (1 - OnGround) * IsPoweredWheel * (1 - k_clutch)
|
||||
|
||||
Wheel.FX = Fx
|
||||
Wheel.skid = ((MaxTraction - (MaxTraction - Vector(absFy,math.abs(ForwardForce * 10),0):Length())) / MaxTraction) - 10
|
||||
|
||||
local RPM = Wheel:VelToRPM( absFx ) * OnGround
|
||||
local GripLossFaktor = math.Clamp(GripLoss,0,MaxTraction) / MaxTraction
|
||||
|
||||
local abswFX = math.abs( wFX )
|
||||
Wheel:SetRPM( Wheel:VelToRPM( wFX ) )
|
||||
if IsPoweredWheel then
|
||||
if abswFX > wVel then
|
||||
wVel = abswFX
|
||||
end
|
||||
end
|
||||
|
||||
self.VehicleData[ "WheelRPM_".. i ] = RPM
|
||||
self.VehicleData[ "GripLossFaktor_".. i ] = GripLossFaktor
|
||||
self.VehicleData[ "Exp_GLF_".. i ] = GripLossFaktor ^ 2
|
||||
|
||||
Wheel:SetGripLoss( GripLossFaktor )
|
||||
|
||||
local WheelOPow = math.abs( self.CurrentGear == 1 and math.min( TorqueConv, 0 ) or math.max( TorqueConv, 0 ) ) > 0
|
||||
local FrontWheelCanTurn = (WheelOPow and 0 or self.Brake) < MaxTraction * 1.75
|
||||
local RearWheelCanTurn = (self.HandBrake < MaxTraction) and (WheelOPow and 0 or self.Brake) < MaxTraction * 2
|
||||
|
||||
if WheelPos.IsFrontWheel then
|
||||
if FrontWheelCanTurn then
|
||||
self.VehicleData[ "spin_" .. i ] = self.VehicleData[ "spin_" .. i ] + TurnWheel
|
||||
end
|
||||
else
|
||||
if RearWheelCanTurn then
|
||||
self.VehicleData[ "spin_" .. i ] = self.VehicleData[ "spin_" .. i ] + TurnWheel
|
||||
end
|
||||
end
|
||||
|
||||
if self.CustomWheels then
|
||||
local GhostEnt = self.GhostWheels[i]
|
||||
|
||||
if IsValid( GhostEnt ) then
|
||||
local Angle = GhostEnt:GetAngles()
|
||||
local offsetang = WheelPos.IsFrontWheel and self.CustomWheelAngleOffset or (self.CustomWheelAngleOffset_R or self.CustomWheelAngleOffset)
|
||||
local Direction = GhostEnt:LocalToWorldAngles( offsetang ):Forward()
|
||||
local TFront = FrontWheelCanTurn and TurnWheel or 0
|
||||
local TBack = RearWheelCanTurn and TurnWheel or 0
|
||||
|
||||
local AngleStep = WheelPos.IsFrontWheel and TFront or TBack
|
||||
Angle:RotateAroundAxis(Direction, WheelPos.IsRightWheel and AngleStep or -AngleStep)
|
||||
|
||||
self.GhostWheels[i]:SetAngles( Angle )
|
||||
end
|
||||
else
|
||||
self:SetPoseParameter(self.VehicleData[ "pp_spin_" .. i ],self.VehicleData[ "spin_" .. i ])
|
||||
end
|
||||
|
||||
if not self.PhysicsEnabled then
|
||||
Wheel:GetPhysicsObject():ApplyForceCenter( Force * 185 * OnGround )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:SetWheelVelocity( wVel )
|
||||
|
||||
local target_diff = math.max(LimitRPM * 0.95 - self.EngineRPM,0)
|
||||
|
||||
if self.FrontWheelPowered and self.RearWheelPowered then
|
||||
self.WheelRPM = math.max(self.VehicleData[ "WheelRPM_1" ] or 0,self.VehicleData[ "WheelRPM_2" ] or 0,self.VehicleData[ "WheelRPM_3" ] or 0,self.VehicleData[ "WheelRPM_4" ] or 0)
|
||||
self.RPM_DIFFERENCE = target_diff * math.max(self.VehicleData[ "GripLossFaktor_1" ] or 0,self.VehicleData[ "GripLossFaktor_2" ] or 0,self.VehicleData[ "GripLossFaktor_3" ] or 0,self.VehicleData[ "GripLossFaktor_4" ] or 0)
|
||||
self.exprpmdiff = target_diff * math.max(self.VehicleData[ "Exp_GLF_1" ] or 0,self.VehicleData[ "Exp_GLF_2" ] or 0,self.VehicleData[ "Exp_GLF_3" ] or 0,self.VehicleData[ "Exp_GLF_4" ] or 0)
|
||||
|
||||
elseif not self.FrontWheelPowered and self.RearWheelPowered then
|
||||
self.WheelRPM = math.max(self.VehicleData[ "WheelRPM_3" ] or 0,self.VehicleData[ "WheelRPM_4" ] or 0)
|
||||
self.RPM_DIFFERENCE = target_diff * math.max(self.VehicleData[ "GripLossFaktor_3" ] or 0,self.VehicleData[ "GripLossFaktor_4" ] or 0)
|
||||
self.exprpmdiff = target_diff * math.max(self.VehicleData[ "Exp_GLF_3" ] or 0,self.VehicleData[ "Exp_GLF_4" ] or 0)
|
||||
|
||||
elseif self.FrontWheelPowered and not self.RearWheelPowered then
|
||||
self.WheelRPM = math.max(self.VehicleData[ "WheelRPM_1" ] or 0,self.VehicleData[ "WheelRPM_2" ] or 0)
|
||||
self.RPM_DIFFERENCE = target_diff * math.max(self.VehicleData[ "GripLossFaktor_1" ] or 0,self.VehicleData[ "GripLossFaktor_2" ] or 0)
|
||||
self.exprpmdiff = target_diff * math.max(self.VehicleData[ "Exp_GLF_1" ] or 0,self.VehicleData[ "Exp_GLF_2" ] or 0)
|
||||
|
||||
else
|
||||
self.WheelRPM = 0
|
||||
self.RPM_DIFFERENCE = 0
|
||||
self.exprpmdiff = 0
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:SimulateTurbo(LimitRPM)
|
||||
if not self.Turbo then return end
|
||||
|
||||
local Throttle = self:GetThrottle()
|
||||
|
||||
self.SmoothTurbo = self.SmoothTurbo + math.Clamp(math.min(self.EngineRPM / LimitRPM,1) * 600 * (0.75 + 0.25 * Throttle) - self.SmoothTurbo,-15,15)
|
||||
|
||||
local Volume = math.Clamp( ((self.SmoothTurbo - 300) / 150) ,0, 1) * 0.5
|
||||
local Pitch = math.Clamp( self.SmoothTurbo / 7 , 0 , 255)
|
||||
|
||||
local boost = math.Clamp( -0.25 + (self.SmoothTurbo / 500) ^ 5,0,1)
|
||||
|
||||
self.Turbo:ChangeVolume( Volume )
|
||||
self.Turbo:ChangePitch( Pitch )
|
||||
|
||||
return boost
|
||||
end
|
||||
|
||||
function ENT:SimulateBlower(LimitRPM)
|
||||
if not self.Blower or not self.BlowerWhine then return end
|
||||
|
||||
local Throttle = self:GetThrottle()
|
||||
|
||||
self.SmoothBlower = self.SmoothBlower + math.Clamp(math.min(self.EngineRPM / LimitRPM,1) * 500 - self.SmoothBlower,-20,20)
|
||||
|
||||
local Volume1 = math.Clamp( self.SmoothBlower / 400 * (1 - 0.4 * Throttle) ,0, 1)
|
||||
local Volume2 = math.Clamp( self.SmoothBlower / 400 * (0.10 + 0.4 * Throttle) ,0, 1)
|
||||
|
||||
local Pitch1 = 50 + math.Clamp( self.SmoothBlower / 4.5 , 0 , 205)
|
||||
local Pitch2 = Pitch1 * 1.2
|
||||
|
||||
local boost = math.Clamp( (self.SmoothBlower / 600) ^ 4 ,0,1)
|
||||
|
||||
self.Blower:ChangeVolume( Volume1 )
|
||||
self.Blower:ChangePitch( Pitch1 )
|
||||
|
||||
self.BlowerWhine:ChangeVolume( Volume2 )
|
||||
self.BlowerWhine:ChangePitch( Pitch2 )
|
||||
|
||||
return boost
|
||||
end
|
||||
710
lua/entities/gmod_sent_vehicle_fphysics_base/spawn.lua
Normal file
710
lua/entities/gmod_sent_vehicle_fphysics_base/spawn.lua
Normal file
@@ -0,0 +1,710 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local function IsServerOK()
|
||||
|
||||
if GetConVar( "gmod_physiterations" ):GetInt() < 4 then
|
||||
RunConsoleCommand("gmod_physiterations", "4")
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetNotSolid( true )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
--self:SetRenderMode( RENDERMODE_TRANSALPHA ) -- fix broken decals
|
||||
self:AddFlags( FL_OBJECT ) -- this allows npcs to see this entity
|
||||
|
||||
if not IsServerOK() then
|
||||
|
||||
self:Remove()
|
||||
|
||||
print("[SIMFPHYS] ERROR COULDN'T INITIALIZE VEHICLE!")
|
||||
end
|
||||
|
||||
local PObj = self:GetPhysicsObject()
|
||||
|
||||
if not IsValid( PObj ) then print("[SIMFPHYS] ERROR COULDN'T INITIALIZE VEHICLE! '"..self:GetModel().."' has no physics model!") self:Remove() return end
|
||||
|
||||
PObj:EnableMotion( false )
|
||||
|
||||
self:SetValues()
|
||||
|
||||
timer.Simple( 0.1, function()
|
||||
if not IsValid( self ) then return end
|
||||
self:InitializeVehicle()
|
||||
end)
|
||||
end
|
||||
|
||||
function ENT:PostEntityPaste( ply , ent , createdEntities )
|
||||
self:SetValues()
|
||||
|
||||
self:SetActive( false )
|
||||
self:SetDriver( NULL )
|
||||
self:SetLightsEnabled( false )
|
||||
self:SetLampsEnabled( false )
|
||||
self:SetFogLightsEnabled( false )
|
||||
|
||||
self:SetDriverSeat( NULL )
|
||||
self:SetFlyWheelRPM( 0 )
|
||||
self:SetThrottle( 0 )
|
||||
end
|
||||
|
||||
function ENT:UpdateTransmitState()
|
||||
return TRANSMIT_ALWAYS
|
||||
end
|
||||
|
||||
function ENT:SetupView()
|
||||
local AttachmentID = self:LookupAttachment( "vehicle_driver_eyes" )
|
||||
local AttachmentID2 = self:LookupAttachment( "vehicle_passenger0_eyes" )
|
||||
|
||||
local a_data1 = self:GetAttachment( AttachmentID )
|
||||
local a_data2 = self:GetAttachment( AttachmentID2 )
|
||||
|
||||
local ID
|
||||
local ViewPos
|
||||
|
||||
if a_data1 then
|
||||
ID = AttachmentID
|
||||
ViewPos = a_data1
|
||||
|
||||
elseif a_data2 then
|
||||
ID = AttachmentID2
|
||||
ViewPos = a_data2
|
||||
|
||||
else
|
||||
ID = false
|
||||
ViewPos = {Ang = self:LocalToWorldAngles( Angle(0, 90,0) ),Pos = self:GetPos()}
|
||||
end
|
||||
|
||||
local ViewAng = ViewPos.Ang - Angle(0,0,self.SeatPitch)
|
||||
ViewAng:RotateAroundAxis(self:GetUp(), -90 - (self.SeatYaw or 0))
|
||||
|
||||
local data = {
|
||||
ID = ID,
|
||||
ViewPos = ViewPos.Pos,
|
||||
ViewAng = ViewAng,
|
||||
}
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
function ENT:SetupEnteringAnims()
|
||||
local attachments = self:GetAttachments()
|
||||
|
||||
self.Exitpoints = {}
|
||||
self.Enterpoints = {}
|
||||
|
||||
for _,i in pairs(attachments) do
|
||||
local curstring = string.lower( i.name )
|
||||
|
||||
if string.match( curstring, "exit", 1 ) then
|
||||
table.insert(self.Exitpoints, curstring)
|
||||
end
|
||||
|
||||
if string.match( curstring, "enter", 1 ) then
|
||||
table.insert(self.Enterpoints, curstring)
|
||||
end
|
||||
end
|
||||
|
||||
if table.Count( self.Enterpoints ) < 1 then
|
||||
self.Enterpoints = nil
|
||||
end
|
||||
|
||||
if table.Count( self.Exitpoints ) < 1 then
|
||||
self.Exitpoints = nil
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:InitializeVehicle()
|
||||
if not IsValid( self ) then return end
|
||||
|
||||
local physObj = self:GetPhysicsObject()
|
||||
|
||||
if not IsValid( physObj ) then return end
|
||||
|
||||
if self.LightsTable then
|
||||
local vehiclelist = list.Get( "simfphys_lights" )[self.LightsTable] or false
|
||||
if vehiclelist then
|
||||
if vehiclelist.PoseParameters then
|
||||
self.LightsPP = vehiclelist.PoseParameters
|
||||
end
|
||||
|
||||
if vehiclelist.BodyGroups then
|
||||
self:SetBodygroup(vehiclelist.BodyGroups.Off[1], vehiclelist.BodyGroups.Off[2] )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
physObj:SetDragCoefficient( self.AirFriction or -250 )
|
||||
physObj:SetMass( self.Mass * 0.75 )
|
||||
|
||||
if self.Inertia then
|
||||
physObj:SetInertia( self.Inertia )
|
||||
end
|
||||
|
||||
local tanksize = self.FuelTankSize and self.FuelTankSize or 65
|
||||
local fueltype = self.FuelType and self.FuelType or FUELTYPE_PETROL
|
||||
|
||||
self:SetMaxFuel( tanksize )
|
||||
self:SetFuel( self:GetMaxFuel() )
|
||||
self:SetFuelType( fueltype )
|
||||
self:SetFuelPos( self.FuelFillPos and self.FuelFillPos or Vector(0,0,0) )
|
||||
|
||||
if fueltype ~= FUELTYPE_NONE then
|
||||
self:AddFuelTank()
|
||||
end
|
||||
|
||||
local View = self:SetupView()
|
||||
|
||||
self.DriverSeat = self:AddDriverSeat( self:WorldToLocal( View.ViewPos ), self:WorldToLocalAngles( View.ViewAng ) )
|
||||
self.DriverSeat:SetParent( NULL )
|
||||
self.DriverSeat:SetMoveType( MOVETYPE_NONE )
|
||||
self.DriverSeat:Spawn()
|
||||
self.DriverSeat:Activate()
|
||||
self.DriverSeat:SetPos( View.ViewPos + self.DriverSeat:GetUp() * (-34 + self.SeatOffset.z) + self.DriverSeat:GetRight() * (self.SeatOffset.y) + self.DriverSeat:GetForward() * (-6 + self.SeatOffset.x) )
|
||||
|
||||
if View.ID ~= false then
|
||||
self:SetupEnteringAnims()
|
||||
self.DriverSeat:SetParent( self , View.ID )
|
||||
else
|
||||
self.DriverSeat:SetParent( self )
|
||||
end
|
||||
|
||||
self.DriverSeat.fphysSeat = true
|
||||
self.DriverSeat.base = self
|
||||
|
||||
if self.PassengerSeats then
|
||||
for i = 1, table.Count( self.PassengerSeats ) do
|
||||
self.pSeat[i] = self:AddPassengerSeat( self.PassengerSeats[i].pos, self.PassengerSeats[i].ang )
|
||||
self.pSeat[i].fphysSeat = true
|
||||
self.pSeat[i].base = self
|
||||
end
|
||||
end
|
||||
|
||||
if istable(WireLib) then
|
||||
local passengersSeats = istable( self.pSeat ) and self.pSeat or {}
|
||||
WireLib.TriggerOutput(self, "PassengerSeats", passengersSeats )
|
||||
|
||||
WireLib.TriggerOutput(self, "DriverSeat", self.DriverSeat )
|
||||
end
|
||||
|
||||
if self.Attachments then
|
||||
for i = 1, table.Count( self.Attachments ) do
|
||||
local prop = ents.Create( "gmod_sent_vehicle_fphysics_attachment" )
|
||||
prop:SetModel( self.Attachments[i].model )
|
||||
prop:SetMaterial( self.Attachments[i].material )
|
||||
prop:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
prop:SetPos( self:LocalToWorld( self.Attachments[i].pos ) )
|
||||
prop:SetAngles( self:LocalToWorldAngles( self.Attachments[i].ang ) )
|
||||
prop:SetOwner( self )
|
||||
prop:Spawn()
|
||||
prop:Activate()
|
||||
prop:DrawShadow( true )
|
||||
prop:SetNotSolid( true )
|
||||
prop:SetParent( self )
|
||||
prop.DoNotDuplicate = true
|
||||
simfphys.SetOwner( self.EntityOwner, prop )
|
||||
|
||||
if self.Attachments[i].skin then
|
||||
prop:SetSkin( self.Attachments[i].skin )
|
||||
end
|
||||
|
||||
if self.Attachments[i].bodygroups then
|
||||
for b = 1, table.Count( self.Attachments[i].bodygroups ) do
|
||||
prop:SetBodygroup(b, self.Attachments[i].bodygroups[b] )
|
||||
end
|
||||
end
|
||||
|
||||
if self.Attachments[i].useVehicleColor == true then
|
||||
self.ColorableProps[i] = prop
|
||||
prop:SetColor( self:GetColor() )
|
||||
else
|
||||
prop:SetColor( self.Attachments[i].color or Color(255,255,255,255) )
|
||||
end
|
||||
|
||||
self:DeleteOnRemove( prop )
|
||||
end
|
||||
end
|
||||
|
||||
self:GetVehicleData()
|
||||
end
|
||||
|
||||
function ENT:GetVehicleData()
|
||||
self:SetPoseParameter("vehicle_steer",1)
|
||||
self:SetPoseParameter("vehicle_wheel_fl_height",1)
|
||||
self:SetPoseParameter("vehicle_wheel_fr_height",1)
|
||||
self:SetPoseParameter("vehicle_wheel_rl_height",1)
|
||||
self:SetPoseParameter("vehicle_wheel_rr_height",1)
|
||||
|
||||
timer.Simple( 0.15, function()
|
||||
if not IsValid(self) then return end
|
||||
self.posepositions["Pose0_Steerangle"] = self.CustomWheels and Angle(0,0,0) or self:GetAttachment( self:LookupAttachment( "wheel_fl" ) ).Ang
|
||||
self.posepositions["Pose0_Pos_FL"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosFL ) or self:GetAttachment( self:LookupAttachment( "wheel_fl" ) ).Pos
|
||||
self.posepositions["Pose0_Pos_FR"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosFR ) or self:GetAttachment( self:LookupAttachment( "wheel_fr" ) ).Pos
|
||||
self.posepositions["Pose0_Pos_RL"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosRL ) or self:GetAttachment( self:LookupAttachment( "wheel_rl" ) ).Pos
|
||||
self.posepositions["Pose0_Pos_RR"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosRR ) or self:GetAttachment( self:LookupAttachment( "wheel_rr" ) ).Pos
|
||||
|
||||
self:WriteVehicleDataTable()
|
||||
end )
|
||||
end
|
||||
|
||||
function ENT:ResetJoystick()
|
||||
self.PressedKeys["joystick_steer_left"] = 0
|
||||
self.PressedKeys["joystick_steer_right"] = 0
|
||||
self.PressedKeys["joystick_brake"] = 0
|
||||
self.PressedKeys["joystick_throttle"] = 0
|
||||
self.PressedKeys["joystick_gearup"] = 0
|
||||
self.PressedKeys["joystick_geardown"] = 0
|
||||
self.PressedKeys["joystick_handbrake"] = 0
|
||||
self.PressedKeys["joystick_clutch"] = 0
|
||||
self.PressedKeys["joystick_air_w"] = 0
|
||||
self.PressedKeys["joystick_air_a"] = 0
|
||||
self.PressedKeys["joystick_air_s"] = 0
|
||||
self.PressedKeys["joystick_air_d"] = 0
|
||||
end
|
||||
|
||||
function ENT:SetValues()
|
||||
if istable( WireLib ) then
|
||||
self:createWireIO()
|
||||
end
|
||||
|
||||
self:SetGear( 2 )
|
||||
|
||||
self.WheelOnGroundDelay = 0
|
||||
self.SmoothAng = 0
|
||||
self.Steer = 0
|
||||
self.EngineIsOn = 0
|
||||
self.EngineTorque = 0
|
||||
|
||||
self.pSeat = {}
|
||||
self.exfx = {}
|
||||
self.Wheels = {}
|
||||
self.Elastics = {}
|
||||
self.GhostWheels = {}
|
||||
self.PressedKeys = {}
|
||||
self:ResetJoystick()
|
||||
|
||||
self.ColorableProps = {}
|
||||
self.posepositions = {}
|
||||
|
||||
self.HandBrakePower = 0
|
||||
self.DriveWheelsOnGround = 0
|
||||
self.WheelRPM = 0
|
||||
self.EngineRPM = 0
|
||||
self.RpmDiff = 0
|
||||
self.Torque = 0
|
||||
self.CurrentGear = 2
|
||||
self.GearUpPressed = 0
|
||||
self.GearDownPressed = 0
|
||||
self.RPM_DIFFERENCE = 0
|
||||
self.exprpmdiff = 0
|
||||
self.OldLockBrakes = 0
|
||||
self.ThrottleDelay = 0
|
||||
self.Brake = 0
|
||||
self.HandBrake = 0
|
||||
self.AutoClutch = 0
|
||||
self.NextShift = 0
|
||||
self.ForwardSpeed = 0
|
||||
self.EngineWasOn = 0
|
||||
self.SmoothTurbo = 0
|
||||
self.SmoothBlower = 0
|
||||
self.cc_speed = 0
|
||||
self.LightsActivated = false
|
||||
|
||||
self.VehicleData = {}
|
||||
for i = 1, 6 do
|
||||
self.VehicleData[ "spin_"..i ] = 0
|
||||
self.VehicleData[ "SurfaceMul_"..i ] = 1
|
||||
self.VehicleData[ "onGround_"..i ] = 0
|
||||
end
|
||||
|
||||
self.VehicleData[ "Steer" ] = 0
|
||||
end
|
||||
|
||||
function ENT:WriteVehicleDataTable()
|
||||
self:SetPoseParameter("vehicle_steer",0)
|
||||
self:SetPoseParameter("vehicle_wheel_fl_height",0)
|
||||
self:SetPoseParameter("vehicle_wheel_fr_height",0)
|
||||
self:SetPoseParameter("vehicle_wheel_rl_height",0)
|
||||
self:SetPoseParameter("vehicle_wheel_rr_height",0)
|
||||
|
||||
timer.Simple( 0.15, function()
|
||||
if not IsValid(self) then return end
|
||||
self.posepositions["Pose1_Steerangle"] = self.CustomWheels and Angle(0,0,0) or self:GetAttachment( self:LookupAttachment( "wheel_fl" ) ).Ang
|
||||
self.posepositions["Pose1_Pos_FL"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosFL ) or self:GetAttachment( self:LookupAttachment( "wheel_fl" ) ).Pos
|
||||
self.posepositions["Pose1_Pos_FR"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosFR ) or self:GetAttachment( self:LookupAttachment( "wheel_fr" ) ).Pos
|
||||
self.posepositions["Pose1_Pos_RL"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosRL ) or self:GetAttachment( self:LookupAttachment( "wheel_rl" ) ).Pos
|
||||
self.posepositions["Pose1_Pos_RR"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosRR ) or self:GetAttachment( self:LookupAttachment( "wheel_rr" ) ).Pos
|
||||
self.posepositions["PoseL_Pos_FL"] = self:WorldToLocal( self.posepositions.Pose1_Pos_FL )
|
||||
self.posepositions["PoseL_Pos_FR"] = self:WorldToLocal( self.posepositions.Pose1_Pos_FR )
|
||||
self.posepositions["PoseL_Pos_RL"] = self:WorldToLocal( self.posepositions.Pose1_Pos_RL )
|
||||
self.posepositions["PoseL_Pos_RR"] = self:WorldToLocal( self.posepositions.Pose1_Pos_RR )
|
||||
|
||||
self.VehicleData["suspensiontravel_fl"] = self.CustomWheels and self.FrontHeight or math.Round( (self.posepositions.Pose0_Pos_FL - self.posepositions.Pose1_Pos_FL):Length() , 2)
|
||||
self.VehicleData["suspensiontravel_fr"] = self.CustomWheels and self.FrontHeight or math.Round( (self.posepositions.Pose0_Pos_FR - self.posepositions.Pose1_Pos_FR):Length() , 2)
|
||||
self.VehicleData["suspensiontravel_rl"] = self.CustomWheels and self.RearHeight or math.Round( (self.posepositions.Pose0_Pos_RL - self.posepositions.Pose1_Pos_RL):Length() , 2)
|
||||
self.VehicleData["suspensiontravel_rr"] = self.CustomWheels and self.RearHeight or math.Round( (self.posepositions.Pose0_Pos_RR - self.posepositions.Pose1_Pos_RR):Length() , 2)
|
||||
|
||||
local Figure1 = math.Round( math.acos( math.Clamp(self.posepositions.Pose0_Steerangle:Up():Dot(self.posepositions.Pose1_Steerangle:Up()),-1,1) ) * (180 / math.pi) , 2)
|
||||
local Figure2 = math.Round( math.acos( math.Clamp(self.posepositions.Pose0_Steerangle:Forward():Dot(self.posepositions.Pose1_Steerangle:Forward()),-1,1) ) * (180 / math.pi) , 2)
|
||||
local Figure3 = math.Round( math.acos( math.Clamp(self.posepositions.Pose0_Steerangle:Right():Dot(self.posepositions.Pose1_Steerangle:Right()),-1,1) ) * (180 / math.pi) , 2)
|
||||
self.VehicleData["steerangle"] = self.CustomWheels and self.CustomSteerAngle or math.max(Figure1,Figure2,Figure3)
|
||||
|
||||
local pFL = self.posepositions.Pose0_Pos_FL
|
||||
local pFR = self.posepositions.Pose0_Pos_FR
|
||||
local pRL = self.posepositions.Pose0_Pos_RL
|
||||
local pRR = self.posepositions.Pose0_Pos_RR
|
||||
local pAngL = self:WorldToLocalAngles( ((pFL + pFR) / 2 - (pRL + pRR) / 2):Angle() )
|
||||
pAngL.r = 0
|
||||
pAngL.p = 0
|
||||
|
||||
self.VehicleData["LocalAngForward"] = pAngL
|
||||
|
||||
local yAngL = self.VehicleData.LocalAngForward - Angle(0,90,0)
|
||||
yAngL:Normalize()
|
||||
|
||||
self.VehicleData["LocalAngRight"] = yAngL
|
||||
self.VehicleData[ "pp_spin_1" ] = "vehicle_wheel_fl_spin"
|
||||
self.VehicleData[ "pp_spin_2" ] = "vehicle_wheel_fr_spin"
|
||||
self.VehicleData[ "pp_spin_3" ] = "vehicle_wheel_rl_spin"
|
||||
self.VehicleData[ "pp_spin_4" ] = "vehicle_wheel_rr_spin"
|
||||
|
||||
self.Turbo = CreateSound(self, "")
|
||||
self.Blower = CreateSound(self, "")
|
||||
self.BlowerWhine = CreateSound(self, "")
|
||||
self.BlowOff = CreateSound(self, "")
|
||||
|
||||
local Health = math.floor(self.MaxHealth ~= -1 and self.MaxHealth or (1000 + self:GetPhysicsObject():GetMass() / 3))
|
||||
self:SetMaxHealth( Health )
|
||||
self:SetCurHealth( Health )
|
||||
|
||||
self:SetAITEAM( self.AITEAM )
|
||||
|
||||
self:SetFastSteerAngle(self.FastSteeringAngle / self.VehicleData["steerangle"])
|
||||
self:SetNotSolid( false )
|
||||
self:SetupVehicle()
|
||||
end )
|
||||
end
|
||||
|
||||
function ENT:SetupVehicle()
|
||||
local BaseMass = self:GetPhysicsObject():GetMass()
|
||||
local MassCenterOffset = self.CustomMassCenter or Vector(0,0,0)
|
||||
local BaseMassCenter = self:LocalToWorld( self:GetPhysicsObject():GetMassCenter() - MassCenterOffset )
|
||||
|
||||
local OffsetMass = BaseMass * 0.25
|
||||
local CenterWheels = (self.posepositions["Pose1_Pos_FL"] + self.posepositions["Pose1_Pos_FR"] + self.posepositions["Pose1_Pos_RL"] + self.posepositions["Pose1_Pos_RR"]) / 4
|
||||
|
||||
local Sub = CenterWheels - BaseMassCenter
|
||||
local Dir = Sub:GetNormalized()
|
||||
local Dist = Sub:Length()
|
||||
local DistAdd = BaseMass * Dist / OffsetMass
|
||||
|
||||
local OffsetMassCenter = BaseMassCenter + Dir * (Dist + DistAdd)
|
||||
|
||||
self.MassOffset = ents.Create( "prop_physics" )
|
||||
self.MassOffset:SetModel( "models/hunter/plates/plate.mdl" )
|
||||
self.MassOffset:SetPos( OffsetMassCenter )
|
||||
self.MassOffset:SetAngles( Angle(0,0,0) )
|
||||
self.MassOffset:Spawn()
|
||||
self.MassOffset:Activate()
|
||||
self.MassOffset:GetPhysicsObject():EnableMotion(false)
|
||||
self.MassOffset:GetPhysicsObject():SetMass( OffsetMass )
|
||||
self.MassOffset:GetPhysicsObject():EnableDrag( false )
|
||||
self.MassOffset:SetOwner( self )
|
||||
self.MassOffset:DrawShadow( false )
|
||||
self.MassOffset:SetNotSolid( true )
|
||||
self.MassOffset:SetNoDraw( true )
|
||||
self.MassOffset.DoNotDuplicate = true
|
||||
simfphys.SetOwner( self.EntityOwner, self.MassOffset )
|
||||
|
||||
local weld = constraint.Weld(self.MassOffset,self, 0, 0, 0,true, true)
|
||||
weld.DoNotDuplicate = true
|
||||
|
||||
local ballsack = constraint.AdvBallsocket(self.MassOffset, self,0,0,Vector(0,0,0),Vector(0,0,0),0,0, -0.01, -0.01, -0.01, 0.01, 0.01, 0.01, 0, 0, 0, 0, 1)
|
||||
ballsack.DoNotDuplicate = true
|
||||
|
||||
if self.CustomWheels then
|
||||
if self.CustomWheelModel then
|
||||
if not file.Exists( self.CustomWheelModel, "GAME" ) then
|
||||
if IsValid( self.EntityOwner ) then
|
||||
self.EntityOwner:PrintMessage( HUD_PRINTTALK, "ERROR: \""..self.CustomWheelModel.."\" does not exist! Removing vehicle. (Class: "..self:GetSpawn_List()..")")
|
||||
end
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
if self.SteerFront ~= false then
|
||||
self.SteerMaster = ents.Create( "prop_physics" )
|
||||
self.SteerMaster:SetModel( self.CustomWheelModel )
|
||||
self.SteerMaster:SetPos( self:GetPos() )
|
||||
self.SteerMaster:SetAngles( self:GetAngles() )
|
||||
self.SteerMaster:Spawn()
|
||||
self.SteerMaster:Activate()
|
||||
|
||||
local pobj = self.SteerMaster:GetPhysicsObject()
|
||||
|
||||
if IsValid(pobj) then
|
||||
pobj:EnableMotion(false)
|
||||
else
|
||||
if IsValid( self.EntityOwner ) then
|
||||
self.EntityOwner:PrintMessage( HUD_PRINTTALK, "ERROR: \""..self.CustomWheelModel.."\" doesn't have an collision model! Removing vehicle. (Class: "..self:GetSpawn_List()..")")
|
||||
end
|
||||
self.SteerMaster:Remove()
|
||||
self:Remove()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self.SteerMaster:SetOwner( self )
|
||||
self.SteerMaster:DrawShadow( false )
|
||||
self.SteerMaster:SetNotSolid( true )
|
||||
self.SteerMaster:SetNoDraw( true )
|
||||
self.SteerMaster.DoNotDuplicate = true
|
||||
self:DeleteOnRemove( self.SteerMaster )
|
||||
simfphys.SetOwner( self.EntityOwner, self.SteerMaster )
|
||||
end
|
||||
|
||||
if self.SteerRear then
|
||||
self.SteerMaster2 = ents.Create( "prop_physics" )
|
||||
self.SteerMaster2:SetModel( self.CustomWheelModel )
|
||||
self.SteerMaster2:SetPos( self:GetPos() )
|
||||
self.SteerMaster2:SetAngles( self:GetAngles() )
|
||||
self.SteerMaster2:Spawn()
|
||||
self.SteerMaster2:Activate()
|
||||
|
||||
local pobj = self.SteerMaster2:GetPhysicsObject()
|
||||
if IsValid(pobj) then
|
||||
pobj:EnableMotion(false)
|
||||
else
|
||||
if IsValid( self.EntityOwner ) then
|
||||
self.EntityOwner:PrintMessage( HUD_PRINTTALK, "ERROR: \""..self.CustomWheelModel.."\" doesn't have an collision model! Removing vehicle. (Class: "..self:GetSpawn_List()..")")
|
||||
end
|
||||
self.SteerMaster2:Remove()
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
self.SteerMaster2:SetOwner( self )
|
||||
self.SteerMaster2:DrawShadow( false )
|
||||
self.SteerMaster2:SetNotSolid( true )
|
||||
self.SteerMaster2:SetNoDraw( true )
|
||||
self.SteerMaster2.DoNotDuplicate = true
|
||||
self:DeleteOnRemove( self.SteerMaster2 )
|
||||
simfphys.SetOwner( self.EntityOwner, self.SteerMaster2 )
|
||||
end
|
||||
|
||||
local radius = IsValid(self.SteerMaster) and (self.SteerMaster:OBBMaxs() - self.SteerMaster:OBBMins()) or (self.SteerMaster2:OBBMaxs() - self.SteerMaster2:OBBMins())
|
||||
self.FrontWheelRadius = self.FrontWheelRadius or math.max( radius.x, radius.y, radius.z ) * 0.5
|
||||
self.RearWheelRadius = self.RearWheelRadius or self.FrontWheelRadius
|
||||
|
||||
self:CreateWheel(1, WheelFL, self:LocalToWorld( self.CustomWheelPosFL ), self.FrontHeight, self.FrontWheelRadius, false , self:LocalToWorld( self.CustomWheelPosFL + Vector(0,0,self.CustomSuspensionTravel * 0.5) ),self.CustomSuspensionTravel, self.FrontConstant, self.FrontDamping, self.FrontRelativeDamping)
|
||||
self:CreateWheel(2, WheelFR, self:LocalToWorld( self.CustomWheelPosFR ), self.FrontHeight, self.FrontWheelRadius, true , self:LocalToWorld( self.CustomWheelPosFR + Vector(0,0,self.CustomSuspensionTravel * 0.5) ),self.CustomSuspensionTravel, self.FrontConstant, self.FrontDamping, self.FrontRelativeDamping)
|
||||
self:CreateWheel(3, WheelRL, self:LocalToWorld( self.CustomWheelPosRL ), self.RearHeight, self.RearWheelRadius, false , self:LocalToWorld( self.CustomWheelPosRL + Vector(0,0,self.CustomSuspensionTravel * 0.5) ),self.CustomSuspensionTravel, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
self:CreateWheel(4, WheelRR, self:LocalToWorld( self.CustomWheelPosRR ), self.RearHeight, self.RearWheelRadius, true , self:LocalToWorld( self.CustomWheelPosRR + Vector(0,0,self.CustomSuspensionTravel * 0.5) ), self.CustomSuspensionTravel, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
|
||||
if self.CustomWheelPosML then
|
||||
self:CreateWheel(5, WheelML, self:LocalToWorld( self.CustomWheelPosML ), self.RearHeight, self.RearWheelRadius, false , self:LocalToWorld( self.CustomWheelPosML + Vector(0,0,self.CustomSuspensionTravel * 0.5) ),self.CustomSuspensionTravel, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
end
|
||||
|
||||
if self.CustomWheelPosMR then
|
||||
self:CreateWheel(6, WheelMR, self:LocalToWorld( self.CustomWheelPosMR ), self.RearHeight, self.RearWheelRadius, true , self:LocalToWorld( self.CustomWheelPosMR + Vector(0,0,self.CustomSuspensionTravel * 0.5) ), self.CustomSuspensionTravel, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
end
|
||||
else
|
||||
if IsValid( self.EntityOwner ) then
|
||||
self.EntityOwner:PrintMessage( HUD_PRINTTALK, "ERROR: no wheel model defined. Removing vehicle. (Class: "..self:GetSpawn_List()..")")
|
||||
end
|
||||
self:Remove()
|
||||
end
|
||||
else
|
||||
self:CreateWheel(1, WheelFL, self:GetAttachment( self:LookupAttachment( "wheel_fl" ) ).Pos, self.FrontHeight, self.FrontWheelRadius, false , self.posepositions.Pose1_Pos_FL, self.VehicleData.suspensiontravel_fl, self.FrontConstant, self.FrontDamping, self.FrontRelativeDamping)
|
||||
self:CreateWheel(2, WheelFR, self:GetAttachment( self:LookupAttachment( "wheel_fr" ) ).Pos, self.FrontHeight, self.FrontWheelRadius, true , self.posepositions.Pose1_Pos_FR, self.VehicleData.suspensiontravel_fr, self.FrontConstant, self.FrontDamping, self.FrontRelativeDamping)
|
||||
self:CreateWheel(3, WheelRL, self:GetAttachment( self:LookupAttachment( "wheel_rl" ) ).Pos, self.RearHeight, self.RearWheelRadius, false , self.posepositions.Pose1_Pos_RL, self.VehicleData.suspensiontravel_rl, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
self:CreateWheel(4, WheelRR, self:GetAttachment( self:LookupAttachment( "wheel_rr" ) ).Pos, self.RearHeight, self.RearWheelRadius, true , self.posepositions.Pose1_Pos_RR, self.VehicleData.suspensiontravel_rr, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
end
|
||||
|
||||
timer.Simple( 0.01, function()
|
||||
if not istable( self.Wheels ) then return end
|
||||
|
||||
for i = 1, table.Count( self.Wheels ) do
|
||||
local Ent = self.Wheels[ i ]
|
||||
local PhysObj = Ent:GetPhysicsObject()
|
||||
|
||||
if IsValid( PhysObj ) then
|
||||
PhysObj:EnableMotion( true )
|
||||
end
|
||||
end
|
||||
|
||||
timer.Simple( 0.1, function()
|
||||
if not IsValid( self ) then return end
|
||||
|
||||
self:GetPhysicsObject():EnableMotion(true)
|
||||
|
||||
local PhysObj = self.MassOffset:GetPhysicsObject()
|
||||
if IsValid( PhysObj ) then
|
||||
PhysObj:EnableMotion(true)
|
||||
end
|
||||
end )
|
||||
end )
|
||||
|
||||
if istable( self.GibModels ) then
|
||||
for _, modelName in ipairs( self.GibModels ) do
|
||||
util.PrecacheModel( modelName )
|
||||
end
|
||||
end
|
||||
|
||||
self:OnSpawn()
|
||||
hook.Run( "simfphysOnSpawn", self )
|
||||
|
||||
self:SetlvsReady( true )
|
||||
|
||||
self.VehicleData["filter"] = self:GetCrosshairFilterEnts()
|
||||
end
|
||||
|
||||
function ENT:CreateWheel(index, name, attachmentpos, height, radius, swap_y , poseposition, suspensiontravel, constant, damping, rdamping)
|
||||
local fAng = self:LocalToWorldAngles( self.VehicleData.LocalAngForward )
|
||||
local rAng = self:LocalToWorldAngles( self.VehicleData.LocalAngRight )
|
||||
|
||||
local Forward = fAng:Forward()
|
||||
local Right = swap_y and -rAng:Forward() or rAng:Forward()
|
||||
local Up = self:GetUp()
|
||||
|
||||
local RopeLength = 150
|
||||
local LimiterLength = 60
|
||||
local LimiterRopeLength = math.sqrt( (suspensiontravel * 0.5) ^ 2 + LimiterLength ^ 2 )
|
||||
local WheelMass = self.Mass / 32
|
||||
|
||||
if self.FrontWheelMass and (index == 1 or index == 2) then
|
||||
WheelMass = self.FrontWheelMass
|
||||
end
|
||||
if self.RearWheelMass and (index == 3 or index == 4 or index == 5 or index == 6) then
|
||||
WheelMass = self.RearWheelMass
|
||||
end
|
||||
|
||||
self.name = ents.Create( "gmod_sent_vehicle_fphysics_wheel" )
|
||||
self.name:SetPos( attachmentpos - Up * height)
|
||||
self.name:SetAngles( fAng )
|
||||
self.name:Spawn()
|
||||
self.name:Activate()
|
||||
self.name:PhysicsInitSphere( radius, "jeeptire" )
|
||||
self.name:SetCollisionBounds( Vector(-radius,-radius,-radius), Vector(radius,radius,radius) )
|
||||
self.name:GetPhysicsObject():EnableMotion(false)
|
||||
self.name:GetPhysicsObject():SetMass( WheelMass )
|
||||
self.name:SetBaseEnt( self )
|
||||
simfphys.SetOwner( self.EntityOwner, self.name )
|
||||
self.name.EntityOwner = self.EntityOwner
|
||||
self.name.Index = index
|
||||
self.name.Radius = radius
|
||||
self.name:SetRadius( radius )
|
||||
|
||||
if self.CustomWheels then
|
||||
local Model = (self.CustomWheelModel_R and (index == 3 or index == 4 or index == 5 or index == 6)) and self.CustomWheelModel_R or self.CustomWheelModel
|
||||
local ghostAng = Right:Angle()
|
||||
local mirAng = swap_y and 1 or -1
|
||||
ghostAng:RotateAroundAxis(Forward,self.CustomWheelAngleOffset.p * mirAng)
|
||||
ghostAng:RotateAroundAxis(Right,self.CustomWheelAngleOffset.r * mirAng)
|
||||
ghostAng:RotateAroundAxis(Up,-self.CustomWheelAngleOffset.y)
|
||||
|
||||
local Camber = self.CustomWheelCamber or 0
|
||||
ghostAng:RotateAroundAxis(Forward, Camber * mirAng)
|
||||
|
||||
self.GhostWheels[index] = ents.Create( "gmod_sent_vehicle_fphysics_attachment" )
|
||||
self.GhostWheels[index]:SetModel( Model )
|
||||
self.GhostWheels[index]:SetPos( self.name:GetPos() )
|
||||
self.GhostWheels[index]:SetAngles( ghostAng )
|
||||
self.GhostWheels[index]:SetOwner( self )
|
||||
self.GhostWheels[index]:Spawn()
|
||||
self.GhostWheels[index]:Activate()
|
||||
self.GhostWheels[index]:SetNotSolid( true )
|
||||
self.GhostWheels[index].DoNotDuplicate = true
|
||||
self.GhostWheels[index]:SetParent( self.name )
|
||||
self:DeleteOnRemove( self.GhostWheels[index] )
|
||||
simfphys.SetOwner( self.EntityOwner, self.GhostWheels[index] )
|
||||
|
||||
self.GhostWheels[index]:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
|
||||
if self.ModelInfo then
|
||||
if self.ModelInfo.WheelColor then
|
||||
self.GhostWheels[index]:SetColor( self.ModelInfo.WheelColor )
|
||||
end
|
||||
end
|
||||
|
||||
self.name.GhostEnt = self.GhostWheels[index]
|
||||
|
||||
local nocollide = constraint.NoCollide(self,self.name,0,0)
|
||||
nocollide.DoNotDuplicate = true
|
||||
end
|
||||
|
||||
local targetentity = self
|
||||
if self.CustomWheels then
|
||||
if index == 1 or index == 2 then
|
||||
targetentity = self.SteerMaster or self
|
||||
end
|
||||
if index == 3 or index == 4 then
|
||||
targetentity = self.SteerMaster2 or self
|
||||
end
|
||||
end
|
||||
|
||||
local Ballsocket = constraint.AdvBallsocket(targetentity,self.name,0,0,Vector(0,0,0),Vector(0,0,0),0,0, -0.01, -0.01, -0.01, 0.01, 0.01, 0.01, 0, 0, 0, 1, 1)
|
||||
local Rope1 = constraint.Rope(self,self.name,0,0,self:WorldToLocal( self.name:GetPos() + Forward * RopeLength * 0.5 + Right * RopeLength), Vector(0,0,0), Vector(RopeLength * 0.5,RopeLength,0):Length(), 0, 0, 0,"cable/cable2", true )
|
||||
local Rope2 = constraint.Rope(self,self.name,0,0,self:WorldToLocal( self.name:GetPos() - Forward * RopeLength * 0.5 + Right * RopeLength), Vector(0,0,0), Vector(RopeLength * 0.5,RopeLength,0):Length(), 0, 0, 0,"cable/cable2", true )
|
||||
|
||||
if self.StrengthenSuspension == true then
|
||||
local Rope3 = constraint.Rope(self,self.name,0,0,self:WorldToLocal( poseposition - Up * suspensiontravel * 0.5 + Right * LimiterLength), Vector(0,0,0),LimiterRopeLength * 0.99, 0, 0, 0,"cable/cable2", false )
|
||||
local Rope4 = constraint.Rope(self,self.name,0,0,self:WorldToLocal( poseposition - Up * suspensiontravel * 0.5 - Right * LimiterLength), Vector(0,0,0),LimiterRopeLength * 1, 0, 0, 0,"cable/cable2", false )
|
||||
local elastic1 = constraint.Elastic(self.name, self, 0, 0, Vector(0,0,height), self:WorldToLocal( self.name:GetPos() ), constant * 0.5, damping * 0.5, rdamping * 0.5,"cable/cable2",0, false)
|
||||
local elastic2 = constraint.Elastic(self.name, self, 0, 0, Vector(0,0,height), self:WorldToLocal( self.name:GetPos() ), constant * 0.5, damping * 0.5, rdamping * 0.5,"cable/cable2",0, false)
|
||||
|
||||
Rope3.DoNotDuplicate = true
|
||||
Rope4.DoNotDuplicate = true
|
||||
elastic1.DoNotDuplicate = true
|
||||
elastic2.DoNotDuplicate = true
|
||||
self.Elastics[index] = elastic1
|
||||
self.Elastics[index * 10] = elastic2
|
||||
else
|
||||
local Rope3 = constraint.Rope(self,self.name,0,0,self:WorldToLocal( poseposition - Up * suspensiontravel * 0.5 + Right * LimiterLength), Vector(0,0,0),LimiterRopeLength, 0, 0, 0,"cable/cable2", false )
|
||||
local elastic = constraint.Elastic(self.name, self, 0, 0, Vector(0,0,height), self:WorldToLocal( self.name:GetPos() ), constant, damping, rdamping,"cable/cable2",0, false)
|
||||
|
||||
Rope3.DoNotDuplicate = true
|
||||
elastic.DoNotDuplicate = true
|
||||
self.Elastics[index] = elastic
|
||||
end
|
||||
|
||||
self.Wheels[index] = self.name
|
||||
|
||||
Ballsocket.DoNotDuplicate = true
|
||||
Rope1.DoNotDuplicate = true
|
||||
Rope2.DoNotDuplicate = true
|
||||
|
||||
if index == 2 then
|
||||
if IsValid( self.Wheels[ 1 ] ) and IsValid( self.Wheels[ 2 ] ) then
|
||||
local nocollide = constraint.NoCollide( self.Wheels[ 1 ], self.Wheels[ 2 ], 0, 0 )
|
||||
nocollide.DoNotDuplicate = true
|
||||
end
|
||||
|
||||
elseif index == 4 then
|
||||
if IsValid( self.Wheels[ 3 ] ) and IsValid( self.Wheels[ 4 ] ) then
|
||||
local nocollide = constraint.NoCollide( self.Wheels[ 3 ], self.Wheels[ 4 ], 0, 0 )
|
||||
nocollide.DoNotDuplicate = true
|
||||
end
|
||||
|
||||
elseif index == 6 then
|
||||
if IsValid( self.Wheels[ 5 ] ) and IsValid( self.Wheels[ 6 ] ) then
|
||||
local nocollide = constraint.NoCollide( self.Wheels[ 5 ], self.Wheels[ 6 ], 0, 0 )
|
||||
nocollide.DoNotDuplicate = true
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user