mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
710 lines
28 KiB
Lua
710 lines
28 KiB
Lua
--[[
|
|
| 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 |