--
-- Iveco Crane Working Script
--
-- by Zippo
-- 


CraneTN = {}

function CraneTN.prerequisitesPresent(specializations)
    Vehicle.registerJointType("frontloader");
    return true;
    --SpecializationUtil.hasSpecialization(Steerable, specializations);
end;

function CraneTN:load(xmlFile)
    print("***************************************************************************************************************");
    print("**  Specialitation Ladekran by TN  ");
    local specName = "crane_by_TN";
    
    self.crane = {};
    self.crane.BaseIndex = getXMLString(xmlFile,"vehicle.".. specName .."#baseIndex");
    self.crane.isActive = false;
    
    local translationHookNode = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, "vehicle.".. specName ..".translationHook#index"));
    if translationHookNode ~= nil then
        self.crane.translationHook = {};
        self.crane.translationHook.node = translationHookNode;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName ..".translationHook#minTrans"));
        self.crane.translationHook.minTrans = {};
        self.crane.translationHook.minTrans[1] = Utils.getNoNil(x, 0);
        self.crane.translationHook.minTrans[2] = Utils.getNoNil(y, 0);
        self.crane.translationHook.minTrans[3] = Utils.getNoNil(z, 0);

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

        self.crane.translationHook.transTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName ..".translationHook#transTime"), 2)*1000;
        self.crane.translationHook.touchTransLimit = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName ..".translationHook#touchTransLimit"), 10);
    end;        

    
      local rotationNode4 = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, "vehicle.".. specName ..".rotation4#index"));
    if rotationNode4 ~= nil then
        self.crane.rotation4 = {};
        self.crane.rotation4.node = rotationNode4;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName ..".rotation4#minRot"));
        self.crane.rotation4.minRot = {};
        self.crane.rotation4.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.rotation4.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.rotation4.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName ..".rotation4#maxRot"));
        self.crane.rotation4.maxRot = {};
        self.crane.rotation4.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.rotation4.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.rotation4.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        self.crane.rotation4.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName ..".rotation4#rotTime"), 2)*1000;
        self.crane.rotation4.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName ..".rotation4#touchRotLimit"), 10));
    end;
 
         local rotationNode5 = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, "vehicle.".. specName ..".rotation5#index"));
    if rotationNode5 ~= nil then
        self.crane.rotation5 = {};
        self.crane.rotation5.node = rotationNode5;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName ..".rotation5#minRot"));
        self.crane.rotation5.minRot = {};
        self.crane.rotation5.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.rotation5.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.rotation5.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName ..".rotation5#maxRot"));
        self.crane.rotation5.maxRot = {};
        self.crane.rotation5.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.rotation5.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.rotation5.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        self.crane.rotation5.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName ..".rotation5#rotTime"), 2)*1000;
        self.crane.rotation5.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName ..".rotation5#touchRotLimit"), 10));
    end;

    
    local componentName = "rotBase";
    local rotationNodeBase = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#index"));
    if rotationNodeBase ~= nil then
        self.crane.BaseRotation = {};
        self.crane.BaseRotation.node = rotationNodeBase;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#minRot"));
        self.crane.BaseRotation.minRot = {};
        self.crane.BaseRotation.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.BaseRotation.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.BaseRotation.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#maxRot"));
        self.crane.BaseRotation.maxRot = {};
        self.crane.BaseRotation.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.BaseRotation.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.BaseRotation.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        self.crane.BaseRotation.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#rotTime"), 2)*1000;
        self.crane.BaseRotation.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#touchRotLimit"), 10));
    end;

    local componentName = "rotMainHyd";
    local rotationNodeBase = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#index"));
    if rotationNodeBase ~= nil then
        self.crane.BaseHydRotation = {};
        self.crane.BaseHydRotation.node = rotationNodeBase;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#minRot"));
        self.crane.BaseHydRotation.minRot = {};
        self.crane.BaseHydRotation.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.BaseHydRotation.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.BaseHydRotation.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#maxRot"));
        self.crane.BaseHydRotation.maxRot = {};
        self.crane.BaseHydRotation.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.BaseHydRotation.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.BaseHydRotation.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        self.crane.BaseHydRotation.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#rotTime"), 2)*1000;
        self.crane.BaseHydRotation.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#touchRotLimit"), 10));
    end;

    local componentName = "transMainHyd";
    local idx = getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#index");
    local translationPartNode = Utils.indexToObject(self.components, self.crane.BaseIndex .. idx);
    if translationPartNode ~= nil then
        self.crane.translationHyd = {};
        self.crane.translationHyd.node = translationPartNode;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#minTrans"));
        self.crane.translationHyd.minTrans = {};
        self.crane.translationHyd.minTrans[1] = Utils.getNoNil(x, 0);
        self.crane.translationHyd.minTrans[2] = Utils.getNoNil(y, 0);
        self.crane.translationHyd.minTrans[3] = Utils.getNoNil(z, 0);

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#maxTrans"));
        self.crane.translationHyd.maxTrans = {};
        self.crane.translationHyd.maxTrans[1] = Utils.getNoNil(x, 0);
        self.crane.translationHyd.maxTrans[2] = Utils.getNoNil(y, 0);
        self.crane.translationHyd.maxTrans[3] = Utils.getNoNil(z, 0);

        self.crane.translationHyd.transTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#transTime"), 2)*1000;
        self.crane.translationHyd.touchTransLimit = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#touchTransLimit"), 10);
        
    end;    
    
    local componentName = "rotMainArm";
    local rotationNodeMainArm = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#index"));
    if rotationNodeMainArm ~= nil then
        self.crane.MainArmRotation = {};
        self.crane.MainArmRotation.node = rotationNodeMainArm;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#minRot"));
        self.crane.MainArmRotation.minRot = {};
        self.crane.MainArmRotation.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.MainArmRotation.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.MainArmRotation.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#maxRot"));
        self.crane.MainArmRotation.maxRot = {};
        self.crane.MainArmRotation.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.MainArmRotation.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.MainArmRotation.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        self.crane.MainArmRotation.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#rotTime"), 2)*1000;
        self.crane.MainArmRotation.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#touchRotLimit"), 10));
    end;
    local componentName = "rotFoldHyd";
    local rotationNodeBase = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#index"));
    if rotationNodeBase ~= nil then
        self.crane.BaseHydRotation1 = {};
        self.crane.BaseHydRotation1.node = rotationNodeBase;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#minRot"));
        self.crane.BaseHydRotation1.minRot = {};
        self.crane.BaseHydRotation1.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.BaseHydRotation1.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.BaseHydRotation1.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#maxRot"));
        self.crane.BaseHydRotation1.maxRot = {};
        self.crane.BaseHydRotation1.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.BaseHydRotation1.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.BaseHydRotation1.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        self.crane.BaseHydRotation1.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#rotTime"), 2)*1000;
        self.crane.BaseHydRotation1.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#touchRotLimit"), 10));
    end;

    local componentName = "transFoldHyd";
    local idx = getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#index");
    local translationPartNode = Utils.indexToObject(self.components, self.crane.BaseIndex .. idx);
    if translationPartNode ~= nil then
        self.crane.translationHyd1 = {};
        self.crane.translationHyd1.node = translationPartNode;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#minTrans"));
        self.crane.translationHyd1.minTrans = {};
        self.crane.translationHyd1.minTrans[1] = Utils.getNoNil(x, 0);
        self.crane.translationHyd1.minTrans[2] = Utils.getNoNil(y, 0);
        self.crane.translationHyd1.minTrans[3] = Utils.getNoNil(z, 0);

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#maxTrans"));
        self.crane.translationHyd1.maxTrans = {};
        self.crane.translationHyd1.maxTrans[1] = Utils.getNoNil(x, 0);
        self.crane.translationHyd1.maxTrans[2] = Utils.getNoNil(y, 0);
        self.crane.translationHyd1.maxTrans[3] = Utils.getNoNil(z, 0);

        self.crane.translationHyd1.transTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#transTime"), 2)*1000;
        self.crane.translationHyd1.touchTransLimit = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#touchTransLimit"), 10);
        
    end;    
    
    local componentName = "rotFoldArm";
    local rotationNodeFoldArm = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#index"));
    if rotationNodeFoldArm ~= nil then
        self.crane.FoldArmRotation = {};
        self.crane.FoldArmRotation.node = rotationNodeFoldArm;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#minRot"));
        self.crane.FoldArmRotation.minRot = {};
        self.crane.FoldArmRotation.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.FoldArmRotation.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.FoldArmRotation.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#maxRot"));
        self.crane.FoldArmRotation.maxRot = {};
        self.crane.FoldArmRotation.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.FoldArmRotation.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.FoldArmRotation.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        self.crane.FoldArmRotation.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#rotTime"), 2)*1000;
        self.crane.FoldArmRotation.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#touchRotLimit"), 10));
    end;  
    
    local componentName = "rotWorkArm";
    local rotationNodeWorkArm = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#index"));
    if rotationNodeBase ~= nil then
        self.crane.WorkArmRotation = {};
        self.crane.WorkArmRotation.node = rotationNodeWorkArm;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#minRot"));
        self.crane.WorkArmRotation.minRot = {};
        self.crane.WorkArmRotation.minRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.WorkArmRotation.minRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.WorkArmRotation.minRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#maxRot"));
        self.crane.WorkArmRotation.maxRot = {};
        self.crane.WorkArmRotation.maxRot[1] = Utils.degToRad(Utils.getNoNil(x, 0));
        self.crane.WorkArmRotation.maxRot[2] = Utils.degToRad(Utils.getNoNil(y, 0));
        self.crane.WorkArmRotation.maxRot[3] = Utils.degToRad(Utils.getNoNil(z, 0));

        self.crane.WorkArmRotation.rotTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#rotTime"), 2)*1000;
        self.crane.WorkArmRotation.touchRotLimit = Utils.degToRad(Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#touchRotLimit"), 10));
    end;      

    local componentName = "transExt1";
    local translationPartNode = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#index"));
    if translationPartNode ~= nil then
        self.crane.Extension1 = {};
        self.crane.Extension1.node = translationPartNode;
        local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#minTrans"));
        self.crane.Extension1.minTrans = {};
        self.crane.Extension1.minTrans[1] = Utils.getNoNil(x, 0);
        self.crane.Extension1.minTrans[2] = Utils.getNoNil(y, 0);
        self.crane.Extension1.minTrans[3] = Utils.getNoNil(z, 0);

        x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#maxTrans"));
        self.crane.Extension1.maxTrans = {};
        self.crane.Extension1.maxTrans[1] = Utils.getNoNil(x, 0);
        self.crane.Extension1.maxTrans[2] = Utils.getNoNil(y, 0);
        self.crane.Extension1.maxTrans[3] = Utils.getNoNil(z, 0);

        self.crane.Extension1.transTime = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#transTime"), 2)*1000;
        self.crane.Extension1.touchTransLimit = Utils.getNoNil(getXMLString(xmlFile, "vehicle.".. specName .."."..componentName.."#touchTransLimit"), 10);
        
    end;    
    
hydra1SoundFile = Utils.getFilename("hydra1.wav", self.baseDirectory);
    self.crane.hydra1SoundId = createSample("HYD1_hydra1");
    loadSample(self.crane.hydra1SoundId, hydra1SoundFile, false);
    self.crane.hydra1Playing = false;
hydra1aSoundFile = Utils.getFilename("hydra1.wav", self.baseDirectory );
    self.crane.hydra1aSoundId = createSample("HYD1_hydra1a");
    loadSample(self.crane.hydra1aSoundId, hydra1aSoundFile, false);
    self.crane.hydra1aPlaying = false;
        
hydra2SoundFile = Utils.getFilename("hydra2.wav", self.baseDirectory);
    self.crane.hydra2SoundId = createSample("HYD2_hydra2");
    loadSample(self.crane.hydra2SoundId, hydra2SoundFile, false);
    self.crane.hydra2Playing = false;

hydra3SoundFile = Utils.getFilename("hydra3.wav", self.baseDirectory);
    self.crane.hydra3SoundId = createSample("HYD3_hydra3");
    loadSample(self.crane.hydra3SoundId, hydra3SoundFile, false);
    self.crane.hydra3Playing = false;

hydraRotSoundFile = Utils.getFilename("hydraRot.wav", self.baseDirectory);
    self.crane.hydraRotSoundId = createSample("HYDRot_hydraRot");
    loadSample(self.crane.hydraRotSoundId, hydraRotSoundFile, false);
    self.crane.hydraRotPlaying = false;
    
hydraRotBSoundFile = Utils.getFilename("hydraRotB.wav", self.baseDirectory );
    self.crane.hydraRotBSoundId = createSample("HYDRotB_hydraRotB");
    loadSample(self.crane.hydraRotBSoundId, hydraRotBSoundFile, false);
    self.crane.hydraRotBPlaying = false;    

support1SoundFile = Utils.getFilename("hydra2.wav", self.baseDirectory);
    self.crane.support1SoundId = createSample("SUP1_hydra1");
    loadSample(self.crane.support1SoundId, support1SoundFile, false);
    self.crane.support1Playing = false;
    
support2SoundFile = Utils.getFilename("hydra1.wav", self.baseDirectory );
    self.crane.support2SoundId = createSample("SUP2_hydra1");
    loadSample(self.crane.support2SoundId, support2SoundFile, false);
    self.crane.support2Playing = false;
    
    -- TN Crane start
    self.crane.support = {}
    self.crane.support.active = false;
    self.crane.support.left = {};
    self.crane.support.right = {};    
    self.crane.support.left.Parts = {};
    self.crane.support.right.Parts = {};
    self.crane.support.left.Parts2 = {};
    self.crane.support.right.Parts2 = {};   
    self.crane.support.MoveHorizFinished = false;
    self.crane.support.MoveVertFinished = false;
    
    self.crane.CraneSupportIn = false;
    self.crane.CraneSupportOut = false;
    self.crane.CransSupportDown = false;
    self.crane.CransSupportUp = false;
    self.crane.help = false;
    
    local numParts = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.".. specName ..".support.left#count"), 0);
    self.crane.support.left.numParts = numParts;
    for i=1, numParts do
      local partnamei = string.format("vehicle.".. specName ..".support.left.part" .. "%d", i);
      self.crane.support.left.Parts[i] = {};
      self.crane.support.left.Parts[i].index = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, partnamei .. "#index"));
      
      local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, partnamei .. "#minTrans"));
      self.crane.support.left.Parts[i].minTrans = {};
      self.crane.support.left.Parts[i].minTrans[1] = Utils.getNoNil(x, 0);
      self.crane.support.left.Parts[i].minTrans[2] = Utils.getNoNil(y, 0);
      self.crane.support.left.Parts[i].minTrans[3] = Utils.getNoNil(z, 0);
      
      x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, partnamei .. "#maxTrans"));
      self.crane.support.left.Parts[i].maxTrans = {};
      self.crane.support.left.Parts[i].maxTrans[1] = Utils.getNoNil(x, 0);
      self.crane.support.left.Parts[i].maxTrans[2] = Utils.getNoNil(y, 0);
      self.crane.support.left.Parts[i].maxTrans[3] = Utils.getNoNil(z, 0);
      self.crane.support.left.Parts[i].transTime = Utils.getNoNil(getXMLString(xmlFile,  partnamei .. "#transTime"), 2)*1000;
    end;
    
    local numParts = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.".. specName ..".support.leftDown#count"), 0);
    self.crane.support.left.numParts2 = numParts;
    for i=1, numParts do
      local partnamei = string.format("vehicle.".. specName ..".support.leftDown.part" .. "%d", i);
      self.crane.support.left.Parts2[i] = {};
      self.crane.support.left.Parts2[i].index = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, partnamei .. "#index"));
      
      local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, partnamei .. "#minTrans"));
      self.crane.support.left.Parts2[i].minTrans = {};
      self.crane.support.left.Parts2[i].minTrans[1] = Utils.getNoNil(x, 0);
      self.crane.support.left.Parts2[i].minTrans[2] = Utils.getNoNil(y, 0);
      self.crane.support.left.Parts2[i].minTrans[3] = Utils.getNoNil(z, 0);
      
      x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, partnamei .. "#maxTrans"));
      self.crane.support.left.Parts2[i].maxTrans = {};
      self.crane.support.left.Parts2[i].maxTrans[1] = Utils.getNoNil(x, 0);
      self.crane.support.left.Parts2[i].maxTrans[2] = Utils.getNoNil(y, 0);
      self.crane.support.left.Parts2[i].maxTrans[3] = Utils.getNoNil(z, 0);
      self.crane.support.left.Parts2[i].transTime = Utils.getNoNil(getXMLString(xmlFile,  partnamei .. "#transTime"), 2)*1000;
    end;
    
    local numParts = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.".. specName ..".support.right#count"), 0);
    self.crane.support.right.numParts = numParts;
    for i=1, numParts do
      local partnamei = string.format("vehicle.".. specName ..".support.right.part" .. "%d", i);
      self.crane.support.right.Parts[i] = {};
      self.crane.support.right.Parts[i].index = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, partnamei .. "#index"));
      
      local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, partnamei .. "#minTrans"));
      self.crane.support.right.Parts[i].minTrans = {};
      self.crane.support.right.Parts[i].minTrans[1] = Utils.getNoNil(x, 0);
      self.crane.support.right.Parts[i].minTrans[2] = Utils.getNoNil(y, 0);
      self.crane.support.right.Parts[i].minTrans[3] = Utils.getNoNil(z, 0);
      
      x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, partnamei .. "#maxTrans"));
      self.crane.support.right.Parts[i].maxTrans = {};
      self.crane.support.right.Parts[i].maxTrans[1] = Utils.getNoNil(x, 0);
      self.crane.support.right.Parts[i].maxTrans[2] = Utils.getNoNil(y, 0);
      self.crane.support.right.Parts[i].maxTrans[3] = Utils.getNoNil(z, 0);
      self.crane.support.right.Parts[i].transTime = Utils.getNoNil(getXMLString(xmlFile,  partnamei .. "#transTime"), 2)*1000;
    end;
    

    local numParts = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.".. specName ..".support.rightDown#count"), 0);
    self.crane.support.right.numParts2 = numParts;
    for i=1, numParts do
      local partnamei = string.format("vehicle.".. specName ..".support.rightDown.part" .. "%d", i);
      self.crane.support.right.Parts2[i] = {};
      self.crane.support.right.Parts2[i].index = Utils.indexToObject(self.components, self.crane.BaseIndex .. getXMLString(xmlFile, partnamei .. "#index"));
      
      local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, partnamei .. "#minTrans"));
      self.crane.support.right.Parts2[i].minTrans = {};
      self.crane.support.right.Parts2[i].minTrans[1] = Utils.getNoNil(x, 0);
      self.crane.support.right.Parts2[i].minTrans[2] = Utils.getNoNil(y, 0);
      self.crane.support.right.Parts2[i].minTrans[3] = Utils.getNoNil(z, 0);
      
      x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, partnamei .. "#maxTrans"));
      self.crane.support.right.Parts2[i].maxTrans = {};
      self.crane.support.right.Parts2[i].maxTrans[1] = Utils.getNoNil(x, 0);
      self.crane.support.right.Parts2[i].maxTrans[2] = Utils.getNoNil(y, 0);
      self.crane.support.right.Parts2[i].maxTrans[3] = Utils.getNoNil(z, 0);
      self.crane.support.right.Parts2[i].transTime = Utils.getNoNil(getXMLString(xmlFile,  partnamei .. "#transTime"), 2)*1000;
    end;

    -- TN Crane End
