--
-- Kverneland 4028 
-- Specialization for a mower.
--
-- author  	Henly20 
-- date  	19-12-2010.
-- www.ls-uk.info
-- ALL RIGHTS RESERVED
  
KevMT = {};
  
function KevMT.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(AnimatedVehicleNew, specializations) and SpecializationUtil.hasSpecialization(PowerShaft, specializations);
end;
  
function KevMT:load(xmlFile)

	self.setTransRot = SpecializationUtil.callSpecializationsFunction("setTransRot");
	self.TransRotAnimation = getXMLString(xmlFile, "vehicle.TransRot#animationName");
	self.TransRot = false;
	self.setWheelRot = SpecializationUtil.callSpecializationsFunction("setWheelRot");
	self.WheelRotAnimation = getXMLString(xmlFile, "vehicle.WheelRot#animationName");
	self.WheelRot = false;
	self.setSideSkirts = SpecializationUtil.callSpecializationsFunction("setSideSkirts");
	self.SideSkirtsAnimation = getXMLString(xmlFile, "vehicle.SideSkirts#animationName");
	self.SideSkirts = false;
	self.sideskirtNode = {};
	self.sideskirtNode.node  = Utils.indexToObject(self.components,getXMLString(xmlFile, "vehicle.sideskirtNode#index"));	
	
    self.setIsTurnedOn = SpecializationUtil.callSpecializationsFunction("setIsTurnedOn");
	
    self.groundReferenceThreshold = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.groundReferenceNode#threshold"), 1);
    self.groundReferenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.groundReferenceNode#index"));
    if self.groundReferenceNode == nil then
        self.groundReferenceNode = self.components[2].node;
    end;
	  
 	self.doJointOrientation = false;
	self.attacherJointCopy = nil;
	self.updateJoint = false;  
 
      local numCuttingAreas = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.cuttingAreas#count"), 0);
      for i=1, numCuttingAreas do
          local areanamei = string.format("vehicle.cuttingAreas.cuttingArea%d", i);
          self.cuttingAreas[i].foldMinLimit = Utils.getNoNil(getXMLFloat(xmlFile, areanamei .. "#foldMinLimit"), 0);
          self.cuttingAreas[i].foldMaxLimit = Utils.getNoNil(getXMLFloat(xmlFile, areanamei .. "#foldMaxLimit"), 1);
      end;
  
      self.isTurnedOn = false;
      self.wasToFast = false;
      
      self.mowerGroundFlag = self.nextDirtyFlag;
      self.nextDirtyFlag = self.mowerGroundFlag*2;

	  self.mowerParticleSystems = {};
      local i = 0;
      while true do
        local namei = string.format("vehicle.mowerParticleSystems.mowerParticleSystems(%d)", i);
		local nodei = Utils.indexToObject(self.components, getXMLString(xmlFile, namei .. "#index"));
		if nodei == nil then
			break;
		end; 
        Utils.loadParticleSystem(xmlFile, self.mowerParticleSystems, namei, nodei, false, nil, self.baseDirectory)		
		i = i +1;		
      end;
  
     self.onlyActiveWhenLowered = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.onlyActiveWhenLowered#value"), true);
	
	self.rotateSpinners = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.rotateSpinners.node(%d)", i);
		local index = getXMLString(xmlFile, baseName.. "#index");
		local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.. "#rotationSpeed"));
		local rotationSpeed = {x,y,z};
		local runOutTime = Utils.getNoNil(getXMLFloat(xmlFile, baseName.. "#runOutTime"), 2)*1000;
		if index == nil or rotationSpeed == nil or runOutTime == nil then
			break;
		end;
		local node = Utils.indexToObject(self.components, index);
		if node ~= nil then
			local entry = {};
			entry.node = node;
			entry.runOutTime = runOutTime;
			entry.rotationSpeedMax = rotationSpeed;
			entry.rotationSpeedMin = {0,0,0};
			entry.rotationSpeedCurrent = {0,0,0};
			table.insert(self.rotateSpinners, entry);
		end;
		i = i+1;
	end;	
	
	local rotarySound = getXMLString(xmlFile, "vehicle.rotarySound#file");
	if rotarySound ~= nil and rotarySound ~= "" then
		rotarySound = Utils.getFilename(rotarySound, self.baseDirectory);
		self.rotarySound = createSample("rotarySound");
		loadSample(self.rotarySound, rotarySound, false);
		self.rotarySoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.rotarySound#pitchOffset"), 0);
		self.rotarySoundVolume = 0.0;
		self.rotarySoundVolumeMin = 0.0;
		self.rotarySoundVolumeMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.rotarySound#volume"), 1.0);
		self.rotarySoundEnabled = false;
	end;
	
      self.sideSkirtsDown = {};
      local i = 0;
      while true do
          local key = string.format("vehicle.sideSkirtsDown.sideskirtsdown(%d)", i);
          if not hasXMLProperty(xmlFile, key) then
              break;
          end;
          local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
           if node ~= nil then
              setVisibility(node, false);
              table.insert(self.sideSkirtsDown, {node=node});
          end;
          i = i + 1;
      end; 
	
      self.sideSkirtsUp = {};
      local i = 0;
      while true do
          local key = string.format("vehicle.sideSkirtsUp.sideskirtsup(%d)", i);
          if not hasXMLProperty(xmlFile, key) then
              break;
          end;
          local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
          if node ~= nil then
              setVisibility(node, true);
              table.insert(self.sideSkirtsUp, {node=node});
          end;
          i = i + 1;
      end;
	
    self.printWarningTime = 0;
    self.printWarningTime1 = 0;
	self.lastArea = 0;
	self.lastAreaBiggerZero = self.lastArea > 0;
 	self.setVehicleRpmUp = SpecializationUtil.callSpecializationsFunction("setVehicleRpmUp");
	self.saveMinRpm = 0; 
	self.lastAreaSent = 0;
	self.MowedArea = 0;
	self.MowedTotalArea = 0;	
	
    self.hudInfoPosX = 0.02;
    self.hudInfoWidth = 0.19;
    self.hudInfoPosY = 0.02;
    self.hudInfoHeight = 0.15;

	self.infoPanelInfoPath = Utils.getFilename("textures/Kevhud.png", self.baseDirectory);
	self.hudInfoOverlay = Overlay:new("hudInfoOverlay", self.infoPanelInfoPath, self.hudInfoPosX, self.hudInfoPosY, self.hudInfoWidth, self.hudInfoHeight);

	self.showhudInfo = false;
