This commit is contained in:
lifestorm
2024-08-05 18:40:29 +03:00
parent 9f505a0646
commit c6d9b6f580
8044 changed files with 1853472 additions and 21 deletions

View 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

View File

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

View 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

File diff suppressed because it is too large Load Diff

View 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 )

View 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

View 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

View 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