@name $Engine#SpeedCar#1
#
@inputs [Pod]:wirelink 
#
@outputs [RPM_N RPM Gear PTCH GNum EAN Fuel]:number
#
@persist [E Plate]:entity
@persist [RPM_N Force_Coeff RPM Torque Power TopGear Efficiency WheelTorque Th_2 Th_3 PGear MaxRPM]:number
@persist [IdleRPM Turn PTCH Pitch_Coeff Pitch_Add Reverse_Gear GNum Rotor TransmVol EngAct EAN Fuel]:number
@persist [Wheels Line]:array
@persist [T G G2 Awh]:table
@persist [Sound]:string
#
HoloScale=0.1
#[
    Hello, its E2 engine (like acf), aand, its all :D
    Made by Halo \ Hahlo :D 
]#

interval(25)

if(duped() | dupefinished()) { reset() }

local Seat = Pod["Entity",entity]
local Driver = Seat:driver()
local Active = Driver:keyReload()
local Throttle = Driver:keyForward()
local ReverseGear = Driver:keyBack()
local GearUp = Driver:keyAttack1()
local GearDown = Driver:keyAttack2()
local Brake = Driver:keyJump()

if(first()) {
  

    E = entity()

    Plate = E:isWeldedTo()

    ####### USUAL_OPTIONS #######
    Turn = (1)  # 1 or -1, Forward or backward motion.
    Force_Coeff = (Plate:mass() / 1337) # automatically applyforce coefficient (L33T!!!).
    #Force_Coeff = (1) # applyforce coefficient.
    
    Reverse_Gear = (1) # 1 or 0
    
    Sound = ("acf_extra/vehiclefx/engines/v8/ClevV8_offlowEX.wav") #acf_engines/v12_dieselsmall.wav
    Pitch_Coeff = (1) # Pitch Coefficient 
    Pitch_Add = 25 # Addtive pitch
    
    TransmVol = 0 # Volume of gears
    
    Efficiency = (15) # Efficiency of transmission.
    IdleRPM = (400) #
    MaxRPM = 5000 #
    
    Fuel = 75
    
    ABS = 0 # 
    ####### USUAL_OPTIONS #######

    T = table(
        0 = 0,
        500 = 22,
        1000 = 38, 
        1500 = 58, 
        2000 = 82, 
        2500 = 96,
        3000 = 106,
        3500 = 110,
        4000 = 118,
        4500 = 118,
        5000 = 110,
        5500 = 106,
        6000 = 100,
        6500 = 96,
        7000 = 90,
        7500 = 80,
        8000 = 70,
        8500 = 58,
        9000 = 40,
        9500 = 12,
        10000 = 0
    ) # Schedule depending torque of the RPM.
    
    G = table(
        0.34, # 1
        0.24, # 2
        0.14, # 3
        0.08, # 4
        0.02, # 5
        -0.64  # -1
    ) # Gear's coefficient.

    G2 = table(
        1500, # 1
        2500, # 2 
        3500, # 3 
        4500, # 4 
        5500, # 5
        1500  # -1
    ) # Blocker of rpm.
    
    for(N = 1, 6) { G2:pushNumber(500 + 9500/(6+1 - N)) }
    
    function number graph(RPM_Func:number) {
        DelRPM = floor(RPM_Func / 500) * 500
        
        Graph = T[DelRPM, number]
        NGraph = T[DelRPM + 500, number]
        SZ = (NGraph - Graph) * (RPM_Func - DelRPM) / 500
        
        Graph += round(SZ * 10) / 10
        return Graph
    }

    Gear = 1 Th_3 = 1
    
    findIncludeClass("prop*")
    findInSphere(Plate:pos(), 200)
    Props = findToArray() soundStop(111)

    foreach(N, Ent:entity = Props) {
        if(Ent:type() == "prop_physics" & Ent:model():find("wheel") & Ent:mass() > 40) {
            local Pos = floor(Plate:toLocal(Ent:pos())) 

            local Num = Pos:y() > 0 ? -Turn : Turn
            Line:pushNumber(Num)
            Wheels:pushEntity(Ent) 
            #if(Pos:x() < 0) { Ent:setColor((hsv2rgb((curtime()*240) % 360, 1, 1))) }
            #if(Pos:x() < 0) { if(Pos:y() < 0) { W_R = Ent } else { W_L = Ent } }
            
            local TurnStr = Pos:y() < 0 ? "Right" : "Left"
            local Str = Pos:y() < 0 ? "R" : "L"
            local PrePos = abs(Awh[TurnStr,number])

            holoCreate(N,Ent:toWorld(vec(0,-8 + 14.5*(Pos:y()<0),0)*HoloScale),vec(1.25,1.25,1.75)*HoloScale,Ent:toWorld(ang(90,90 + 180*(Pos:y()<0),0)))
            holoModel(N,"models/props_phx/wheels/magnetic_medium.mdl")
            holoParent(N,Ent) 

            holoCreate(N+20,Ent:toWorld(vec(0,0.3,0)*HoloScale),vec(1.5,1.5,1.3)*HoloScale,Ent:toWorld(ang(90,90,0)))
            holoModel(N+20,"models/Mechanics/wheels/bmw.mdl")
            holoMaterial(N+20,"sprops/textures/sprops_metal3") holoColor(N+20,vec(50))
            holoParent(N+20,Ent)

            holoMaterial(N,"")

            if(Pos:x() < 0 & (abs(Pos:x()) > PrePos | !PrePos)) { 
                Awh[TurnStr,number] = abs(Pos:x())
                #print("["+Wheels:count()+"] " + TurnStr + " | Pos: " + abs(Pos:x()) + " | PrePos: " + PrePos)
                Awh[Str,entity] = Ent
            }
        }
    }
    #Awh["R",entity]:setColor(vec(255,0,0)) Awh["L",entity]:setColor(vec(0,255,0))
}

