--
-- Autopilot
-- Specialization for AP Tractors
--
-- @author  zartask / Mr. F
-- @date  10/12/09
--
-- Copyright (C) www.planet-ls.de
--
--	edit by gotchTOM
--	@date: 20-Feb-2011
--  Specialization for AP Combine (corn harvester) 
--	add: inputbindings, new helpPanel, cornering maneuvers, use Lights when needed, aiTrailerTrigger, apBackTrafficCollisionTrigger, apOtherCombineCollisionTrigger(left&right)+otherCombineColliTriggerActiv, 
--       workwidthArrows, waitMode, stop@rain
--
--  last edit by MRA-Modding(Alex2009(www.alex2009.de))(www.mra-modding.com)
--  code source: AICombine.lua by Giants Software    
 
APCombine = {};
APCombine.Folder = g_currentModDirectory;

function APCombine.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Hirable, specializations) and SpecializationUtil.hasSpecialization(Steerable, specializations);
end;

function APCombine:load(xmlFile)
    self.SingleplayerWarning = 0;
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        self.createpressInput = APCombine.createpressInput;
        self.pressInputs = {};
        self:createpressInput(self,"Textur/APMenu/gross.png","SWBAdd", false, 0.023, 0.203, 0.0345, 0.03);                 
        self:createpressInput(self,"Textur/APMenu/klein.png","SWBDel", false, 0.2625, 0.2005, 0.033, 0.03);                
        self:createpressInput(self,"Textur/APMenu/tankfahren.png","AbtankenFahrend", false, 0.023, 0.167, 0.0365, 0.03);    
        self:createpressInput(self,"Textur/APMenu/tankstehen.png","AbtankenStehend", true, 0.2625, 0.1625, 0.0365, 0.03);  
        self:createpressInput(self,"Textur/APMenu/links.png","APSeiteLinks", true, 0.023, 0.1285, 0.0345, 0.03);            
        self:createpressInput(self,"Textur/APMenu/rechts.png","APSeiteRechts", false, 0.2625, 0.127, 0.033, 0.03);
        self:createpressInput(self,"Textur/APMenu/an.png","AbstandAn", false, 0.023, 0.0935, 0.0345, 0.03);
        self:createpressInput(self,"Textur/APMenu/aus.png","AbstandAus", true, 0.2625, 0.089, 0.033, 0.03);
        self:createpressInput(self,"Textur/APMenu/apon.png","StartAP", false, 0.0455, 0.0295, 0.032, 0.029);
        self:createpressInput(self,"Textur/APMenu/apoff.png","StopAP", true, 0.0825, 0.0285, 0.0315, 0.03);
        self:createpressInput(self,"Textur/APMenu/exit.png","Exit", false, 0.1455, 0.029, 0.03, 0.03);
        --Lexion750:createpressInput(self,"Textur/Metall.png","Reset", false, 0.2075, 0.029, 0.0.03, 0.0275);-- Reset
        self.APHud = Overlay:new("APHud",Utils.getFilename("Textur/APMenu/APMenu.png", self.baseDirectory),0.0, 0.00099999999999967, 0.3455, 0.349);
        self.apDelayTimeToStopMovement = 12;	
        self.apDelayTimeToMoveBack = 30;
        self.apDelayTimeToStopAutoPilot = 250;
        self.otherCombineColliTriggerActiv = false;
        self.waitMode = true;

        self.startAutopilot = SpecializationUtil.callSpecializationsFunction("startAutopilot");
        self.stopAutopilot = SpecializationUtil.callSpecializationsFunction("stopAutopilot");
        
        self.onTrafficCollisionTrigger = APCombine.onTrafficCollisionTrigger;
        self.onOtherCombineCollisionTrigger = APCombine.onOtherCombineCollisionTrigger;
        self.addBackTrafficCollisionTrigger = APCombine.addBackTrafficCollisionTrigger;
        self.removeBackTrafficCollisionTrigger = APCombine.removeBackTrafficCollisionTrigger;
        self.addOtherCombineCollisionTrigger = APCombine.addOtherCombineCollisionTrigger;
        self.removeOtherCombineCollisionTrigger = APCombine.removeOtherCombineCollisionTrigger;	
        
        self.apTrafficCollisionTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.autoPilotAreas.apTrafficCollisionTrigger#index"));
        self.apBackTrafficCollisionTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.autoPilotAreas.apBackTrafficCollisionTrigger#index"));
        self.apOtherCombineCollisionTriggerL = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.autoPilotAreas.apOtherCombineCollisionTriggerL#index"));
        self.apOtherCombineCollisionTriggerR = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.autoPilotAreas.apOtherCombineCollisionTriggerR#index"));	
        
        self.trafficCollisionIgnoreList = {};
        for k,v in pairs(self.components) do
            self.trafficCollisionIgnoreList[v.node] = true;
        end;
        self.numCollidingVehicles = 0;
        self.numToolsCollidingVehicles = {};
            
        self.onTrailerTrigger = APCombine.onTrailerTrigger;
        self.aiTrailerTriggers = {};
        local i = 0;
        while true do
            local key = string.format("vehicle.aiTrailerTriggers.aiTrailerTrigger(%d)", i);
            if not hasXMLProperty(xmlFile, key) then
                break;
            end;
            local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
            local pipeState = getXMLInt(xmlFile, key.."#pipeState");
            if node ~= nil and pipeState ~= nil then
                self.aiTrailerTriggers[node] = {node=node, pipeState=pipeState};
            end;
            i = i + 1;
        end;
        local aiTrailerTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.aiTrailerTrigger#index"));
        if aiTrailerTrigger ~= nil then
            self.aiTrailerTriggers[aiTrailerTrigger] = {node=aiTrailerTrigger, pipeState=2};
        end;
        for _, aiTrailerTrigger in pairs(self.aiTrailerTriggers) do
            addTrigger(aiTrailerTrigger.node, "onTrailerTrigger", self);
        end;
      
        self.trailersInRange = {};
        self.isTrailerInRange = false;
        self.trailerInRangePipeState = 0;
        self.waitingForTrailerToUnload = false;
        self.waitingForDischarge = false;
        self.waitForDischargeTime = 0;
        self.waitForDischargeTimeout = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.waitForDischargeTime"), 5000);
     
        self.isAutopilotActivated = false;
        self.dtSum = 0;

        local aiMotorSound = getXMLString(xmlFile, "vehicle.aiMotorSound#file");
        if aiMotorSound  ~= nil and aiMotorSound  ~= "" then
            aiMotorSound  = Utils.getFilename(aiMotorSound, self.baseDirectory);
            self.aiMotorSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundRun#pitchOffset"), 0);
            self.aiMotorSoundRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundRun#radius"), 50);
            self.aiMotorSoundInnerRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundRun#innerRadius"), 10);
            self.aiMotorSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundRun#volume"), 1);
            self.aiMotorSound = createAudioSource("aiMotorSound", aiMotorSound, self.aiMotorSoundRadius, self.aiMotorSoundInnerRadius, self.aiMotorSoundVolume, 0);
            link(self.components[1].node, self.aiMotorSound);
            setVisibility(self.aiMotorSound, false);
        end;

        local translationPartNodeLeft = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#index"));
        if translationPartNodeLeft ~= nil then
            self.translationPartLeft = {};
            self.translationPartLeft.node = translationPartNodeLeft;
            local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#minTrans"));
            self.translationPartLeft.minTrans = {};
            self.translationPartLeft.minTrans[1] = Utils.getNoNil(x, 0);
            self.translationPartLeft.minTrans[2] = Utils.getNoNil(y, 0);
            self.translationPartLeft.minTrans[3] = Utils.getNoNil(z, 0);

            x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#maxTrans"));
            self.translationPartLeft.maxTrans = {};
            self.translationPartLeft.maxTrans[1] = Utils.getNoNil(x, 0);
            self.translationPartLeft.maxTrans[2] = Utils.getNoNil(y, 0);
            self.translationPartLeft.maxTrans[3] = Utils.getNoNil(z, 0);

            self.translationPartLeft.transTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#transTime"), 5)*2500;
            self.translationPartLeft.touchTransLimit = Utils.getNoNil(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#touchTransLimit"), 5);
        end;
        
        local translationPartNodeRight = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#index"));
        if translationPartNodeRight ~= nil then
            self.translationPartRight = {};
            self.translationPartRight.node = translationPartNodeRight;
            local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#minTrans"));
            self.translationPartRight.minTrans = {};
            self.translationPartRight.minTrans[1] = Utils.getNoNil(x, 0);
            self.translationPartRight.minTrans[2] = Utils.getNoNil(y, 0);
            self.translationPartRight.minTrans[3] = Utils.getNoNil(z, 0);

            x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#maxTrans"));
            self.translationPartRight.maxTrans = {};
            self.translationPartRight.maxTrans[1] = Utils.getNoNil(x, 0);
            self.translationPartRight.maxTrans[2] = Utils.getNoNil(y, 0);
            self.translationPartRight.maxTrans[3] = Utils.getNoNil(z, 0);

            self.translationPartRight.transTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#transTime"), 5)*2500;
            self.translationPartRight.touchTransLimit = Utils.getNoNil(getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#touchTransLimit"), 5);
        end;

        self.autoPilotAreaLeft = {};
        self.autoPilotAreaLeft.available = getXMLBool(xmlFile, "vehicle.autoPilotAreas#left");
        self.autoPilotAreaLeft.startOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#startOutside"));
        self.autoPilotAreaLeft.widthOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#widthOutside"));
        self.autoPilotAreaLeft.heightOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#heightOutside"));
        self.autoPilotAreaLeft.startInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#startInside"));
        self.autoPilotAreaLeft.widthInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#widthInside"));
        self.autoPilotAreaLeft.heightInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#heightInside"));
        self.autoPilotAreaLeft.startCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#startCheck"));
        self.autoPilotAreaLeft.widthCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#widthCheck"));
        self.autoPilotAreaLeft.heightCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#heightCheck"));
        self.autoPilotAreaLeft.active = true;

        self.autoPilotAreaRight = {};
        self.autoPilotAreaRight.available = getXMLBool(xmlFile, "vehicle.autoPilotAreas#right");
        self.autoPilotAreaRight.startOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#startOutside"));
        self.autoPilotAreaRight.widthOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#widthOutside"));
        self.autoPilotAreaRight.heightOutside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#heightOutside"));
        self.autoPilotAreaRight.startInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#startInside"));
        self.autoPilotAreaRight.widthInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#widthInside"));
        self.autoPilotAreaRight.heightInside = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#heightInside"));	
        self.autoPilotAreaRight.startCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#startCheck"));
        self.autoPilotAreaRight.widthCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#widthCheck"));
        self.autoPilotAreaRight.heightCheck = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#heightCheck"));
        self.autoPilotAreaRight.active = false;

        if self.autoPilotAreaLeft.available or self.autoPilotAreaRight.available then
            self.autoPilotPresent = true;
        else
            self.autoPilotPresent = false;
        end;  	
        self.FilltypeNotAccpeptedWarningTime = 0;
        self.workWidth = nil;
        self.autoPilotEnabled = false;
        self.apDelayLeftCounting = false;
        self.autoPilotDelayLeft = 0;
        self.autoPilotDelayRight = 0;
        self.gotFruitArea = nil;	
        self.autoPilotAreaLeft.arrowLeft = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaLeft#arrowL"));
        self.autoPilotAreaRight.arrowRight = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.autoPilotAreas.autoPilotAreaRight#arrowR"));
        self.turnDirection = 0;
        self.autoRotateBackSpeedBackup = self.autoRotateBackSpeed;
        self.APHudEnabled = false;
    end;
end;

function APCombine:delete()
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        self:stopAutopilot();
        for _, aiTrailerTrigger in pairs(self.aiTrailerTriggers) do
            removeTrigger(aiTrailerTrigger.node);
        end;
        self:removeOtherCombineCollisionTrigger()
        self:removeBackTrafficCollisionTrigger();
    end;
end;

function APCombine:mouseEvent(posX, posY, isDown, isUp, button) 
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
	    if self:getIsActiveForInput() then
            if self.APHudEnabled then
                InputBinding.setShowMouseCursor(true); 
	        end;
            if isDown and self.APHudEnabled and button == 1 and self.isEntered then
                for name,pressInput in pairs(self.pressInputs) do
                    if posX > self.pressInputs[name].x and posX < self.pressInputs[name].x2 and posY > self.pressInputs[name].y and posY < self.pressInputs[name].y2 then
                        self.pressInputs[name].parameter = not self.pressInputs[name].parameter;    	
                    end;
                end;
            elseif self.pressInputs['SWBAdd'].parameter or self.pressInputs['SWBDel'].parameter then
	            self.pressInputs['SWBAdd'].parameter = false;
	        	self.pressInputs['SWBDel'].parameter = false;
            end;
	    end;
    end;
end;

function APCombine:keyEvent(unicode, sym, modifier, isDown)
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        if isDown and sym == Input.KEY_s then
            self.speed2Level = 0;
        end;
    end;
end;

function APCombine:update(dt)
	if self:getIsActiveForInput() and not g_currentMission.missionDynamicInfo.isMultiplayer then
	    if self.FilltypeNotAccpeptedWarningTime > 0 then
	        g_currentMission:addWarning(g_i18n:getText("FilltypeNotAllowedUsageHelper"), 0.018, 0.033);
	        self.FilltypeNotAccpeptedWarningTime = (self.FilltypeNotAccpeptedWarningTime - 1);
	    end;
	    if self.SingleplayerWarning > 0 then
            g_currentMission:addWarning(g_i18n:getText("SingleplayerOnly"), 0.018, 0.033);
            self.SingleplayerWarning = (self.SingleplayerWarning - 1);
        end;
		if InputBinding.hasEvent(InputBinding.Menu0On) then
			if not g_currentMission.missionDynamicInfo.isMultiplayer then
				self.APHudEnabled = true;
			else
				self.SingleplayerWarning = 50;
			end;
		end;
		local fruitType = "0";
		if self.currentGrainTankFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
			fruitType = FruitUtil.fruitIndexToDesc[self.currentGrainTankFruitType].name;
			self.fruitType = self.currentGrainTankFruitType;
		end;
       	if InputBinding.hasEvent(InputBinding.SPEED_LEVEL1) then
        	self.speed2Level = 1;
       	elseif InputBinding.hasEvent(InputBinding.SPEED_LEVEL2) then
        	self.speed2Level = 2;
        elseif InputBinding.hasEvent(InputBinding.SPEED_LEVEL4) then
        	self.speed2Level = 4;
      	end;
	end;
end;

function APCombine:updateTick(dt)
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        if self.isAutopilotActivated and not self.IsThreshing then
            if self:getIshreshingAllowed(true) then
                self:setIsThreshing(true);
            end; 
        end;
        if self.APHudEnabled then 
            setVisibility(self.autoPilotAreaLeft.arrowLeft, true);
            setVisibility(self.autoPilotAreaRight.arrowRight, true);
            if self.pressInputs["Exit"].parameter then
                setVisibility(self.autoPilotAreaLeft.arrowLeft, false);
                setVisibility(self.autoPilotAreaRight.arrowRight, false);
                self.APHudEnabled = false;
                InputBinding.setShowMouseCursor(false); 
                self.pressInputs["Exit"].parameter = false;
            end;
            if self.pressInputs["StartAP"].parameter and not self.isAutopilotActivated then
                if self.isThreshing and self.grainTankFillLevel > 0 and not self.isAIThreshing then
                    if (self.currentGrainTankFruitType == 4) then
                        self.FilltypeNotAccpeptedWarningTime = 90;
                        self.pressInputs["StartAP"].parameter = false;
                    else
                        if self.motor.speedLevel ~= 0 then
                            self.motor:setSpeedLevel(0, false);
                        end;
                        if self.motor.speedLevel == 0 then
                            self.speed2Level = 1;
                        end;
                        self:startAutopilot();
                        self.autoPilotEnabled = true;
                        self.pressInputs["StopAP"].parameter = false;
                    end;
                else
                    self.pressInputs["StartAP"].parameter = false;
                end;
            elseif not self.pressInputs["StartAP"].parameter and self.isAutopilotActivated then
                self.pressInputs["StartAP"].parameter = true;
            end;
            if self.pressInputs["StopAP"].parameter and self.isAutopilotActivated then
                if self.isAutopilotActivated then
                    self:stopAutopilot();
                    self.autoPilotEnabled = false;
                    self.pressInputs["StartAP"].parameter = false;
                else
                    self.pressInputs["StopAP"].parameter = false;
                end;
            elseif not self.pressInputs["StopAP"].parameter and not self.isAutopilotActivated then
                self.pressInputs["StopAP"].parameter = true;
            end;
            if self.pressInputs["APSeiteLinks"].parameter and not self.autoPilotAreaLeft.active then
                self.autoPilotAreaLeft.active = self.autoPilotAreaLeft.available;
                self.autoPilotAreaRight.active = false;
                self.pressInputs["APSeiteRechts"].parameter = false;
                self.autoPilotDelayLeft = 0;
                self.autoPilotDelayRight = 0;     
            elseif self.autoPilotAreaLeft.active and not self.pressInputs["APSeiteLinks"].parameter then
                self.pressInputs["APSeiteLinks"].parameter = true;		
            end;
            if self.pressInputs["APSeiteRechts"].parameter and not self.autoPilotAreaRight.active then
                self.autoPilotAreaRight.active = self.autoPilotAreaRight.available;
                self.autoPilotAreaLeft.active = false;
                self.pressInputs["APSeiteLinks"].parameter = false;
                self.autoPilotDelayRight = 0;
                self.autoPilotDelayLeft = 0;
            elseif self.autoPilotAreaRight.active and not self.pressInputs["APSeiteRechts"].parameter then
                self.pressInputs["APSeiteRechts"].parameter = true;
            end;		
            if self.pressInputs["AbstandAn"].parameter and not self.otherCombineColliTriggerActiv then
                self.otherCombineColliTriggerActiv = true
                self.pressInputs["AbstandAus"].parameter = false;    
            elseif self.otherCombineColliTriggerActiv and not self.pressInputs["AbstandAn"].parameter then
                self.pressInputs["AbstandAn"].parameter = true;		
            end;
            if self.pressInputs["AbstandAus"].parameter and self.otherCombineColliTriggerActiv then
                self.otherCombineColliTriggerActiv = false;
                self.numCollidingVehicles = 0;
                self.pressInputs["AbstandAn"].parameter = false;
             elseif not self.otherCombineColliTriggerActiv and not self.pressInputs["AbstandAus"].parameter then
                self.pressInputs["AbstandAus"].parameter = true;
            end;  
            if self.pressInputs["AbtankenFahrend"].parameter and self.waitMode then
                self.waitMode = false;
                self.pressInputs["AbtankenStehend"].parameter = false;    
            elseif not self.waitMode and not self.pressInputs["AbtankenFahrend"].parameter then
                self.pressInputs["AbtankenFahrend"].parameter = true;		
            end;
            if self.pressInputs["AbtankenStehend"].parameter and not self.waitMode then
                self.waitMode = true;
                self.pressInputs["AbtankenFahrend"].parameter = false;
            elseif self.waitMode and not self.pressInputs["AbtankenStehend"].parameter then
                self.pressInputs["AbtankenStehend"].parameter = true;
            end;
            if self.pressInputs["SWBAdd"].parameter and not self.translationMaxLeft then
                self.translationMaxLeft = true;
                self.translationMaxRight = true; 
                self.translationMinLeft = false;
                self.translationMinRight = false;
                --self.pressInputs["SWBAdd"].parameter = false;
            elseif self.translationMaxRight and not self.pressInputs["SWBAdd"].parameter then
                self.translationMaxLeft = false;
                self.translationMaxRight = false;	
            end;
            if self.pressInputs["SWBDel"].parameter and not self.translationMinLeft then
                self.translationMinLeft = true;
                self.translationMinRight = true;
                self.translationMaxLeft = false;
                self.translationMaxRight = false; 
                --self.pressInputs["SWBDel"].parameter = false;
            elseif self.translationMinLeft and not self.pressInputs["SWBDel"].parameter then
                self.translationMinLeft = false;
                self.translationMinRight = false;
            end;
        end;
        self:removeOtherCombineCollisionTrigger();
        self:removeBackTrafficCollisionTrigger();	
        if self.isServer then	
            self.workWidth = getTranslation(self.translationPartLeft.node) * 1.75;	
            if self.isEntered then
                if self.autoPilotAreaRight.available then
                    if self.translationPartRight ~= nil and (self.translationMaxRight or self.translationMinRight) then
                    local x, y, z = getTranslation(self.translationPartRight.node);
                    local trans = {x,y,z};
                    local newTrans = Utils.getMovedLimitedValues(trans, self.translationPartRight.maxTrans, self.translationPartRight.minTrans, 3, self.translationPartRight.transTime, dt, not self.translationMaxRight);
                    setTranslation(self.translationPartRight.node, unpack(newTrans));
                    end;
                end;	
                if self.autoPilotAreaLeft.available then
                    if self.translationPartLeft ~= nil and (self.translationMaxLeft or self.translationMinLeft) then
                    local x, y, z = getTranslation(self.translationPartLeft.node);
                    local trans = {x,y,z};
                    local newTrans = Utils.getMovedLimitedValues(trans, self.translationPartLeft.maxTrans, self.translationPartLeft.minTrans, 3, self.translationPartLeft.transTime, dt, not self.translationMaxRight);
                    setTranslation(self.translationPartLeft.node, unpack(newTrans));
                    end;
                end;
            else
                setVisibility(self.autoPilotAreaLeft.arrowLeft, false);
                setVisibility(self.autoPilotAreaRight.arrowRight, false);
            end;
            if self.isAutopilotActivated then
                if self.isBroken then
                    self:stopAutopilot();
                end;		
                self.dtSum = self.dtSum + dt;
                if self.dtSum > 20 then
                    APCombine.updateAIMovement(self, self.dtSum);
                    self.dtSum = 0;
                end;
                if (self.grainTankFillLevel > 0 or self.grainTankCapacity <= 0) and (self.grainTankFillLevel >= self.grainTankCapacity or self.isTrailerInRange) then
                    if self.trailerInRangePipeState > 0 then
                        self:setPipeState(self.trailerInRangePipeState);
                        if self.waitMode then
                            self.waitingForDischarge = true;
                        end;
                    else
                        self:setPipeState(2);
                    end;
                    --self:setPipeOpening(true);
                    if self.isTrailerInRange then
                        self.waitForDischargeTime = self.time + self.waitForDischargeTimeout;
                    end;
                    if self.waitMode then 
                        if self.grainTankFillLevel >= self.grainTankCapacity and self.grainTankCapacity > 0 then                    
                            self.waitingForDischarge = true;
                            self.waitForDischargeTime = self.time + self.waitForDischargeTimeout;
                        end;
                    else
                        if self.grainTankFillLevel < self.grainTankCapacity and self.grainTankCapacity > 0 then                    
                            self.waitingForDischarge = false;
                            self.waitForDischargeTime = self.time + self.waitForDischargeTimeout;
                            if self:getIshreshingAllowed(true) then
                                self:setIsThreshing(true);
                            end; 
                        end;
                    end;
                else
                    -- no trailer in range and not full
                    if (self.waitingForDischarge and self.grainTankFillLevel <= 0) or self.waitForDischargeTime <= self.time then
                        self.waitingForDischarge = false;
                        if not self.isTrailerInRange then
                            -- only close the pipe if no trailer is in range
                            self:setPipeState(1);
                        end;
                        --self:setPipeOpening(false);
                        if self:getIshreshingAllowed(true) then
                            self:setIsThreshing(true);
                        end;                
                    end;
                end;			
                if self.speed2Level == 2 or self.speed2Level == 4 then
                    self.apDelayTimeToStopMovement = 8;	
                else
                    self.apDelayTimeToStopMovement = 12;
                end;
                self:addOtherCombineCollisionTrigger()
            else
                self.dtSum = 0;
                self:removeOtherCombineCollisionTrigger()
                self:removeBackTrafficCollisionTrigger();
            end;		
        end;
	end;	
end;

function APCombine:startAutopilot(noEventSend)
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        self:hire();
        if not self.isAutopilotActivated then
            self.isAutopilotActivated = true;		
            self.isTrailerInRange = false;
            self.waitingForDischarge = false;
            self.pressInputs["StartAP"].parameter = true;
            self.pressInputs["StopAP"].parameter = false;
            if self.autoPilotPresent then
                if not self.autoPilotAreaLeft.active and not self.autoPilotAreaRight.active then
                    if self.autoPilotAreaLeft.available then
                        self.autoPilotAreaLeft.active = true;
                    elseif self.autoPilotAreaRight.available then
                        self.autoPilotAreaRight.active = true;
                    end;
                end;
                if self.autoPilotEnabled then
                    self.autoRotateBackSpeed = 0;
                else
                    self.autoRotateBackSpeed = self.autoRotateBackSpeedBackup;
                end;
            end;
            self.numCollidingVehicles = 0;
            if self.apTrafficCollisionTrigger ~= nil then
                addTrigger(self.apTrafficCollisionTrigger, "onTrafficCollisionTrigger", self);
            end;  		
            self.checkSpeedLimit = false;
            setVisibility(self.aiMotorSound, true);
            for cutter,implement in pairs(self.attachedCutters) do
                self:setJointMoveDown(implement.jointDescIndex, true, true);
            end;
        end;
    end;
end;

function APCombine:stopAutopilot(noEventSend)
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        self:dismiss();
        if self.isAutopilotActivated then       
            local wlf = self.B3.work[1];
            if wlf.a then
                self:setState("work:1",false);
            end;
            local wl = self.B3.work[3];
            if wl.a then
                self:setState("work:3",false);
            end;
            self.isAutopilotActivated = false;     
            self.checkSpeedLimit = true;
            setVisibility(self.aiMotorSound, false);			
            self.autoPilotDelayRight = 0;
            self.autoPilotDelayLeft = 0;
            self:setIsThreshing(false);		
            self.pressInputs["StartAP"].parameter = false;
            self.pressInputs["StopAP"].parameter = true;
            for cutter,implement in pairs(self.attachedCutters) do
                self:setJointMoveDown(implement.jointDescIndex, false, true);
            end;
            self.motor:setSpeedLevel(0, false);
            self.motor.maxRpmOverride = nil;
            WheelsUtil.updateWheelsPhysics(self, 0, 0, 0, false, self.requiredDriveMode);	
            if self.apTrafficCollisionTrigger ~= nil then
                removeTrigger(self.apTrafficCollisionTrigger, "onTrafficCollisionTrigger", self);
            end;    
        end;
    end;
end;

function APCombine.updateAIMovement(self, dt, onLeave)
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        local allowedToDrive = true;
        if self.grainTankCapacity == 0 and ((self.pipeParticleActivated and not self.isPipeUnloading) or not self.pipeStateIsUnloading[self.currentPipeState]) then
            -- there is some fruit to unload, but there is no trailer. Stop and wait for a trailer
            self.waitingForTrailerToUnload = true;
        end;
        if self.waitingForTrailerToUnload then
            if self.currentGrainTankFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
                local trailer = self:findTrailerToUnload(self.currentGrainTankFruitType);
                if trailer ~= nil then
                   -- there is a trailer to unload. Continue working
                    self.waitingForTrailerToUnload = false;
                end;
            else
               -- we did not cut anything yet. We shouldn't have ended in this state. Just continue working
                self.waitingForTrailerToUnload = false;
            end;
        end;
      
        if (self.grainTankFillLevel >= self.grainTankCapacity and self.grainTankCapacity > 0) or self.waitingForTrailerToUnload or self.waitingForDischarge or self.numCollidingVehicles > 0 then
            allowedToDrive = false;
        end;
        if not self:getIshreshingAllowed(true) then
            allowedToDrive = false;
            --self:setIsThreshing(false);
            self.motor:setSpeedLevel(0, false);
            self.waitingForWeather = true;
        else
            if self.waitingForWeather then
                self:startThreshing();
                self.waitingForWeather = false;
            end;
        end;
        
        if self.numCollidingVehicles > 0 then
            allowedToDrive = false;
        end;
        for k,v in pairs(self.numToolsCollidingVehicles) do
            if v > 0 then
                allowedToDrive = false;
                break;
            end;
        end;

        if self.autoPilotPresent then
            if self.autoPilotEnabled then
                local wlf = self.B3.work[1];
                if not g_currentMission.environment.isSunOn and not wlf.a then
                    self:setState("work:1",true);
                elseif g_currentMission.environment.isSunOn and wlf.a then
                    self:setState("work:1",false);
                end;
                if self.targetPipeState == 2 then
                    local wl = self.B3.work[3];
                    if not g_currentMission.environment.isSunOn and not wl.a then
                        self:setState("work:3",true);
                    elseif g_currentMission.environment.isSunOn and wl.a then
                        self:setState("work:3",false);
                    end;
                else
                    local wl = self.B3.work[3];
                    if wl.a then
                        self:setState("work:3",false);
                    end;
                end;
                self.turnDirection = 0;
                if self.autoPilotAreaRight.available and self.autoPilotAreaRight.active and self.fruitType ~= nil  then--Start AP Areas
                    local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightOutside);
                    local right = Utils.getFruitArea(self.fruitType, x, z, x1, z1, x2, z2);
                    local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startInside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthInside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightInside);
                    local left = Utils.getFruitArea(self.fruitType, x, z, x1, z1, x2, z2);
                    local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startCheck);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthCheck);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightCheck);
                    local rightCheck = Utils.getFruitArea(self.fruitType, x, z, x1, z1, x2, z2);   
                    local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightOutside);
                    local checkLeft = Utils.getFruitArea(self.fruitType, x, z, x1, z1, x2, z2);								
                    self.turnDirection = right -(9 -left);
                    self.turnDirection = right*4 -(20 -left);
                    if (left < 1 and right < 1) then
                        self.apDelayRightCounting = true;
                        self.gotFruitArea = false;
                    else
                        self.apDelayRightCounting = false;
                        self.autoPilotDelayRight = 0;
                        self.gotFruitArea = true;
                    end;					
                    if self.autoPilotDelayRight >= self.apDelayTimeToStopMovement then
                        allowedToDrive = false;						
                        for cutter,implement in pairs(self.attachedCutters) do
                            local jointDesc = self.attacherJoints[implement.jointDescIndex];
                            jointDesc.moveDown = false;
                        end;						
                    end;
                    if self.autoPilotDelayRight >= self.apDelayTimeToMoveBack then
                        if self.numCollidingVehicles == 0 then
                            allowedToDrive = true;
                            self.apDelayRightCounting = true;
                        else
                            allowedToDrive = false;
                            self.apDelayRightCounting = false;
                        end;
                        moveForwards = false;
                        self.turnDirection = ((20 -right) -left*4);
                    end;
                    if not self.gotFruitArea and rightCheck >0 then
                        moveForwards = true;
                        self.turnDirection = 0;
                        self.apDelayRightCounting = false;
                        self.autoPilotDelayRight = 0;
                        for cutter,implement in pairs(self.attachedCutters) do
                            local jointDesc = self.attacherJoints[implement.jointDescIndex];
                            jointDesc.moveDown = true;
                        end;
                        if checkLeft > 0 then
                            self.turnDirection = right -(9 -left);
                            self.turnDirection = right*4 -(20 -left);
                        end;
                    elseif self.gotFruitArea then
                        moveForwards = true;
                        self.turnDirection = right -(9 -left);
                        self.turnDirection = right*4 -(20 -left);
                        for cutter,implement in pairs(self.attachedCutters) do
                            local jointDesc = self.attacherJoints[implement.jointDescIndex];
                            jointDesc.moveDown = true;
                        end;						
                    end;				
                end;
                if self.autoPilotAreaLeft.available and self.autoPilotAreaLeft.active and self.fruitType ~= nil then
                    local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightOutside);
                    local left = Utils.getFruitArea(self.fruitType, x, z, x1, z1, x2, z2);
                    local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startInside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthInside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightInside);
                    local right = Utils.getFruitArea(self.fruitType, x, z, x1, z1, x2, z2);
                    local x,y,z = getWorldTranslation(self.autoPilotAreaLeft.startCheck);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaLeft.widthCheck);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaLeft.heightCheck);
                    local leftCheck = Utils.getFruitArea(self.fruitType, x, z, x1, z1, x2, z2); 
                    local x,y,z = getWorldTranslation(self.autoPilotAreaRight.startOutside);
                    local x1,y1,z1 = getWorldTranslation(self.autoPilotAreaRight.widthOutside);
                    local x2,y2,z2 = getWorldTranslation(self.autoPilotAreaRight.heightOutside);
                    local checkRight = Utils.getFruitArea(self.fruitType, x, z, x1, z1, x2, z2);
                    self.turnDirection = ((20 -right) -left*4);
                    if (left < 1 and right < 1) then
                        self.apDelayLeftCounting = true;
                        self.gotFruitArea = false;
                    else
                        self.apDelayLeftCounting = false;
                        self.autoPilotDelayLeft = 0;
                        self.gotFruitArea = true;
                    end;
                    if self.autoPilotDelayLeft >= self.apDelayTimeToStopMovement then
                        allowedToDrive = false;						
                        for cutter,implement in pairs(self.attachedCutters) do
                            local jointDesc = self.attacherJoints[implement.jointDescIndex];
                            jointDesc.moveDown = false;
                        end;						
                    end;
                    if self.autoPilotDelayLeft >= self.apDelayTimeToMoveBack then 
                        if self.numCollidingVehicles == 0 then
                            allowedToDrive = true;
                            self.apDelayLeftCounting = true;
                        else
                            allowedToDrive = false;
                            self.apDelayLeftCounting = false;
                        end;
                        moveForwards = false;
                        self.turnDirection = right -(9 -left);
                        self.turnDirection = right*4 -(20 -left);						
                    end;
                    if not self.gotFruitArea and leftCheck > 0 then
                        moveForwards = true;
                        self.turnDirection = 0;
                        self.apDelayLeftCounting = false;
                        self.autoPilotDelayLeft = 0;
                        for cutter,implement in pairs(self.attachedCutters) do
                            local jointDesc = self.attacherJoints[implement.jointDescIndex];
                            jointDesc.moveDown = true;
                        end;
                        if checkRight > 0 then
                            self.turnDirection = ((20 -right) -left*4);
                        end;
                    elseif self.gotFruitArea then
                        moveForwards = true;
                        self.turnDirection = ((20 -right) -left*4);
                        for cutter,implement in pairs(self.attachedCutters) do
                            local jointDesc = self.attacherJoints[implement.jointDescIndex];
                            jointDesc.moveDown = true;
                        end;
                    end;				
                end;
                local acceleration = 0;					
                if self.isMotorStarted then
                    if self.motor.speedLevel ~= 0 then
                        acceleration = 1.0;
                    end;
                end;
                if self.fuelFillLevel == 0 then
                    acceleration = 0;
                end;
                if self.apDelayLeftCounting then
                    self.autoPilotDelayLeft = self.autoPilotDelayLeft +1;
                end;
                if self.apDelayRightCounting then
                    self.autoPilotDelayRight = self.autoPilotDelayRight +1;
                end;
                local rotScale = math.min(1.0/(self.lastSpeed*50+1), 1);
                if self.autoPilotAreaLeft.active and self.turnDirection < -19 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*rotScale, 0.90);-----self.minRotTime
                elseif self.turnDirection < -18 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*70, 0.84);----self.maxRotTime
                elseif self.turnDirection < -17 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*65, 0.78);----self.maxRotTime
                elseif self.turnDirection < -16 then
                    self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*55, 0.72);----self.maxRotTime
                elseif self.turnDirection < -15 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*45, 0.66);----self.maxRotTime
                    elseif self.turnDirection < -14 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*35, 0.60);----self.maxRotTime
                    elseif self.turnDirection < -13 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*30, 0.54);----self.maxRotTime
                    elseif self.turnDirection < -12 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*25, 0.36);----self.maxRotTime
                    elseif self.turnDirection < -11 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*20, 0.28);----self.maxRotTime
                    elseif self.turnDirection < -10 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*15, 0.22);----self.maxRotTime
                    elseif self.turnDirection < -9 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*10, 0.18);----self.maxRotTime
                    elseif self.turnDirection < -8 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*5, 0.16);----self.maxRotTime
                    elseif self.turnDirection < -7 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*1, 0.14);----self.maxRotTime
                    elseif self.turnDirection < -6 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.5, 0.12);----self.maxRotTime
                    elseif self.turnDirection < -5 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.1, 0.10);----self.maxRotTime
                    elseif self.turnDirection < -4 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.08, 0.08);----self.maxRotTime
                    elseif self.turnDirection < -3 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.06, 0.06);----self.maxRotTime
                    elseif self.turnDirection < -2 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.04, 0.04);----self.maxRotTime
                    elseif self.turnDirection < -1 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.02, 0.02);----self.maxRotTime
                    elseif self.autoPilotAreaLeft.active and self.turnDirection > 19 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*rotScale, -0.90);-----self.minRotTime
                    elseif self.turnDirection > 18 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*70, -0.84);-----self.minRotTime
                    elseif self.turnDirection > 17 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*65, -0.78);-----self.minRotTime
                    elseif self.turnDirection > 16 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*55, -0.72);-----self.minRotTime
                    elseif self.turnDirection > 15 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*45, -0.66);-----self.minRotTime
                    elseif self.turnDirection > 14 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*35, -0.60);-----self.minRotTime
                    elseif self.turnDirection > 13 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*30, -0.54);-----self.minRotTime
                    elseif self.turnDirection > 12 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*25, -0.36);-----self.minRotTime
                    elseif self.turnDirection > 11 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*20, -0.28);-----self.minRotTime
                    elseif self.turnDirection > 10 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*15, -0.22);-----self.minRotTime
                    elseif self.turnDirection > 9 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*10, -0.18);-----self.minRotTime
                    elseif self.turnDirection > 8 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*5, -0.16);-----self.minRotTime
                    elseif self.turnDirection > 7 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*1, -0.14);-----self.minRotTime
                    elseif self.turnDirection > 6 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.5, -0.12);-----self.minRotTime
                    elseif self.turnDirection > 5 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.10, -0.10);-----self.minRotTime
                    elseif self.turnDirection > 4 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.08, -0.08);-----self.minRotTime
                    elseif self.turnDirection > 3 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.06, -0.06);-----self.minRotTime
                    elseif self.turnDirection > 2 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.04, -0.04);-----self.minRotTime
                    elseif self.turnDirection > 1 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.02, -0.02);-----self.minRotTime
                else
                    self.rotatedTime = 0;
                end;
                local rotScale = math.min(1.0/(self.lastSpeed*50+1), 1);
                if self.autoPilotAreaRight.active and self.turnDirection < -19 then
                       self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*rotScale, 0.90);-----self.minRotTime
                elseif self.turnDirection < -18 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*70, 0.84);----self.maxRotTime
                    elseif self.turnDirection < -17 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*65, 0.78);----self.maxRotTime
                    elseif self.turnDirection < -16 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*55, 0.72);----self.maxRotTime
                    elseif self.turnDirection < -15 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*45, 0.66);----self.maxRotTime
                    elseif self.turnDirection < -14 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*35, 0.60);----self.maxRotTime
                    elseif self.turnDirection < -13 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*30, 0.54);----self.maxRotTime
                    elseif self.turnDirection < -12 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*25, 0.36);----self.maxRotTime
                    elseif self.turnDirection < -11 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*20, 0.28);----self.maxRotTime
                    elseif self.turnDirection < -10 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*15, 0.22);----self.maxRotTime
                    elseif self.turnDirection < -9 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*10, 0.18);----self.maxRotTime
                    elseif self.turnDirection < -8 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*5, 0.16);----self.maxRotTime
                    elseif self.turnDirection < -7 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*1, 0.14);----self.maxRotTime
                    elseif self.turnDirection < -6 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.5, 0.12);----self.maxRotTime
                    elseif self.turnDirection < -5 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.1, 0.10);----self.maxRotTime
                    elseif self.turnDirection < -4 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.08, 0.08);----self.maxRotTime
                    elseif self.turnDirection < -3 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.06, 0.06);----self.maxRotTime
                    elseif self.turnDirection < -2 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.04, 0.04);----self.maxRotTime
                    elseif self.turnDirection < -1 then
                        self.rotatedTime = math.min(self.rotatedTime - dt/1000*self.turnDirection*0.02, 0.02);----self.maxRotTime
                    elseif self.autoPilotAreaRight.active and self.turnDirection > 19 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*rotScale, -0.90);-----self.minRotTime
                    elseif self.turnDirection > 18 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*70, -0.84);-----self.minRotTime
                    elseif self.turnDirection > 17 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*65, -0.78);-----self.minRotTime
                    elseif self.turnDirection > 16 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*55, -0.72);-----self.minRotTime
                    elseif self.turnDirection > 15 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*45, -0.66);-----self.minRotTime
                    elseif self.turnDirection > 14 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*35, -0.60);-----self.minRotTime
                    elseif self.turnDirection > 13 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*30, -0.54);-----self.minRotTime
                    elseif self.turnDirection > 12 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*25, -0.36);-----self.minRotTime
                    elseif self.turnDirection > 11 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*20, -0.28);-----self.minRotTime
                    elseif self.turnDirection > 10 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*15, -0.22);-----self.minRotTime
                    elseif self.turnDirection > 9 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*10, -0.18);-----self.minRotTime
                    elseif self.turnDirection > 8 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*5, -0.16);-----self.minRotTime
                    elseif self.turnDirection > 7 then
                        self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*1, -0.14);-----self.minRotTime
                elseif self.turnDirection > 6 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.5, -0.12);-----self.minRotTime
                elseif self.turnDirection > 5 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.10, -0.10);-----self.minRotTime
                elseif self.turnDirection > 4 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.08, -0.08);-----self.minRotTime
                elseif self.turnDirection > 3 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.06, -0.06);-----self.minRotTime
                elseif self.turnDirection > 2 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.04, -0.04);-----self.minRotTime
                elseif self.turnDirection > 1 then
                    self.rotatedTime = math.max(self.rotatedTime - dt/1000*self.turnDirection*0.02, -0.02);-----self.minRotTime
                else
                    self.rotatedTime = 0;
                end;
                if self.firstTimeRun then
                    local acc = acceleration;
                    if speedLevel ~= nil and speedLevel ~= 0 then
                        acc = self.motor.accelerations[speedLevel];
                        self.motor:setSpeedLevel(speedLevel, true);
                        if math.abs(angle) >= slowAngleLimit then
                            self.motor.maxRpmOverride = self.motor.maxRpm[speedLevel]*slowMaxRpmFactor;
                        else
                            self.motor.maxRpmOverride = nil;
                        end;
                    end;
                    if not allowedToDrive then
                        acc = 0;
                    end;
                    if not moveForwards then
                        acc = -acc;
                        self:addBackTrafficCollisionTrigger()
                    else
                        self:removeBackTrafficCollisionTrigger()
                    end;
                    if self.maxAccelerationSpeed ~= nil then
                        acc = Steerable.calculateRealAcceleration(self, acc, dt);
                    end;
                    WheelsUtil.updateWheelsPhysics(self, dt, self.lastSpeed, acc, not allowedToDrive, self.requiredDriveMode);
                end;
                if self.steering ~= nil then
                    setRotation(self.steering, 0, self.rotatedTime*self.steeringSpeed, 0);
                end;
                if self.autoPilotDelayLeft > self.apDelayTimeToStopAutoPilot or self.autoPilotDelayRight > self.apDelayTimeToStopAutoPilot then
                    self:stopAutopilot();	
                    self.motor.speedLevel = 0;
                end;					
                if allowedToDrive then				
                    self.motor.speedLevel = self.speed2Level;		
                else
                    self.motor.speedLevel = 0;
                end;	
            else
                self.autoPilotDelayLeft = 0;
                self.autoPilotDelayRight = 0;
            end;	
        end; 
    end;
