SipmaZ224 = {};

SipmaZ224.UNLOADING_CLOSED = 1;
SipmaZ224.UNLOADING_OPENING = 2;
SipmaZ224.UNLOADING_OPEN = 3;
SipmaZ224.UNLOADING_CLOSING = 4;

function SipmaZ224.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Fillable, specializations);
end;

function SipmaZ224:load(xmlFile)
    self.setIsTurnedOn = SpecializationUtil.callSpecializationsFunction("setIsTurnedOn");
    self.getTimeFromLevel = SipmaZ224.getTimeFromLevel;
    self.moveBales = SpecializationUtil.callSpecializationsFunction("moveBales");
    self.moveBale = SpecializationUtil.callSpecializationsFunction("moveBale");
    self.allowFillType = SipmaZ224.allowFillType;
    self.allowPickingUp = SipmaZ224.allowPickingUp;
    self.setIsUnloadingBale = SipmaZ224.setIsUnloadingBale;
	self.moveBalesOutForTransport = SipmaZ224.moveBalesOutForTransport;

    self.fillScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fillScale#value"), 1);

    local firstBaleMarker = getXMLFloat(xmlFile, "vehicle.baleAnimation#firstBaleMarker");
    if firstBaleMarker ~= nil then
        local baleAnimCurve = AnimCurve:new(linearInterpolatorN);
		local baleAnimCurveBackup = AnimCurve:new(linearInterpolatorN); -- new --
        local keyI = 0;
        while true do
            local key = string.format("vehicle.baleAnimation.key(%d)", keyI);
            local t = getXMLFloat(xmlFile, key.."#time");
            local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#pos"));
            if x == nil or y == nil or z == nil then
                break;
            end;
            local rx, ry, rz = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rot"));
            rx = math.rad(Utils.getNoNil(rx, 0));
            ry = math.rad(Utils.getNoNil(ry, 0));
            rz = math.rad(Utils.getNoNil(rz, 0));
            baleAnimCurve:addKeyframe({ v={x, y, z, rx, ry, rz}, time = t});
            keyI = keyI +1;
        end;
        if keyI > 0 then
            self.baleAnimCurve = baleAnimCurve;
			self.baleAnimCurveBackup = self.baleAnimCurve; -- new --
            self.firstBaleMarker = firstBaleMarker;
			self.firstBaleMarkerBackup = firstBaleMarker; -- new --
        end;
	end;
    self.baleAnimRoot = Utils.getNoNil(Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.baleAnimation#node")), self.components[1].node);

    -- there is no standard bale animation, load the unload animation
    if self.firstBaleMarker == nil then
        local unloadAnimationName = getXMLString(xmlFile, "vehicle.baleAnimation#unloadAnimationName");
        local closeAnimationName = getXMLString(xmlFile, "vehicle.baleAnimation#closeAnimationName");
        local unloadAnimationSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.baleAnimation#unloadAnimationSpeed"), 1);
        local closeAnimationSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.baleAnimation#closeAnimationSpeed"), 1);
        if unloadAnimationName ~= nil and closeAnimationName ~= nil then
            if self.playAnimation ~= nil and self.animations ~= nil then
                if self.animations[unloadAnimationName] ~= nil and self.animations[closeAnimationName] ~= nil then
                    --print("has unload animation");
                    self.baleUnloadAnimationName = unloadAnimationName;
                    self.baleUnloadAnimationSpeed = unloadAnimationSpeed;

                    self.baleCloseAnimationName = closeAnimationName;
                    self.baleCloseAnimationSpeed = closeAnimationSpeed;

                    self.baleDropAnimTime = getXMLFloat(xmlFile, "vehicle.baleAnimation#baleDropAnimTime");
                    if self.baleDropAnimTime == nil then
                        self.baleDropAnimTime = self:getAnimationDuration(self.baleUnloadAnimationName);
                    else
                        self.baleDropAnimTime = self.baleDropAnimTime * 1000;
                    end;
                else
                    print("Error: Failed to find unload animations '"..unloadAnimationName.."' and '"..closeAnimationName.."' in '"..self.configFileName.."'.");
                end;
            else
                print("Error: There is an unload animation in '"..self.configFileName.."' but it is not a AnimatedVehicle. Change to a vehicle type which has the AnimatedVehicle specialization.");
            end;
        end;
    end;

    self.baleTypes = {};
    local i = 0;
    while true do
		local key = string.format("vehicle.baleTypes.baleType(%d)", i);
		local t = getXMLString(xmlFile, key.."#fruitType");
		local filename = getXMLString(xmlFile, key.."#filename");
		if t==nil or filename==nil then
			break;
		end;

		local entry = {};
		entry.filename = filename;
		local desc = FruitUtil.fruitTypes[t];
		if desc ~= nil then
			self.baleTypes[desc.index] = entry;

			if self.defaultBaleType == nil then
				self.defaultBaleType = entry;
			end;
		end;
		i = i +1;
	end;
	if self.defaultBaleType == nil then
		self.baleTypes = nil;
	end;

	local balerSound = getXMLString(xmlFile, "vehicle.balerSound#file");
	if balerSound ~= nil and balerSound ~= "" then
		balerSound = Utils.getFilename(balerSound, self.baseDirectory);
		self.balerSound = createSample("balerSound");
		self.balerSoundEnabled = false;
		loadSample(self.balerSound, balerSound, false);
		self.balerSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerSound#pitchOffset"), 1);
		self.balerSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerSound#volume"), 1);
	end;

	local balerAlarm = getXMLString(xmlFile, "vehicle.balerAlarm#file");
	if balerAlarm ~= nil and balerAlarm ~= "" then
		balerAlarm = Utils.getFilename(balerAlarm, self.baseDirectory);
		self.balerAlarm = createSample("balerAlarm");
		self.balerAlarmEnabled = false;
		loadSample(self.balerAlarm, balerAlarm, false);
		self.balerAlarmPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerAlarm#pitchOffset"), 1);
		self.balerAlarmVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerAlarm#volume"), 1);
	end;

	local balerBaleEject = getXMLString(xmlFile, "vehicle.balerBaleEject#file");
	if balerBaleEject ~= nil and balerBaleEject ~= "" then
		balerBaleEject = Utils.getFilename(balerBaleEject, self.baseDirectory);
		self.balerBaleEject = createSample("balerBaleEject");
		self.balerBaleEjectEnabled = false;
		loadSample(self.balerBaleEject, balerBaleEject, false);
		self.balerBaleEjectPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerBaleEject#pitchOffset"), 1);
		self.balerBaleEjectVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerBaleEject#volume"), 1);
	end;

	local balerDoor = getXMLString(xmlFile, "vehicle.balerDoor#file");
	if balerDoor ~= nil and balerDoor ~= "" then
		balerDoor = Utils.getFilename(balerDoor, self.baseDirectory);
		self.balerDoor = createSample("balerDoor");
		self.balerDoorEnabled = false;
		loadSample(self.balerDoor, balerDoor, false);
		self.balerDoorPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerDoor#pitchOffset"), 1);
		self.balerDoorVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerDoor#volume"), 1);
	end;

	local balerKnotCleaning = getXMLString(xmlFile, "vehicle.balerKnotCleaning#file");
	if balerKnotCleaning ~= nil and balerKnotCleaning ~= "" then
		balerKnotCleaning = Utils.getFilename(balerKnotCleaning, self.baseDirectory);
		self.balerKnotCleaning = createSample("balerKnotCleaning");
		self.balerKnotCleaningEnabled = false;
		self.balerKnotCleaningTime = 100000;
		loadSample(self.balerKnotCleaning, balerKnotCleaning, false);
		self.balerKnotCleaningPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerKnotCleaning#pitchOffset"), 1);
		self.balerKnotCleaningVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerKnotCleaning#volume"), 1);
	end;

	self.balerUVScrollParts = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.balerUVScrollParts.balerUVScrollPart(%d)", i);
		if not hasXMLProperty(xmlFile, key) then
			break;
		end;
		local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
		local speed = Utils.getVectorNFromString(getXMLString(xmlFile, key.."#speed"), 2);
		if node ~= nil and speed then
			table.insert(self.balerUVScrollParts, {node=node, speed=speed});
		end;
		i = i +1;
	end;

	self.pickupAnimationName = Utils.getNoNil(getXMLString(xmlFile, "vehicle.pickupAnimation#name"), "");
	if self.playAnimation == nil or self.getIsAnimationPlaying == nil then
		self.pickupAnimationName = "";
	end;
	self.pickupAnimationLowerSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pickupAnimation#lowerSpeed"), 1);
	self.pickupAnimationLiftSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pickupAnimation#liftSpeed"), -self.pickupAnimationLowerSpeed);

	self.baleLastPositionTime = 0;

	self.SipmaZ224UnloadingState = SipmaZ224.UNLOADING_CLOSED;

	self.bales = {};
	self.wasToFast = false;
	self.isTurnedOn = false;
   
	-- new --
	self.setBackFlap = SpecializationUtil.callSpecializationsFunction("setBackFlap");
	self.resetBaleCounter = SpecializationUtil.callSpecializationsFunction("resetBaleCounter");
	self.setRopePanel = SpecializationUtil.callSpecializationsFunction("setRopePanel");
	self.setMechanismPanel = SpecializationUtil.callSpecializationsFunction("setMechanismPanel");
	self.setCounterweightPanel = SpecializationUtil.callSpecializationsFunction("setCounterweightPanel");
	self.setHasRopes = SpecializationUtil.callSpecializationsFunction("setHasRopes");
	self.setBaleTransporterPosition = SpecializationUtil.callSpecializationsFunction("setBaleTransporterPosition");
	self.setBaleTransporterVisibility = SpecializationUtil.callSpecializationsFunction("setBaleTransporterVisibility");
	self.moveBalesOut = SpecializationUtil.callSpecializationsFunction("moveBalesOut");
	self.doMoveBalesOut = SpecializationUtil.callSpecializationsFunction("doMoveBalesOut");

	self.backFlap = false;
	
	local pickupNode = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.pickupNode#index"));
	if pickupNode ~= nil then
		self.pickupNode = pickupNode;
	end;
	
	local attacherNode = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.attacherNode#index"));
	if attacherNode ~= nil then
		self.attacherNode = attacherNode;
	end;
	
	local backOptionsNode = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.backOptionsNode#index"));
	if backOptionsNode ~= nil then
		self.backOptionsNode = backOptionsNode;
	end;
	
	self.pickupWheel = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.pickupWheel#index"));
	self.baleStarNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.baleStar#index"));
	self.baleStarSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.baleStar#speed"), 1);

	self.strawParticleSystems = {};
	local i=0;
	while true do
		local key = string.format("vehicle.strawParticleSystems.strawParticleSystem(%d)", i);
		local node = getXMLString(xmlFile, key.. "#node");
		if node == nil then
			break;
		end;
		node = Utils.indexToObject(self.components, node);
		if node ~= nil then
			local psFile = getXMLString(xmlFile, key.. "#file");
			local strawParticleSystem = {};
			strawParticleSystem.particleSystem = {};
			local isStatic = Utils.getNoNil(getXMLBool(xmlFile, key.."#static"), false);
			if isStatic then
				StaticParticleSystem.loadParticleSystem(xmlFile, strawParticleSystem.particleSystem, key, self.components, false, nil, self.baseDirectory);
			else
				Utils.loadParticleSystem(xmlFile, strawParticleSystem.particleSystem, key, self.components, false, nil, self.baseDirectory);
			end;
			table.insert(self.strawParticleSystems, strawParticleSystem);
		end;
		i = i+1;
	end;
	self.grassParticleSystems = {};
	local i=0;
	while true do
		local key = string.format("vehicle.grassParticleSystems.grassParticleSystem(%d)", i);
		local node = getXMLString(xmlFile, key.. "#node");
		if node == nil then
			break;
		end;
		node = Utils.indexToObject(self.components, node);
		if node ~= nil then
			local psFile = getXMLString(xmlFile, key.. "#file");
			local grassParticleSystem = {};
			grassParticleSystem.particleSystem = {};
			local isStatic = Utils.getNoNil(getXMLBool(xmlFile, key.."#static"), false);
			if isStatic then
				StaticParticleSystem.loadParticleSystem(xmlFile, grassParticleSystem.particleSystem, key, self.components, false, nil, self.baseDirectory);
			else
				Utils.loadParticleSystem(xmlFile, grassParticleSystem.particleSystem, key, self.components, false, nil, self.baseDirectory);
			end;
			table.insert(self.grassParticleSystems, grassParticleSystem);
		end;
		i = i+1;
	end;

	self.powerShaftNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.powerShaft#index"));
	self.detachedPowerShaftNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.detachedPowerShaft#index"));
	
	self.soundOffset = 0;
    local balerStopSound = getXMLString(xmlFile, "vehicle.balerStopSound#file");
    if balerStopSound ~= nil and balerStopSound ~= "" then
        balerStopSound = Utils.getFilename(balerStopSound, self.baseDirectory);
        self.balerStopSound = createSample("balerStopSound");
        loadSample(self.balerStopSound, balerStopSound, false);
        self.balerStopSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehiclebalerStopSound#pitchOffset"), 1);
        self.balerStopSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerSound#volume"), 1.0);
    end;

    local balerStartSound = getXMLString(xmlFile, "vehicle.balerStartSound#file");
    if balerStartSound ~= nil and balerStartSound ~= "" then
        balerStartSound = Utils.getFilename(balerStartSound, self.baseDirectory);
        self.balerStartSound = createSample("balerStartSound");
        loadSample(self.balerStartSound, balerStartSound, false);
        self.balerStartSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerStartSound#pitchOffset"), 1);
        self.balerStartSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerStartSound#volume"), 1.0);
    end;
	
	local balerAISound = getXMLString(xmlFile, "vehicle.balerAISound#file");
		if balerAISound ~= nil and balerAISound ~= "" then
		balerAISound = Utils.getFilename(balerAISound, self.baseDirectory);
		self.balerAISoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerAISound#pitchOffset"), 0);
		self.balerAISoundRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerAISound#radius"), 50);
		self.balerAISoundInnerRadius = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerAISound#innerRadius"), 10);
		self.balerAISoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.balerAISound#volume"), 1);
		self.balerAISound = createAudioSource("balerAISound", balerAISound, self.balerAISoundRadius, self.balerAISoundInnerRadius, self.balerAISoundVolume, 0);
		link(self.components[1].node, self.balerAISound);
		setVisibility(self.balerAISound, false);
	end;
	
	self.lastArea = 0;
	self.lastAreaBiggerZero = self.lastArea > 0;
	
	self.File = Utils.getFilename("Textures/Sipma_HUD.png", self.baseDirectory);
	self.hudPoxX = 0.65;
    self.hudPoxY = 1-0.170; 
    self.hudWidth = 0.264;
    self.hudHeight = 0.156;
    self.HUDSipma = Overlay:new("HUDSipma", self.File, self.hudPoxX, self.hudPoxY, self.hudWidth, self.hudHeight);
    self.HUD = false;
	
	self.TotalBalesCount = 0;
	self.CurrentBalesCount = 0;
	self.NoRopesBalesCount = 0;
	
	self.moveBalesOutsideForTransport = false;
	self.doResetBaleCounter = false;
	
	self.ropePanelAnimation = getXMLString(xmlFile, "vehicle.ropePanel#animationName");
	self.mechanismPanelAnimation = getXMLString(xmlFile, "vehicle.mechanismPanel#animationName");
	self.counterweightPanelAnimation = getXMLString(xmlFile, "vehicle.counterweightPanel#animationName");	
	self.ropePanel = true;
	self.mechanismPanel = true;
	self.counterweightPanel = true;
	
	local ropeDoor = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.ropePanel#index"));
	if ropeDoor ~= nil then
		self.ropeDoor = ropeDoor;
	end;
	
	local mechanismDoor = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.mechanismPanel#index"));
	if mechanismDoor ~= nil then
		self.mechanismDoor = mechanismDoor;
	end;
	
	local counterweightDoor = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.counterweightPanel#index"));
	if counterweightDoor ~= nil then
		self.counterweightDoor = counterweightDoor;
	end;
	
	self.ropes = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.ropes#index"));
	self.ropesCapacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.ropes#capacity"), 4);
	self.hasRopes = true;
	self.isLoaded = true;
	
    NoRopeSoundFile = Utils.getFilename("Sounds/NoRope.ogg", self.baseDirectory);
    self.NoRopeSoundId = createSample("NoRopeSound");
    loadSample(self.NoRopeSoundId, NoRopeSoundFile, false);
    self.NoRopePlaying = false;
	
	-- additional bales animation (for bale transporter)
    local firstBaleMarker2 = getXMLFloat(xmlFile, "vehicle.baleTransporterAnimation#firstBaleMarker");
    if firstBaleMarker2 ~= nil then
		local baleAnimCurve2 = AnimCurve:new(linearInterpolatorN);
		local keyI2 = 0;
		while true do
            local key = string.format("vehicle.baleTransporterAnimation.key(%d)", keyI2);
            local t = getXMLFloat(xmlFile, key.."#time");
            local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#pos"));
            if x == nil or y == nil or z == nil then
                break;
            end;
            local rx, ry, rz = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rot"));
            rx = math.rad(Utils.getNoNil(rx, 0));
            ry = math.rad(Utils.getNoNil(ry, 0));
            rz = math.rad(Utils.getNoNil(rz, 0));
            baleAnimCurve2:addKeyframe({ v={x, y, z, rx, ry, rz}, time = t});
            keyI2 = keyI2 +1;
        end;
        if keyI2 > 0 then
			self.baleAnimCurve2 = baleAnimCurve2;
            self.firstBaleMarker2 = firstBaleMarker2;
        end;
    end;
	
	self.baleTransporterAnimation = getXMLString(xmlFile, "vehicle.baleTransporter#animationName");	
	
	local baleTransporter = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.baleTransporter#index"));
	if baleTransporter ~= nil then
		self.baleTransporterNode = baleTransporter;
	end;
	
	local chainNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.baleTransporter#chainIndex"));
	if chainNode ~= nil then
		self.chainNode = chainNode;
	end;
	
	self.baleTransporterActive = false;
	self.baleTransporterChainActive = false;
	self.baleTransporterVisibility = false;
	self.moveBalesOutside = true;
	self.doMoveBalesOutside = false;
	self.firstTimeStart = true;
   -- end new --  
end;

function SipmaZ224:delete()
	if self.balerSound ~= nil then
		delete(self.balerSound);
		self.balerSoundEnabled = false;
	end;
	
	-- new --
	if self.balerStopSound ~= nil then
        delete(self.balerStopSound);
		self.balerStopSound = nil;
    end;
	if self.balerStopSound ~= nil then
        stopSample(self.balerStopSound);
	end;
	if self.balerAlarm ~= nil then
        delete(self.balerAlarm);
        self.balerAlarmEnabled = false;
	end;
	if self.balerBaleEject ~= nil then
        delete(self.balerBaleEject);
        self.balerBaleEjectEnabled = false;
	end;
	if self.balerDoor ~= nil then
        delete(self.balerDoor);
        self.balerDoorEnabled = false;
	end;
	if self.balerKnotCleaning ~= nil then
		delete(self.balerKnotCleaning);
        self.balerKnotCleaningEnabled = false;
    end;
    if self.NoRopeSound ~= nil then
        delete(self.NoRopeSound);
    end;
	-- end new --
end;

function SipmaZ224:readStream(streamId, connection)
	local turnedOn = streamReadBool(streamId);
	self:setIsTurnedOn(turnedOn, true);
	local numBales = streamReadInt16(streamId);
	for i=1, numBales do
		local fruitType = streamReadInt8(streamId);
		SipmaZ224.createBale(self, fruitType);
		if self.baleAnimCurve ~= nil then
			local baleTime = streamReadFloat32(streamId);
			SipmaZ224.setBaleTime(self, i, baleTime);
		end;
	end;
	
	-- new --
	self:setBackFlap(streamReadBool(streamId), true);
	self:resetBaleCounter(streamReadBool(streamId), true);
	self.lastAreaBiggerZero = streamReadBool(streamId);

    self.TotalBalesCount = streamReadInt32(streamId);
    self.NoRopesBalesCount = streamReadInt32(streamId);
    self.CurrentBalesCount = streamReadInt32(streamId);
	
	self:setCounterweightPanel(streamReadBool(streamId), true);
    self:setMechanismPanel(streamReadBool(streamId), true);
	self:setRopePanel(streamReadBool(streamId), true);
    self:setHasRopes(streamReadBool(streamId), true);
	
    self:setBaleTransporterPosition(streamReadBool(streamId), true);
	self:setBaleTransporterVisibility(streamReadBool(streamId), true);
	-- end new --
end;

function SipmaZ224:writeStream(streamId, connection)
    streamWriteBool(streamId, self.isTurnedOn);
    streamWriteInt16(streamId, table.getn(self.bales));
	for i=1, table.getn(self.bales) do
		local bale = self.bales[i];
		streamWriteInt8(streamId, bale.fruitType);
		if self.baleAnimCurve ~= nil then
			streamWriteFloat32(streamId, bale.time);
		end;
    end;
	
	-- new --
	streamWriteBool(streamId, self.backFlap);
	streamWriteBool(streamId, self.doResetBaleCounter);
	streamWriteBool(streamId, self.lastAreaBiggerZero);

    streamWriteInt32(streamId, self.TotalBalesCount);
    streamWriteInt32(streamId, self.NoRopesBalesCount);
    streamWriteInt32(streamId, self.CurrentBalesCount);
	
	streamWriteBool(streamId, self.counterweightPanel);
    streamWriteBool(streamId, self.mechanismPanel);
	streamWriteBool(streamId, self.ropePanel);
    streamWriteBool(streamId, self.isLoaded);
	
	streamWriteBool(streamId, self.baleTransporterActive);
	streamWriteBool(streamId, self.baleTransporterVisibility);
	-- end new --
end;

function SipmaZ224:readUpdateStream(streamId, timestamp, connection)
	-- new --
	if connection:getIsServer() then
		self.lastAreaBiggerZero = streamReadBool(streamId);
	end;
	-- end new --
end;

function SipmaZ224:writeUpdateStream(streamId, connection, dirtyMask)
	-- new --
	if not connection:getIsServer() then
		streamWriteBool(streamId, self.lastAreaBiggerZero);
	end;
	-- end new --
end;

function SipmaZ224:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	local numBales = getXMLInt(xmlFile, key.."#numBales");
	if numBales ~= nil then
		for i=1, numBales do
			local baleKey = key..string.format(".bale(%d)", i-1);

			local fruitType = getXMLString(xmlFile, baleKey.."#fruitType");
			local baleTime = getXMLFloat(xmlFile, baleKey.."#baleTime");
			if fruitType ~= nil and (baleTime ~= nil or self.baleAnimCurve == nil) then
				local fruitTypeDesc = FruitUtil.fruitTypes[fruitType];
				if fruitTypeDesc ~= nil then
					SipmaZ224.createBale(self, fruitTypeDesc.index);
					if self.baleAnimCurve ~= nil then
						SipmaZ224.setBaleTime(self, table.getn(self.bales), baleTime);
					end;
				end;
			end;
		end;
	end;
	local TotalBalesCount = Utils.getNoNil(getXMLInt(xmlFile, key.."#totalBalesCount"),0);
	local NoRopesBalesCount = Utils.getNoNil(getXMLInt(xmlFile, key.."#noRopesBalesCount"),0);
	self.TotalBalesCount = TotalBalesCount;
	self.NoRopesBalesCount = NoRopesBalesCount;
	
	if not resetVehicles then
		if self.animationParts[6].isLoading and self.animationParts[6].inputTime > self.animationParts[6].offSet then
			self:setBackFlap(true);
		end;
		baleTransporterState = Utils.getNoNil(getXMLInt(xmlFile, key.."#baleTransporterState"),0);
		if baleTransporterState == 0 then
			self:setBaleTransporterVisibility(false);
		elseif baleTransporterState == 1 then
			self:setBaleTransporterVisibility(true);
		elseif baleTransporterState == 2 then
			self:setBaleTransporterVisibility(true);
			self:setBaleTransporterPosition(true);
		end;
	end;
	return BaseMission.VEHICLE_LOAD_OK;
end

function SipmaZ224:getSaveAttributesAndNodes(nodeIdent)
	if self.baleTransporterVisibility then
		if self.baleTransporterActive then
			baleTransporterState = 2;
		else
			baleTransporterState = 1;
		end;
	else
		baleTransporterState = 0;
	end;
		
	local TotalBalesCount= Utils.getNoNil(self.TotalBalesCount, 0);
	local NoRopesBalesCount= Utils.getNoNil(self.NoRopesBalesCount, 0);
	local attributes = 'numBales="'..table.getn(self.bales)..'" totalBalesCount="'..string.format("%d",TotalBalesCount)..'" noRopesBalesCount="'..string.format("%d",NoRopesBalesCount)..'" baleTransporterState="'.. tostring(baleTransporterState) ..'"';
	local nodes = "";
	local baleNum = 0;

	for i=1, table.getn(self.bales) do
		local bale = self.bales[i];
		local fruitType = "unknown";
		if bale.fruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
			fruitType = FruitUtil.fruitIndexToDesc[bale.fruitType].name;
		end;

		if baleNum>0 then
			nodes = nodes.."\n";
		end;
		nodes = nodes..nodeIdent..'<bale fruitType="'..fruitType..'"';
		if self.baleAnimCurve ~= nil then
			nodes = nodes..' baleTime="'..bale.time..'"';
		end;
		nodes = nodes..' />';
		baleNum = baleNum+1;
	end;
	return attributes,nodes;
end

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

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

function SipmaZ224:update(dt)
	if self.firstTimeStart then
		self.firstTimeStart = false;
	end;
	
	if self:getIsActiveForInput() then
		if self.backFlap then
			if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) then
				self:setIsTurnedOn(not self.isTurnedOn);
			end;
		end;
	   
		-- new --		
		if InputBinding.hasEvent(InputBinding.SIPMAZ224_HUD_ON) then
			self.HUD = not self.HUD;
		end;
		if InputBinding.hasEvent(InputBinding.SIPMAZ224_RESET_BALECOUNTER) then
			self:resetBaleCounter(true);
		end;
		-- end new --

		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
			if self.baleUnloadAnimationName ~= nil then
				if self.SipmaZ224UnloadingState == SipmaZ224.UNLOADING_CLOSED then
					if table.getn(self.bales) > 0 then
						self:setIsUnloadingBale(true);
					end;
				elseif self.SipmaZ224UnloadingState == SipmaZ224.UNLOADING_OPEN then
					self:setIsUnloadingBale(false);
				end;
			end;
		end;
	end;
	
	-- new --
	if self.isClient then
		if self.pickupInRange then
			if InputBinding.hasEvent(InputBinding.SIPMAZ224_LOWER_PICKUP) then
				if self.animationParts[4].clipEndTime then
					self:setAnimationTime(4, self.animationParts[4].offSet);
				else
					self:setAnimationTime(4, self.animationParts[4].animDuration);
				end;
			end;
			if self.animationParts[4].clipEndTime then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_PICKUP_LIFT"), self.typeDesc), InputBinding.SIPMAZ224_LOWER_PICKUP);
			else
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_PICKUP_LOWER"), self.typeDesc), InputBinding.SIPMAZ224_LOWER_PICKUP);
			end;
		end;
		if self.attacherInRange then
			if self.isTurnedOn == false then
				if InputBinding.hasEvent(InputBinding.SIPMAZ224_WORK_MODE) then
					if self.animationParts[5].clipEndTime then
						self:setAnimationTime(5, self.animationParts[5].offSet);
					else
						self:setAnimationTime(5, self.animationParts[5].animDuration);
					end;
				end;
			end;
			if self.isTurnedOn then
				g_currentMission:addExtraPrintText(g_i18n:getText("SIPMAZ224_TURNOFF_TO_SET_TRANSPORT_MODE"));
			else
				if self.animationParts[5].clipEndTime then
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_TRANSPORT_ON"), self.typeDesc), InputBinding.SIPMAZ224_WORK_MODE);
				else
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_TRANSPORT_OFF"), self.typeDesc), InputBinding.SIPMAZ224_WORK_MODE);
				end;
			end;
		end;
		if self.backOptionsNodeInRange then
			if self.baleTransporterActive == false then
				if InputBinding.hasEvent(InputBinding.SIPMAZ224_LOWER_PICKUP) then
					self:setBackFlap(not self.backFlap);
				end;
				if self.backFlap then
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_BACK_FLAP_LIFT"), self.typeDesc), InputBinding.SIPMAZ224_LOWER_PICKUP);
				else
					g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_BACK_FLAP_LOWER"), self.typeDesc), InputBinding.SIPMAZ224_LOWER_PICKUP);
				end;
			end;
			local numAttachedTrailers = table.getn(self.attachedImplements);
			if numAttachedTrailers == 0 then
				if InputBinding.hasEvent(InputBinding.SIPMAZ224_ATTACHER_SLIDE) then
					if self.animationParts[7].clipEndTime then
						self:setAnimationTime(7, self.animationParts[7].offSet);
					else
						self:setAnimationTime(7, self.animationParts[7].animDuration);
					end;
				end;
				if self.animationParts[7].clipEndTime then
					g_currentMission:addHelpButtonText(g_i18n:getText("SIPMAZ224_SLIDE_OUT_ATTACHER"), InputBinding.SIPMAZ224_ATTACHER_SLIDE);
				else
					g_currentMission:addHelpButtonText(g_i18n:getText("SIPMAZ224_SLIDE_IN_ATTACHER"), InputBinding.SIPMAZ224_ATTACHER_SLIDE);
				end;
			else
				g_currentMission:addExtraPrintText(g_i18n:getText("SIPMAZ224_DETACH_TRAILER_TO_OPERATE_BACK_ATTACHER"));
			end;
			
			if self.animationParts[6].clipEndTime then 
				local baleCountInBaler = table.getn(self.bales);
				if baleCountInBaler > 1 then
					g_currentMission:addHelpButtonText(g_i18n:getText("SIPMAZ224_REMOVE_BALES"), InputBinding.SIPMAZ224_MOVE_BALES);
					if InputBinding.hasEvent(InputBinding.SIPMAZ224_MOVE_BALES) then
						self:doMoveBalesOut(true);
					end;
					g_currentMission:addExtraPrintText(g_i18n:getText("SIPMAZ224_REMOVE_BALES_TO_OPERATE_BALETRANSPORTER"));
				else
					if InputBinding.hasEvent(InputBinding.SIPMAZ224_MOUNT_BALE_TRANSPORTER) then
						self:setBaleTransporterVisibility(not self.baleTransporterVisibility);
					end;
					if self.baleTransporterVisibility then
						g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_BALETRANSPORTER_UNMOUNT"), self.typeDesc), InputBinding.SIPMAZ224_MOUNT_BALE_TRANSPORTER);
						if InputBinding.hasEvent(InputBinding.SIPMAZ224_LOWER_BALE_TRANSPORTER) then
							self:setBaleTransporterPosition(not self.baleTransporterActive);
						end;
						if self.baleTransporterActive then
							g_currentMission:addHelpButtonText(g_i18n:getText("SIPMAZ224_BALETRANSPORTER_LIFT"), InputBinding.SIPMAZ224_LOWER_BALE_TRANSPORTER);
						else
							g_currentMission:addHelpButtonText(g_i18n:getText("SIPMAZ224_BALETRANSPORTER_LOWER"), InputBinding.SIPMAZ224_LOWER_BALE_TRANSPORTER);
						end;
					else
						g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_BALETRANSPORTER_MOUNT"), self.typeDesc), InputBinding.SIPMAZ224_MOUNT_BALE_TRANSPORTER);
					end;
				end;
			else
				g_currentMission:addExtraPrintText(g_i18n:getText("SIPMAZ224_LOWER_FLAP_TO_OPERATE_BALETRANSPORTER"));
			end;
		end;
	end;
	
	if self.ropeDoorInRange then
		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then
			self:setRopePanel(not self.ropePanel);
		end;
		if not self.isLoaded then
			if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
				self:setHasRopes(true);
			end;
		end;
		if self.ropePanel then
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_OPEN_DOOR"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA3);
		else
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_CLOSE_DOOR"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA3);
			if not self.isLoaded then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_RELOAD_ROPES"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA2);
			end;
		end;
	end;
	if self.mechanismDoorInRange then
		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then
			self:setMechanismPanel(not self.mechanismPanel);
		end;
		if self.mechanismPanel then
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_OPEN_DOOR"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA3);
		else
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_CLOSE_DOOR"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA3);
		end;
	end;
	if self.counterweightDoorInRange then
		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then
			self:setCounterweightPanel(not self.counterweightPanel);
		end;
		if self.counterweightPanel then
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_OPEN_DOOR"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA3);
		else
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_CLOSE_DOOR"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA3);
		end;
	end;
	if self.NoRopesBalesCount >= self.ropesCapacity then
		self:setHasRopes(false);
	end;
	-- end new --