local Driver = Pod["Entity",entity]:driver()

if(changed(Driver) & Driver & EAN | changed(IdleRPM)) {
    soundStop(111) E:soundPlay(111,0,Sound)
}

if(changed(Fuel) & !Fuel | changed(EngAct) & !Fuel) {
    EngAct = 0 
}

if(changed(Active) & Active) {
    EngAct = !EngAct
    local String = EngAct & Fuel ? "acf_extra/vehiclefx/engines/coh/car_up.wav" : "acf_extra/vehiclefx/engines/coh/car_end.wav"
    local R = randint(1,100) Plate:soundPlay(R,2,String) soundPitch(R,randint(120,130)) 
} # 

EAN = EngAct ? (clamp(EAN + 0.05, EAN, 1 )) : (clamp(EAN - 0.02, 0, EAN )) 
local MxR = (MaxRPM + randint(-200,200))
local Overload = ((RPM_N) > G2[Gear,number]) ####
local PA = (PGear == 1 ? 1 : PGear/1.7)
local MinR = IdleRPM/42.8
Rotor = (Rotor < MinR) ? MinR : ( (RPM_N / (43 / 0.4))/(PGear/2.5) ) * PA

local AddSnd = RPM_N > abs(G2[Gear,number]) ? (RPM_N - abs(G2[Gear,number]))/120 : 0

local P = ( (Rotor) + (Throttle)*8 + (5) + (Overload*22) + (AddSnd) )
PTCH = ( PTCH < P ? clamp(PTCH + 1, PTCH, P) : clamp(PTCH - 2, P, PTCH) ) * EAN

soundPitch(111,( (PTCH * Pitch_Coeff + Pitch_Add)*Th_2 + (IdleRPM/10)/(Th_2+1) ) * EAN)

#local AF = (RPM_N < G2[Gear-1,number] & Th_2 & RPM_N > IdleRPM*1.5) # OLD -> (- Af/400)

Fuel = clamp(Fuel - RPM/1400000 - Overload/1000, 0, Fuel)

foreach(N, Wheel:entity = Wheels) { 
    RPM_N = ( RPM_N + abs(Wheel:angVel():pitch()) + Torque * 0.8 + IdleRPM ) * EAN
} 

Th_2 = ( Throttle & Th_3 ? clamp(Th_2 + 0.03, Th_2, 1 ) : clamp(Th_2 - 0.03, 0.3, Th_2 ) ) * EAN

RPM_N = RPM_N / Wheels:count()

local Num = clamp(PTCH*30, PTCH*30, MxR)

RPM = RPM < Num ? (clamp(RPM + (70 + RPM/30), RPM, Num)) : (clamp(RPM - (100 + RPM/30), Num, RPM )) # NEW