end;

function APCombine:addBackTrafficCollisionTrigger()
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        if self.apBackTrafficCollisionTrigger ~= nil then
            addTrigger(self.apBackTrafficCollisionTrigger, "onTrafficCollisionTrigger", self);
        end;
    end;
end;
function APCombine:removeBackTrafficCollisionTrigger()
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        if self.apBackTrafficCollisionTrigger ~= nil then		
            removeTrigger(self.apBackTrafficCollisionTrigger);
        end;
    end;
end;

function APCombine:addOtherCombineCollisionTrigger()
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        if self.otherCombineColliTriggerActiv then	
            if self.apOtherCombineCollisionTriggerL ~= nil and self.apOtherCombineCollisionTriggerR ~= nil then
                if self.autoPilotAreaLeft.active then
                    addTrigger(self.apOtherCombineCollisionTriggerL, "onOtherCombineCollisionTrigger", self);
                    removeTrigger(self.apOtherCombineCollisionTriggerR, "onOtherCombineCollisionTrigger", self);
                    
                elseif self.autoPilotAreaRight.active then
                    addTrigger(self.apOtherCombineCollisionTriggerR, "onOtherCombineCollisionTrigger", self);
                    removeTrigger(self.apOtherCombineCollisionTriggerL, "onOtherCombineCollisionTrigger", self);
                end;
            end;
        end;	
    end;
