--jakeBrake.lua 
--Engine Jake Brake for FS15 Trucks by westmorgan.
--	Credits:
--Based on original enginebrake.lua by TwistedGA & Looseterror
--hud overlay Aspect Ratio Independent code Decker_MMIV
--3/22/2015 ver. 0.1a Initial FS15 Script.
--3/23/2015 ver. 0.1b Added hud overlay beta.
--3/29/2015 ver. 0.1c Start adding code for Mogli Gearbox compatibility. Functional with Standard Giants, Drive Control, and some mrGearboxMogli features(installed in mod/not Global).
--4/12/2015 ver. 0.1d Clean up code. Add variables for jake brake high and low with mrGearboxMogli. Works with auto trans, auto/manual clutch, and range selection.
--4/18/2015 ver. 0.1e Rewrite sections of code to take control of braking. Removed to a separate script 5/1/2015.
--5/1/2015  ver. 0.1f Try to update code to be compatible with MP and implement suggested code changes.
--11/23/2015 ver. 0.1g Shut off realisticRoll global script when using the manual transmission script.
--11/29/2015 ver. 1 Added code to save jake brake settings in game vehicles.xml.

--Add the following to your vehicle.xml if you wish to use this script in your mod truck.
--[[
		<!-- Jake Brake Script -->
	<jakeBrakeSound file="jakeBrake/jakeBrake.wav" pitchOffset="1" pitchScale="0.01" pitchMax="1.5" volume="20" />
	<jakeBrakeSound3d file="jakeBrake/jakeBrake3d.wav" pitchOffset="1" pitchScale="0.01" pitchMax="1.5" volume="1" />
	<motorBrakeHigh>0.99</motorBrakeHigh> <!-- EB high brake scale -->
	<motorBrakeLow>0.5</motorBrakeLow> <!-- EB low brake scale -->
	<motorMTBrakeHigh>6</motorMTBrakeHigh> <!-- mrGearboxMogli EB high brake scale -->
	<motorMTBrakeLow>1.5</motorMTBrakeLow> <!-- mrGearboxMogli EB low brake scale -->
		<!-- Remember to adjust the lowBrakeForceScale in the engine section to a low number, 0.1 recommended -->
		<!-- End Jake Brake Script -->
--]]

jakeBrake = {};

function jakeBrake.prerequisitesPresent(specializations)
	return SpecializationUtil.hasSpecialization(Motorized, specializations);
end;

function jakeBrake:load(xmlFile)
-- Configure Engine Brake Sound	
	if self.isClient then -- only client need sound
        self.jakeBrakeSound = Utils.loadSample(xmlFile, {}, "vehicle.jakeBrakeSound", nil, self.baseDirectory, self.components[1].node); 
        self.jakeBrakePitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.jakeBrakeSound#pitchOffset"), 1.0); 
        self.jakeBrakePitchScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.jakeBrakeSound#pitchScale"), 0.05); 
        self.jakeBrakePitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.jakeBrakeSound#pitchMax"), 2.0); 
        self.jakeBrakeVolumeMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.jakeBrakeSound#volumeMax"), 2.0); 
	end;

-- Configure Variables
	self.jakeBrake = false;
	self.ebHiLo = true;
	self.lowBrakeForceBackup = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motor#lowBrakeForceScale"), self.motor.lowBrakeForceScale);
	self.brakeForceBackup = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motor#brakeForce"), self.motor.brakeForce );
	self.lowMTBrakeForceBackup = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.gearboxMogli#motorBrakeFx"), self.motor.lowBrakeForceScale)
	self.motorBrakeHigh = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorBrakeHigh"), 0.9);
	self.motorBrakeLow = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorBrakeLow"), 0.5);
	self.motorMTBrakeHigh = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorMTBrakeHigh"), 0.9);
	self.motorMTBrakeLow = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorMTBrakeLow"), 0.5);
	self.currentMTRange = 3;
	self.isGBon = false;