end;

function SipmaZ224:updateTick(dt)
	-- new --
	if self.attacherVehicle ~= nil then
		for k, implement in pairs(self.attacherVehicle.attachedImplements) do
			local jointDesc = self.attacherVehicle.attacherJoints[implement.jointDescIndex];
			if k == self.attacherVehicle.selectedImplement  then
				setJointFrame(jointDesc.jointIndex, 1, self.attacherJoint.node);
			end;
		end;
	end;

	if self.attacherVehicle ~= nil then
		if self.powerShaftNode ~= nil then 
			setVisibility(self.powerShaftNode, true);
		end;
		if self.detachedPowerShaftNode ~= nil then 
			setVisibility(self.detachedPowerShaftNode, false);
		end;
	else
		if self.powerShaftNode ~= nil then 
			setVisibility(self.powerShaftNode, false);
		end;
		if self.detachedPowerShaftNode ~= nil then 
			setVisibility(self.detachedPowerShaftNode, true);
		end;
	end;
	
	if self.attacherVehicle ~= nil then
		self:setAnimationTime(3, self.animationParts[3].animDuration);
	else
		self:setAnimationTime(3, self.animationParts[3].offSet);
	end;

	if self.attacherVehicle and g_currentMission.player ~= nil then
		local nearestDistance = 1.5;
		local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);
		
		local px, py, pz = getWorldTranslation(self.pickupNode); 
		local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);	
		if distance < nearestDistance then
			self.pickupInRange = true; 
		else
			self.pickupInRange = false; 
		end;
		
		local rx, ry, rz = getWorldTranslation(self.attacherNode); 
		local distance = Utils.vector3Length(rx-vx, ry-vy, rz-vz);	
		if distance < nearestDistance then
			self.attacherInRange = true; 
		else
			self.attacherInRange = false; 
		end;
		
		local sx, sy, sz = getWorldTranslation(self.backOptionsNode); 
		local distance = Utils.vector3Length(sx-vx, sy-vy, sz-vz);	
		if distance < nearestDistance then
			self.backOptionsNodeInRange = true; 
		else
			self.backOptionsNodeInRange = false; 
		end;
		
		local tx, ty, tz = getWorldTranslation(self.ropeDoor); 
		local distance = Utils.vector3Length(tx-vx, ty-vy, tz-vz);	
		if distance < nearestDistance then
			self.ropeDoorInRange = true; 
		else
			self.ropeDoorInRange = false; 
		end;
		
		local qx, qy, qz = getWorldTranslation(self.mechanismDoor); 
		local distance = Utils.vector3Length(qx-vx, qy-vy, qz-vz);	
		if distance < nearestDistance then
			self.mechanismDoorInRange = true; 
		else
			self.mechanismDoorInRange = false; 
		end;
		
		local wx, wy, wz = getWorldTranslation(self.counterweightDoor); 
		local distance = Utils.vector3Length(wx-vx, wy-vy, wz-vz);	
		if distance < nearestDistance then
			self.counterweightDoorInRange = true; 
		else
			self.counterweightDoorInRange = false; 
		end;
	end;
	
	if self:getIsActive() then
		if self.animationParts[4].clipEndTime then
			rotate(self.pickupWheel, 2.5 * self.lastSpeedReal * self.movingDirection * dt ,0,0);
		end;
		if self.isTurnedOn then
			if self.CurrentBalesCount ~= 0 then
				if self.CurrentBalesCount % 2 == 0 then
					self:setAnimationTime(1, self.animationParts[1].offSet);
				else
					self:setAnimationTime(1, self.animationParts[1].animDuration);
				end;
			end;
			
			if self:getIsActiveForSound() then		
				if self.time > self.soundOffset then
					if not self.balerSoundEnabled then
						playSample(self.balerSound, 0, self.balerSoundVolume, 0);
						self.balerSoundEnabled = true;
					end;
				else
					stopSample(self.balerSound);
					self.balerSoundEnabled = false;
				end;
			end;
		end;
	end;
	
	self.lastArea = 0;

	if self.backFlap == false then
		if self.moveBalesOutsideForTransport then
			self:setAnimationTime(6, self.animationParts[6].offSet);
		else
			self:moveBalesOutForTransport(dt, self);
		end;
	else
		self:setAnimationTime(6, self.animationParts[6].animDuration);
		self.moveBalesOutsideForTransport = false;
	end;
	
	if self.doResetBaleCounter then
		self.TotalBalesCount = 0;
		self.doResetBaleCounter = false;
	end;
	
	if self.isTurnedOn and not self:getIsActiveForSound() then
		if self.balerAISound ~= nil then
			setVisibility(self.balerAISound, true);
		end;
	else
		if self.balerAISound ~= nil then
			setVisibility(self.balerAISound, false);
		end;		
	end;
	-- end new --
	
	self.wasToFast = false;
	if self:getIsActive() then
		if self.isTurnedOn then
			local toFast = self:doCheckSpeedLimit() and self.lastSpeed*3600 > 30;
			if not toFast then
				if self.isServer and self:allowPickingUp() then
					local totalArea = 0;
					local usedFruitType = FruitUtil.FRUITTYPE_UNKNOWN;

					local fruitTypes = {};
					for fillType,enabled in pairs(self.fillTypes) do
						if enabled then
							local fruitType = FruitUtil.fillTypeToFruitType[fillType];
							if fruitType ~= nil and fruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then
								table.insert(fruitTypes, fruitType);
							end;
						end;
					end;
					if table.getn(fruitTypes) > 0 then
						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});
							end;
						end;

						if table.getn(cuttingAreasSend) > 0 then
							totalArea, usedFruitType = BalerAreaEvent.runLocally(cuttingAreasSend, fruitTypes);
							-- new --
							self.lastArea = totalArea;
							self.lastAreaBiggerZero = (self.lastArea > 0);
							-- end new --
							if totalArea > 0 then
								if (table.getn(cuttingAreasSend) > 0) then
									g_server:broadcastEvent(BalerAreaEvent:new(cuttingAreasSend, fruitTypes));
								end;
							end;
						end;
					end;
					
					if totalArea > 0 then
						local literPerPixel = g_currentMission:getFruitPixelsToSqm()*g_strawLitersPerSqm;  --8000/1200 / 6 / (2*2) *12/4 / 4;

						local deltaLevel = totalArea * literPerPixel * self.fillScale;

						if self.baleUnloadAnimationName == nil then
							-- move all bales
							local deltaTime = self:getTimeFromLevel(deltaLevel);
							self:moveBales(deltaTime);
						end;

						local usedFillType = FruitUtil.fruitTypeToFillType[usedFruitType];

						local oldFillLevel = self.fillLevel;
						self:setFillLevel(self.fillLevel+deltaLevel, usedFillType);
						if self.fillLevel == self.capacity then
							if self.baleTypes ~= nil then
								-- create bale
								if self.baleAnimCurve ~= nil then
									local restDeltaFillLevel = deltaLevel - (self.fillLevel-oldFillLevel)
									self:setFillLevel(restDeltaFillLevel, usedFillType);

									SipmaZ224.createBale(self, usedFruitType);

									local numBales = table.getn(self.bales);
									local bale = self.bales[numBales]

									self:moveBale(numBales, self:getTimeFromLevel(restDeltaFillLevel), true);
									-- note: self.bales[numBales] can not be accessed anymore since the bale might be dropped already
									g_server:broadcastEvent(SipmaZ224CreateBaleEvent:new(self, usedFruitType, bale.time), nil, nil, self);
								elseif self.baleUnloadAnimationName ~= nil then
									SipmaZ224.createBale(self, usedFruitType);
									g_server:broadcastEvent(SipmaZ224CreateBaleEvent:new(self, usedFruitType, 0), nil, nil, self);
								end;
							end;
						end;
					end;
				-- new --
				else
					for k, strawParticleSystem in pairs(self.strawParticleSystems) do
						Utils.setEmittingState(strawParticleSystem.particleSystem, false);
					end;
					for k, grassParticleSystem in pairs(self.grassParticleSystems) do
						Utils.setEmittingState(grassParticleSystem.particleSystem, false);
					end;
				-- end new --
				end;
			end;
			
			-- new --
			if self.currentFillType == Fillable.FILLTYPE_GRASS or self.currentFillType == Fillable.FILLTYPE_DRYGRASS then
				for k, grassParticleSystem in pairs(self.grassParticleSystems) do
					Utils.setEmittingState(grassParticleSystem.particleSystem, self.lastAreaBiggerZero);
				end;
			else
				for k, strawParticleSystem in pairs(self.strawParticleSystems) do
					Utils.setEmittingState(strawParticleSystem.particleSystem, self.lastAreaBiggerZero);
				end;
			end;
			-- end new --
			
			if self.isClient then
				if self.balerKnotCleaning ~= nil and self.balerKnotCleaningTime <= self.time and self:getIsActiveForSound() then
					playSample(self.balerKnotCleaning, 1, self.balerKnotCleaningVolume, 0);
					setSamplePitch(self.balerKnotCleaning, self.balerKnotCleaningPitchOffset);

					self.balerKnotCleaningTime = self.time + 120000;
					self.balerKnotCleaningEnabled = true;
				end;
			end;

			self.wasToFast = toFast;
		-- new --
		else
			for k, strawParticleSystem in pairs(self.strawParticleSystems) do
				Utils.setEmittingState(strawParticleSystem.particleSystem, false);
			end;
			for k, grassParticleSystem in pairs(self.grassParticleSystems) do
				Utils.setEmittingState(grassParticleSystem.particleSystem, false);
			end;
		-- end new --
		end;
		
		local baleCountInBaler = table.getn(self.bales);
		if self.lastAreaBiggerZero and self.isTurnedOn and baleCountInBaler > 1 and self.baleStarNode ~= nil then
			rotate(self.baleStarNode, self.baleStarSpeed * self.lastSpeedReal * dt ,0,0);
		end;
		
		if self.isClient then
			if not self.isTurnedOn and self.balerSoundEnabled then
				stopSample(self.balerSound);
				self.balerSoundEnabled = false;
			end;
		end;

		if self.isTurnedOn and self.fillLevel > (self.capacity * 0.93) and self.fillLevel < self.capacity then
			-- start alarm sound
			if not self.balerAlarmEnabled and self:getIsActiveForSound() then
				setSamplePitch(self.balerAlarm, self.balerAlarmPitchOffset);
				playSample(self.balerAlarm, 0, self.balerAlarmVolume, 0);
				self.balerAlarmEnabled = true;
			end;
		else
			-- stop alarm sound
			if self.balerAlarmEnabled then
				stopSample(self.balerAlarm);
				self.balerAlarmEnabled = false;
			end;
		end;

		if self.SipmaZ224UnloadingState == SipmaZ224.UNLOADING_OPENING then
			if not self.balerBaleEjectEnabled and self:getIsActiveForSound() then
				setSamplePitch(self.balerBaleEject, self.balerBaleEjectPitchOffset);
				playSample(self.balerBaleEject, 1, self.balerBaleEjectVolume, 0);
				self.balerBaleEjectEnabled = true;
			end;

			if not self.balerDoorEnabled and self:getIsActiveForSound() then
				setSamplePitch(self.balerDoor, self.balerDoorPitchOffset);
				playSample(self.balerDoor, 1, self.balerDoorVolume, 0);
				self.balerDoorEnabled = true;
			end;

				local isPlaying = self:getIsAnimationPlaying(self.baleUnloadAnimationName);
				local animTime = self:getRealAnimationTime(self.baleUnloadAnimationName);
				if not isPlaying or animTime >= self.baleDropAnimTime then
					if table.getn(self.bales) > 0 then
						SipmaZ224.dropBale(self, 1);
						if self.isServer then
							self:setFillLevel(0, self.currentFillType);
						end;
					end;
				if not isPlaying then
					self.SipmaZ224UnloadingState = SipmaZ224.UNLOADING_OPEN;

					if self.balerBaleEjectEnabled then
						stopSample(self.balerBaleEject);
						self.balerBaleEjectEnabled = false;
					end;
					if self.balerDoorEnabled then
						stopSample(self.balerDoor);
						self.balerDoorEnabled = false;
					end;

				end;
			end;
		elseif self.SipmaZ224UnloadingState == SipmaZ224.UNLOADING_CLOSING then

			if not self.balerDoorEnabled and self:getIsActiveForSound() then
				setSamplePitch(self.balerDoor, self.balerDoorPitchOffset);
				playSample(self.balerDoor, 1, self.balerDoorVolume, 0);
				self.balerDoorEnabled = true;
			end;

			if not self:getIsAnimationPlaying(self.baleCloseAnimationName) then
					self.SipmaZ224UnloadingState = SipmaZ224.UNLOADING_CLOSED;
				end;

			if not self.balerDoorEnabled and self:getIsActiveForSound() then
				setSamplePitch(self.balerDoor, self.balerDoorPitchOffset);
				playSample(self.balerDoor, 1, self.balerDoorVolume, 0);
				self.balerDoorEnabled = true;
			end;

		elseif self.SipmaZ224UnloadingState == SipmaZ224.UNLOADING_CLOSING then
			if self.balerDoorEnabled then
				stopSample(self.balerDoor);
				self.balerDoorEnabled = false;
			end;
		end;
		if self.isServer then
			if self.time > self.baleLastPositionTime+100 then
				for i=1, table.getn(self.bales) do
					local bale = self.bales[i];
					bale.lastX, bale.lastY, bale.lastZ = getWorldTranslation(bale.id);
				end;
				self.baleLastPositionTime = self.time;
			end;
		end;
	end;
	
	-- new --
	if self.setAnimationTime ~= nil then
		if self.isTurnedOn then
			self:setAnimationTime(2, 1);
		else
			self:setAnimationTime(2, 0);
		end;
	end;
	
	setVisibility(self.chainNode, self.baleTransporterActive);
	setVisibility(self.baleTransporterNode, self.baleTransporterVisibility);

	if self.moveBalesOutside == false then
		self:moveBalesOut(dt, self);
	end;
	
	if self.doMoveBalesOutside then
		self:moveBalesOut(dt, self);
		self.doMoveBalesOutside = false;
	end;
	-- end new --
end;

function SipmaZ224:draw()
	if self.isClient then
		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.baleUnloadAnimationName ~= nil then
			if self.SipmaZ224UnloadingState == SipmaZ224.UNLOADING_CLOSED then
				if table.getn(self.bales) > 0 then
					g_currentMission:addHelpButtonText(g_i18n:getText("baler_unload"), InputBinding.IMPLEMENT_EXTRA2);
				end;
			elseif self.SipmaZ224UnloadingState == SipmaZ224.UNLOADING_OPEN then
				g_currentMission:addHelpButtonText(g_i18n:getText("baler_unload_stop"), InputBinding.IMPLEMENT_EXTRA2);
			end;
		end;
		
		-- new --
		if self.animationParts[6].clipEndTime 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;
		else
			g_currentMission:addExtraPrintText(g_i18n:getText("SIPMAZ224_LOWER_FLAP_TO_TURNON"));
		end;
		
		if self.HUD then
			setTextBold(false);
			self.HUDSipma:render();
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_HUD_OFF"), self.typeDesc), InputBinding.SIPMAZ224_HUD_ON);
			totalBalesCountString = string.format("%d", self.TotalBalesCount);
			totalBalesCountPadded = string.rep('0', 4 - #totalBalesCountString) .. totalBalesCountString;
			totalBalesCountPaddedSpaced = "";
			for k in totalBalesCountPadded:gmatch"." do
				totalBalesCountPaddedSpaced = totalBalesCountPaddedSpaced .. " " .. k;
			end;
			if totalBalesCountPaddedSpaced ~= nil then
				renderText(0.673, 0.926, 0.028, string.format(totalBalesCountPaddedSpaced));
			end;
		else
			g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_HUD_ON"), self.typeDesc), InputBinding.SIPMAZ224_HUD_ON);	
		end;
		g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SIPMAZ224_RESET_COUNTER"), self.typeDesc), InputBinding.SIPMAZ224_RESET_BALECOUNTER);	
		if not self.isLoaded then
			g_currentMission:addWarning(g_i18n:getText("SIPMAZ224_NOROPE") .. "\n" .. g_i18n:getText("SIPMAZ224_NOROPE_WARNING"), 0.07+0.022, 0.019+0.029);	
		end;		
		-- end new --
	end;
end;

function SipmaZ224:onDetach()
	self.isTurnedOn = false;
	if self.deactivateOnDetach then
		SipmaZ224.onDeactivate(self);
	else
		SipmaZ224.onDeactivateSounds(self);
	end;
	
	-- new --
	for k, strawParticleSystem in pairs(self.strawParticleSystems) do
		Utils.setEmittingState(strawParticleSystem.particleSystem, false);
	end;
	for k, grassParticleSystem in pairs(self.grassParticleSystems) do
		Utils.setEmittingState(grassParticleSystem.particleSystem, false);
	end;
	if self.balerStartSound ~= nil then
		stopSample(self.balerStartSound);
	end;
	if self.balerStopSound ~= nil then
		stopSample(self.balerStopSound);
	end;
	-- end new --
end;

function SipmaZ224:onLeave()
	if self.deactivateOnLeave then
		SipmaZ224.onDeactivate(self);
	else
		SipmaZ224.onDeactivateSounds(self);
	end;
	
	-- new --
	for k, strawParticleSystem in pairs(self.strawParticleSystems) do
		Utils.setEmittingState(strawParticleSystem.particleSystem, false);
	end;
	for k, grassParticleSystem in pairs(self.grassParticleSystems) do
		Utils.setEmittingState(grassParticleSystem.particleSystem, false);
	end;
	-- end new --
end;

function SipmaZ224:onDeactivate()
	self.wasToFast = false;
	--self.isTurnedOn = false;
	SipmaZ224.onDeactivateSounds(self)
	
	-- new --
	for k, strawParticleSystem in pairs(self.strawParticleSystems) do
		Utils.setEmittingState(strawParticleSystem.particleSystem, false);
	end;
	for k, grassParticleSystem in pairs(self.grassParticleSystems) do
		Utils.setEmittingState(grassParticleSystem.particleSystem, false);
	end;
	-- end new --
end;

function SipmaZ224:onDeactivateSounds()
	if self.balerSoundEnabled then
		stopSample(self.balerSound);
		self.balerSoundEnabled = false;
	end;
	if self.balerAlarmEnabled then
		stopSample(self.balerAlarm);
		self.balerAlarmEnabled = false;
	end;
	if self.balerBaleEjectEnabled then
		stopSample(self.balerBaleEject);
		self.balerBaleEjectEnabled = false;
	end;
	if self.balerDoorEnabled then
		stopSample(self.balerDoor);
		self.balerDoorEnabled = false;
	end;
	if self.balerKnotCleaningEnabled then
		stopSample(self.balerKnotCleaning);
		self.balerKnotCleaningEnabled = false;
	end;
end;

function SipmaZ224:setIsTurnedOn(isTurnedOn, noEventSend)
	SetTurnedOnEvent.sendEvent(self, isTurnedOn, noEventSend)
	self.isTurnedOn = isTurnedOn;
	for _, part in pairs(self.balerUVScrollParts) do
		if self.isTurnedOn then
			setShaderParameter(part.node, "uvScrollSpeed", part.speed[1], part.speed[2], 0, 0, false);
		else
			setShaderParameter(part.node, "uvScrollSpeed", 0, 0, 0, 0, false);
		end;
	end;

	if self.pickupAnimationName ~= "" then
		local animTime = nil;
		if self:getIsAnimationPlaying(self.pickupAnimationName) then
			animTime = self:getAnimationTime(self.pickupAnimationName);
		end;
		if isTurnedOn then
			self:playAnimation(self.pickupAnimationName, self.pickupAnimationLowerSpeed, animTime, true)
		else
			self:playAnimation(self.pickupAnimationName, self.pickupAnimationLiftSpeed, animTime, true)
		end;
	end;
	
	-- new --
	local soundOffset = 0;
	if not isTurnedOn then
		if self.balerAISound ~= nil then
			--setVisibility(self.balerAISound, false);
		end;
		self.animationEnabled = true;
		if self:getIsActive() then
			if self:getIsActiveForSound() then	
				if self.time < self.soundOffset then
					stopSample(self.balerStartSound);
				else
					if self.balerStopSound ~= nil then
						playSample(self.balerStopSound, 1, self.balerStopSoundVolume, 0);
						soundOffset = getSampleDuration(self.balerStopSound);
					end;
				end;
			end;
		end;
	else
		if self:getIsActive() then
			if self:getIsActiveForSound() then					
				self.balerSoundEnabled = false;
				stopSample(self.balerSound);
				
				if self.time < self.soundOffset then
					stopSample(self.balerStopSound);
				end;
				playSample(self.balerStartSound, 1, self.balerStartSoundVolume, 0);
				soundOffset = getSampleDuration(self.balerStartSound);		
			end;
		end;
	end;
	self.soundOffset = self.time + soundOffset;
	-- end new --
end;

function SipmaZ224:setIsUnloadingBale(isUnloadingBale, noEventSend)
	if self.baleUnloadAnimationName ~= nil then
		if isUnloadingBale then
			if self.SipmaZ224UnloadingState ~= SipmaZ224.UNLOADING_OPENING then
				BalerSetIsUnloadingBaleEvent.sendEvent(self, isUnloadingBale, noEventSend)
				self.SipmaZ224UnloadingState = SipmaZ224.UNLOADING_OPENING;
				self:playAnimation(self.baleUnloadAnimationName, self.baleUnloadAnimationSpeed, nil, true);
			end;
		else
			if self.SipmaZ224UnloadingState ~= SipmaZ224.UNLOADING_CLOSING then
				BalerSetIsUnloadingBaleEvent.sendEvent(self, isUnloadingBale, noEventSend)
				self.SipmaZ224UnloadingState = SipmaZ224.UNLOADING_CLOSING;
				self:playAnimation(self.baleCloseAnimationName, self.baleCloseAnimationSpeed, nil, true);
			end;
		end;
	end;
end;

function SipmaZ224:getTimeFromLevel(level)
	-- level = capacity -> time = firstBaleMarker
	-- level = 0           -> time = 0
	if self.firstBaleMarker ~= nil then
		return level / self.capacity * self.firstBaleMarker;
	end;
	return 0;
end;

function SipmaZ224:moveBales(dt)
	for i=table.getn(self.bales), 1, -1 do
		self:moveBale(i, dt);
	end;
end;

function SipmaZ224:moveBale(i, dt, noEventSend)
	local bale = self.bales[i];
	SipmaZ224.setBaleTime(self, i, bale.time + dt, noEventSend)
end;

function SipmaZ224.setBaleTime(self, i, baleTime, noEventSend)
	if self.baleAnimCurve ~= nil then
		local bale = self.bales[i];
		bale.time = baleTime;
		local v = self.baleAnimCurve:get(bale.time);
		setTranslation(bale.id, v[1], v[2], v[3]);
		setRotation(bale.id, v[4], v[5], v[6]);
		if bale.time >= 1 then
			SipmaZ224.dropBale(self, i);
		end;
		if self.isServer then
			if noEventSend == nil or not noEventSend then
				g_server:broadcastEvent(SipmaZ224SetBaleTimeEvent:new(self, i, bale.time), nil, nil, self);
			end;
		end;
	end;
end;

--overwrite Fillable.allowFillType
function SipmaZ224:allowFillType(fillType)
	return self.fillTypes[fillType] == true;
end;

function SipmaZ224:allowPickingUp()
	if self.baleUnloadAnimationName == nil then
		local allow = false;
		if self.animationParts[4].clipEndTime then
			allow = true;
		end;
		return allow;
	end;
	return table.getn(self.bales) == 0 and self.SipmaZ224UnloadingState == SipmaZ224.UNLOADING_CLOSED;
end;

function SipmaZ224.createBale(self, usedFruitType)
	local baleType = self.baleTypes[usedFruitType];
	if baleType == nil then
		baleType = self.defaultBaleType;
	end;
	local SipmaZ224oot = Utils.loadSharedI3DFile(baleType.filename, self.baseDirectory);

	local baleId = getChildAt(SipmaZ224oot, 0);
	setRigidBodyType(baleId, "None");
	link(self.baleAnimRoot, baleId);
	delete(SipmaZ224oot);

	local bale = {};
	bale.id = baleId;
	bale.time = 0;
	bale.fruitType = usedFruitType;
	bale.filename = Utils.getFilename(baleType.filename, self.baseDirectory);
	bale.lastX, bale.lastY, bale.lastZ = getWorldTranslation(bale.id);
	table.insert(self.bales, bale);
	local i = table.getn(self.bales);
end;

function SipmaZ224.dropBale(self, baleIndex)
	local bale = self.bales[baleIndex];
	local deltaRealTime = (self.time - self.baleLastPositionTime)/1000;
	local x,y,z = getWorldTranslation(bale.id);
	local rx,ry,rz = getWorldRotation(bale.id);

   --link(getRootNode(), bale.id);
   
	if self.isServer then
		local baleObject = Bale:new(self.isServer, self.isClient);
		baleObject:load(bale.filename, x,y,z,rx,ry,rz);
		baleObject:register();

		local lx, ly, lz = bale.lastX, bale.lastY, bale.lastZ;
		setLinearVelocity(baleObject.nodeId, (x-lx)/deltaRealTime, (y-ly)/deltaRealTime, (z-lz)/deltaRealTime);
	end;
	delete(bale.id);
	table.remove(self.bales, baleIndex);

	-- increase bale count if variable exists (baling mission)
	if g_currentMission.baleCount ~= nil then
		g_currentMission.baleCount = g_currentMission.baleCount + 1;
	end;
	
	if self.CurrentBalesCount ~= nil and self.TotalBalesCount ~= nil and self.NoRopesBalesCount ~= nil then
		self.CurrentBalesCount = self.CurrentBalesCount +1;
		self.TotalBalesCount = self.TotalBalesCount +1;
		self.NoRopesBalesCount = self.NoRopesBalesCount +1;
	end;
end;

function SipmaZ224:getIsAreaActive(superFunc, area)
    if superFunc ~= nil then
		return superFunc(self, area) and self.animationParts[4].clipEndTime;
    end;
	return self.animationParts[4].clipEndTime	
end;

function SipmaZ224:moveBalesOutForTransport(dt, self)
	local done = true;
	for k, bale in pairs(self.bales) do
		if bale.time > 0.55 then
			local sendTime = math.min(1, bale.time+dt/5000);
			SipmaZ224.setBaleTime(self, k, sendTime, true);
			done = false;
		end;
	end;
	self.moveBalesOutsideForTransport = done;
	return;
end;

function SipmaZ224:setBackFlap(isBackFlap,noEventSend)
	SetBackFlapEvent.sendEvent(self, isBackFlap, noEventSend);
	self.backFlap = isBackFlap;
	if self.backFlap == false then
		self:setIsTurnedOn(false);
	end;
end;

function SipmaZ224:resetBaleCounter(doBalebaleCounter,noEventSend)
	ResetBaleCounterEvent.sendEvent(self, resetBaleCounter, noEventSend);
	self.doResetBaleCounter = doBalebaleCounter;	
end;

function SipmaZ224:setRopePanel(isRopePanel,noEventSend)
	SetRopePanelEvent.sendEvent(self, isRopePanel, noEventSend);
	if isRopePanel then
		if self.ropePanelAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.ropePanelAnimation, -1, nil, true);
			self.ropePanel = true;
		end;
	else
		if self.ropePanelAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.ropePanelAnimation, 1, nil, true);
			self.ropePanel = false;
		end;
	end;