Torque = graph(RPM_N) * Th_2

Power = Torque * RPM_N / 7000

if(changed(GearUp) & GearUp | changed(GearDown) & GearDown) {
    Gear = (GearUp) ? (clamp(Gear + 1, Gear, 6 )) : (clamp(Gear - 1, 1, Gear ))
}

if(Reverse_Gear & (changed(ReverseGear) & ReverseGear & Gear != 6 | changed(Throttle) & Throttle & Gear == 6)) {
    Gear = ReverseGear ? 6 : 1
}

if(Gear == 6 & ReverseGear) { Throttle = 2 Th_2 = 1.5 }



if(changed(Gear)) { 
    PGear = (Gear == 6) ? 1 : Gear
    
    local R = randint(1,100)
    
    if(TransmVol) { 
        Plate:soundPlay(R,2,"buttons/lever7.wav") soundPitch(R,105 + randint(-2,2)) soundVolume(R,TransmVol) 
    }
    
    if(Overload) { 
        Plate:soundPlay(R+1,2,"acf_extra/vehiclefx/boost/gear_change_dump1.wav") 
        soundPitch(R+1,80 + randint(-10,10) + PGear*20)  
    }
    
    #PTCH = (MinR*6 + PGear*1.5) # NEW \ MinR*5
    #PTCH = PTCH/2
    Th_3 = 0 timer("th",400)
    PTCH = (GearDown & RPM_N > G2[Gear,number]) ? PTCH : PTCH/2
    GNum = (PGear == 1) ? G[Gear,number]/1.5 : G[Gear,number]/7 # NEW
}

if(clk("th")) { Th_3 = 1 }

GNum = (RPM_N > G2[Gear-1,number]) ? (clamp(GNum + 0.0015, GNum, G[Gear,number]/1.3)) : (clamp(GNum - 0.002, G[Gear,number]/2.2, GNum)) # NEW

WheelTorque = Torque * Efficiency * GNum # NEW

foreach(N, Wheel:entity = Wheels) {
    local Ang = ang()
    
    if(Throttle) {
        local Arg = ( (RPM_N < (G2[Gear,number] + randint(-300,300))) ) # & RPM_N > G2[Gear,number]/randint(7 + Gear*2,3)
        
        if(Arg) {
            Ang = (ang((Line[N,number] * Wheel:mass() * Force_Coeff * (Power/(Power*0.04)) * WheelTorque),0,0))
        } if(Gear == 6 & !Arg) { Brake = 1 }
        
        local Pos = floor(Plate:toLocal(Wheel:pos())) 
        

        if(RPM_N < (G2[1,number]) / 3) { Ang = Ang * 3 }
        
        if(PGear == 1) {
            local Pw = (abs(Wheel:angVel():pitch()) < G2[1,number]/3) ? (Pos:x() > 0 ? 3.5 : 1.5) : 1
            Ang = Ang * Pw
        }
  
    }

    if(Brake | !Driver | !Fuel) {
        Ang = (-Wheel:angVel()*Wheel:mass()*Force_Coeff*1.5)
    }
        
    local Pos = Plate:toLocal(Wheel:pos())
        
    local STR = Pos:x() < 0 ? 0.6 : 1
        
    Wheel:applyAngForce(Ang * STR)

    if(ABS) {
        local AB = abs(Plate:velL():y())
    
        if(AB > 50) {
            local Str = (Plate:velL():y() < 0) ? "R" : "L"
            local Ent = Awh[Str,entity]
            local SN = RPM_N/2000 if(SN < 1) { SN = 1 }
            Ent:applyAngForce((-Ent:angVel()*AB/130*Ent:mass()*Force_Coeff/2/SN))
        }
    }
}

#C_Y = (clamp(abs(Plate:velL():y()), abs(Plate:velL():y()), 368))/120 + 1

#TA = (clamp(Plate:velL():x(), Plate:velL():x(), 170)) * -Turn / 2 * Plate:mass() / 500 / C_Y

#Plate:applyOffsetForce( (Plate:right()) * TA * (!Brake+0.2) * Plate:mass(), Plate:toWorld(vec(70,0,0)) )

#local Right = -(clamp(Plate:velL():y(), Plate:velL():y(), 125))/50

#Plate:applyForce( (-Plate:right()*2*Right / (Brake + 1))*Plate:mass() ) 