-- Hud overlay -- Original Aspect Ratio Independent code by Decker_MMIV
    local iconWidth = math.floor(0.015 * g_screenWidth) / g_screenWidth; --0.0095
    local iconHeight = iconWidth * g_screenAspectRatio;
    local iconWidth2 = math.floor(0.0095 * g_screenWidth) / g_screenWidth; --0.0095
    local iconHeight2 = iconWidth * g_screenAspectRatio;
    local xAdjust = iconWidth * 0.25
    local yAdjust = iconHeight * 0.4
 
    local x,y = g_currentMission.speedHud.x,g_currentMission.speedHud.y;
    local w,h = g_currentMission.speedHud.width,g_currentMission.speedHud.height;
    local xIndent,yIndent = 0,0
 
    local halfTextW = getTextWidth(g_currentMission.speedUnitTextSize, "100%") / 2

    self.jakeBrakeOffIcon = Overlay:new("jakeBrakeOffIcon", Utils.getFilename("jakeBrake/jbOff.dds", self.baseDirectory), x+w+4.0*iconWidth2,y+h-yIndent-iconHeight2+yAdjust, iconWidth,iconHeight);
    self.jakeBrakeLoIcon = Overlay:new("jakeBrakeLoIcon",   Utils.getFilename("jakeBrake/jbLo.dds",  self.baseDirectory), x+w+4.0*iconWidth2,y+h-yIndent-iconHeight2+yAdjust, iconWidth,iconHeight);
    self.jakeBrakeHiIcon = Overlay:new("jakeBrakeHiIcon",   Utils.getFilename("jakeBrake/jbHi.dds",  self.baseDirectory), x+w+4.0*iconWidth2,y+h-yIndent-iconHeight2+yAdjust, iconWidth,iconHeight);
end;

function jakeBrake:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if not resetVehicles then
        local brakeOnOff = Utils.getNoNil(getXMLBool(xmlFile, key .. "#JakeBrakeOnOff"), self.jakeBrake); 
        local brakeHiLo = Utils.getNoNil(getXMLBool(xmlFile, key .. "#JakeBrakeHiLo"), self.ebHiLo); 
		self.jakeBrake = brakeOnOff;
		self.ebHiLo = brakeHiLo;
	end;
	return BaseMission.VEHICLE_LOAD_OK;
end;

function jakeBrake:getSaveAttributesAndNodes(nodeIdent)
    local attributes = 'JakeBrakeOnOff="'..tostring(self.jakeBrake)..'" JakeBrakeHiLo="' .. tostring(self.ebHiLo) ..'"'; 
	
	local nodes = nil;
	return attributes,nodes;
end;

function jakeBrake:update(dt)
	if self:getIsActive() and self.isMotorStarted then
		if InputBinding.hasEvent(InputBinding.JAKEBRAKE) then		
			self.jakeBrake = not self.jakeBrake
			jakeBrakeInputEvent.sendEvent(self)  
		end;
		if InputBinding.hasEvent(InputBinding.EBHILO) then		
			self.ebHiLo = not self.ebHiLo
			jakeBrakeInputEvent.sendEvent(self)  
		end;
		-- Test if mrGearboxMogli script is being used.
		if self.mrGbMS ~= nil then
			self.isGBon = self.mrGbMS.IsOnOff;
		-- End Test if mrGearboxMogli script is being used.
			
		-- Mogli Gearbox / realisticRoll.lua fix
			if self.kmhIsNull ~= nil and self.isGBon then
				self.kmhIsNull = false;
			end;
		-- End Mogli Gearbox / realisticRoll.lua fix
		end;
	end;
			
	if self.jakeBrake and self.isMotorStarted and not (self.getIsCourseplayDriving and self:getIsCourseplayDriving()) and self.cruiseControl.state == 0 then
        local accInput = 0; 
        if self.axisForward ~= nil then 
            accInput = self.axisForward; 
        end; 
-- Set sample Pitch and Volume
        if table.getn(self.wheels) > 0 then 
            local minRpm = self.motor.minRpm; 
            local maxRpm = self.motor.maxRpm;
						
            local maxSpeed; 
            if self.movingDirection >= 0 then 
                maxSpeed = self.motor.maxForwardSpeed*0.001; 
            else 
                maxSpeed = self.motor.maxBackwardSpeed*0.001; 
            end 
 
            local targetRpmOffset = (self.motor.lastMotorRpm-minRpm)*0.8 + math.min(self.lastSpeed/maxSpeed, 1)*(maxRpm-minRpm)*0.2; 
 
            local alpha = math.pow(0.01, dt*0.001); 
            local roundPerMinute = targetRpmOffset + alpha*(self.lastRoundPerMinute-targetRpmOffset); 
            self.lastRoundPerMinute = roundPerMinute; 
            local roundPerSecond = roundPerMinute / 240; --60
            if self.isClient then 
                local jakeBrakePitch = math.min(self.jakeBrakePitchOffset + self.jakeBrakePitchScale*math.abs(roundPerSecond), self.jakeBrakePitchMax) 
                Utils.setSamplePitch(self.jakeBrakeSound, jakeBrakePitch); 
 
                local rpmRunVolume = math.abs(roundPerMinute)/(maxRpm - minRpm); 
                if math.abs(accInput) < 0.01 then 
                    rpmRunVolume = rpmRunVolume * 0.666; 
                end; 
                rpmRunVolume = Utils.clamp(rpmRunVolume, 0.0, 1.0); 
                Utils.setSampleVolume(self.jakeBrakeSound, rpmRunVolume*self.jakeBrakeVolumeMax); 
            end; 
        end; 
-- End set sample Pitch and Volume
		local groundSpeed = self.lastSpeed * 3600;
		--
		if self.jakeBrakeSound ~= nil and not self.isGBon then
			local enoughRpm = false;
			if self.motor.lastMotorRpm > self.motor.minRpm then
				enoughRpm = true;
			end;
			if self.jakeBrakeSoundEnabled and accInput == -1 then
				Utils.stopSample(self.jakeBrakeSound);
				self.jakeBrakeSoundEnabled = false;
			end;
			if self.ebHiLo then
				self.motor.lowBrakeForceScale = self.motorBrakeLow;
			else 
				self.motor.lowBrakeForceScale = self.motorBrakeHigh;
			end;
			if accInput == -1 and enoughRpm then
				self.jakeBrakeSoundEnabled = false;
			end;
			if accInput >= 0 and not self.jakeBrakeSoundEnabled and enoughRpm then
				if self:getIsActiveForSound() then
					if not Utils.isSamplePlaying(self.jakeBrakeSound, 1.8*dt) then 
						Utils.playSample(self.jakeBrakeSound, 0, 0, nil); 
					end; 
                    Utils.stop3DSample(self.jakeBrakeSound); 
				else 
					Utils.play3DSample(self.jakeBrakeSound); 
				end;
				self.jakeBrakeSoundEnabled = true;
			else if groundSpeed < 1 then
				Utils.stopSample(self.jakeBrakeSound);
			end;
			end;
		end;
-- Mogli Gearbox Addon code
		if self.jakeBrakeSound ~= nil and self.isGBon and self.motor.clutchPercent ~= nil then
			if self.jakeBrakeSoundEnabled and accInput == -1 then
				Utils.stopSample(self.jakeBrakeSound);
				Utils.stop3DSample(self.jakeBrakeSound); 
				self.jakeBrakeSoundEnabled = false;
			end;
			if self.ebHiLo then
				self.mrGbMS.RealMotorBrakeFx = self.motorMTBrakeLow;
				local lowBrakeForceScale = self.motorMTBrakeLow;
				self.motor:setLowBrakeForce(lowBrakeForceScale, lowBrakeForceSpeedLimit); 
			else 
				self.mrGbMS.RealMotorBrakeFx = self.motorMTBrakeHigh;
				local lowBrakeForceScale = self.motorMTBrakeHigh;
				self.motor:setLowBrakeForce(lowBrakeForceScale, lowBrakeForceSpeedLimit); 
			end;
			if self.motor.clutchPercent ~= nil then
				if self.motor.clutchPercent < 0.25 then
					Utils.stopSample(self.jakeBrakeSound);
					Utils.stop3DSample(self.jakeBrakeSound); 
					self.jakeBrakeSoundEnabled = false;
				end;
			end;
			if self.mrGbMS.CurrentRange ~= self.currentMTRange then
				self.mrGbMS.RealMotorBrakeFx = self.lowMTBrakeForceBackup;
				Utils.stopSample(self.jakeBrakeSound);
				Utils.stop3DSample(self.jakeBrakeSound); 
				self.jakeBrakeSoundEnabled = false;
			end;
			if accInput >= 0 and not self.jakeBrakeSoundEnabled and self.motor.clutchPercent > 0.5 then
				if self:getIsActiveForSound() then
					if not Utils.isSamplePlaying(self.jakeBrakeSound, 1.8*dt) then 
						Utils.playSample(self.jakeBrakeSound, 0, 0, nil); 
					end; 
                    Utils.stop3DSample(self.jakeBrakeSound); 
				else 
					Utils.play3DSample(self.jakeBrakeSound); 
				end;
				self.jakeBrakeSoundEnabled = true;
			end;
			self.currentMTRange = self.mrGbMS.CurrentRange;
		end;