end;

function KevMT:delete()
	Utils.deleteParticleSystem(self.mowerParticleSystems);
	
	if self.rotarySound ~= nil then
		delete(self.rotarySound);
	end;
 
end;

function KevMT:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if not resetVehicles then
		local MowedTotalArea = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#MowedTotalArea"), self.MowedTotalArea);
		self.MowedTotalArea = MowedTotalArea;
		local isSideSkirtsOn = Utils.getNoNil(getXMLBool(xmlFile, key .. "#isSideSkirtsOn"), false);
		if isSideSkirtsOn ~= nil then
			self:setSideSkirts(isSideSkirtsOn);
		end;
		local CondPanel = Utils.getNoNil(getXMLBool(xmlFile, key .. "#CondPanel"), false);
		if CondPanel ~= nil then
			self:setCondPanel(CondPanel);
		end;
	end;
    return BaseMission.VEHICLE_LOAD_OK;
end;

function KevMT:getSaveAttributesAndNodes(nodeIdent)
	local attributes = ' ';
	
	local mystring = 'MowedTotalArea="' .. tostring(self.MowedTotalArea) ..'"';	
	attributes = attributes .. mystring;
	
	local mystring = 'isSideSkirtsOn="' .. tostring(self.isSideSkirtsOn) ..'"';	
	attributes = attributes .. mystring;

	local mystring = 'CondPanel="' .. tostring(self.CondPanel) ..'"';	
	attributes = attributes .. mystring;
	
    local node = nil;
	return attributes, node;
end;
  
function KevMT:readStream(streamId, connection)
	  
    local turnedOn = streamReadBool(streamId);
    self:setIsTurnedOn(turnedOn, true);
	  
    self:setWheelRot(streamReadBool(streamId), true); 
    self:setTransRot(streamReadBool(streamId), true);
    self:setSideSkirts(streamReadBool(streamId), true);
	
	self.lastAreaBiggerZero = streamReadBool(streamId);
	
    local MowedTotalArea = streamReadFloat32(streamId);
    local MowedArea = streamReadFloat32(streamId);
	self.MowedTotalArea = MowedTotalArea;	
    self.MowedArea = MowedArea;	

end;
  
function KevMT:writeStream(streamId, connection)

    streamWriteBool(streamId, self.isTurnedOn);
	  
    streamWriteBool(streamId, self.WheelRot);
    streamWriteBool(streamId, self.TransRot);
    streamWriteBool(streamId, self.SideSkirts);
	
	streamWriteBool(streamId, self.lastAreaBiggerZero);
	
	streamWriteFloat32(streamId, self.MowedTotalArea);
	streamWriteFloat32(streamId, self.MowedArea);
	self.lastAreaSent = 0;
end;
  
function KevMT:readUpdateStream(streamId, timestamp, connection)
	if connection:getIsServer() then
		self.lastAreaBiggerZero = streamReadBool(streamId);

	end;
end;
  
function KevMT:writeUpdateStream(streamId, connection, dirtyMask)
	if not connection:getIsServer() then
		streamWriteBool(streamId, self.lastAreaBiggerZero);
	end;
end;
  
function KevMT:mouseEvent(posX, posY, isDown, isUp, button)
end;
  
function KevMT:keyEvent(unicode, sym, modifier, isDown)

end;
  
function KevMT:update(dt)

	if not self:getIsActive() then
		if self.sideskirtInRange and not self.isTransRotOn then
			if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
				self:setSideSkirts(not self.isSideSkirtsOn);
			end;
			if self.isSideSkirtsOn then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("transport"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA2);
			else
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("field"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA2);
			end;
		end;
	end;
  
      if self:getIsActiveForInput() then
        if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) then
              self:setIsTurnedOn(not self.isTurnedOn);
        end;
        if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) and self.isSideSkirtsOn then
				self:setTransRot(not self.isTransRotOn);
        end;
        if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) then
				self:setWheelRot(not self.isWheelRotOn);
        end;
		if InputBinding.isPressed(InputBinding.IMPLEMENT_EXTRA2) and not self.isSideSkirtsOn then
				self.printWarningTime = self.time + 1500;
			end;
		if InputBinding.isPressed(InputBinding.IMPLEMENT_EXTRA) and self.PTOId then
				self.printWarningTime1 = self.time + 1500;
		end;
		if InputBinding.hasEvent(InputBinding.IMPLEMENTHUD) then
		    self.showhudInfo = not self.showhudInfo;
		end;
      end;
end;
  
function KevMT:updateTick(dt)
		
		if g_currentMission.player ~= nil then
			local nearestDistance = 3;
			local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);		
			local px, py, pz = getWorldTranslation(self.sideskirtNode.node); 
			local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);	
			if distance < nearestDistance then
				self.sideskirtInRange = true; 
			else
				self.sideskirtInRange = false; 
			end;
		end;

	if self.doJointOrientation and self.attacherVehicle ~= nil then
		for k,v in pairs(self.attacherVehicle.attachedImplements) do
			if v.object == self then
				local joint = self.attacherVehicle.attacherJoints[v.jointDescIndex];
				self.attacherJointCopy = {};
				self.attacherJointCopy.joint = joint;	

				joint.minRot = {Utils.degToRad(-12),0,0};			
				joint.maxRot = {0, 0, 0};
				self.attacherJointCopy.minRotCopy = joint.minRot;
				self.attacherJointCopy.maxRotCopy = joint.maxRot;
				joint.minRot = joint.maxRot;
			end;
		end;
		self.doJointOrientation = false;
	end;

    self.wasToFast = false;
	self.lastArea = 0;	
    if self:getIsActive() then
		if self.attacherVehicle ~= nil then	
			local jointDesc = self.attacherJointCopy.joint;
			setJointRotationLimit(jointDesc.jointIndex, 2, true, math.rad(-60), math.rad(60));
			jointDesc.moveDown = false;		
		end;
		if not self.attacherVehicle.isMotorStarted then
			self.isTurnedOn = false;
		end;
		if self.PTOId then
			self.isTurnedOn = false;
		end;
		local isKeyEvent = false;	
		if self.isTurnedOn then
 			isKeyEvent = true;	
		else
 			isKeyEvent = false;	
		end;

		self:setVehicleRpmUp(dt, isKeyEvent);	
		local volume = Utils.getMovedLimitedValues({self.rotarySoundVolume}, {self.rotarySoundVolumeMax}, {self.rotarySoundVolumeMin}, 1, 1200, dt, not self.isTurnedOn);
		self.rotarySoundVolume = volume[1];
			if self.isTurnedOn and not self.PTOId then
				if not self.rotarySoundEnabled and self:getIsActiveForSound() then
					playSample(self.rotarySound, 0, self.rotarySoundVolume, 0);
					setSamplePitch(self.rotarySound, self.rotarySoundPitchOffset);
					self.rotarySoundEnabled = true;
				end;
				if self.rotarySoundVolume < self.rotarySoundVolumeMax then
					setSampleVolume(self.rotarySound, self.rotarySoundVolume);
				end;
				else
				if self.rotarySoundEnabled then
					if self.rotarySoundVolume <= self.rotarySoundVolumeMin then
						stopSample(self.rotarySound);
						self.rotarySoundEnabled = false;
					else
						setSampleVolume(self.rotarySound, self.rotarySoundVolume);
					end;
				end;
			end;	
			for k, spinner in pairs(self.rotateSpinners) do
				local values = Utils.getMovedLimitedValues(spinner.rotationSpeedCurrent, spinner.rotationSpeedMax, spinner.rotationSpeedMin, 3, spinner.runOutTime, dt, not self.isTurnedOn);
				spinner.rotationSpeedCurrent = values;
				rotate(spinner.node, unpack(spinner.rotationSpeedCurrent));
			end;
        if self.isTurnedOn and self.isServer then
			
              local toFast = self:doCheckSpeedLimit() and self.lastSpeed*3600 > 31;
              if not toFast and not self.isWheelRotOn then
                  if self.isServer then
                      local x,y,z = getWorldTranslation(self.groundReferenceNode);
                      local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 0, z);
                      if terrainHeight+self.groundReferenceThreshold >= y then
                          local foldAnimTime = self.foldAnimTime;
						  local totalArea = 0;
                          local cuttingAreasSend = {};
                          for k, cuttingArea in pairs(self.cuttingAreas) do
                              if self:getIsAreaActive(cuttingArea) then
                                  local x,y,z = getWorldTranslation(cuttingArea.start);
                                  local x1,y1,z1 = getWorldTranslation(cuttingArea.width);
                                  local x2,y2,z2 = getWorldTranslation(cuttingArea.height);
                                  table.insert(cuttingAreasSend, {x,z,x1,z1,x2,z2});
                                  --Utils.updateMeadowArea(x, z, x1, z1, x2, z2);
                              end;
                          end;
                          if (table.getn(cuttingAreasSend) > 0) then
                            -- KevMowerAreaEvent.runLocally(cuttingAreasSend);
                            -- g_server:broadcastEvent(KevMowerAreaEvent:new(cuttingAreasSend));
							-- self.lastArea = totalArea;
							-- self.lastAreaBiggerZero = (self.lastArea > 0);
							
 							totalArea = KevMowerAreaEvent.runLocally(cuttingAreasSend);
		
							self.lastArea = totalArea;
							self.lastAreaBiggerZero = (self.lastArea > 0);
							
							local pixelToSqm = g_currentMission:getFruitPixelsToSqm(); -- 8192px are mapped to 2048m
                            local sqm = totalArea*pixelToSqm;
                            local ha = sqm/40000;
							
							self.lastAreaSent = self.lastAreaSent + ha;	
							self.MowedArea = self.MowedArea + ha;
							self.MowedTotalArea = self.MowedTotalArea + ha;
	
							if self.lastAreaSent > 0.02 then
								g_server:broadcastEvent(MowedTotalAreaEvent:new(self, self.lastAreaSent));
								self.lastAreaSent = 0;
							end;
							if totalArea > 0 then
								if (table.getn(cuttingAreasSend) > 0) then
									g_server:broadcastEvent(KevMowerAreaEvent:new(cuttingAreasSend));
								end;
							end;

							end;
                      end;
                  end;
              end;
  
              if self.isClient then
                  if not self.mowerSoundEnabled and self:getIsActiveForSound() then
                      setSamplePitch(self.mowerSound, self.mowerSoundPitchOffset);
                      playSample(self.mowerSound, 0, self.mowerSoundVolume, 0);
                      self.mowerSoundEnabled = true;
                  end;
              end;
  
              self.wasToFast = toFast;
  
          else
              if self.isClient then
                  if self.mowerSoundEnabled then
                      stopSample(self.mowerSound);
                      self.mowerSoundEnabled = false;
                  end;
              end;
          end;
			
			if self.isTurnedOn and self.movingDirection ~= 0 and not self.isWheelRotOn and self.lastAreaBiggerZero then
				Utils.setEmittingState(self.mowerParticleSystems, true);
			else
				Utils.setEmittingState(self.mowerParticleSystems, false);
			end;

      end;
	
	for i, jointDesc in pairs(self.componentJoints) do
	   setJointFrame(self.componentJoints[i].jointIndex, 0, self.componentJoints[i].jointNode);
	end;
end;
  
function KevMT:draw()
      if self.isClient then
		if not self.PTOId then
			if self.isTurnedOn then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_off_OBJECT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA);
			else
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_on_OBJECT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA);
			end;
		end;
        if self.wasToFast then
            g_currentMission:addWarning(g_i18n:getText("Dont_drive_to_fast") .. "\n" .. string.format(g_i18n:getText("Cruise_control_levelN"), "2", InputBinding.getKeyNamesOfDigitalAction(InputBinding.SPEED_LEVEL2)), 0.07+0.022, 0.019+0.029);
        end;
        if self.isTransRotOn then
            g_currentMission:addHelpButtonText(string.format(g_i18n:getText("transport"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA2);
        else
            g_currentMission:addHelpButtonText(string.format(g_i18n:getText("field"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA2);
        end;
        if self.isWheelRotOn then
            g_currentMission:addHelpButtonText(string.format(g_i18n:getText("lower"), self.typeDesc), InputBinding.LOWER_IMPLEMENT);
        else
            g_currentMission:addHelpButtonText(string.format(g_i18n:getText("raise"), self.typeDesc), InputBinding.LOWER_IMPLEMENT);
        end;
		if self.printWarningTime > self.time then
			g_currentMission:addWarning(g_i18n:getText("bodyRotate_Error"), 0.018, 0.033);
		end;
		if self.printWarningTime1 > self.time then
			g_currentMission:addWarning(g_i18n:getText("turnON_Error"), 0.018, 0.033);
		end;
		if self.showhudInfo then
			self.hudInfoOverlay:render();
			g_currentMission:addHelpButtonText(g_i18n:getText("IMPLEMENTHUDOFF"), InputBinding.IMPLEMENTHUD);
			setTextAlignment(RenderText.ALIGN_LEFT);
			setTextBold(true);
			renderText(0.108, 0.067, 0.021, string.format("%.1f", self.MowedArea));
			renderText(0.108, 0.032, 0.021, string.format("%.1f", self.MowedTotalArea));
			renderText(0.15, 0.067, 0.021, string.format("%.1f", self.MowedArea*2.471));
			renderText(0.15, 0.032, 0.021, string.format("%.1f", self.MowedTotalArea*2.471));
			setTextBold(false);			
			else
			g_currentMission:addHelpButtonText(g_i18n:getText("IMPLEMENTHUD"), InputBinding.IMPLEMENTHUD);
		end;
      end;
end;
  
function KevMT:onDetach()
      if self.deactivateOnDetach then
          KevMT.onDeactivate(self);
      else
          KevMT.onDeactivateSounds(self)
      end;
	if self.mowerParticleSystems ~= nil then
		Utils.setEmittingState(self.mowerParticleSystems, false);
	end;
	if self.attacherJointCopy ~= nil then
		local jointDesc = self.attacherJointCopy.joint;
		jointDesc.maxRot = self.attacherJointCopy.maxRotCopy;
		jointDesc.minRot = self.attacherJointCopy.minRotCopy;
	end;
	setJointRotationLimit(self.componentJoints[1].jointIndex, 1, true, math.rad(-60), math.rad(60));
	setJointRotationLimit(self.componentJoints[1].jointIndex, 2, true, math.rad(0), math.rad(0));
	for k, steerable in pairs(g_currentMission.steerables) do
		if self.attacherVehicleCopy == steerable then
			steerable.motor.minRpm = self.saveMinRpm;
			self.attacherVehicleCopy = nil;
		end;
	end;
end;

function KevMT:onAttach(attacherVehicle)
	self.doJointOrientation = true;	
	setJointRotationLimit(self.componentJoints[1].jointIndex, 1, true, math.rad(-140), math.rad(140));
	setJointRotationLimit(self.componentJoints[1].jointIndex, 2, true, math.rad(-7), math.rad(7));
	self.attacherVehicle = attacherVehicle;
	if self.attacherVehicleCopy == nil then
		self.attacherVehicleCopy = self.attacherVehicle;
	end;
	self.saveMinRpm = self.attacherVehicle.motor.minRpm;

end;
  
function KevMT:onLeave()
	if self.mowerParticleSystems ~= nil then
		Utils.setEmittingState(self.mowerParticleSystems, false);
	end; 

 if self.deactivateOnLeave then
          KevMT.onDeactivate(self);
      else
          KevMT.onDeactivateSounds(self)
      end;

	  self:setIsTurnedOn(false, true);

end;
  
function KevMT:onDeactivate()
      KevMT.onDeactivateSounds(self)
 
	  self:setIsTurnedOn(false, true);
	if self.mowerParticleSystems ~= nil then
		Utils.setEmittingState(self.mowerParticleSystems, false);
	end; 
end;
  
function KevMT:onDeactivateSounds()
      if self.isClient then
		if self.rotarySoundEnabled then
			stopSample(self.rotarySound);
			self.rotarySoundEnabled = false;
		end;
     end;
end;

function KevMT:validateAttacherJoint(implement, jointDesc, dt)
    return true;
end;
  
function KevMT:setIsTurnedOn(turnedOn, noEventSend)
      SetTurnedOnEvent.sendEvent(self, turnedOn, noEventSend)
      self.isTurnedOn = turnedOn;
end;

function KevMT:setVehicleRpmUp(dt, isActive)
	if self.attacherVehicle ~= nil and self.saveMinRpm ~= 0 then
		if dt ~= nil then
			if isActive == true then
				self.attacherVehicle.motor.minRpm = math.max(self.attacherVehicle.motor.minRpm-dt, -1000);
			else
				self.attacherVehicle.motor.minRpm = math.min(self.attacherVehicle.motor.minRpm+dt*2, self.saveMinRpm);
			end;
		else
			self.attacherVehicle.motor.minRpm = self.saveMinRpm;
		end;
		if self.attacherVehicle.isMotorStarted then
			local fuelUsed = 0.0000011*math.abs(self.attacherVehicle.motor.minRpm);
			self.attacherVehicle:setFuelFillLevel(self.attacherVehicle.fuelFillLevel-fuelUsed);
			g_currentMission.missionStats.fuelUsageTotal = g_currentMission.missionStats.fuelUsageTotal + fuelUsed;
			g_currentMission.missionStats.fuelUsageSession = g_currentMission.missionStats.fuelUsageSession + fuelUsed;
		end;
	end;
end;

function KevMT:setWheelRot(isWheelRot,noEventSend)
	SetWheelRotEvent.sendEvent(self, isWheelRot, noEventSend);
	-- Play WheelRot animation --
	self.isWheelRotOn = isWheelRot;
	if self.isWheelRotOn then
		if self.WheelRotAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.WheelRotAnimation, 1, nil, true);
			self.WheelRot = true;

		end;
	else
		if self.WheelRotAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.WheelRotAnimation, -1, nil, true);
			self.WheelRot = false;
	
		end;
	end;
end;

function KevMT:setTransRot(isTransRot,noEventSend)
	SetTransRotEvent.sendEvent(self, isTransRot, noEventSend);
	-- Play TransRot animation --
	self.isTransRotOn = isTransRot;
	if self.isTransRotOn then
		if self.TransRotAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.TransRotAnimation, 1, nil, true);
			self.TransRot = true;
		end;
	else
		if self.TransRotAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.TransRotAnimation, -1, nil, true);
			self.TransRot = false;
		end;
	end;	