end;

function SipmaZ224:setMechanismPanel(isMechanismPanel,noEventSend)
	SetMechanismPanelEvent.sendEvent(self, isMechanismPanel, noEventSend);
	if isMechanismPanel then
		if self.mechanismPanelAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.mechanismPanelAnimation, -1, nil, true);
			self.mechanismPanel = true;
		end;
	else
		if self.mechanismPanelAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.mechanismPanelAnimation, 1, nil, true);
			self.mechanismPanel = false;
		end;
	end;
end;

function SipmaZ224:setCounterweightPanel(isCounterweightPanel,noEventSend)
	SetCounterweightPanelEvent.sendEvent(self, isCounterweightPanel, noEventSend);
	if isCounterweightPanel then
		if self.counterweightPanelAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.counterweightPanelAnimation, -1, nil, true);
			self.counterweightPanel = true;
		end;
	else
		if self.counterweightPanelAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.counterweightPanelAnimation, 1, nil, true);
			self.counterweightPanel = false;
		end;
	end;
end;

function SipmaZ224:setHasRopes(isLoaded,noEventSend)
	self.isLoaded = isLoaded;
	SetHasRopesEvent.sendEvent(self, self.isLoaded, noEventSend);
	if self.isLoaded then
		self.NoRopesBalesCount = 0;
		setVisibility(self.ropes, true);
		if self.NoRopePlaying then
			stopSample(self.NoRopeSoundId);
			self.NoRopePlaying = false;
		end;
	else
		setVisibility(self.ropes, false);	
		self:setIsTurnedOn(false);
		if self:getIsActiveForSound() then
			if not self.NoRopePlaying then
				playSample(self.NoRopeSoundId, 1, 1, 0);
				self.NoRopePlaying = true;
			end;
		end;
	end;
