288 | function AIFieldWorker:updateAIFieldWorker(dt) |
289 | local spec = self.spec_aiFieldWorker |
290 | if spec.aiDriveParams.valid then |
291 | local moveForwards = spec.aiDriveParams.moveForwards |
292 | local tX = spec.aiDriveParams.tX |
293 | local tY = spec.aiDriveParams.tY |
294 | local tZ = spec.aiDriveParams.tZ |
295 | local maxSpeed = spec.aiDriveParams.maxSpeed |
296 | |
297 | local pX, _, pZ = worldToLocal(self:getAISteeringNode(), tX,tY,tZ) |
298 | if not moveForwards and self.spec_articulatedAxis ~= nil then |
299 | if self.spec_articulatedAxis.aiRevereserNode ~= nil then |
300 | pX, _, pZ = worldToLocal(self.spec_articulatedAxis.aiRevereserNode, tX,tY,tZ) |
301 | end |
302 | end |
303 | |
304 | if not moveForwards and self:getAIReverserNode() ~= nil then |
305 | pX, _, pZ = worldToLocal(self:getAIReverserNode(), tX,tY,tZ) |
306 | end |
307 | |
308 | local acceleration = 1.0 |
309 | local isAllowedToDrive = maxSpeed ~= 0 |
310 | |
311 | AIVehicleUtil.driveToPoint(self, dt, acceleration, isAllowedToDrive, moveForwards, pX, pZ, maxSpeed) |
312 | end |
313 | end |
486 | function AIFieldWorker:updateAIFieldWorkerDriveStrategies() |
487 | local spec = self.spec_aiFieldWorker |
488 | |
489 | if #spec.aiImplementList > 0 then |
490 | if spec.driveStrategies ~= nil and #spec.driveStrategies > 0 then |
491 | for i=#spec.driveStrategies,1,-1 do |
492 | spec.driveStrategies[i]:delete() |
493 | table.remove(spec.driveStrategies, i) |
494 | end |
495 | spec.driveStrategies = {} |
496 | end |
497 | |
498 | local foundCombine = false |
499 | local foundBaler = false |
500 | local foundStonePicker = false |
501 | for _, childVehicle in pairs(self.rootVehicle.childVehicles) do -- using all vehicles since the combine can also be standalone without cutter - so no ai implement |
502 | if SpecializationUtil.hasSpecialization(Combine, childVehicle.specializations) then |
503 | foundCombine = true |
504 | end |
505 | if SpecializationUtil.hasSpecialization(Baler, childVehicle.specializations) then |
506 | foundBaler = true |
507 | end |
508 | if SpecializationUtil.hasSpecialization(StonePicker, childVehicle.specializations) then |
509 | foundStonePicker = true |
510 | end |
511 | end |
512 | |
513 | foundCombine = foundCombine or SpecializationUtil.hasSpecialization(Combine, spec.specializations) |
514 | if foundCombine then |
515 | local driveStrategyCombine = AIDriveStrategyCombine.new() |
516 | driveStrategyCombine:setAIVehicle(self) |
517 | table.insert(spec.driveStrategies, driveStrategyCombine) |
518 | end |
519 | |
520 | foundBaler = foundBaler or SpecializationUtil.hasSpecialization(Baler, spec.specializations) |
521 | if foundBaler then |
522 | local driveStrategyBaler = AIDriveStrategyBaler.new() |
523 | driveStrategyBaler:setAIVehicle(self) |
524 | table.insert(spec.driveStrategies, driveStrategyBaler) |
525 | end |
526 | |
527 | foundStonePicker = foundStonePicker or SpecializationUtil.hasSpecialization(StonePicker, spec.specializations) |
528 | if foundStonePicker then |
529 | local driveStrategyStonePicker = AIDriveStrategyStonePicker.new() |
530 | driveStrategyStonePicker:setAIVehicle(self) |
531 | table.insert(spec.driveStrategies, driveStrategyStonePicker) |
532 | end |
533 | |
534 | local driveStrategyStraight = AIDriveStrategyStraight.new() |
535 | local driveStrategyCollision = AIDriveStrategyCollision.new(driveStrategyStraight) |
536 | |
537 | driveStrategyCollision:setAIVehicle(self) |
538 | driveStrategyStraight:setAIVehicle(self) |
539 | |
540 | table.insert(spec.driveStrategies, driveStrategyCollision) |
541 | table.insert(spec.driveStrategies, driveStrategyStraight) |
542 | end |
543 | end |
549 | function AIFieldWorker:updateAIFieldWorkerLowFrequency(dt) |
550 | local spec = self.spec_aiFieldWorker |
551 | |
552 | self:clearAIDebugTexts() |
553 | self:clearAIDebugLines() |
554 | |
555 | if self:getIsFieldWorkActive() then |
556 | if spec.driveStrategies ~= nil and #spec.driveStrategies > 0 then |
557 | local vX,vY,vZ = getWorldTranslation(self:getAISteeringNode()) |
558 | |
559 | local tX, tZ, moveForwards, maxSpeedStra, maxSpeed, distanceToStop |
560 | for i=1,#spec.driveStrategies do |
561 | local driveStrategy = spec.driveStrategies[i] |
562 | tX, tZ, moveForwards, maxSpeedStra, distanceToStop = driveStrategy:getDriveData(dt, vX,vY,vZ) |
563 | maxSpeed = math.min(maxSpeedStra or math.huge, maxSpeed or math.huge) |
564 | if tX ~= nil or not self:getIsFieldWorkActive() then |
565 | break |
566 | end |
567 | end |
568 | |
569 | if tX == nil then |
570 | if self:getIsFieldWorkActive() then -- check if AI is still active, because it might have been kicked by a strategy |
571 | self:stopCurrentAIJob(AIMessageSuccessFinishedJob.new()) |
572 | end |
573 | end |
574 | |
575 | if not self:getIsFieldWorkActive() then |
576 | return |
577 | end |
578 | |
579 | local minimumSpeed = 5 |
580 | local lookAheadDistance = 5 |
581 | |
582 | -- use different settings while turning |
583 | -- so we are more pricise when stopping at end point in small turning segments |
584 | if self:getAIFieldWorkerIsTurning() then |
585 | minimumSpeed = 1.5 |
586 | lookAheadDistance = 2 |
587 | end |
588 | |
589 | local distSpeed = math.max(minimumSpeed, maxSpeed * math.min(1, distanceToStop/lookAheadDistance)) |
590 | local speedLimit, _ = self:getSpeedLimit(true) |
591 | maxSpeed = math.min(maxSpeed, distSpeed, speedLimit) |
592 | maxSpeed = math.min(maxSpeed, self:getCruiseControlMaxSpeed()) |
593 | |
594 | if VehicleDebug.state == VehicleDebug.DEBUG_AI then |
595 | self:addAIDebugText(string.format("===> maxSpeed = %.2f", maxSpeed)) |
596 | end |
597 | |
598 | local isAllowedToDrive = maxSpeed ~= 0 |
599 | |
600 | -- set drive values |
601 | spec.aiDriveParams.moveForwards = moveForwards |
602 | spec.aiDriveParams.tX = tX |
603 | spec.aiDriveParams.tY = vY |
604 | spec.aiDriveParams.tZ = tZ |
605 | spec.aiDriveParams.maxSpeed = maxSpeed |
606 | spec.aiDriveParams.valid = true |
607 | |
608 | -- worst case check: did not move but should have moved |
609 | if isAllowedToDrive and self:getLastSpeed() < 0.5 then |
610 | spec.didNotMoveTimer = spec.didNotMoveTimer - dt |
611 | else |
612 | spec.didNotMoveTimer = spec.didNotMoveTimeout |
613 | end |
614 | |
615 | if spec.didNotMoveTimer < 0 then |
616 | if self:getAIFieldWorkerIsTurning() then |
617 | if spec.lastTurnStrategy ~= nil then |
618 | spec.lastTurnStrategy:skipTurnSegment() |
619 | end |
620 | else |
621 | self:stopCurrentAIJob(AIMessageErrorBlockedByObject.new()) |
622 | end |
623 | |
624 | spec.didNotMoveTimer = spec.didNotMoveTimeout |
625 | end |
626 | end |
627 | |
628 | self:raiseAIEvent("onAIFieldWorkerActive", "onAIImplementActive") |
629 | end |
630 | end |