Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --@name BMW_i7_chassis
- --@author artybyte
- --@shared
- --@model models/hunter/plates/plate2x4.mdl
- -- IT CLOULD LOAD MESHES FROM LOCAL FOLDER. BE CAREFUL. UPDATE MESH .TXT EVENTUALLY (via local python script)
- if CLIENT then
- local chassis = { }
- --@include bmw_i7.txt
- local BMW = require('bmw_i7.txt')
- chassis.moveSound = nil
- chassis.driverPresented = false
- chassis.passengerPresented = false
- chassis.moveSound = sound.create(chip(), "k_lab2.DropshipRotorLoop")
- chassis.moveSound:play()
- chassis.moveSound:setPitch(0)
- chassis.front_vel = 0
- chassis.fl_wheel = nil
- chassis.fr_wheel = nil
- chassis.rl_wheel = nil
- chassis.rr_wheel = nil
- chassis.wheels = { }
- chassis.tires = { }
- chassis.steering = 0
- chassis.LerpSteering = 0
- chassis.steeringArc = 32
- chassis.fl_wheel_tire = nil
- chassis.fr_wheel_tire = nil
- chassis.rl_wheel_tire = nil
- chassis.rr_wheel_tire = nil
- BMW.Loader.SetOnPasteDoneContinuousFunction( function()
- local targ = chassis.steering - chassis.LerpSteering
- chassis.LerpSteering = chassis.LerpSteering + math.clamp( (chassis.steering) - chassis.LerpSteering, -targ/2, targ/2) / 2
- ComplexMeshLoader.HologramCollection["interior_steering_wheel"]:setAngles(
- ComplexMeshLoader.HologramCollection["interior_steering_wheel"].parent:localToWorldAngles(Angle(chassis.LerpSteering * 8, 0, 0))
- )
- end )
- BMW.on_done_paste = function(fl, fr, rl, rr, fl_tire, fr_tire, rl_tire, rr_tire)
- table.insert(chassis.wheels, fl)
- table.insert(chassis.wheels, fr)
- table.insert(chassis.wheels, rl)
- table.insert(chassis.wheels, rr)
- table.insert(chassis.tires, fl_tire)
- table.insert(chassis.tires, fr_tire)
- table.insert(chassis.tires, rl_tire)
- table.insert(chassis.tires, rr_tire)
- net.start('BMW_i7_network')
- net.writeTable({case="send_wheels", user=player():entIndex() })
- net.send()
- end
- net.receive('BMW_i7_network', function()
- local t = net.readTable()
- local case = t.case
- if case == 'parent_wheels' then
- local wheels = t.wheels
- local entsWheels = { }
- local add_ang = Angle(0, -90, 0)
- table.insert(entsWheels, entity(wheels[2]))
- table.insert(entsWheels, entity(wheels[1]))
- table.insert(entsWheels, entity(wheels[4]))
- table.insert(entsWheels, entity(wheels[3]))
- for i = 1, 4 do
- local wheel = chassis.wheels[i]
- local tire = chassis.tires[i]
- local target = entsWheels[i]
- wheel:setParent(target)
- tire:setParent(target)
- wheel:setPos(target:localToWorld(Vector()))
- tire:setPos(target:localToWorld(Vector()))
- wheel:setAngles(target:localToWorldAngles(add_ang))
- tire:setAngles(target:localToWorldAngles(add_ang))
- end
- elseif case == 'steering' then
- chassis.steering = t.steeringAngle
- elseif case == 'abc' then
- end
- end )
- end
- if SERVER then
- -- Ultimate Ray Chassis
- //--@include infernus.txt
- --local BMW = require('infernus.txt')
- --@include module/module_server_prop_spawner.txt
- local SPAWNER = require('module/module_server_prop_spawner.txt')
- local chassis = { }
- chassis.params = { }
- chassis.params.height = 28
- chassis.params.zstabilization = 6
- chassis.params.turnAng = 38
- chassis.params.mass = 2500
- chassis.params.spring = 6
- chassis.params.power = 0.7 -- rusbuild. orig: 0.7
- chassis.params.baseVec = Vector(35, 70, 0)
- chassis.params.frontAxle = Vector(36, 65, 0)
- chassis.params.rearAxle = Vector(36, 71, 0)
- chassis.params.sideVec = { Vector(1, 1, 1), Vector(-1, 1, 1), Vector(1, -1, 1),Vector(-1, -1, 1) }
- chassis.controls = { }
- chassis.controls.W = 0
- chassis.controls.A = 0
- chassis.controls.S = 0
- chassis.controls.D = 0
- chassis.controls.SPACE = 0
- chassis.controls.SHIFT = 0
- chassis.controls.ALT = 0
- chassis.phys_obj = chip():getPhysicsObject()
- chassis.self = chip()
- chassis.VC = { } -- main vector container and core of system
- chassis.wheels = { }
- chassis.driver = nil
- chassis.passenger = nil
- chassis.wheelModel = 'models/sprops/trans/wheel_d/t_wheel30.mdl'
- chassis.wheelBodygroup = 5 -- ONLY FOR SPROPS. type -1 if no bodygroup
- chassis.wheelColor = Color(45, 45, 45, 255)
- chassis.driverSeatModel = 'models/nova/jeep_seat.mdl'
- chassis.driverSeatLocalPos = Vector(18, -6, -5)
- chassis.driverSeatLocalAng = Angle(0, 180, 15)
- chassis.wheelHeight = 30 -- only for declared wheel model
- chassis.wheelWideAX = 1
- chassis.wheelContact = { }
- chassis.wheelRotation = { }
- chassis.wheelInertia = { }
- chassis.steeringAngle = 0
- chassis.dynamicLerp = 0
- chassis.dynamicMult = 3.6 -- speed of acceleration \ decceleration
- chassis.steeringAngleArc = 32 -- STEERING IN DEGREES
- chassis.steeringAngleArcMin = 6 -- minimum degrees while speed at top
- chassis.steeringDescendingCoeff = 0.025 -- until speed
- chassis.steeringSpeed = 1
- chassis.steeringPow = 4
- chassis.accelerationLeanPower = 3
- chassis.accelerationLean = 0
- chassis.accelerationSubtractSpeed = 0.025
- chassis.lastW = 0
- chassis.lastS = 0
- chassis.wheelAnchors = { }
- chassis.wheelScale = Vector(0, 0, 0)
- chassis.calcWheelHeight = false
- chassis.tickSkip = 6 -- throttler to send networks
- chassis.onSkip = 0
- -- TODO: sound only when W \ S with interpolation smoothness of start and end!!!!
- -- and same interpolation to gas and brake.
- -- WHEELS SHOULD BE SAME!!!!
- chassis.Initialize = function()
- chassis.self:setMass(chassis.params.mass)
- chassis.self:setColor(Color(0, 0, 0, 0))
- chassis.self:setFrozen(true)
- SPAWNER.parent = chassis.self
- SPAWNER.add {
- name='driverSeat',
- seat=true,
- local_pos=chassis.driverSeatLocalPos*Vector(1,0.5,-0.2),
- local_ang=chassis.driverSeatLocalAng,
- model=chassis.driverSeatModel,
- color=Color(0,0,0,0)
- }
- SPAWNER.add {
- name='passengerSeat',
- seat=true,
- local_pos=chassis.driverSeatLocalPos*Vector(-1,0.5,-0.2),
- local_ang=chassis.driverSeatLocalAng,
- model=chassis.driverSeatModel,
- color=Color(0,0,0,0)
- }
- SPAWNER.add {
- name='passengerRLSeat',
- seat=true,
- local_pos=chassis.driverSeatLocalPos*Vector(1,-7,-0.6),
- local_ang=chassis.driverSeatLocalAng,
- model=chassis.driverSeatModel,
- color=Color(0,0,0,0)
- }
- SPAWNER.add {
- name='passengerRRSeat',
- seat=true,
- local_pos=chassis.driverSeatLocalPos*Vector(-1,-7,-0.6),
- local_ang=chassis.driverSeatLocalAng,
- model=chassis.driverSeatModel,
- color=Color(0,0,0,0)
- }
- SPAWNER.parentTable = chassis
- SPAWNER.spawn()
- end
- -- GET RIGHT IS FORWARD-BACK!!!!
- -- GET FOWARD IS LEFT-RIGHT!!!!!!
- chassis.calc = function()
- chassis.phys_obj = chip():getPhysicsObject()
- local speedDecrement = chassis.self:getVelocity():getLength() * chassis.steeringDescendingCoeff
- local limitedAng = math.clamp( chassis.steeringAngleArc - speedDecrement*1.5, chassis.steeringAngleArcMin, chassis.steeringAngleArc )
- local AD = chassis.controls.A - chassis.controls.D
- local WS = chassis.controls.W - chassis.controls.S
- -- this variable create lerp in accelerating and breaking
- chassis.dynamicLerp = chassis.dynamicLerp + math.clamp( (WS) - chassis.dynamicLerp, -0.05, 0.05 ) / 3
- if chassis.lastW ~= chassis.controls.W then
- chassis.lastW = chassis.controls.W
- if chassis.controls.W == 1 then
- chassis.accelerationLean = chassis.accelerationLeanPower
- end
- end
- if chassis.lastS ~= chassis.controls.S then
- chassis.lastS = chassis.controls.S
- if chassis.controls.S == 1 then
- chassis.accelerationLean = -chassis.accelerationLeanPower
- end
- end
- chassis.accelerationLean = chassis.accelerationLean - chassis.accelerationSubtractSpeed
- if chassis.accelerationLean < 0 then chassis.accelerationLean = chassis.accelerationLean + chassis.accelerationSubtractSpeed end
- if chassis.accelerationLean > 0 then chassis.accelerationLean = chassis.accelerationLean - chassis.accelerationSubtractSpeed end
- -- calculate steer ang
- chassis.steeringAngle = chassis.steeringAngle + math.clamp( ( ( AD ) * limitedAng ) - chassis.steeringAngle,
- -chassis.steeringSpeed, chassis.steeringSpeed ) / ( chassis.steeringPow * ( AD == 0 and math.clamp( 0.5 + speedDecrement/3, 0.05, 1 ) or 0.5 ) ) -- this divider makes steering comes to center slower
- if SPAWNER.pasteDone then
- if chassis.driverSeat:getDriver() ~= nil then
- if chassis.driverSeat:getDriver():isValid() then
- chassis.driver = chassis.driverSeat:getDriver()
- else
- chassis.driver = nil
- end
- else
- chassis.driver = nil
- end
- if chassis.passengerSeat:getDriver() ~= nil then
- if chassis.passengerSeat:getDriver():isValid() then
- chassis.passenger = chassis.passengerSeat:getDriver()
- else
- chassis.passenger = nil
- end
- else
- chassis.passenger = nil
- end
- end
- if chassis.driver ~= nil then
- chassis.controls.W = chassis.driver:keyDown(IN_KEY.FORWARD) and 1 or 0
- chassis.controls.S = chassis.driver:keyDown(IN_KEY.BACK) and 1 or 0
- chassis.controls.A = chassis.driver:keyDown(IN_KEY.MOVELEFT) and 1 or 0
- chassis.controls.D = chassis.driver:keyDown(IN_KEY.MOVERIGHT) and 1 or 0
- chassis.controls.SPACE = chassis.driver:keyDown(IN_KEY.JUMP) and 1 or 0
- chassis.controls.SHIFT = chassis.driver:keyDown(IN_KEY.SPEED) and 1 or 0
- chassis.controls.ALT = chassis.driver:keyDown(IN_KEY.WALK) and 1 or 0
- end
- local localVel = chassis.self:worldToLocal( chassis.self:getVelocity() + chassis.self:getPos() )
- local fl = math.floor
- --print("" .. tostring( fl(chassis.self:getLocalVelocity()[1]) ) .. ', ' .. tostring(fl(chassis.self:getLocalVelocity()[2])) .. ', ' .. fl(chassis.self:getLocalVelocity()[3]))
- for i = 1, 4 do -- this module will have only 4 wheels. hardcoded
- local is_wheels_rear = i < 3
- local isWheelLeft = i%2==1
- local isWheelFront = i > 2
- local wheel_pos = chassis.params.frontAxle * chassis.params.sideVec[i] -- abstract wheel pos according no sideVec
- if is_wheels_rear then
- wheel_pos = chassis.params.rearAxle * chassis.params.sideVec[i]
- end
- if chassis.wheels[i] == nil then
- chassis.wheels[i] = hologram.create(chassis.self:getPos(), chassis.self:localToWorldAngles(Angle()), chassis.wheelModel)
- chassis.wheelAnchors[i] = hologram.create(chassis.self:localToWorld(wheel_pos), chassis.self:localToWorldAngles(Angle()), "models/holograms/rcylinder_thick.mdl")
- chassis.wheelAnchors[i]:setParent(chassis.self)
- chassis.wheelAnchors[i]:setScale(Vector(0.1, 0.1, 0.1))
- chassis.wheels[i]:setParent(chassis.self)
- chassis.wheels[i]:setPos(chassis.self:localToWorld(wheel_pos ))
- chassis.wheels[i]:setScale(chassis.wheelScale)
- chassis.wheels[i]:setColor(chassis.wheelColor)
- if chassis.wheelBodygroup ~= -1 then chassis.wheels[i]:setBodygroup(1, chassis.wheelBodygroup) end
- chassis.wheelContact[i] = false
- chassis.wheelRotation[i] = 0
- chassis.wheelInertia[i] = 0
- chassis.VC[i + 4] = chassis.wheelAnchors[i]:getPos()
- if i == 4 then
- if chassis.calcWheelHeight then
- local sz = chassis.wheels[i]:obbSize()
- local X, Y, Z = sz.x, sz.y, sz.z
- local height = math.max(X, Y)
- height = math.max(height, Z)
- -- test
- chassis.wheelHeight = height
- end
- end
- end
- local additionToDistance = isWheelFront and -chassis.accelerationLean or chassis.accelerationLean
- -- TODO: add this >additionToDistance< to applyForce, not to rays distance!!!!!!
- -- setting up trace
- local tracedata = {
- start = chassis.self:localToWorld( wheel_pos ),
- endpos = chassis.self:localToWorld( wheel_pos ) + chassis.self:getUp() * ( -chassis.params.height ),
- filter = { chassis.self, chip(), unpack(chassis.wheels)}
- }
- local traceResult = trace.hull(tracedata.start, tracedata.endpos, Vector(), Vector(), tracedata.filter, nil, nil, false)
- local wheelHeight = 0
- local V2 = chassis.VC[i + 4] ~= nil and chassis.VC[i + 4] or Vector(0, 0, 0)
- chassis.VC[i + 4] = chassis.wheelAnchors[i]:getPos()
- local L = chassis.wheelAnchors[i]:worldToLocal(V2)
- -- apply body leaning on gas / brake
- local rawDist__ = traceResult.HitPos:getDistance(tracedata.start)
- local rawDist = rawDist__
- local dist = math.clamp( chassis.params.height - rawDist + L[3] * chassis.params.zstabilization, 1.1, chassis.params.height )
- local vecBase = ( traceResult.HitNormal * dist ) * chassis.params.power * chassis.params.mass / 4
- -- CT
- local curTime = chassis.VC[i + 8] ~= nil and chassis.VC[i + 8] or 0
- chassis.VC[i + 8] = timer.curtime()
- -- DT
- local rawDistSaved = chassis.VC[i + 12] ~= nil and chassis.VC[i + 12] or 0
- chassis.VC[i + 12] = rawDist
- -- JTRC
- local hitPosSaved = chassis.VC[i + 16] ~= nil and chassis.VC[i + 16] or Vector(0, 0, 0)
- if traceResult.Entity:isValid() then
- chassis.VC[i + 16] = traceResult.Entity:worldToLocal(traceResult.HitPos)
- else
- chassis.VC[i + 16] = traceResult.HitPos
- end
- chassis.wheels[i]:setPos(chassis.self:localToWorld(wheel_pos - Vector(0, 0, rawDist + chassis.wheelHeight * -0.5) ))
- chassis.wheels[i]:setAngles(chassis.self:localToWorldAngles(Angle(chassis.wheelRotation[i] * (isWheelLeft and 1 or -1), -90 + (isWheelLeft and 0 or 180) + (isWheelFront and chassis.steeringAngle or 0), 0) ))
- if isWheelFront then
- chassis.wheelAnchors[i]:setAngles(chassis.self:localToWorldAngles(Angle(0, chassis.steeringAngle, 0) ))
- end
- -- TODO: make setAng for wheelAnchors!!!
- local climbAngle = math.round( math.rad( chassis.self:getAngles()[1] ), 2 ) * 0.1
- if traceResult.Hit then
- local V = chassis.VC[ i ] ~= nil and chassis.VC[i] or Vector(0, 0, 0)
- local V2R = chassis.VC[ i + 4 ] ~= nil and chassis.VC[i + 4] or Vector(0, 0, 0)
- local R_D = chassis.VC[ i + 12 ] ~= nil and chassis.VC[i + 12] or 0
- local Delta = vecBase - V
- local TimeDelta = timer.curtime() - curTime
- local DistDelta = ( rawDistSaved - R_D ) * 3
- local L = chassis.wheelAnchors[i]:worldToLocal( V2 )
- local ForceVec = vecBase + Delta * chassis.params.spring
- local ML = ( chassis.wheelHeight * (math.pi * 1.5) * 0.75 ) * 0.0254
- local V_L = ( localVel[2] * 0.75 ) * 0.0294--0.0254
- local Round = V_L / ML
- local FakeRotation = Round * 360 * TimeDelta
- local UC = V2 - V2R
- --local L = ( (-chassis.self:getRight() * ( math.clamp(L[2],-5,5) / 3 )) + (chassis.self:getForward() * L[1] * 10 ) + chassis.self:getForward() * -climbAngle * chassis.params.mass / 220 ) * chassis.params.mass / 4
- local L = ( (-chassis.self:getRight() * ( math.clamp(L[2],-5,5) / 3 )) + (chassis.self:getForward() * L[1] * 10 ) ) * chassis.params.mass / 4
- if chassis.wheelContact[i] then
- if traceResult.Entity:isValid() then
- local Na = -chassis.wheels[i]:worldToLocal( traceResult.Entity:localToWorld( hitPosSaved ) )[2] * (chassis.wheelHeight / math.pi)
- chassis.wheelRotation[i] = ( chassis.wheelRotation[i] - Na ) % 360
- chassis.wheelInertia[i] = Na
- else
- chassis.wheelRotation[i] = ( chassis.wheelRotation[i] - FakeRotation ) % 360
- chassis.wheelInertia[i] = FakeRotation
- end
- end
- chassis.VC[i] = vecBase
- if not chassis.wheelContact[i] then
- if DistDelta > 2.5 and DistDelta < 13 then
- chassis.self:emitSound('physics/rubber/rubber_tire_impact_soft' .. math.random( 1, 3 ) .. '.wav', 100, 120, 1, 0)
- elseif DistDelta > 13 and DistDelta < 17 then
- chassis.self:emitSound('physics/rubber/rubber_tire_impact_bullet' .. math.random( 1, 3 ) .. '.wav', 100, 120, 1, 0)
- elseif DistDelta > 17 and DistDelta then
- chassis.self:emitSound('physics/rubber/rubber_tire_impact_hard' .. math.random( 1, 3 ) .. '.wav', 100, 120, 1, 0)
- end
- local XD = chassis.self:getRight() * chassis.wheelInertia[i] * chassis.params.mass / 4
- chassis.self:getPhysicsObject():applyForceOffset( ForceVec + L + XD , V2R )
- chassis.wheelContact[i] = true
- end
- -- i%2==1 and 0 or 180
- local isRear = i > 2//( i % 2 ) == 1
- -- force
- if isRear then
- chassis.self:getPhysicsObject():applyForceOffset( ForceVec + L, V2R + UC )
- else
- local Accel = chassis.self:getRight() * chassis.params.mass * chassis.dynamicMult * ( ( chassis.controls.W - chassis.controls.S ) * math.abs(chassis.dynamicLerp) )
- chassis.self:getPhysicsObject():applyForceOffset( ForceVec + L + Accel, V2R + UC )
- end
- else
- -- not .Hit
- if chassis.wheelContact[i] then
- chassis.wheelContact[i] = false
- end
- chassis.wheelInertia[i] = math.normalizeAngle( chassis.wheelInertia[i] - chassis.wheelInertia[i] / 300 )
- chassis.wheelRotation[i] = math.normalizeAngle( chassis.wheelRotation[i] - chassis.wheelInertia[i] )
- end
- -- X - side
- -- Y - prodolnyaya LENGTH
- -- Z - height
- end
- chassis.onSkip = chassis.onSkip + 1
- local angle = ( chassis.steeringAngleArc + chassis.steeringAngle ) / 2
- chip():setColor(Color(angle, 0, 0, 0))
- if chassis.onSkip == chassis.tickSkip then
- chassis.onSkip = 0
- local front_vel = chip():getLocalVelocity()[2]
- -- PLACE TO SEND TETWORKS WITH PROVIDED INTERVAL
- -- net.start ... there
- net.start('BMW_i7_network')
- net.writeTable( { case="steering", steeringAngle=chassis.steeringAngle } )
- net.send()
- end
- end
- net.receive('BMW_i7_network', function( )
- local t = net.readTable()
- if t.case == 'send_wheels' then
- local userIndex = t.user
- net.start('BMW_i7_network')
- net.writeTable( { case="parent_wheels", wheels={ chassis.wheels[1]:entIndex(), chassis.wheels[2]:entIndex(), chassis.wheels[3]:entIndex(), chassis.wheels[4]:entIndex() } } )
- net.send(entity(userIndex))
- end
- end )
- hook.add('Think', 'abt_urc', chassis.calc)
- chassis.Initialize()
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement