-- tipAnywhere 
-- 
-- by Defender

tipAnywhere = {};

local oldSaveSelectedGame = CareerScreen.saveSelectedGame;

CareerScreen.saveSelectedGame = function(self)
  oldSaveSelectedGame(self);
  if g_currentMission.tipAnywhereTriggers ~= nil then
    if table.maxn(g_currentMission.tipAnywhereTriggers)>0 then
      local siloSaveDir = g_currentMission.missionInfo.savegameDirectory;
      local siloSaveXML = siloSaveDir .. "/tipAnywhere.xml";
	    local existDir = io.open (siloSaveXML, "w");
	    if existDir == nil then
		    createXMLFile("createsilo", siloSaveXML, "tipAnywhere");
	    end;
      local siloFile = io.open (siloSaveXML, "w");
      if siloFile ~= nil then
        siloFile:write('<?xml version="1.0" encoding="utf-8" standalone="no" ?>\n');
        siloFile:write('<tipAnywhere>\n');
        for i=1, table.maxn(g_currentMission.tipAnywhereTriggers) do
          local tmp = g_currentMission.tipAnywhereTriggers[i];
          if tmp~=nil then
            if tmp.isActive then
              local x,y,z = getWorldTranslation(tmp.hromadaId);
              local rx,ry,rz = getWorldRotation(tmp.hromadaId);
              siloFile:write(string.format('  <tipAnywhereTrigger position="%f %f %f" rotation="%f %f %f" fillType="%s" fillLevel="%f" />\n', x, y, z, rx, ry, rz, Fillable.fillTypeIntToName[tmp.currentFillType], tmp.fillLevel));
            end;
          end;
        end;
        siloFile:write("</tipAnywhere>");
        siloFile:close();
      end;
    end;
  end;
end;

function getText(s)
  local d = "";
  local l = g_currentMission.defendersModsLanguage;
  if s == "klavesa" then
    if l == "cz" then 
      d="Klavesa";
    elseif l == "en" then
      d="Key";
    elseif l == "de" then
      d="Taste";
    elseif l == "hu" then
      d="Kulcs";
    elseif l == "pl" then
      d="Klucz";
    end;
  elseif s == "zaloz_hromadu" then
    if l == "cz" then 
      d="Zalozit hromadu";
    elseif l == "en" then
      d="Create heap";
    elseif l == "de" then
      d="Heap Erstellen";
    elseif l == "hu" then
      d="Teremt halom";
    elseif l == "pl" then
      d="Tworzenie kupie";
    end;
  elseif s == "vysypat_hromadu" then
    if l == "cz" then 
      d="Vysypat na hromadu";
    elseif l == "en" then
      d="Empty at heap";
    elseif l == "de" then
      d="Leeren Sie den Haufen";
    elseif l == "hu" then
      d="Uritse ki a halom";
    elseif l == "pl" then
      d="Pusty stos";
    end;
  elseif s == "vysypat_ukoncit" then
    if l == "cz" then 
      d="Ukoncit vysypavani";
    elseif l == "en" then
      d="End tipping";
    elseif l == "de" then
      d="End Kippen";
    elseif l == "hu" then
      d="Vegen billenes";
    elseif l == "pl" then
      d="Koniec skladowanie";
    end;
  elseif s == "WHEAT" then
    if l == "cz" then 
      d="Psenice";
    elseif l == "en" then
      d="Wheat";
    elseif l == "de" then
      d="Weizen";
    elseif l == "hu" then
      d="Buza";
    elseif l == "pl" then
      d="Pszenica";
    end;
  elseif s == "BARLEY" then
    if l == "cz" then 
      d="Jecmen";
    elseif l == "en" then
      d="Barley";
    elseif l == "de" then
      d="Gerste";
    elseif l == "hu" then
      d="Arpa";
    elseif l == "pl" then
      d="Jeczmien";
    end;
  elseif s == "RAPE" then
    if l == "cz" then 
      d="Repka olejna";
    elseif l == "en" then
      d="Rape";
    elseif l == "de" then
      d="Raps";
    elseif l == "hu" then
      d="Olajrepce";
    elseif l == "pl" then
      d="Rzepak";
    end;
  elseif s == "MAIZE" then
    if l == "cz" then 
      d="Kukurice";
    elseif l == "en" then
      d="Maize";
    elseif l == "de" then
      d="Mais";
    elseif l == "hu" then
      d="Kukorica";
    elseif l == "pl" then
      d="Kukurydza";
    end;
  elseif s == "RYE" then
    if l == "cz" then 
      d="Zito";
    elseif l == "en" then
      d="Rye";
    elseif l == "de" then
      d="Roggen";
    elseif l == "hu" then
      d="Rozs";
    elseif l == "pl" then
      d="Zyto";
    end;
  elseif s == "OAT" then
    if l == "cz" then 
      d="Oves";
    elseif l == "en" then
      d="Oat";
    elseif l == "de" then
      d="Hafer";
    elseif l == "hu" then
      d="Zab";
    elseif l == "pl" then
      d="Owies";
    end;
  elseif s == "SOYBEAN" then  
    if l == "cz" then 
      d="Sojove boby";
    elseif l == "en" then
      d="Soybeans";
    elseif l == "de" then
      d="Sojabohnen";
    elseif l == "hu" then
      d="Szojabab";
    elseif l == "pl" then
      d="Soja";
    end;
  elseif s == "SUNFLOWER" then
    if l == "cz" then 
      d="Slunecnice";
    elseif l == "en" then
      d="Sunflower";
    elseif l == "de" then
      d="Sonnenblume";
    elseif l == "hu" then
      d="Napraforgo";
    elseif l == "pl" then
      d="Slonecznik";
    end;
  elseif s == "POTATO" then
    if l == "cz" then 
      d="Brambory";
    elseif l == "en" then
      d="Potato";
    elseif l == "de" then
      d="Kartoffel";
    elseif l == "hu" then
      d="Burgonya";
    elseif l == "pl" then
      d="Ziemniak";
    end;
  elseif s == "CARROT" then
    if l == "cz" then 
      d="Mrkev";
    elseif l == "en" then
      d="Carrot";
    elseif l == "de" then
      d="Karotte";
    elseif l == "hu" then
      d="Sargarepa";
    elseif l == "pl" then
      d="Marchew";
    end;
  elseif s == "KARROTE" then
    if l == "cz" then 
      d="Mrkev";
    elseif l == "en" then
      d="Carrot";
    elseif l == "de" then
      d="Karotte";
    elseif l == "hu" then
      d="Sargarepa";
    elseif l == "pl" then
      d="Marchew";
    end;
  elseif s == "DUNG" or s == "MANURE" then
    if l == "cz" then 
      d="Hnuj";
    elseif l == "en" then
      d="Dung";
    elseif l == "de" then
      d="Mist";
    elseif l == "hu" then
      d="Tragya";
    elseif l == "pl" then
      d="Nawoz";
    end;
  elseif s == "SILAGE" or s == "CHAFF" then
    if l == "cz" then 
      d="Silaz";
    elseif l == "en" then
      d="Silage";
    elseif l == "de" then
      d="Silage";
    elseif l == "hu" then
      d="Silózás";
    elseif l == "pl" then
      d="Kiszonki";
    end;
  elseif s == "GRASS" then
    if l == "cz" then 
      d="Trava";
    elseif l == "en" then
      d="Grass";
    elseif l == "de" then
      d="Gras";
    elseif l == "hu" then
      d="Fu";
    elseif l == "pl" then
      d="Trawa";
    end;
  elseif s == "DRYGRASS" then
    if l == "cz" then 
      d="Seno";
    elseif l == "en" then
      d="Hay";
    elseif l == "de" then
      d="Heu";
    elseif l == "hu" then
      d="Szena";
    elseif l == "pl" then
      d="Siano";
    end;
  end;
  return d;