end;
      
function CraneTN:delete()
end;

function CraneTN:mouseEvent(posX, posY, isDown, isUp, button)
end;
	  
function CraneTN:keyEvent(unicode, sym, modifier, isDown)

-- TN Crane Start
  if sym == Input.KEY_home then
    self.crane.CraneSupportOut = isDown;
  end;

  if sym == Input.KEY_end then
    self.crane.CraneSupportIn = isDown;
  end;
  
  if sym == Input.KEY_pagedown then
    self.crane.CraneSupportUp = isDown;
  end;
  
  if sym == Input.KEY_pageup then
    self.crane.CraneSupportDown = isDown;
  end;
  -- TN Crane End

    	if sym == Input.KEY_KP_divide then
		self.crane.Extension1Min = isDown;
		self.crane.translationHookMin = isDown;
	end;
	if sym == Input.KEY_KP_multiply then
		self.crane.Extension1Max = isDown;
		self.crane.translationHookMax = isDown;
	end;
	if sym == Input.KEY_KP_4 then
		self.crane.MainArmRotationMin = isDown;
		self.crane.translationHydMin = isDown;
		self.crane.BaseHydRotationMin = isDown;
	end;
	if sym == Input.KEY_KP_7 then
		self.crane.MainArmRotationMax = isDown;
		self.crane.translationHydMax = isDown;
		self.crane.BaseHydRotationMax = isDown;
	end;
	if sym == Input.KEY_KP_5 then
		self.crane.FoldArmRotationMin = isDown;
		self.crane.translationHydMin1 = isDown;
		self.crane.BaseHydRotationMin1 = isDown;
	end;
	if sym == Input.KEY_KP_8 then
		self.crane.FoldArmRotationMax = isDown;
		self.crane.translationHydMax1 = isDown;
		self.crane.BaseHydRotationMax1 = isDown;
	end;	
	if sym == Input.KEY_KP_9 then
		self.crane.WorkArmRotationMin = isDown;
	end;
	if sym == Input.KEY_KP_6 then
		self.crane.WorkArmRotationMax = isDown;
	end;
	if sym == Input.KEY_KP_0 then
		self.crane.rotation5Max = isDown;
	end;
	if sym == Input.KEY_KP_2 then
		self.crane.rotation5Min = isDown;
	end;
	-- Base Rotation
	if sym == Input.KEY_j then
		self.crane.BaseRotationMax = isDown;
	end;
	if sym == Input.KEY_k then
		self.crane.BaseRotationMin = isDown;
	end;
	
	
	if sym == Input.KEY_n then
		self.crane.rotation4Max = isDown;
	end;
	if sym == Input.KEY_m then
		self.crane.rotation4Min = isDown;
	end;

	
end;

function CraneTN:update(dt)


    
-- TN Crane Start
    if self.supportFlasherOn then
	self.fl_activeLights["blitzer"] = true;
    else
	self.fl_activeLights["blitzer"] = false;
	self.fl_waitCounter["blitzer"] = 0;
    end;
    
    -- move support horizontally
    local doMove = self.crane.CraneSupportIn or self.crane.CraneSupportOut;
    if self.crane.support.left.Parts ~= nil and doMove then
	for i=1, self.crane.support.left.numParts do
	  if self.crane.support.left.Parts[i].index ~= nil then
	    local trans = {getTranslation(self.crane.support.left.Parts[i].index)};
	    local newTrans = Utils.getMovedLimitedValues(trans, self.crane.support.left.Parts[i].maxTrans, self.crane.support.left.Parts[i].minTrans, 3, self.crane.support.left.Parts[i].transTime, dt, not self.crane.CraneSupportIn);
	    setTranslation(self.crane.support.left.Parts[i].index, unpack(newTrans));
	    
	    if trans[3] < 0.00655 then
	      self.supportFlasherOn = true;
	      self.crane.isActive = true;
	    else
	      self.supportFlasherOn = false;
	      self.crane.isActive = false;
	    end;

	  end;
	end; 
        if not self.crane.support1Playing then
            playSample(self.crane.support1SoundId, 0, 1, 0);
            self.crane.support1Playing = true;
        end;
    else
        if self.crane.support1Playing then
            stopSample(self.crane.support1SoundId);
            self.crane.support1Playing = false;
        end;	
    end;
    if self.crane.support.right.Parts ~= nil and doMove then
	for i=1, self.crane.support.right.numParts do
	  if self.crane.support.right.Parts[i].index ~= nil then
	    local trans = {getTranslation(self.crane.support.right.Parts[i].index)};
	    local newTrans = Utils.getMovedLimitedValues(trans, self.crane.support.right.Parts[i].maxTrans, self.crane.support.right.Parts[i].minTrans, 3, self.crane.support.right.Parts[i].transTime, dt, not self.crane.CraneSupportIn);
	    setTranslation(self.crane.support.right.Parts[i].index, unpack(newTrans));
	  end;
	end; 
        if not self.crane.support2Playing then
            playSample(self.crane.support2SoundId, 0, 1, 0);
            self.crane.support2Playing = true;
        end;
    else
        if self.crane.support2Playing then
            stopSample(self.crane.support2SoundId);
            self.crane.support2Playing = false;
        end;
    end; 	

  if self.crane.isActive then    
    local doMove = self.crane.CraneSupportUp or self.crane.CraneSupportDown;
    if self.crane.support.left.Parts2 ~= nil and doMove then
	for i=1, self.crane.support.left.numParts2 do
	  if self.crane.support.left.Parts2[i].index ~= nil then
	    local trans = {getTranslation(self.crane.support.left.Parts2[i].index)};
	    local newTrans = Utils.getMovedLimitedValues(trans, self.crane.support.left.Parts2[i].maxTrans, self.crane.support.left.Parts2[i].minTrans, 3, self.crane.support.left.Parts2[i].transTime, dt, not self.crane.CraneSupportUp);
	    setTranslation(self.crane.support.left.Parts2[i].index, unpack(newTrans));
	  end;
	end; 
        if not self.crane.hydra3Playing then
            playSample(self.crane.hydra3SoundId, 0, 1, 0);
            self.crane.hydra3Playing = true;
        end;
    else
        if self.crane.hydra3Playing then
            stopSample(self.crane.hydra3SoundId);
            self.crane.hydra3Playing = false;
        end;	
    end;
    if self.crane.support.right.Parts2 ~= nil and doMove then
	for i=1, self.crane.support.right.numParts2 do
	  if self.crane.support.right.Parts2[i].index ~= nil then
	    local trans = {getTranslation(self.crane.support.right.Parts2[i].index)};
	    local newTrans = Utils.getMovedLimitedValues(trans, self.crane.support.right.Parts2[i].maxTrans, self.crane.support.right.Parts2[i].minTrans, 3, self.crane.support.right.Parts2[i].transTime, dt, not self.crane.CraneSupportUp);
	    setTranslation(self.crane.support.right.Parts2[i].index, unpack(newTrans));
	  end;
	end;
        if not self.crane.hydra3Playing then
            playSample(self.crane.hydra3SoundId, 0, 1, 0);
            self.crane.hydra3Playing = true;
        end;
    else
        if self.crane.hydra3Playing then
            stopSample(self.crane.hydra3SoundId);
            self.crane.hydra3Playing = false;
        end;	
    end; 
    
-- TN Crane End
    -- Base Rotation
    local doRotate = self.crane.BaseRotationMax or self.crane.BaseRotationMin 
    if self.crane.BaseRotation ~= nil and doRotate then
        local x, y, z = getRotation(self.crane.BaseRotation.node);
        local rot = {x,y,z};
        local newRot = Utils.getMovedLimitedValues(rot, self.crane.BaseRotation.maxRot, self.crane.BaseRotation.minRot, 3, self.crane.BaseRotation.rotTime, dt, not self.crane.BaseRotationMax);
        setRotation(self.crane.BaseRotation.node, unpack(newRot));
        if not self.crane.hydraRotPlaying then
            playSample(self.crane.hydraRotSoundId, 0, 1, 0);
            self.crane.hydraRotPlaying = true;
        end;
    else
        if self.crane.hydraRotPlaying then
            stopSample(self.crane.hydraRotSoundId);
            self.crane.hydraRotPlaying = false;
        end;
    end;
    
	local doTranslate = self.crane.Extension1Max or self.crane.Extension1Min 
	if self.crane.Extension1 ~= nil and doTranslate then 
		local x, y, z = getTranslation(self.crane.Extension1.node); 
		local trans = {x,y,z}; 
		local newTrans = Utils.getMovedLimitedValues(trans, self.crane.Extension1.maxTrans, self.crane.Extension1.minTrans, 3, self.crane.Extension1.transTime, dt, not self.crane.Extension1Max); 
		setTranslation(self.crane.Extension1.node, unpack(newTrans)); 
	end; 
	
	local doTranslate = self.crane.translationHookMax or self.crane.translationHookMin 
	if self.crane.translationHook ~= nil and doTranslate then 
		local x, y, z = getTranslation(self.crane.translationHook.node); 
		local trans = {x,y,z}; 
		local newTrans = Utils.getMovedLimitedValues(trans, self.crane.translationHook.maxTrans, self.crane.translationHook.minTrans, 3, self.crane.translationHook.transTime, dt, not self.crane.translationHookMax); 
		setTranslation(self.crane.translationHook.node, unpack(newTrans)); 
	end;	

	local doTranslate = self.crane.translationHydMax or self.crane.translationHydMin 
	if self.crane.translationHyd ~= nil and doTranslate then 
		local x, y, z = getTranslation(self.crane.translationHyd.node); 
		local trans = {x,y,z}; 
		local newTrans = Utils.getMovedLimitedValues(trans, self.crane.translationHyd.maxTrans, self.crane.translationHyd.minTrans, 3, self.crane.translationHyd.transTime, dt, not self.crane.translationHydMax); 
		setTranslation(self.crane.translationHyd.node, unpack(newTrans)); 
	end;
        local doRotate = self.crane.BaseHydRotationMax or self.crane.BaseHydRotationMin 
        if self.crane.MainArmRotation ~= nil and doRotate then
            local x, y, z = getRotation(self.crane.BaseHydRotation.node);
            local rot = {x,y,z};
            local newRot = Utils.getMovedLimitedValues(rot, self.crane.BaseHydRotation.maxRot, self.crane.BaseHydRotation.minRot, 3, self.crane.BaseHydRotation.rotTime, dt, not self.crane.BaseHydRotationMax);
            setRotation(self.crane.BaseHydRotation.node, unpack(newRot));	
        end;
        

        local doTranslate = self.crane.translationHydMax1 or self.crane.translationHydMin1 
	if self.crane.translationHyd1 ~= nil and doTranslate then 
		local x, y, z = getTranslation(self.crane.translationHyd1.node); 
		local trans = {x,y,z}; 
		local newTrans = Utils.getMovedLimitedValues(trans, self.crane.translationHyd1.maxTrans, self.crane.translationHyd1.minTrans, 3, self.crane.translationHyd1.transTime, dt, not self.crane.translationHydMax1); 
		setTranslation(self.crane.translationHyd1.node, unpack(newTrans)); 
	end;
        local doRotate = self.crane.BaseHydRotationMax1 or self.crane.BaseHydRotationMin1 
        if self.crane.MainArmRotation1 ~= nil and doRotate then
            local x, y, z = getRotation(self.crane.BaseHydRotation1.node);
            local rot = {x,y,z};
            local newRot = Utils.getMovedLimitedValues(rot, self.crane.BaseHydRotation1.maxRot, self.crane.BaseHydRotation1.minRot, 3, self.crane.BaseHydRotation1.rotTime, dt, not self.crane.BaseHydRotationMax1);
            setRotation(self.crane.BaseHydRotation1.node, unpack(newRot));	
        end;

    local doRotate = self.crane.MainArmRotationMax or self.crane.MainArmRotationMin 
    if self.crane.MainArmRotation ~= nil and doRotate then
        local x, y, z = getRotation(self.crane.MainArmRotation.node);
        local rot = {x,y,z};
        local newRot = Utils.getMovedLimitedValues(rot, self.crane.MainArmRotation.maxRot, self.crane.MainArmRotation.minRot, 3, self.crane.MainArmRotation.rotTime, dt, not self.crane.MainArmRotationMax);
        setRotation(self.crane.MainArmRotation.node, unpack(newRot));
        if not self.crane.hydra1Playing then
            playSample(self.crane.hydra1SoundId, 0, 1, 0);
            self.crane.hydra1Playing = true;
        end;
    else
        if self.crane.hydra1Playing then
            stopSample(self.crane.hydra1SoundId);
            self.crane.hydra1Playing = false;
        end;
    end;
	
    local doRotate = self.crane.FoldArmRotationMax or self.crane.FoldArmRotationMin 
    if self.crane.FoldArmRotation ~= nil and doRotate then
        local x, y, z = getRotation(self.crane.FoldArmRotation.node);
        local rot = {x,y,z};
        local newRot = Utils.getMovedLimitedValues(rot, self.crane.FoldArmRotation.maxRot, self.crane.FoldArmRotation.minRot, 3, self.crane.FoldArmRotation.rotTime, dt, not self.crane.FoldArmRotationMax);
        setRotation(self.crane.FoldArmRotation.node, unpack(newRot));
        if not self.crane.hydra1aPlaying then
            playSample(self.crane.hydra1aSoundId, 0, 1, 0);
            self.crane.hydra1aPlaying = true;
        end;
    else
        if self.crane.hydra1aPlaying then
            stopSample(self.crane.hydra1aSoundId);
            self.crane.hydra1aPlaying = false;
        end;
    end;
	    
	local doRotate = self.crane.WorkArmRotationMax or self.crane.WorkArmRotationMin 
	if self.crane.WorkArmRotation ~= nil and doRotate then
        local x, y, z = getRotation(self.crane.WorkArmRotation.node);
        local rot = {x,y,z};
        local newRot = Utils.getMovedLimitedValues(rot, self.crane.WorkArmRotation.maxRot, self.crane.WorkArmRotation.minRot, 3, self.crane.WorkArmRotation.rotTime, dt, not self.crane.WorkArmRotationMax);
        setRotation(self.crane.WorkArmRotation.node, unpack(newRot));
        if not self.crane.hydra2Playing then
            playSample(self.crane.hydra2SoundId, 0, 1, 0);
            self.crane.hydra2Playing = true;
        end;
    else
        if self.crane.hydra2Playing then
            stopSample(self.crane.hydra2SoundId);
            self.crane.hydra2Playing = false;
        end;
    end;
    

    
       local doRotate = self.crane.rotation4Max or self.crane.rotation4Min 
	if self.crane.rotation4 ~= nil and doRotate then
        local x, y, z = getRotation(self.crane.rotation4.node);
        local rot = {x,y,z};
        local newRot = Utils.getMovedLimitedValues(rot, self.crane.rotation4.maxRot, self.crane.rotation4.minRot, 3, self.crane.rotation4.rotTime, dt, not self.crane.rotation4Max);
        setRotation(self.crane.rotation4.node, unpack(newRot));
        if not self.crane.hydra3Playing then
            playSample(self.crane.hydra3SoundId, 0, 1, 0);
            self.crane.hydra3Playing = true;
        end;
    else
        if self.crane.hydra3Playing then
            stopSample(self.crane.hydra3SoundId);
            self.crane.hydra3Playing = false;
        end;
    end;
	
	   local doRotate = self.crane.rotation5Max or self.crane.rotation5Min 
	if self.crane.rotation5 ~= nil and doRotate then
        local x, y, z = getRotation(self.crane.rotation5.node);
        local rot = {x,y,z};
        local newRot = Utils.getMovedLimitedValues(rot, self.crane.rotation5.maxRot, self.crane.rotation5.minRot, 3, self.crane.rotation5.rotTime, dt, not self.crane.rotation5Max);
        setRotation(self.crane.rotation5.node, unpack(newRot));
        if not self.crane.hydraRotBPlaying then
            playSample(self.crane.hydraRotBSoundId, 0, 1, 0);
            self.crane.hydraRotBPlaying = true;
        end;
    else
        if self.crane.hydraRotBPlaying then
            stopSample(self.crane.hydraRotBSoundId);
            self.crane.hydraRotBPlaying = false;
        end;
    end;
  end;	
	for i, jointDesc in pairs(self.componentJoints) do
	   setJointFrame(self.componentJoints[i].jointIndex, 0, self.componentJoints[i].jointNode);
	end;
	
    if self:getIsActiveForInput() then    
    --Start of Menu
        if self.crane.isActive then
	       renderText(0.01, 0.01, 0.02, "--= FASSI HNJ aktivni =--");
        end;
        
	if self.WorklightsHelp then
		--self.helpBoxOverlay:render();
		local x1   = 0.010;
		local x2   = x1 + 0.135;
		local x3   = x1 + 0.100;
		local y    = 0.300;
		local step = 0.013;
		
		y = y - step;
		renderText(x1, y, 0.015, "--=== FASSI HNJ ===--");
		y = y - step;
		y = y - step;
	        renderText(x1, y, 0.015, "HNJ je aktivni pouze v pripade");
		y = y - step;
	        renderText(x1, y, 0.015, "alespon castecne vysunutych oper.");
		y = y - step;
		y = y - step;
	        renderText(x2, y, 0.015, "Home / End");
		renderText(x1, y, 0.015, "Opery vysunuti/zasunuti " );
		y = y - step;
		renderText(x2, y, 0.015, "PageUp / PageDown");
		renderText(x1, y, 0.015, "Opery nahoru/dolu" );
		y = y - step;
	        renderText(x2, y, 0.015, "J / K");
		renderText(x1, y, 0.015, "Otaceni" );
		y = y - step;
	        renderText(x2, y, 0.015, "Num 7 / Num 4");
		renderText(x1, y, 0.015, "Zakladni rameno" );
		y = y - step;
	        renderText(x2, y, 0.015, "Num 8 / Num 9");
		renderText(x1, y, 0.015, "Stredni rameno" );
		y = y - step;
	        renderText(x2, y, 0.015, "Num 9 / Num 6");
		renderText(x1, y, 0.015, "Pracovni rameno" );
		y = y - step;
	        renderText(x2, y, 0.015, "NUM /");
		renderText(x1, y, 0.015, "Vyloznik zasunout" );
		y = y - step;
	        renderText(x2, y, 0.015, "NUM *");
		renderText(x1, y, 0.015, "Vyloznik vysunout" );
		y = y - step;
	        renderText(x2, y, 0.015, "N / M");
		renderText(x1, y, 0.015, "Hak otaceni" );
		y = y - step;
	        renderText(x2, y, 0.015, "Num 2 / Num 0");
		renderText(x1, y, 0.015, "Hak nahoru/dolu" );
        end;
    end;    
    --End of Menu    
end;

function CraneTN:draw()
end;

function CraneTN:validateAttacherJoint(implement, jointDesc, dt)
    return true;
end;