end;

function SipmaZ224:setBaleTransporterPosition(baleTransporterActive,noEventSend)
	SetBaleTransporterPositionEvent.sendEvent(self, baleTransporterActive, noEventSend);
	self.baleTransporterActive = baleTransporterActive;
	if baleTransporterActive then
		if self.baleTransporterAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.baleTransporterAnimation, 1, nil, true);
		end;
	else
		if self.baleTransporterAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.baleTransporterAnimation, -1, nil, true);
		end;
	end;
	if baleTransporterActive then
		self.baleAnimCurve = self.baleAnimCurve2
		self.firstBaleMarker = self.firstBaleMarker2;
	else
		self.baleAnimCurve = self.baleAnimCurveBackup;
		self.firstBaleMarker = self.firstBaleMarkerBackup;
	end;
	self:moveBales(0);
end;

function SipmaZ224:setBaleTransporterVisibility(baleTransporterVisibility,noEventSend)
	SetBaleTransporterVisibilityEvent.sendEvent(self, baleTransporterVisibility, noEventSend);
	self.baleTransporterVisibility = baleTransporterVisibility;
	if self.baleTransporterActive and self.firstTimeStart == false then
		self:setBaleTransporterPosition(false);
	end;
end;

function SipmaZ224:moveBalesOut(dt, self)
	local done = true;
	for k, bale in pairs(self.bales) do
		if bale.time > 0.15 then
			local sendTime = math.min(1, bale.time+dt/5000);
			SipmaZ224.setBaleTime(self, k, sendTime, true);
			done = false;
		end;
	end;
	self.moveBalesOutside = done;
	return;
end;

function SipmaZ224:doMoveBalesOut(moveBales, noEventSend)
	MoveBalesOutEvent.sendEvent(self, moveBales, noEventSend);
	self.doMoveBalesOutside = moveBales;
end;