end;

function tipAnywhere.prerequisitesPresent(specializations)
  return SpecializationUtil.hasSpecialization(Trailer, specializations);
end;

function tipAnywhere:load(xmlFile)
  print("Pridavam tipAnywhere ...");
  
  local tAxmlFile = loadXMLFile("hromadaXML", getUserProfileAppPath().."mods/zzz_tipAnywhere/hromada/hromada.xml");

  self.tipAnywherefillTypes = {};
  self.tipAnywherefillTypes[FruitUtil.FRUITTYPE_UNKNOWN] = true;
  
  local fruitTypes = getXMLString(tAxmlFile, "plane.fillTypes#fruitTypes");
  if fruitTypes ~= nil then
    local types = Utils.splitString(" ", fruitTypes);
    for k,v in pairs(types) do
      local desc = Fillable.fillTypeNameToInt[v];
      if desc ~= nil then
        self.tipAnywherefillTypes[desc] = true;
      end;
    end;
  end;  
end;

function tipAnywhere:delete()
end;

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

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

function tipAnywhere:update(dt)
  self.enabled = self.currentFillType ~= FruitUtil.FRUITTYPE_UNKNOWN and self.tipAnywherefillTypes[self.currentFillType] and self.allowTipDischarge and not TipTriggerInRange(self) and self.tipState == Trailer.TIPSTATE_CLOSED and not self.isShovel; 
  if self.enabled then        
    if self:getIsActiveForInput() then
      if InputBinding.hasEvent(InputBinding.TIPANYWHERE_CREATE) then
        local fname = getUserProfileAppPath().."mods/zzz_tipAnywhere/hromada/hromada.i3d";
        local hromada = loadI3DFile(fname);
        local x, y, z = getWorldTranslation(self.tipReferencePoint);
        y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 0, z)-0.6;
        setTranslation(hromada, x, y, z);
        local rx, ry, rz = getWorldRotation(self.tipReferencePoint); --self.rootNode
        setRotation(hromada, rx, ry, rz);         
        link(getRootNode(), hromada);

        for i=1, table.maxn(g_currentMission.tipAnywhereTriggers) do
          local tr = g_currentMission.tipAnywhereTriggers[i];
          if tr~=nil then
            if tr.triggerId ==  Utils.indexToObject(hromada,"0|1") then              
              self:toggleTipState(tr);
            end; 
          end;
        end;       
      end;
    end;
  end;    
end;

function tipAnywhere:draw()
  if self.enabled then 
    g_currentMission:addExtraPrintText(getText("klavesa").." Insert"..":              "..getText("zaloz_hromadu"));
--    g_currentMission:addHelpButtonText(g_i18n:getText("zaloz_hromadu"), InputBinding.TIPANYWHERE_CREATE);
  end;
end;

function TipTriggerInRange(self)
  local nearestObject = false;
  local itemNode;
  local nearestDistance = 10;
  local objectCopy = self.tipReferencePoint;
  if objectCopy ~= nil then	
    local px, py, pz = getWorldTranslation(objectCopy);
    for k,v in pairs(g_currentMission.tipTriggers) do
      itemNode = g_currentMission.tipTriggers[k].triggerId;
      local vx, vy, vz = getWorldTranslation(itemNode);
      local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
      if distance < nearestDistance then
        nearestObject = true;
        nearestDistance = distance;
      end;		
    end;
    if g_currentMission.tipAnywhereTriggers~=nil then
      for i=1, table.getn(g_currentMission.tipAnywhereTriggers) do
	    if g_currentMission.tipAnywhereTriggers[i]~=nil then
          if g_currentMission.tipAnywhereTriggers[i].isActive then
            itemNode = g_currentMission.tipAnywhereTriggers[i].triggerId;        
 	        local vx, vy, vz = getWorldTranslation(itemNode);
  	        local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
            if distance < nearestDistance then
 	  	      nearestObject = true;
              nearestDistance = distance;
		    end;
		  end;
        end;		
	  end;
    end;	  
  end;
  return nearestObject;
end;

tipAnywhereTrigger = {};

local tipAnywhereTrigger_mt = Class(tipAnywhereTrigger);

tipAnywhereTrigger.tipAnywhereOnCreate = function(id)
  print("Pridavam tipAnywhereTrigger");
	table.insert(g_currentMission.updateables, tipAnywhereTrigger:new(id));
end;

tipAnywhereOnCreate = tipAnywhereTrigger.tipAnywhereOnCreate;

function tipAnywhereTrigger:new(id, customMt)
  local instance = {};
  if customMt ~= nil then
    setmetatable(instance, customMt);
  else
    setmetatable(instance, tipAnywhereTrigger_mt);
  end;
  instance.updateablesId = table.maxn(g_currentMission.updateables);
  instance.isActive = true;
  instance.triggerId = id;
  instance.hromadaId = getParent(id);
  instance.allowFillType = tipAnywhereTrigger.allowFillType;
  --instance.setFillLevel = SpecializationUtil.callSpecializationsFunction("setFillLevel");
  instance.setFillLevel = tipAnywhereTrigger.setFillLevel;
  instance.updateMoving = tipAnywhereTrigger.updateMoving;
  self.shovelInRange = tipAnywhereTrigger.shovelInRange;
  local xmlFile = loadXMLFile("hromadaXML", getUserProfileAppPath().."mods/zzz_tipAnywhere/hromada/hromada.xml");
  instance.grainPlanes = {};
  local i = 0;
  while true do
    local key = string.format("plane.grainPlane.node(%d)", i);
    local t = getXMLString(xmlFile, key.."#type");
    local index = getXMLString(xmlFile, key.."#index");
    if t==nil or index==nil then
        break;
    end;

    local node = Utils.indexToObject(instance.hromadaId, index);
    if node ~= nil then
        setVisibility(node, false);
        if instance.defaultGrainPlane == nil then
            instance.defaultGrainPlane = node;
        end;
        instance.grainPlanes[t] = node;
    end;
    i = i +1;
  end;
  if instance.defaultGrainPlane==nil then
    instance.grainPlanes = nil;
  end;

  instance.grainPlaneMinY, instance.grainPlaneMaxY = Utils.getVectorFromString(getXMLString(xmlFile, "plane.grainPlane#minMaxY"));
  
  instance.fillTypes = {};
  instance.fillTypes[FruitUtil.FRUITTYPE_UNKNOWN] = true;

  local fruitTypes = getXMLString(xmlFile, "plane.fillTypes#fruitTypes");
  if fruitTypes ~= nil then
    local types = Utils.splitString(" ", fruitTypes);
    for k,v in pairs(types) do
      local desc = Fillable.fillTypeNameToInt[v]; --FruitUtil.fruitTypes[v];      
      if desc ~= nil then
        instance.fillTypes[desc] = true;
      end;
    end;
  end;
  
  
  instance.capacity = Utils.getNoNil(getXMLFloat(xmlFile, "plane.capacity"), 0.0);
  
  instance.isFarmTrigger = false;
  instance.isTipAnywhereTrigger = true;
  instance.isDefendersTrigger = true;
  
  instance.fillLevel = 0;
  instance.currentFillType = FruitUtil.FRUITTYPE_UNKNOWN;
  instance.minThreshold = 0.000001;
  
  instance.trailerInTrigger = 0;
  instance.CiziId = {};
  
  if g_currentMission.tipAnywhereTriggers == nil then
    g_currentMission.tipAnywhereTriggers = {};      
  end;
  instance.infoPanelPath = getUserProfileAppPath().."mods/zzz_tipAnywhere/info.png";
  instance.infoLayer = Overlay:new("infoOverlay", instance.infoPanelPath, 0, 0, 0.3, 0.3);
  table.insert(g_currentMission.tipAnywhereTriggers, instance);
  instance.golbalId = table.maxn(g_currentMission.tipAnywhereTriggers);
  addTrigger(id, "tipAnywhereTriggerCallback", instance); 
  return instance;
end;

function tipAnywhereTrigger:delete()
  self.isActive = false;
  removeTrigger(self.triggerId);
--  table.remove(g_currentMission.tipAnywhereTriggers, self.globalId);
  if self.infoLayer ~= nil then
		self.infoLayer:delete();
	end; 
end;

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

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

function tipAnywhereTrigger:update(dt)
  if self.isActive then
    if self.trailerInTrigger>0 then
      local vlek=g_currentMission.objectToTrailer[self.trailerInTrigger];
      if vlek ~= nil and vlek:getIsActiveForInput() and ((vlek.isShovel==nil) or (not vlek.isShovel)) and (vlek.currentFillType~=nil) then
        local tipPoint = Utils.getNoNil(vlek.tipReferencePoint, vlek.components[1].node); 	      
        local px, py, pz = getWorldTranslation(self.triggerId);
        local vx, vy, vz = getWorldTranslation(tipPoint);
  	    local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
        local m = (self.grainPlaneMaxY - self.grainPlaneMinY) / self.capacity;
        local yTranslation = m*self.fillLevel + self.grainPlaneMinY;
        local nearestDistance = 10.0 + yTranslation;
        if distance < nearestDistance then 
          if (vlek.tipState == Trailer.TIPSTATE_CLOSED) and (self.currentFillType == vlek.currentFillType) and (self.fillLevel<self.capacity) then
            g_currentMission:addExtraPrintText(getText("klavesa").." Space:               "..getText("vysypat_hromadu"));
--            g_currentMission:addHelpButtonText(g_i18n:getText("vysypat_hromadu"), InputBinding.TIPANYWHERE);
            if InputBinding.hasEvent(InputBinding.TIPANYWHERE) then
              vlek:toggleTipState(self);
            end;
          elseif (vlek.tipState ~= Trailer.TIPSTATE_CLOSED) and (self.fillLevel<self.capacity) then
            g_currentMission:addExtraPrintText(getText("klavesa").." Space:               "..getText("vysypat_ukoncit"));
--            g_currentMission:addHelpButtonText(g_i18n:getText("vysypat_ukoncit"), InputBinding.TIPANYWHERE);
            if InputBinding.hasEvent(InputBinding.TIPANYWHERE) then
              vlek:toggleTipState(self);
            end;
          end;
        end;
      end;
    end;
    self:shovelInRange(dt);
  end;
end;

function tipAnywhereTrigger:draw()
  if self.isActive and g_currentMission.showHelpText and (self.trailerInTrigger>0) and g_currentMission.objectToTrailer[self.trailerInTrigger]:getIsActiveForInput() then
    if self.currentFillType ~= FruitUtil.FRUITTYPE_UNKNOWN then
      local overlay = g_currentMission.fruitOverlays[FruitUtil.fillTypeToFruitType[self.currentFillType]];
      if overlay ~= nil then
        local x, y, z = getWorldTranslation(self.hromadaId); 
        x, y, z = project(x, y + 3, z);
        x = x - overlay.width /2;   
        if (x<1) and (y<1) and (z<1) and (x>0) and (y>0) and (z>0) then          
          renderOverlay(self.infoLayer.overlayId, x-0.05, y-0.075, overlay.width+0.1, overlay.height+0.1);
          renderOverlay(overlay.overlayId, x, y, overlay.width, overlay.height);          
          local s=getText(string.upper(Fillable.fillTypeIntToName[self.currentFillType]));
--          local s=g_i18n:getText(Fillable.fillTypeIntToName[self.currentFillType]);
          setTextAlignment(RenderText.ALIGN_CENTER);
          renderText(x+overlay.width/2, y+g_currentMission.hudTipperOverlay.height+0.02,0.02,s);	
          renderText(x+overlay.width/2, y-0.01,0.02,string.format("(%d)",self.fillLevel));

          setTextAlignment(RenderText.ALIGN_LEFT);
        end;
      end;
    end;       
  end;  
end;

function tipAnywhereTrigger:updateMoving(fillLevel)
end;

function tipAnywhereTrigger:allowFillType(fillType, allowEmptying)
  local allowed = false;
  if self.fillTypes[fillType] then
    if self.currentFillType ~= FruitUtil.FRUITTYPE_UNKNOWN then
      if self.currentFillType ~= fillType then
        if self.fillLevel / self.capacity <= self.minThreshold then
          allowed = true;
          if allowEmptying then
            self.fillLevel = 0;
          end;
        end;
      else
        allowed = true; 
      end;
    else
      allowed = true; 
    end;
  end;
  return allowed;
end;

function tipAnywhereTrigger:setFillLevel(fillLevel, fillType)
  if not self:allowFillType(fillType, false) then
    return;
  end;

  self.currentFillType = fillType;
  self.fillLevel = fillLevel;
  if self.fillLevel > self.capacity then
    self.fillLevel = self.capacity;
  end;
  if self.fillLevel < 0 then
    self.fillLevel = 0;
    self.currentFillType = FruitUtil.FRUITTYPE_UNKNOWN;    
  end;
  if self.currentGrainPlane ~= nil then
    setVisibility(self.currentGrainPlane, false);
  end;
  if self.grainPlanes ~= nil and self.defaultGrainPlane ~= nil and fillType ~= FruitUtil.FRUITTYPE_UNKNOWN then
    local fillTypeName = Fillable.fillTypeIntToName[fillType]; --FruitUtil.fruitIndexToDesc[fillType].name;
    local grainPlane = self.grainPlanes[fillTypeName];
    if grainPlane == nil then
      grainPlane = self.defaultGrainPlane;
    end;
    local yTranslation;
    local m = (self.grainPlaneMaxY - self.grainPlaneMinY) / self.capacity;
    yTranslation = m*self.fillLevel + self.grainPlaneMinY;
    local xPos, yPos, zPos = getTranslation(grainPlane);
    setTranslation(grainPlane, xPos, yTranslation, zPos);
    setVisibility(grainPlane, self.fillLevel > 0);
    self.currentGrainPlane = grainPlane;
  end;
  if self.fillLevel<self.minThreshold then
    self.isActive = false;
  end;    
end;

function tipAnywhereTrigger:shovelInRange(dt)
	self.inRangeShovel = false;   
  local m = (self.grainPlaneMaxY - self.grainPlaneMinY) / self.capacity;
  local yTranslation = m*self.fillLevel + self.grainPlaneMinY;
  local nearestDistance = 5.0 + yTranslation;
	local px, py, pz = getWorldTranslation(self.triggerId);
	for i=1, table.getn(g_currentMission.attachables) do
		local vx, vy, vz = getWorldTranslation(g_currentMission.attachables[i].rootNode);
		local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
		if distance < nearestDistance then
			local attachable = g_currentMission.attachables[i];	
			self.trailerInRange = g_currentMission.attachables[i];
			if attachable.setFillLevel ~= nil then
				for fruitType,v in pairs(attachable.fillTypes) do
					if fruitType == self.currentFillType and attachable.rootNode ~= self.rootNode and attachable.isShovel then
						if  attachable.fillLevel ~= attachable.capacity  then
							self.inRangeShovel = true; 
							local deltaLevel = 50;
							deltaLevel = math.min(deltaLevel, attachable.capacity - attachable.fillLevel);
							local fT = self.currentFillType;
							self:setFillLevel(self.fillLevel - deltaLevel, self.currentFillType);
              if not self.isActive then
                attachable:setFillLevel(attachable.fillLevel + deltaLevel, fT);
                break;
              else
                attachable:setFillLevel(attachable.fillLevel + deltaLevel, self.currentFillType);             
              end;								
						end;
					end; 	
				end;
			end; 		
			nearestDistance = distance;
		end; 
  end;
end;


function tipAnywhereTrigger:tipAnywhereTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
  if onEnter then
    if otherId ~= nil then
      local nalezeno=false;
      for a=1, table.maxn(self.CiziId) do
        if self.CiziId[a]~= nil and self.CiziId[a]==otherId then
          nalezeno=true;
          break;
        end;
      end;
      if not nalezeno then
        table.insert(self.CiziId,otherId);
      end;
		end;		
	elseif onLeave then
	  for a=1, table.maxn(self.CiziId) do
      if self.CiziId[a]~= nil and self.CiziId[a]==otherId then
        table.remove(self.CiziId,otherId);
        break;
      end;
    end;      
	elseif onStay then
		if otherId ~= nil then
		end;
	end;
	local nearestDistance = 10;
  local tr = 0;	
	for a=1, table.maxn(self.CiziId) do
	  local index = self.CiziId[a];
    if index ~= nil then
      local vlek=g_currentMission.objectToTrailer[index];
      if vlek ~= nil and vlek:getIsActiveForInput() and ((vlek.isShovel==nil) or (not vlek.isShovel))  then
        local tipPoint = Utils.getNoNil(vlek.tipReferencePoint, vlek.components[1].node); 	      
        local px, py, pz = getWorldTranslation(triggerId);
        local vx, vy, vz = getWorldTranslation(tipPoint);
  	    local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
        if distance<nearestDistance then
          nearestDistance = distance;
          tr = index;
        end; 
      end;
    end;	  
	end;
	self.trailerInTrigger = tr;
end;
	