end;

function KevMT:setSideSkirts(isSideSkirts,noEventSend)
	SetSideSkirtsEvent.sendEvent(self, isSideSkirts, noEventSend);
	-- Play SideSkirts animation --
	self.isSideSkirtsOn = isSideSkirts;
	if self.isSideSkirtsOn then
		if self.SideSkirtsAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.SideSkirtsAnimation, 1, nil, true);
			self.SideSkirts = true;
			for _, sideskirtsdown in pairs(self.sideSkirtsDown) do
				setVisibility(sideskirtsdown.node, true);
			end;
			for _, sideskirtsup in pairs(self.sideSkirtsUp) do
				setVisibility(sideskirtsup.node, false);
			end;
		end;
	else
		if self.SideSkirtsAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.SideSkirtsAnimation, -1, nil, true);
			self.SideSkirts = false;
			self.SideSkirtsScale = false;
			for _, sideskirtsdown in pairs(self.sideSkirtsDown) do
				setVisibility(sideskirtsdown.node, false);
			end;
			for _, sideskirtsup in pairs(self.sideSkirtsUp) do
				setVisibility(sideskirtsup.node, true);

			end;			  
		end;
	end;


end;

SetWheelRotEvent = {};
SetWheelRotEvent_mt = Class(SetWheelRotEvent, Event);

