266 lines
7.3 KiB
Lua
266 lines
7.3 KiB
Lua
--
|
|
-- OCTOSIMFPHYS
|
|
--
|
|
|
|
function simfphys.GetRight(ent, index, WheelPos)
|
|
local Steer = ent:GetTransformedDirection()
|
|
|
|
local Right = ent.Right
|
|
|
|
if WheelPos.IsFrontWheel then
|
|
Right = (IsValid(ent.SteerMaster) and Steer.Right or ent.Right) * (WheelPos.IsRightWheel and 1 or -1)
|
|
else
|
|
Right = (IsValid(ent.SteerMaster) and Steer.Right2 or ent.Right) * (WheelPos.IsRightWheel and 1 or -1)
|
|
end
|
|
|
|
return Right
|
|
end
|
|
|
|
function simfphys.SetWheelOffset(ent, offset_front, offset_rear)
|
|
if not IsValid(ent) then return end
|
|
|
|
offset_front = math.Clamp(offset_front, -8, 4)
|
|
offset_rear = math.Clamp(offset_rear, -8, 4)
|
|
|
|
ent.wOffsetF = offset_front
|
|
ent.wOffsetR = offset_rear
|
|
|
|
if not istable(ent.Wheels) or not istable(ent.GhostWheels) then return end
|
|
|
|
for i = 1, table.Count(ent.GhostWheels) do
|
|
local Wheel = ent.Wheels[ i ]
|
|
local WheelModel = ent.GhostWheels[i]
|
|
local WheelPos = ent:LogicWheelPos(i)
|
|
|
|
if IsValid(Wheel) and IsValid(WheelModel) then
|
|
local Pos = Wheel:GetPos()
|
|
local Right = simfphys.GetRight(ent, i, WheelPos)
|
|
local offset = WheelPos.IsFrontWheel and offset_front or offset_rear
|
|
|
|
WheelModel:SetParent(nil)
|
|
|
|
local physObj = WheelModel:GetPhysicsObject()
|
|
if IsValid(physObj) then
|
|
physObj:EnableMotion(false)
|
|
end
|
|
|
|
WheelModel:SetPos(Pos + Right * offset)
|
|
WheelModel:SetParent(Wheel)
|
|
end
|
|
end
|
|
end
|
|
|
|
function simfphys.ApplyWheel(ent, camber, front, rear)
|
|
|
|
rear = rear or front
|
|
local aof, aor = simfphys.GetWheelAngle(front), simfphys.GetWheelAngle(rear)
|
|
if not aof or not aor then print('Wheel model not registered') return end
|
|
|
|
ent.wModelF = front
|
|
ent.wModelR = rear
|
|
ent.waOffsetF = aof
|
|
ent.waOffsetR = aor
|
|
ent.camber = math.Clamp(camber or 0, -18, 10)
|
|
|
|
ent.PressedKeys["A"] = nil
|
|
ent.PressedKeys["D"] = nil
|
|
ent.SmoothAng = 0
|
|
ent:SteerVehicle(0)
|
|
|
|
timer.Simple(0.05, function()
|
|
if not IsValid(ent) then return end
|
|
|
|
for i = 1, table.Count(ent.GhostWheels) do
|
|
local Wheel = ent.GhostWheels[i]
|
|
|
|
if IsValid(Wheel) then
|
|
local isfrontwheel = (i == 1 or i == 2)
|
|
local swap_y = (i == 2 or i == 4 or i == 6)
|
|
|
|
local angleoffset = isfrontwheel and ent.waOffsetF or ent.waOffsetR
|
|
|
|
local model = isfrontwheel and ent.wModelF or ent.wModelR
|
|
|
|
local fAng = ent:LocalToWorldAngles(ent.VehicleData.LocalAngForward)
|
|
local rAng = ent:LocalToWorldAngles(ent.VehicleData.LocalAngRight)
|
|
|
|
local Forward = fAng:Forward()
|
|
local Right = swap_y and -rAng:Forward() or rAng:Forward()
|
|
local Up = ent:GetUp()
|
|
|
|
local ghostAng = Right:Angle()
|
|
local mirAng = swap_y and 1 or -1
|
|
ghostAng:RotateAroundAxis(Forward,angleoffset.p * mirAng)
|
|
ghostAng:RotateAroundAxis(Right,angleoffset.r * mirAng)
|
|
ghostAng:RotateAroundAxis(Up,-angleoffset.y)
|
|
|
|
ghostAng:RotateAroundAxis(Forward, ent.camber * mirAng)
|
|
|
|
Wheel:SetModelScale(1)
|
|
Wheel:SetModel(model)
|
|
Wheel:SetAngles(ghostAng)
|
|
|
|
timer.Simple(0.05, function()
|
|
if not IsValid(Wheel) or not IsValid(ent) then return end
|
|
local wheelsize = Wheel:OBBMaxs() - Wheel:OBBMins()
|
|
local radius = isfrontwheel and ent.FrontWheelRadius or ent.RearWheelRadius
|
|
local size = (radius * 2) / math.max(wheelsize.x,wheelsize.y,wheelsize.z)
|
|
|
|
Wheel:SetModelScale(size)
|
|
end)
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
function simfphys.ValidateModel(model)
|
|
local v_list = list.Get("simfphys_vehicles")
|
|
for listname, _ in pairs(v_list) do
|
|
if v_list[listname].Members.CustomWheels then
|
|
local FrontWheel = v_list[listname].Members.CustomWheelModel
|
|
local RearWheel = v_list[listname].Members.CustomWheelModel_R
|
|
|
|
if FrontWheel then
|
|
FrontWheel = string.lower(FrontWheel)
|
|
end
|
|
|
|
if RearWheel then
|
|
RearWheel = string.lower(RearWheel)
|
|
end
|
|
|
|
if model == FrontWheel or model == RearWheel then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
local list = list.Get("simfphys_Wheels")[model]
|
|
|
|
if list then
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function simfphys.SetupSuspension(ent, susp)
|
|
|
|
local carData = list.Get("simfphys_vehicles")[ent.VehicleName].Members
|
|
susp[1] = math.Clamp(susp[1], -1, 1)
|
|
susp[2] = math.Clamp(susp[2], carData.FrontConstant, carData.FrontConstant * 2)
|
|
susp[3] = math.Clamp(susp[3], 0, carData.FrontDamping * 1.5)
|
|
susp[4] = math.Clamp(susp[4], math.max(susp[1] - 1, -1), math.min(susp[1] + 1, 1))
|
|
susp[5] = math.Clamp(susp[5], carData.RearConstant, carData.RearConstant * 2)
|
|
susp[6] = math.Clamp(susp[6], 0, carData.RearDamping * 1.5)
|
|
local data = {
|
|
[1] = {susp[2], susp[3]},
|
|
[2] = {susp[2], susp[3]},
|
|
[3] = {susp[5], susp[6]},
|
|
[4] = {susp[5], susp[6]},
|
|
[5] = {susp[5], susp[6]},
|
|
[6] = {susp[5], susp[6]}
|
|
}
|
|
|
|
local elastics = ent.Elastics
|
|
if (elastics) then
|
|
for i = 1, table.Count(elastics) do
|
|
local elastic = elastics[i]
|
|
if not elastic or not data[i] then continue end
|
|
|
|
if (ent.StrengthenSuspension == true) then
|
|
if (IsValid(elastic)) then
|
|
elastic:Fire("SetSpringConstant", data[i][1] * 0.5, 0)
|
|
elastic:Fire("SetSpringDamping", data[i][2] * 0.5, 0)
|
|
end
|
|
local elastic2 = elastics[i * 10]
|
|
if (IsValid(elastic2)) then
|
|
elastic2:Fire("SetSpringConstant", data[i][1] * 0.5, 0)
|
|
elastic2:Fire("SetSpringDamping", data[i][2] * 0.5, 0)
|
|
end
|
|
else
|
|
if (IsValid(elastic)) then
|
|
elastic:Fire("SetSpringConstant", data[i][1], 0)
|
|
elastic:Fire("SetSpringDamping", data[i][2], 0)
|
|
end
|
|
end
|
|
|
|
ent.dampF = data[1][2]
|
|
ent.consF = data[1][1]
|
|
ent.dampR = data[4][2]
|
|
ent.consR = data[4][1]
|
|
end
|
|
end
|
|
|
|
ent:SetFrontSuspensionHeight(susp[1])
|
|
ent:SetRearSuspensionHeight(susp[4])
|
|
|
|
end
|
|
|
|
function simfphys.CanPlayerTune(ply, ent)
|
|
|
|
if not IsValid(ply) or not IsValid(ent) then return false, L.car_not_found end
|
|
if ent:GetIsLocked() then return false, L.car_closed end
|
|
|
|
local owner = ent:CPPIGetOwner()
|
|
if not IsValid(owner) or ply ~= owner and not (owner.Buddies and owner.Buddies[ply] and table.HasValue(owner.Buddies[ply], true)) then return false, L.car_you_need_be_friend end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
simfphys.postSpawn = simfphys.postSpawn or {}
|
|
function simfphys.AddPostSpawnAction(class, func)
|
|
simfphys.postSpawn[class] = func
|
|
end
|
|
|
|
function simfphys.GetSeatProperty(seat, property)
|
|
|
|
if not IsValid(seat) then return end
|
|
local car = seat:GetParent()
|
|
if not IsValid(car) or car:GetClass() ~= 'gmod_sent_vehicle_fphysics_base' then return end
|
|
if seat[property] ~= nil then return seat[property] end
|
|
|
|
car.spawnlist = car.spawnlist or list.Get('simfphys_vehicles')[car:GetSpawn_List()]
|
|
local lst = car.spawnlist.Members
|
|
local lPos = car:WorldToLocal(seat:GetPos())
|
|
for _,v in ipairs(lst.PassengerSeats) do
|
|
if lPos:DistToSqr(v.pos) < 10 then
|
|
if v[property] ~= nil then
|
|
seat[property] = v[property]
|
|
else
|
|
seat[property] = false
|
|
end
|
|
break
|
|
end
|
|
end
|
|
|
|
return seat[property]
|
|
|
|
end
|
|
|
|
simfphys.fuelPrices = {
|
|
[FUELTYPE_DIESEL] = 80,
|
|
[FUELTYPE_PETROL] = 120,
|
|
[FUELTYPE_ELECTRIC] = 10,
|
|
}
|
|
|
|
util.AddNetworkString 'car.steer'
|
|
net.Receive('car.steer', function(len, ply)
|
|
local seat = ply:GetVehicle()
|
|
if not IsValid(seat) or not IsValid(seat.base) then return end
|
|
|
|
local car = seat.base
|
|
if car:GetDriverSeat() ~= seat then return end
|
|
|
|
car.wantedSteer = net.ReadFloat()
|
|
end)
|
|
|
|
hook.Add('CanTool', 'octo-cars', function(ply, tr, tool)
|
|
|
|
local ent = tr.Entity
|
|
if tool ~= 'remover' and IsValid(ent) and ent:GetClass() == 'gmod_sent_vehicle_fphysics_base'
|
|
and IsValid(ply) and not ply:query('DBG: Изменять автомобили') then
|
|
return false
|
|
end
|
|
|
|
end)
|