-- -- KvernelandCTC -- Specialization for KvernelandCTC mod -- -- @author Manuel Leithner -- @version 1.1 -- @date 21/10/09 KvernelandCTC = {}; function KvernelandCTC.prerequisitesPresent(specializations) return SpecializationUtil.hasSpecialization(Attachable, specializations); end; function KvernelandCTC:load(xmlFile) self.safeMode = true self.aiTerrainDetailChannel1 = g_currentMission.sowingChannel; self.aiTerrainDetailChannel2 = g_currentMission.ploughChannel; self.attacherBackup = nil; self.TurnRadiusBackup = 0; self.AiLeftMarkerBackup = self.aiLeftMarker; self.onBrakeDrums = SpecializationUtil.callSpecializationsFunction("onBrakeDrums"); local hydraulicsCount = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.hydraulics#count"), 0); self.hydraulics = {}; for i=1, hydraulicsCount do local hydraulicName = string.format("vehicle.hydraulics.hydraulic%d", i); self.hydraulics[i] = {}; self.hydraulics[i].node = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#index")); self.hydraulics[i].punch = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#punch")); self.hydraulics[i].translationPunch = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#punchFixpoint")); self.hydraulics[i].fixPoint = Utils.indexToObject(self.components, getXMLString(xmlFile, hydraulicName .. "#fixpoint")); local ax, ay, az = getWorldTranslation(self.hydraulics[i].punch); local bx, by, bz = getWorldTranslation(self.hydraulics[i].translationPunch); self.hydraulics[i].punchDistance = Utils.vector3Length(ax-bx, ay-by, az-bz); self.hydraulics[i].doScale = Utils.getNoNil(getXMLBool(xmlFile, hydraulicName .. "#doScale"), false); end; local hydraulicSound = getXMLString(xmlFile, "vehicle.ctcHydraulicSound#file"); if hydraulicSound ~= nil and hydraulicSound ~= "" then hydraulicSound = Utils.getFilename(hydraulicSound, self.baseDirectory); self.hydraulicSound = createSample("hydraulicSound"); loadSample(self.hydraulicSound, hydraulicSound, false); self.hydraulicSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.ctcHydraulicSound#pitchOffset"), 1); self.hydraulicSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.ctcHydraulicSound#pitchMax"), 2.0); self.hydraulicSoundEnabled = false; end; local cultivatorSound = getXMLString(xmlFile, "vehicle.cultivatorSound#file"); if cultivatorSound ~= nil and cultivatorSound ~= "" then cultivatorSound = Utils.getFilename(cultivatorSound, self.baseDirectory); self.cultivatorSound = createSample("cultivatorSound"); loadSample(self.cultivatorSound, cultivatorSound, false); self.cultivatorSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cultivatorSound#pitchOffset"), 0); self.cultivatorSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.cultivatorSound#volume"), 1.0); self.cultivatorSoundEnabled = false; end; self.axis = {}; self.axis.minRot = {Utils.degToRad(getXMLFloat(xmlFile, "vehicle.axis#minRot"))}; self.axis.maxRot = {Utils.degToRad(getXMLFloat(xmlFile, "vehicle.axis#maxRot"))}; self.axis.rotTime = getXMLFloat(xmlFile, "vehicle.axis#rotTime")*1000; self.drawbar = {}; self.drawbar.node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.drawbar#index")); self.drawbar.minRot = {Utils.degToRad(getXMLFloat(xmlFile, "vehicle.drawbar#minRot"))}; self.drawbar.maxRot = {Utils.degToRad(getXMLFloat(xmlFile, "vehicle.drawbar#maxRot"))}; self.drawbar.rotTime = self.axis.rotTime; self.currentTranslationLimit = {0}; self.frame = {}; self.frame.minRot = {Utils.degToRad(getXMLFloat(xmlFile, "vehicle.frame#minRot"))}; self.frame.maxRot = {Utils.degToRad(getXMLFloat(xmlFile, "vehicle.frame#maxRot"))}; self.frame.rotTime = getXMLFloat(xmlFile, "vehicle.frame#rotTime")*1000; self.groundParticleSystems = {}; Utils.loadParticleSystem(xmlFile, self.groundParticleSystems, "vehicle.leftGroundParticleSystem", self.components[5].node, false, nil, self.baseDirectory); Utils.loadParticleSystem(xmlFile, self.groundParticleSystems, "vehicle.rightGroundParticleSystem", self.components[4].node, false, nil, self.baseDirectory); self.groundParticleSystemActive = false; self.speedViolationMaxTime = 2500; self.speedViolationTimer = self.speedViolationMaxTime; self.cultivatorContactReportsActive = false; self.startActivationTimeout = 5000; self.startActivationTime = 0; self.frameIsDown = true; self.isDown = true; self.isExpanded = true; self.doJointOrientation = false; self.attacherJointCopy = nil; self.jointFixationTime = 1500; self.jointTimeLeft = self.jointFixationTime; self.isJointFixed = false; end; function KvernelandCTC:delete() Utils.deleteParticleSystem(self.groundParticleSystems); if self.cultivatorSound ~= nil then delete(self.cultivatorSound); end; if self.hydraulicSound ~= nil then delete(self.hydraulicSound); end; end; function KvernelandCTC:mouseEvent(posX, posY, isDown, isUp, button) end; function KvernelandCTC:keyEvent(unicode, sym, modifier, isDown) end; function KvernelandCTC:update(dt) if self:getIsActiveForInput() then if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then self.safeMode = not self.safeMode end; end; if self.attacherBackup == nil and self.attacherVehicle ~= nil then self.attacherBackup = self.attacherVehicle; end; if self.doJointOrientation and self.attacherVehicle ~= nil then for k,v in pairs(self.attacherVehicle.attachedImplements) do if v.object == self then local joint = self.attacherVehicle.attacherJoints[v.jointDescIndex]; self.attacherJointCopy = joint; self.rotationCopy = {joint.minRot[1], joint.minRot[2], joint.minRot[3]}; joint.minRot[1] = math.rad(-20); self.isDown = not joint.moveDown; setJointRotationLimit(self.attacherJointCopy.jointIndex, 2, true, math.rad(-50), math.rad(50)); end; end; self.doJointOrientation = false; end; if self:getIsActiveForInput() then if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) then self.isDown = not self.isDown; end; if not self.frameIsDown then if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then self.isExpanded = not self.isExpanded; end; end; end; if self:getIsActive() then self.jointTimeLeft = self.jointTimeLeft - dt; if not self.isJointFixed and self.jointTimeLeft < 0 then setJointRotationLimit(self.componentJoints[1].jointIndex, 0, true, math.rad(-7), math.rad(7)); self.isJointFixed = true; end; self.wasToFast = false; if self.attacherJointCopy ~= nil then self.attacherJointCopy.moveDown = false; self.attacherVehicle.needsLowering = false; else self.attacherVehicle.needsLowering = true; end; self.frameIsDown = false; if self.attacherJointCopy ~= nil then setJointRotationLimit(self.attacherJointCopy.jointIndex, 2, true, math.rad(-50), math.rad(50)); end; local x,y,z = getRotation(self.componentJoints[2].jointNode); if math.abs(self.axis.maxRot[1] - x) > 0.04 then self.frameIsDown = true; else self:onBrakeDrums(); end; if self.frameIsDown and self.isExpanded then local toFast = false; toFast = self:doCheckSpeedLimit() and self.lastSpeed*3600 > 30; if self.startActivationTime <= self.time and not toFast then for k, cuttingArea in pairs(self.cuttingAreas) do local x,y,z = getWorldTranslation(cuttingArea.start); local x1,y1,z1 = getWorldTranslation(cuttingArea.width); local x2,y2,z2 = getWorldTranslation(cuttingArea.height); if self.safeMode then Cultivator.updateSafeArea(x, z, x1, z1, x2, z2) else Utils.updateCultivatorArea(x, z, x1, z1, x2, z2); end; end; end; if self.cultivatorSound ~= nil and not self.cultivatorSoundEnabled and self:getIsActiveForSound() then if self.lastSpeed*3600 > 3 then playSample(self.cultivatorSound, 0, self.cultivatorSoundVolume, 0); setSamplePitch(self.cultivatorSound, self.cultivatorSoundPitchOffset); self.cultivatorSoundEnabled = true; end; end; if self.lastSpeed*3600 > 5 and not self.groundParticleSystemActive then self.groundParticleSystemActive = true; Utils.setEmittingState(self.groundParticleSystems, true); end; if self.lastSpeed*3600 < 5 and self.groundParticleSystemActive then self.groundParticleSystemActive = false; Utils.setEmittingState(self.groundParticleSystems, false); end; self.wasToFast = toFast; else self.speedViolationTimer = self.speedViolationMaxTime; if self.cultivatorSoundEnabled then stopSample(self.cultivatorSound); self.cultivatorSoundEnabled = false; end; if self.groundParticleSystemActive then self.groundParticleSystemActive = false; Utils.setEmittingState(self.groundParticleSystems, false); end; end; x,y,z = getRotation(self.componentJoints[2].jointNode); local newRot = Utils.getMovedLimitedValues({x}, self.axis.maxRot, self.axis.minRot, 1, self.axis.rotTime, dt, not self.isDown); setRotation(self.componentJoints[2].jointNode, newRot[1],y,z); x,y,z = getRotation(self.drawbar.node); newRot = Utils.getMovedLimitedValues({x}, self.drawbar.maxRot, self.drawbar.minRot, 1, self.drawbar.rotTime, dt, not self.isDown); setRotation(self.drawbar.node, newRot[1],y,z); if self.attacherJointCopy ~= nil and self.isExpanded then local newTrans = Utils.getMovedLimitedValues(self.currentTranslationLimit, {0.5}, {0}, 1, self.drawbar.rotTime, dt, self.isDown); setJointTranslationLimit(self.attacherJointCopy.jointIndex, 1, true, -newTrans[1], newTrans[1]); self.currentTranslationLimit = newTrans; end; if math.abs(newRot[1] - x) > 0.001 then setJointFrame(self.componentJoints[2].jointIndex, 1, self.componentJoints[2].jointNode); setJointFrame(self.componentJoints[1].jointIndex, 1, self.componentJoints[1].jointNode); 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; self.isAxixSoundActive = true; end; else if self.hydraulicSoundEnabled and not self.isFoldingSoundActive then stopSample(self.hydraulicSound); self.hydraulicSoundEnabled = false; self.isAxixSoundActive = false; end; end; x,y,z = getRotation(self.componentJoints[3].jointNode); newRot = Utils.getMovedLimitedValues({z}, self.frame.maxRot, self.frame.minRot, 1, self.frame.rotTime, dt, self.isExpanded); setRotation(self.componentJoints[3].jointNode, x,y,newRot[1]); setRotation(self.componentJoints[4].jointNode, x,y,-newRot[1]); if math.abs(newRot[1] - z) > 0.001 then setJointFrame(self.componentJoints[3].jointIndex, 1, self.componentJoints[3].jointNode); setJointFrame(self.componentJoints[4].jointIndex, 1, self.componentJoints[4].jointNode); 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; self.isFoldingSoundActive = true; end; else if self.hydraulicSoundEnabled and not self.isAxixSoundActive then stopSample(self.hydraulicSound); self.hydraulicSoundEnabled = false; self.isFoldingSoundActive = false; end; end; for i=1, table.getn(self.hydraulics) do local ax, ay, az = getWorldTranslation(self.hydraulics[i].node); local bx, by, bz = getWorldTranslation(self.hydraulics[i].fixPoint); local x, y, z = worldDirectionToLocal(getParent(self.hydraulics[i].node), bx-ax, by-ay, bz-az); if i == 1 then setDirection(self.hydraulics[i].node, x, y, z, 1, 1, 0); else setDirection(self.hydraulics[i].node, x, y, z, 0, 1, 0); end; local distance = Utils.vector3Length(ax-bx, ay-by, az-bz); if self.hydraulics[i].doScale then local xScale, yScale, zScale = getScale(self.hydraulics[i].punch); local newScale = yScale * (distance / self.hydraulics[i].punchDistance); setScale(self.hydraulics[i].punch, 1, 1, newScale); else if self.hydraulics[i].punch ~= nil then setTranslation(self.hydraulics[i].punch, 0, 0, distance-self.hydraulics[i].punchDistance); end; end; end; else if self.groundParticleSystemActive then self.groundParticleSystemActive = false; Utils.setEmittingState(self.groundParticleSystems, false); end; end; if self.cultivatorSoundEnabled then if self.lastSpeed*3600 < 3 then stopSample(self.cultivatorSound); self.cultivatorSoundEnabled = false; end; end; end; function KvernelandCTC:draw() if self.safeMode then g_currentMission:addHelpButtonText("switch to normal Mode", InputBinding.IMPLEMENT_EXTRA2); else g_currentMission:addHelpButtonText("switch to safe Mode", InputBinding.IMPLEMENT_EXTRA2); end; if not self.frameIsDown then if self.isExpanded then g_currentMission:addHelpButtonText(g_i18n:getText("CTC_CollapseFrame"), InputBinding.IMPLEMENT_EXTRA2); else g_currentMission:addHelpButtonText(g_i18n:getText("CTC_ExpandFrame"), InputBinding.IMPLEMENT_EXTRA2); end; end; if self.isDown then g_currentMission:addHelpButtonText(g_i18n:getText("CTC_LowerFrame"), InputBinding.LOWER_IMPLEMENT); else g_currentMission:addHelpButtonText(g_i18n:getText("CTC_LiftFrame"), InputBinding.LOWER_IMPLEMENT); end; if self.wasToFast then g_currentMission:addWarning(g_i18n:getText("Dont_drive_to_fast") .. "\n" .. string.format(g_i18n:getText("Cruise_control_levelN"), "2", InputBinding.getButtonKeyName(InputBinding.SPEED_LEVEL1)), 0.07+0.022, 0.019+0.029); end; end; function KvernelandCTC:onAttach(attacherVehicle) setJointRotationLimit(self.componentJoints[1].jointIndex, 0, true, math.rad(-60), math.rad(60)); setJointRotationLimit(self.componentJoints[1].jointIndex, 1, true, math.rad(-95), math.rad(95)); setJointRotationLimit(self.componentJoints[1].jointIndex, 2, true, math.rad(-7), math.rad(7)); self.doJointOrientation = true; self.startActivationTime = self.time + self.startActivationTimeout; self.jointTimeLeft = self.jointFixationTime; self.isJointFixed = false; self.TurnRadiusBackup = self.attacherVehicle.aiTractorTurnRadius; self.attacherVehicle.aiTractorTurnRadius = 0; end; function KvernelandCTC:onDetach() setJointRotationLimit(self.componentJoints[1].jointIndex, 0, true, 0, 0); setJointRotationLimit(self.componentJoints[1].jointIndex, 1, true, 0, 0); setJointRotationLimit(self.componentJoints[1].jointIndex, 2, true, 0, 0); if self.attacherJointCopy ~= nil then self.attacherJointCopy.minRot = self.rotationCopy; self.attacherJointCopy = nil; end; if self.deactivateOnDetach then KvernelandCTC.onDeactivate(self); else KvernelandCTC.onDeactivateSounds(self); end; self.attacherBackup.aiTractorTurnRadius = self.TurnRadiusBackup; self.attacherVehicle = self.attacherBackup; self.attacherVehicle = nil; self.attacherBackup = nil; end; function KvernelandCTC:onLeave() if self.deactivateOnLeave then KvernelandCTC.onDeactivate(self); else KvernelandCTC.onDeactivateSounds(self); end; end; function KvernelandCTC:onDeactivate() KvernelandCTC.onDeactivateSounds(self); self.speedViolationTimer = self.speedViolationMaxTime; if self.groundParticleSystemActive then self.groundParticleSystemActive = false; Utils.setEmittingState(self.groundParticleSystems, false); end; end; function KvernelandCTC:onDeactivateSounds() if self.hydraulicSoundEnabled then stopSample(self.hydraulicSound); self.hydraulicSoundEnabled = false; end; if self.cultivatorSoundEnabled then stopSample(self.cultivatorSound); self.cultivatorSoundEnabled = false; end; end; function KvernelandCTC:onBrakeDrums() if self.attachTime+2000 < self.time then for i=3, table.getn(self.wheels) do local wheel = self.wheels[i]; setWheelShapeProps(wheel.node, wheel.wheelShape, 0, 0.5, wheel.steeringAngle); end; end; end; function KvernelandCTC:aiLower() self.isDown = not self.isDown; self.isExpanded = true; end; function KvernelandCTC:aiRaise() self.isDown = not self.isDown; self.isExpanded = true; end;