InitEventClass(SetWheelRotEvent, "SetWheelRotEvent");

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

function SetWheelRotEvent:new(vehicle, isWheelRot)
    local self = SetWheelRotEvent:emptyNew()
    self.vehicle = vehicle;
	self.isWheelRot = isWheelRot;
    return self;
end;

function SetWheelRotEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.isWheelRot = streamReadBool(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function SetWheelRotEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.isWheelRot);
end;

function SetWheelRotEvent:run(connection)   
	self.vehicle:setWheelRot(self.isWheelRot, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(SetWheelRotEvent:new(self.vehicle, self.isWheelRot), nil, connection, self.vehicle);
    end;
end;

function SetWheelRotEvent.sendEvent(vehicle, isWheelRot, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(SetWheelRotEvent:new(vehicle, isWheelRot), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(SetWheelRotEvent:new(vehicle, isWheelRot));
		end;
	end;
end;

SetSideSkirtsEvent = {};
SetSideSkirtsEvent_mt = Class(SetSideSkirtsEvent, Event);

InitEventClass(SetSideSkirtsEvent, "SetSideSkirtsEvent");

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

function SetSideSkirtsEvent:new(vehicle, isSideSkirts)
    local self = SetSideSkirtsEvent:emptyNew()
    self.vehicle = vehicle;
	self.isSideSkirts = isSideSkirts;
    return self;
end;

function SetSideSkirtsEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.isSideSkirts = streamReadBool(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function SetSideSkirtsEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.isSideSkirts);
end;

function SetSideSkirtsEvent:run(connection)   
	self.vehicle:setSideSkirts(self.isSideSkirts, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(SetSideSkirtsEvent:new(self.vehicle, self.isSideSkirts), nil, connection, self.vehicle);
    end;
end;

function SetSideSkirtsEvent.sendEvent(vehicle, isSideSkirts, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(SetSideSkirtsEvent:new(vehicle, isSideSkirts), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(SetSideSkirtsEvent:new(vehicle, isSideSkirts));
		end;
	end;
end;

SetTransRotEvent = {};
SetTransRotEvent_mt = Class(SetTransRotEvent, Event);

InitEventClass(SetTransRotEvent, "SetTransRotEvent");

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

function SetTransRotEvent:new(vehicle, isTransRot)
    local self = SetTransRotEvent:emptyNew()
    self.vehicle = vehicle;
	self.isTransRot = isTransRot;
    return self;
end;

function SetTransRotEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.isTransRot = streamReadBool(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function SetTransRotEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.isTransRot);
end;

function SetTransRotEvent:run(connection)   
	self.vehicle:setTransRot(self.isTransRot, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(SetTransRotEvent:new(self.vehicle, self.isTransRot), nil, connection, self.vehicle);
    end;
end;

function SetTransRotEvent.sendEvent(vehicle, isTransRot, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(SetTransRotEvent:new(vehicle, isTransRot), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(SetTransRotEvent:new(vehicle, isTransRot));
		end;
	end;
end;

MowedTotalAreaEvent = {};
MowedTotalAreaEvent_mt = Class(MowedTotalAreaEvent, Event);

InitEventClass(MowedTotalAreaEvent, "MowedTotalAreaEvent");

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

function MowedTotalAreaEvent:new(vehicle, totalArea)
    local self = MowedTotalAreaEvent:emptyNew()
    self.vehicle = vehicle;
	self.totalArea = totalArea;
    return self;
end;

function MowedTotalAreaEvent:readStream(streamId, connection)
	local vehicle = networkGetObject(streamReadInt32(streamId));
	local newArea = streamReadFloat32(streamId);
	vehicle.MowedArea = vehicle.MowedArea + newArea;
	vehicle.MowedTotalArea = vehicle.MowedTotalArea + newArea;

end;

function MowedTotalAreaEvent:writeStream(streamId, connection)
     streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteFloat32(streamId, self.totalArea);
end;

function MowedTotalAreaEvent:run(connection)

end;