end;
function APCombine:removeOtherCombineCollisionTrigger()
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        if self.apOtherCombineCollisionTriggerL ~= nil and self.apOtherCombineCollisionTriggerR ~= nil then
            removeTrigger(self.apOtherCombineCollisionTriggerL);		
            removeTrigger(self.apOtherCombineCollisionTriggerR);	
        end;
    end;
end;
		
function APCombine:onTrafficCollisionTrigger(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        if onEnter or onLeave then
            if otherId == g_currentMission.player.rootNode then
                if onEnter then
                    self.numCollidingVehicles = self.numCollidingVehicles+1;
                elseif onLeave then
                    self.numCollidingVehicles = math.max(self.numCollidingVehicles-1, 0);
                end;
            else
                local vehicle = g_currentMission.nodeToVehicle[otherId];
                if vehicle ~= nil and self.trafficCollisionIgnoreList[otherId] == nil then
                    if onEnter then
                        self.numCollidingVehicles = self.numCollidingVehicles+1;
                    elseif onLeave then
                        self.numCollidingVehicles = math.max(self.numCollidingVehicles-1, 0);
                    end;
                end;
            end;
        end;
    end;
end;

function APCombine:onOtherCombineCollisionTrigger(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        if onEnter or onLeave then
            if otherId == Player.rootNode then
                if onEnter then
                    self.numCollidingVehicles = self.numCollidingVehicles+1;
                elseif onLeave then
                    self.numCollidingVehicles = math.max(self.numCollidingVehicles-1, 0);
                end;
            else            
                local cutter = g_currentMission.nodeToVehicle[otherId];
                if cutter ~= nil and self.trafficCollisionIgnoreList[otherId] == nil then
                    if onEnter then
                        self.numCollidingVehicles = self.numCollidingVehicles+1;
                    elseif onLeave then
                        self.numCollidingVehicles = math.max(self.numCollidingVehicles-1, 0);
                    end;
                end;
            end;
        end;
    end;
end;

function APCombine:onTrailerTrigger(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        if onEnter or onLeave then
            local trailer = g_currentMission.nodeToVehicle[otherId];
            if trailer ~= nil and trailer.fillRootNode ~= nil then
                if onEnter then
                    self.trailersInRange[trailer] = self.aiTrailerTriggers[triggerId].pipeState;
                    self.trailerInRangePipeState = math.max(self.trailerInRangePipeState, self.aiTrailerTriggers[triggerId].pipeState);
                    self.isTrailerInRange = true;
                else
                    self.trailersInRange[trailer] = nil;
                    self.isTrailerInRange = false;
                    self.trailerInRangePipeState = 0;
                    for trailer, pipeState in pairs(self.trailersInRange) do
                        self.trailerInRangePipeState = math.max(self.trailerInRangePipeState, pipeState);
                        self.isTrailerInRange = true;
                    end;
                end;
            end;
        end;
    end;
end;

function APCombine:draw()
    if not g_currentMission.missionDynamicInfo.isMultiplayer then
        if self.APHudEnabled then
            self.APHud:render();
            renderText(0.1595, 0.204, 0.0315,string.format("%0.1fm",self.workWidth));
            for name,pressInput in pairs(self.pressInputs) do
                if self.pressInputs[name].parameter then
                    self.pressInputs[name].overlay:render();
                end;
            end;
        end;
    end;
end;

function APCombine:createpressInput(self, image, name, parameter, x, y, width, height)
  local overlay = Overlay:new(image, Utils.getFilename(image, APCombine.Folder), x, y, width, height);
  self.pressInputs[name] = {overlay=overlay, parameter = parameter, x=x, x2=(x+width), y=y, y2=(y+height)}
end;

function APCombine:onLeave()
    self.SingleplayerWarning = 0;
    self.FilltypeNotAccpeptedWarningTime = 0;
end;