function Trailer:updateTick(dt)

    if self.tipState == Trailer.TIPSTATE_OPENING or self.tipState == Trailer.TIPSTATE_OPEN then

        if self.isServer then

            if self.currentFillType ~= Fillable.FILLTYPE_UNKNOW and self.currentTipTrigger ~= nil and (g_currentMission:getIsTrailerInTipRange(self, self.currentTipTrigger) or (self.currentTipTrigger.isDefendersTrigger~=nil and self.currentTipTrigger.isDefendersTrigger)) then
                local fillType = self.currentFillType;
                local m = self.capacity/(self.tipDischargeEndTime/self.tipAnimSpeedScale);
                local curFill = self.fillLevel;
                self:setFillLevel(self.fillLevel - (m* dt), self.currentFillType);
                local fillDelta = self.fillLevel - curFill;
                self.lastFillDelta = fillDelta;

                if self.currentTipTrigger.isFarmTrigger then
                    -- put load into storage
                    local siloFillType = fillType;
                    if fillType == Fillable.FILLTYPE_DRYGRASS then
                        siloFillType = Fillable.FILLTYPE_GRASS
                    end;

                    g_currentMission:setSiloAmount(siloFillType, g_currentMission:getSiloAmount(siloFillType)- fillDelta);
              
                elseif self.currentTipTrigger.isDefendersTrigger~=nil and self.currentTipTrigger.isDefendersTrigger then
                    if self.currentTipTrigger.setFillLevel ~= nil then
                      local fill = (self.currentTipTrigger.fillLevel-self.lastFillDelta);
                      if self.currentTipTrigger.capacity~= nil then
                        fill = math.min((self.currentTipTrigger.fillLevel-self.lastFillDelta),self.currentTipTrigger.capacity);
                      end;
                      self.currentTipTrigger:setFillLevel(fill, self.currentFillType);
                      if self.currentTipTrigger.capacity~= nil and fill == self.currentTipTrigger.capacity then
                        self:toggleTipState(self.currentTipTrigger);
                      end;
                    end;
                else
                    -- increase money according to price of current fill type
                    local fruitType = FruitUtil.fillTypeToFruitType[fillType];
                    if fruitType ~= nil then
                        local priceMultiplier = self.currentTipTrigger.priceMultipliers[fruitType];

                        --local difficultyMultiplier = 2 ^ (3 - g_currentMission.missionStats.difficulty);
                        local difficultyMultiplier = math.max(3 * (3 - g_currentMission.missionStats.difficulty), 1); -- 1  3  6
                        local money = FruitUtil.fruitIndexToDesc[fruitType].pricePerLiter * priceMultiplier * difficultyMultiplier * -fillDelta;
                        --g_currentMission.missionStats.money = g_currentMission.missionStats.money + money;
                        g_currentMission:addSharedMoney(money);
                    end;
                end;

                if fillDelta < 0 then
                    if self.currentTipTrigger ~= nil and self.currentTipTrigger.updateMoving~=nil then 
                      self.currentTipTrigger:updateMoving(-fillDelta);
                    end;
                end;
            else
                self:onEndTip();
            end;
        end;

        if self.isClient then
            if self.tipState == Trailer.TIPSTATE_OPENING then
                if not self.hydraulicSoundEnabled and self.hydraulicSound ~= nil and self:getIsActiveForSound() then
                    playSample(self.hydraulicSound, 0, self.hydraulicSoundVolume, 0);
                    setSamplePitch(self.hydraulicSound, self.hydraulicSoundPitchOffset-0.4);
                    self.hydraulicSoundEnabled = true;
                end;
            end;

            -- check if we still are in opening/open state. Maybe we ended tipping before.
            if (self.tipState == Trailer.TIPSTATE_OPENING or self.tipState == Trailer.TIPSTATE_OPEN) and self.fillLevel > 0 then
                if not self.fillSoundEnabled and self.fillSound ~= nil and self:getIsActiveForSound() then
                    playSample(self.fillSound, 0, self.fillSoundVolume, 0);
                    self.fillSoundEnabled = true;
                end;
            else
                if self.fillSoundEnabled then
                    stopSample(self.fillSound);
                    self.fillSoundEnabled = false;
                end;
            end;
        end;

        if self.tipState == Trailer.TIPSTATE_OPENING then
            if getAnimTrackTime(self.tipAnimCharSet, 0) > self.tipAnimDuration then
                self.tipState = Trailer.TIPSTATE_OPEN;
                if self.hydraulicSoundEnabled then
                    stopSample(self.hydraulicSound);
                    self.hydraulicSoundEnabled = false;
                end;
            end;
        else
            if getAnimTrackTime(self.tipAnimCharSet, 0) > self.tipDischargeEndTime then
                self:onEndTip(true);
            end;
        end;

    elseif self.tipState == Trailer.TIPSTATE_CLOSING then

        if self.isClient then
            if not self.hydraulicSoundEnabled and self.hydraulicSound ~= nil and self:getIsActiveForSound() then
                playSample(self.hydraulicSound, 0, self.hydraulicSoundVolume, 0);
                setSamplePitch(self.hydraulicSound, self.hydraulicSoundPitchOffset);
                self.hydraulicSoundEnabled = true;
            end;
        end;

        if getAnimTrackTime(self.tipAnimCharSet, 0) <= 0.0 then
            if self.hydraulicSoundEnabled then
                stopSample(self.hydraulicSound);
                self.hydraulicSoundEnabled = false;
            end;
            disableAnimTrack(self.tipAnimCharSet, 0);
            self.tipState = Trailer.TIPSTATE_CLOSED;
        end;
    end;

    if self.isClient then
        if (self.tipState == Trailer.TIPSTATE_OPENING or self.tipState == Trailer.TIPSTATE_OPEN) and self.fillLevel > 0 then
            Utils.setEmittingState(self.dischargeParticleSystems[self.currentFillType], true);
        else
            Utils.setEmittingState(self.dischargeParticleSystems[self.currentFillType], false);
        end;
    end;
end;