-- End Mogli Gearbox Addon code
	else
		if self.isGBon then
			self.mrGbMS.RealMotorBrakeFx = self.lowMTBrakeForceBackup;
		end;
		self.motor.lowBrakeForceScale = self.lowBrakeForceBackup;
		self.jakeBrakeSoundEnabled = false;
		Utils.stopSample(self.jakeBrakeSound);
        Utils.stop3DSample(self.jakeBrakeSound); 
	end;
end;

function jakeBrake:draw()
	if self:getIsActive() and self.isMotorStarted and not (self.getIsCourseplayDriving and self:getIsCourseplayDriving()) then
		if self.jakeBrake then
			g_currentMission:addHelpButtonText(g_i18n:getText("JAKEBRAKE_ON"),InputBinding.JAKEBRAKE);		
			if self.ebHiLo then
				g_currentMission:addHelpButtonText(g_i18n:getText("EBHILO_Lo"),InputBinding.EBHILO);
				if self.jakeBrake then
				self.jakeBrakeLoIcon:render();
				end;
			else
				g_currentMission:addHelpButtonText(g_i18n:getText("EBHILO_Hi"),InputBinding.EBHILO);
				if self.jakeBrake then
				self.jakeBrakeHiIcon:render();
				end;
			end;
		else
			g_currentMission:addHelpButtonText(g_i18n:getText("JAKEBRAKE_OFF"),InputBinding.JAKEBRAKE);
			self.jakeBrakeOffIcon:render();
		end;
	end;
end;

function jakeBrake:mouseEvent(posX, posY, isDown, isUp, button)
end;

function jakeBrake:keyEvent(unicode, sym, modifier, isDown)
end;

function jakeBrake:delete()
	if self.isClient then
		Utils.deleteSample(self.jakeBrakeSound);
	end;
	self.jakeBrakeOffIcon:delete();
	self.jakeBrakeLoIcon:delete();
	self.jakeBrakeHiIcon:delete();
end;

-- MP Compatiable Code????

jakeBrakeInputEvent = {};
jakeBrakeInputEvent_mt = Class(jakeBrakeInputEvent, Event);

InitEventClass(jakeBrakeInputEvent, "jakeBrakeInputEvent");

function jakeBrakeInputEvent:emptyNew()
    local self = Event:new(jakeBrakeInputEvent_mt);
    self.className="jakeBrakeInputEvent";
    return self;
end;

function jakeBrakeInputEvent:new(vehicle)
    local self = jakeBrakeInputEvent:emptyNew()
    self.vehicle = vehicle;
	self.jakeBrake = vehicle.jakeBrake.jakeBrake
	self.ebHiLo = vehicle.jakeBrake.ebHiLo
	
	
	--print("event new")
    return self;
end;

function jakeBrakeInputEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.jakeBrake);
	streamWriteBool(streamId, self.ebHiLo);
	--print("event writeStream")
end;

function jakeBrakeInputEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    local vehicle = networkGetObject(id);
	
	local jakeBrake = streamReadBool(streamId);
	local ebHiLo = streamReadBool(streamId);
	
	vehicle.jakeBrake.jakeBrake = jakeBrakeActive;
	vehicle.jakeBrake.ebHiLo = ebHiLoSelected;
	
	--print("event readStream")
	--print(jakeBrake,ebHiLo)
	if g_server ~= nil then	
		g_server:broadcastEvent(jakeBrakeInputEvent:new(vehicle), nil, nil, vehicle);
		-- print("broadcasting")
	end;
end;

function jakeBrakeInputEvent.sendEvent(vehicle)
	if g_server ~= nil then	
		--g_server:broadcastEvent(jakeBrakeInputEvent:new(vehicle), nil, nil, self);
		-- print("broadcasting")
	else
		g_client:getServerConnection():sendEvent(jakeBrakeInputEvent:new(vehicle));
		-- print("sending event to server...")
	end;
end;