28 | function AIVehicleUtil.driveToPoint(self, dt, acceleration, allowedToDrive, moveForwards, tX, tZ, maxSpeed, doNotSteer) |
29 | |
30 | if self.firstTimeRun then |
31 | |
32 | if allowedToDrive then |
33 | |
34 | local tX_2 = tX * 0.5; |
35 | local tZ_2 = tZ * 0.5; |
36 | |
37 | local d1X, d1Z = tZ_2, -tX_2; |
38 | if tX > 0 then |
39 | d1X, d1Z = -tZ_2, tX_2; |
40 | end |
41 | |
42 | local hit,_,f2 = Utils.getLineLineIntersection2D(tX_2,tZ_2, d1X,d1Z, 0,0, tX, 0); |
43 | |
44 | if doNotSteer == nil or not doNotSteer then |
45 | local rotTime = 0; |
46 | local radius = 0; |
47 | if hit and math.abs(f2) < 100000 then |
48 | radius = tX * f2; |
49 | rotTime = self.wheelSteeringDuration * ( math.atan(1/radius) / math.atan(1/self.maxTurningRadius) ); |
50 | end |
51 | |
52 | local targetRotTime = 0; |
53 | if rotTime >= 0 then |
54 | targetRotTime = math.min(rotTime, self.maxRotTime) |
55 | else |
56 | targetRotTime = math.max(rotTime, self.minRotTime) |
57 | end |
58 | |
59 | if targetRotTime > self.rotatedTime then |
60 | self.rotatedTime = math.min(self.rotatedTime + dt*self.aiSteeringSpeed, targetRotTime); |
61 | else |
62 | self.rotatedTime = math.max(self.rotatedTime - dt*self.aiSteeringSpeed, targetRotTime); |
63 | end |
64 | |
65 | -- adjust maxSpeed |
66 | local steerDiff = targetRotTime - self.rotatedTime; |
67 | local fac = math.abs(steerDiff) / math.max(self.maxRotTime, -self.minRotTime); |
68 | maxSpeed = maxSpeed * math.max( 0.01, 1.0 - math.pow(fac,0.25)); |
69 | end; |
70 | end |
71 | |
72 | self.motor:setSpeedLimit(maxSpeed); |
73 | if self.cruiseControl.state ~= Drivable.CRUISECONTROL_STATE_ACTIVE then |
74 | self:setCruiseControlState(Drivable.CRUISECONTROL_STATE_ACTIVE); |
75 | end |
76 | |
77 | if not allowedToDrive then |
78 | acceleration = 0; |
79 | end |
80 | if not moveForwards then |
81 | acceleration = -acceleration; |
82 | end |
83 | |
84 | if not g_currentMission.missionInfo.stopAndGoBraking then |
85 | if acceleration ~= self.nextMovingDirection then |
86 | if not self.hasStopped then |
87 | if math.abs(self.lastSpeedAcceleration) < 0.0001 and math.abs(self.lastSpeedReal) < 0.0001 and math.abs(self.lastMovedDistance) < 0.001 then |
88 | acceleration = 0; |
89 | end |
90 | end |
91 | end |
92 | end |
93 | |
94 | WheelsUtil.updateWheelsPhysics(self, dt, self.lastSpeedReal, acceleration, not allowedToDrive, self.requiredDriveMode); |
95 | |
96 | end |
97 | |
98 | end |
114 | function AIVehicleUtil.driveInDirection(self, dt, steeringAngleLimit, acceleration, slowAcceleration, slowAngleLimit, allowedToDrive, moveForwards, lx, lz, maxSpeed, slowDownFactor) |
115 | |
116 | local angle = 0; |
117 | if lx ~= nil and lz ~= nil then |
118 | local dot = lz; |
119 | angle = math.deg(math.acos(dot)); |
120 | if angle < 0 then |
121 | angle = angle+180; |
122 | end |
123 | |
124 | local turnLeft = lx > 0.00001; |
125 | if not moveForwards then |
126 | turnLeft = not turnLeft; |
127 | end |
128 | |
129 | local targetRotTime = 0; |
130 | |
131 | if turnLeft then |
132 | --rotate to the left |
133 | targetRotTime = self.maxRotTime*math.min(angle/steeringAngleLimit, 1); |
134 | else |
135 | --rotate to the right |
136 | targetRotTime = self.minRotTime*math.min(angle/steeringAngleLimit, 1); |
137 | end |
138 | |
139 | if targetRotTime > self.rotatedTime then |
140 | self.rotatedTime = math.min(self.rotatedTime + dt*self.aiSteeringSpeed, targetRotTime); |
141 | else |
142 | self.rotatedTime = math.max(self.rotatedTime - dt*self.aiSteeringSpeed, targetRotTime); |
143 | end |
144 | end |
145 | |
146 | |
147 | if self.firstTimeRun then |
148 | local acc = acceleration; |
149 | if maxSpeed ~= nil and maxSpeed ~= 0 then |
150 | if math.abs(angle) >= slowAngleLimit then |
151 | maxSpeed = maxSpeed * slowDownFactor; |
152 | end |
153 | self.motor:setSpeedLimit(maxSpeed); |
154 | |
155 | if self.cruiseControl.state ~= Drivable.CRUISECONTROL_STATE_ACTIVE then |
156 | self:setCruiseControlState(Drivable.CRUISECONTROL_STATE_ACTIVE); |
157 | end |
158 | else |
159 | if math.abs(angle) >= slowAngleLimit then |
160 | acc = slowAcceleration; |
161 | end |
162 | end |
163 | if not allowedToDrive then |
164 | acc = 0; |
165 | end |
166 | if not moveForwards then |
167 | acc = -acc; |
168 | end |
169 | WheelsUtil.updateWheelsPhysics(self, dt, self.lastSpeedReal, acc, not allowedToDrive, self.requiredDriveMode); |
170 | end |
171 | end |
257 | function AIVehicleUtil.getMaxToolRadius(implement) |
258 | |
259 | local radius = 0; |
260 | |
261 | if implement.object.aiTurningRadiusLimitation ~= nil then |
262 | if implement.object.aiTurningRadiusLimitation.radius ~= nil then |
263 | return implement.object.aiTurningRadiusLimitation.radius; |
264 | end |
265 | end |
266 | |
267 | if implement.object.aiTurningRadiusLimitation ~= nil and implement.object.aiTurningRadiusLimitation.rotationJoint ~= nil then |
268 | |
269 | local refNode = implement.object.aiTurningRadiusLimitation.rotationJoint; |
270 | -- If the refNode is any attacher joint, we always use the currently used attacher joint |
271 | for _, inputAttacherJoint in pairs(implement.object.inputAttacherJoints) do |
272 | if refNode == inputAttacherJoint.node then |
273 | refNode = implement.object.attacherJoint.node; |
274 | break; |
275 | end |
276 | end |
277 | |
278 | local rx,_,rz = localToLocal(refNode, implement.object.components[1].node, 0,0,0); |
279 | |
280 | for _,wheelIndex in pairs(implement.object.aiTurningRadiusLimitation.wheelIndices) do |
281 | |
282 | -- use first component as cosy?! |
283 | local wheel = implement.object.wheels[wheelIndex+1]; |
284 | local nx,_,nz = localToLocal(wheel.repr, implement.object.components[1].node, 0,0,0); |
285 | |
286 | local x,z = nx-rx, nz-rz; |
287 | local cx,cz = 0,0; |
288 | |
289 | -- get max rotation |
290 | local rotMax; |
291 | if refNode == implement.object.attacherJoint.node then |
292 | local jointDesc = implement.object.attacherVehicle.attacherJoints[implement.jointDescIndex]; |
293 | rotMax = math.max(jointDesc.upperRotLimit[2], jointDesc.lowerRotLimit[2]) * implement.object.attacherJoint.lowerRotLimitScale[2]; |
294 | else |
295 | for _,compJoint in pairs(implement.object.componentJoints) do |
296 | if refNode == compJoint.jointNode then |
297 | rotMax = compJoint.rotLimit[2]; |
298 | if implement.object.aiVehicleDirectionNode ~= nil then |
299 | cx,_,cz = localToLocal(implement.object.aiVehicleDirectionNode, refNode, 0,0,0); |
300 | end |
301 | break; |
302 | end |
303 | end |
304 | end |
305 | |
306 | -- calc turning radius |
307 | local x1 = x*math.cos(rotMax) - z*math.sin(rotMax); |
308 | local z1 = x*math.sin(rotMax) + z*math.cos(rotMax); |
309 | |
310 | local dx = -z1; |
311 | local dz = x1; |
312 | if wheel.steeringAxleScale ~= 0 and wheel.steeringAxleRotMax ~= 0 then |
313 | local tmpx, tmpz = dx, dz; |
314 | dx = tmpx*math.cos(wheel.steeringAxleRotMax) - tmpz*math.sin(wheel.steeringAxleRotMax); |
315 | dz = tmpx*math.sin(wheel.steeringAxleRotMax) + tmpz*math.cos(wheel.steeringAxleRotMax); |
316 | end |
317 | |
318 | local hit,f1,f2 = Utils.getLineLineIntersection2D(cx,cz, 1,0, x1,z1, dx,dz); |
319 | if hit then |
320 | radius = math.max(radius, math.abs(f1)); |
321 | end |
322 | |
323 | end |
324 | |
325 | end |
326 | |
327 | return radius; |
328 | end |
369 | function AIVehicleUtil.getValidityOfTurnDirections(vehicle, checkFrontDistance, turnData) |
370 | -- let's check the area at/around the marker which is farest behind of vehicle |
371 | |
372 | checkFrontDistance = 5; |
373 | |
374 | local leftAreaPercentage = 0; |
375 | local rightAreaPercentage = 0; |
376 | |
377 | local minZ = math.huge; |
378 | local maxZ = -math.huge; |
379 | for _,implement in pairs(vehicle.aiImplementList) do |
380 | local _,_,zl = localToLocal(implement.object.aiLeftMarker, vehicle.aiVehicleDirectionNode, 0,0,0); |
381 | local _,_,zr = localToLocal(implement.object.aiRightMarker, vehicle.aiVehicleDirectionNode, 0,0,0); |
382 | local _,_,zb = localToLocal(implement.object.aiBackMarker, vehicle.aiVehicleDirectionNode, 0,0,0); |
383 | minZ = math.min(minZ, zl, zr, zb); |
384 | maxZ = math.max(maxZ, zl, zr, zb); |
385 | end |
386 | |
387 | local sideDistance; |
388 | if turnData == nil then |
389 | local minAreaWidth = math.huge; |
390 | for _,implement in pairs(vehicle.aiImplementList) do |
391 | local lx, _, _ = localToLocal(implement.object.aiLeftMarker, vehicle.aiVehicleDirectionNode, 0,0,0); |
392 | local rx, _, _ = localToLocal(implement.object.aiRightMarker, vehicle.aiVehicleDirectionNode, 0,0,0) |
393 | minAreaWidth = math.min(minAreaWidth, math.abs(lx-rx)); |
394 | end |
395 | sideDistance = minAreaWidth; |
396 | else |
397 | sideDistance = math.abs(turnData.sideOffsetRight - turnData.sideOffsetLeft); |
398 | end |
399 | --checkFrontDistance = math.max(checkFrontDistance, maxAreaWidth); |
400 | |
401 | local dx, dz = vehicle.aiDriveDirection[1], vehicle.aiDriveDirection[2]; |
402 | local sx, sz = -dz, dx; |
403 | |
404 | for _,implement in pairs(vehicle.aiImplementList) do |
405 | local lx, ly, lz = localToLocal(implement.object.aiLeftMarker, vehicle.aiVehicleDirectionNode, 0,0,0); |
406 | local rx, ry, rz = localToLocal(implement.object.aiRightMarker, vehicle.aiVehicleDirectionNode, 0,0,0); |
407 | |
408 | local width = math.abs(lx-rx); |
409 | local length = checkFrontDistance + (maxZ - minZ) + math.max(sideDistance*1.3 + 2, checkFrontDistance); -- 1.3~tan(53) allows detecting back along a field side with angle 53 (and 2m extra compensates for some variances, or higher angles with small tools) |
410 | |
411 | lx, ly, lz = localToWorld(vehicle.aiVehicleDirectionNode, lx,ly,maxZ + checkFrontDistance); |
412 | rx, ry, rz = localToWorld(vehicle.aiVehicleDirectionNode, rx,ry,maxZ + checkFrontDistance); |
413 | |
414 | |
415 | local lSX = lx; |
416 | local lSZ = lz; |
417 | local lWX = lSX - sx * width; |
418 | local lWZ = lSZ - sz * width; |
419 | local lHX = lSX - dx * length; |
420 | local lHZ = lSZ - dz * length; |
421 | |
422 | local rSX = rx; |
423 | local rSZ = rz; |
424 | local rWX = rSX + sx * width; |
425 | local rWZ = rSZ + sz * width; |
426 | local rHX = rSX - dx * length; |
427 | local rHZ = rSZ - dz * length; |
428 | |
429 | local lArea, lTotal = AIVehicleUtil.getAIAreaOfVehicle(implement.object, lSX,lSZ, lWX,lWZ, lHX,lHZ, false); |
430 | local rArea, rTotal = AIVehicleUtil.getAIAreaOfVehicle(implement.object, rSX,rSZ, rWX,rWZ, rHX,rHZ, false); |
431 | |
432 | --leftAreaPercentage = math.max(leftAreaPercentage, (lArea / lTotal)); |
433 | --rightAreaPercentage = math.max(rightAreaPercentage, (rArea / rTotal)); |
434 | if lTotal > 0 then |
435 | leftAreaPercentage = leftAreaPercentage + (lArea / lTotal); |
436 | end |
437 | if rTotal > 0 then |
438 | rightAreaPercentage = rightAreaPercentage + (rArea / rTotal); |
439 | end |
440 | |
441 | -- just visual debuging |
442 | if AIVehicle.aiDebugRendering then |
443 | local lSY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, lSX,0,lSZ)+2; |
444 | local lWY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, lWX,0,lWZ)+2; |
445 | local lHY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, lHX,0,lHZ)+2; |
446 | local rSY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, rSX,0,rSZ)+2; |
447 | local rWY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, rWX,0,rWZ)+2; |
448 | local rHY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, rHX,0,rHZ)+2; |
449 | table.insert(vehicle.debugLines, { s={lSX,lSY,lSZ}, e={lWX,lWY,lWZ}, c={0.5, 0.5, 0.5} }); |
450 | table.insert(vehicle.debugLines, { s={lSX,lSY,lSZ}, e={lHX,lHY,lHZ}, c={0.5, 0.5, 0.5} }); |
451 | table.insert(vehicle.debugLines, { s={rSX,rSY,rSZ}, e={rWX,rWY,rWZ}, c={0.5, 0.5, 0.5} }); |
452 | table.insert(vehicle.debugLines, { s={rSX,rSY,rSZ}, e={rHX,rHY,rHZ}, c={0.5, 0.5, 0.5} }); |
453 | end |
454 | end |
455 | |
456 | leftAreaPercentage = leftAreaPercentage / table.getn(vehicle.aiImplementList); |
457 | rightAreaPercentage = rightAreaPercentage / table.getn(vehicle.aiImplementList); |
458 | --print(" ==> left/rightAreaPercentage = "..tostring(leftAreaPercentage).." / "..tostring(rightAreaPercentage)); |
459 | |
460 | return leftAreaPercentage, rightAreaPercentage; |
461 | end |
467 | function AIVehicleUtil.getImplementList(vehicle, implementList) |
468 | local validAttacherUsed = false |
469 | if vehicle.attachedImplements ~= nil then |
470 | for _,implement in pairs(vehicle.attachedImplements) do |
471 | if implement.object ~= nil then |
472 | AIVehicleUtil.getImplementList(implement.object, implementList); |
473 | if implement.object.aiLeftMarker ~= nil and implement.object.aiRightMarker ~= nil and implement.object.aiBackMarker ~= nil then |
474 | -- check if tool is attached with correct attacherJoint |
475 | if table.getn(implement.object.inputAttacherJoints) > 1 then |
476 | |
477 | local usedJointType; |
478 | local hasCutterOrImplementJoint = false |
479 | for j,inputAttacherJoint in pairs (implement.object.inputAttacherJoints) do |
480 | local joinType = inputAttacherJoint.jointType; |
481 | if implement.object.inputAttacherJointDescIndex == j then |
482 | usedJointType = jointType; |
483 | end |
484 | if jointType == AttacherJoints.JOINTTYPE_CUTTER or jointType == AttacherJoints.JOINTTYPE_CUTTERHARVESTER or jointType == AttacherJoints.JOINTTYPE_IMPLEMENT then |
485 | hasCutterOrImplementJoint = true; |
486 | end |
487 | end |
488 | -- If the tool has cutter or implement attacher joint, it needs to be attached to this attacher joint (e.g. a cutter with a trailer attacher) |
489 | if not hasCutterOrImplementJoint or (usedJointType == AttacherJoints.JOINTTYPE_CUTTER or usedJointType == AttacherJoints.JOINTTYPE_CUTTERHARVESTER or usedJointType == AttacherJoints.JOINTTYPE_IMPLEMENT) then |
490 | table.insert(implementList, implement); |
491 | end |
492 | else |
493 | table.insert(implementList, implement); |
494 | end |
495 | end |
496 | end |
497 | end |
498 | end |
499 | end |
545 | function AIVehicleUtil.getAIAreaOfVehicle(vehicle, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, ignoreProhibitedValues) |
546 | local terrainDetailRequiredValueRanges = vehicle.terrainDetailRequiredValueRanges; |
547 | local terrainDetailProhibitValueRanges = vehicle.terrainDetailProhibitValueRanges; |
548 | local requiredFruitType = vehicle.aiRequiredFruitType; |
549 | local requiredMinGrowthState = vehicle.aiRequiredMinGrowthState; |
550 | local requiredMaxGrowthState = vehicle.aiRequiredMaxGrowthState; |
551 | local requiredFruitType2 = vehicle.aiRequiredFruitType2; |
552 | local requiredMinGrowthState2 = vehicle.aiRequiredMinGrowthState2; |
553 | local requiredMaxGrowthState2 = vehicle.aiRequiredMaxGrowthState2; |
554 | local prohibitedFruitType = vehicle.aiProhibitedFruitType; |
555 | local prohibitedMinGrowthState = vehicle.aiProhibitedMinGrowthState; |
556 | local prohibitedMaxGrowthState = vehicle.aiProhibitedMaxGrowthState; |
557 | local useWindrowed = vehicle.aiUseWindrowFruitType; |
558 | local useDensityHeightMap = vehicle.aiUseDensityHeightMap; |
559 | if ignoreProhibitedValues then |
560 | terrainDetailProhibitValueRanges = {}; |
561 | prohibitedFruitType = FruitUtil.FRUITTYPE_UNKNOWN; |
562 | prohibitedMinGrowthState = nil; |
563 | prohibitedMaxGrowthState = nil; |
564 | end |
565 | |
566 | if not useDensityHeightMap then |
567 | if vehicle.fruitTypes == nil then -- no cutter |
568 | local area, totalArea = AIVehicleUtil.getAIArea(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, terrainDetailRequiredValueRanges, terrainDetailProhibitValueRanges, requiredFruitType, requiredMinGrowthState, requiredMaxGrowthState, prohibitedFruitType, prohibitedMinGrowthState, prohibitedMaxGrowthState, useWindrowed, requiredFruitType2, requiredMinGrowthState2, requiredMaxGrowthState2); |
569 | return area, totalArea; |
570 | else |
571 | -- cutter |
572 | local area, totalArea = 0, 0; |
573 | |
574 | local fruitTypesToUse = vehicle.fruitTypes; |
575 | if vehicle.currentInputFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then |
576 | fruitTypesToUse = {}; |
577 | fruitTypesToUse[vehicle.currentInputFruitType] = true; |
578 | end |
579 | for index,_ in pairs(fruitTypesToUse) do |
580 | |
581 | local desc = FruitUtil.fruitIndexToDesc[index]; |
582 | local isAllowed = true; |
583 | |
584 | if vehicle.getCombine ~= nil then |
585 | local combine = vehicle:getCombine(); |
586 | if combine ~= nil then |
587 | if vehicle.fillTypeConverters ~= nil and vehicle.fillTypeConverters[index] ~= nil then |
588 | isAllowed = combine:allowFillType(vehicle.fillTypeConverters[index].fillTypeTarget, false); |
589 | else |
590 | isAllowed = combine:allowFillType(FruitUtil.fruitTypeToFillType[index], false); |
591 | end |
592 | end |
593 | end |
594 | |
595 | if isAllowed then |
596 | requiredFruitType = index; |
597 | local minGrowthState, maxGrowthState, minGrowthState2, maxGrowthState2; |
598 | if vehicle.fruitPreparer ~= nil and vehicle.fruitPreparer.fruitType ~= nil then |
599 | minGrowthState = Utils.getNoNil(requiredMinGrowthState, desc.minPreparingGrowthState); |
600 | maxGrowthState = Utils.getNoNil(requiredMaxGrowthState, desc.maxPreparingGrowthState); |
601 | |
602 | requiredFruitType2 = requiredFruitType |
603 | minGrowthState2 = Utils.getNoNil(requiredMinGrowthState2, desc.minHarvestingGrowthState); |
604 | maxGrowthState2 = Utils.getNoNil(requiredMaxGrowthState2, desc.maxHarvestingGrowthState); |
605 | if vehicle.allowsForageGrowhtState then |
606 | minGrowthState2 = math.min(minGrowthState2, desc.minForageGrowthState); |
607 | end |
608 | else |
609 | minGrowthState = Utils.getNoNil(requiredMinGrowthState, desc.minHarvestingGrowthState); |
610 | maxGrowthState = Utils.getNoNil(requiredMaxGrowthState, desc.maxHarvestingGrowthState); |
611 | if vehicle.allowsForageGrowhtState then |
612 | minGrowthState = math.min(minGrowthState, desc.minForageGrowthState); |
613 | end |
614 | end |
615 | area, totalArea = AIVehicleUtil.getAIArea(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, terrainDetailRequiredValueRanges, terrainDetailProhibitValueRanges, requiredFruitType, minGrowthState, maxGrowthState, prohibitedFruitType, prohibitedMinGrowthState, prohibitedMaxGrowthState, useWindrowed, requiredFruitType2, minGrowthState2, maxGrowthState2); |
616 | end |
617 | |
618 | if area > 0 then |
619 | break; |
620 | end |
621 | end |
622 | return area, totalArea; |
623 | end |
624 | else |
625 | -- first check if we are on a field |
626 | local detailId = g_currentMission.terrainDetailId; |
627 | local x,z, widthX,widthZ, heightX,heightZ = Utils.getXZWidthAndHeight(nil, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ); |
628 | |
629 | setDensityCompareParams(detailId, "greater", 0); |
630 | local _,area,_ = getDensityParallelogram(detailId, x, z, widthX, widthZ, heightX, heightZ, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels); |
631 | setDensityCompareParams(detailId, "greater", -1); |
632 | if area == 0 then |
633 | return 0, 0; |
634 | end |
635 | |
636 | if requiredFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then |
637 | local fillType; |
638 | if useWindrowed then |
639 | fillType = FruitUtil.fruitTypeToWindrowFillType[requiredFruitType]; |
640 | else |
641 | fillType = FruitUtil.fruitTypeToFillType[requiredFruitType]; |
642 | end |
643 | local _, area, totalArea = TipUtil.getFillLevelAtArea(fillType, startWorldX,startWorldZ, widthWorldX,widthWorldZ, heightWorldX,heightWorldZ); |
644 | return area, totalArea; |
645 | else |
646 | if useWindrowed then |
647 | for _,desc in pairs(FruitUtil.fruitTypes) do |
648 | if desc.hasWindrow then |
649 | local fillType = FruitUtil.fruitTypeToWindrowFillType[desc.index]; |
650 | local fillLevel, area, totalArea = TipUtil.getFillLevelAtArea(fillType, startWorldX,startWorldZ, widthWorldX,widthWorldZ, heightWorldX,heightWorldZ); |
651 | if fillLevel > 0 then |
652 | return area, totalArea; |
653 | end |
654 | end |
655 | end |
656 | end |
657 | end |
658 | end |
659 | return 0, 0; |
660 | end |
681 | function AIVehicleUtil.getAIArea(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, terrainDetailRequiredValueRanges, terrainDetailProhibitValueRanges, requiredFruitType, requiredMinGrowthState, requiredMaxGrowthState, prohibitedFruitType, prohibitedMinGrowthState, prohibitedMaxGrowthState, useWindrowed, requiredFruitType2, requiredMinGrowthState2, requiredMaxGrowthState2) |
682 | |
683 | local query = g_currentMission.fieldCropsQuery; |
684 | |
685 | if requiredFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then |
686 | local ids = g_currentMission.fruits[requiredFruitType]; |
687 | if ids ~= nil and ids.id ~= 0 then |
688 | local id = ids.id; |
689 | if useWindrowed then |
690 | return 0, 1; |
691 | end |
692 | |
693 | query:addRequiredCropType(ids.id, requiredMinGrowthState+1, requiredMaxGrowthState+1, 0, g_currentMission.numFruitStateChannels, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels); |
694 | end |
695 | end |
696 | if requiredFruitType2 ~= FruitUtil.FRUITTYPE_UNKNOWN and requiredFruitType2 ~= nil then |
697 | local ids = g_currentMission.fruits[requiredFruitType2]; |
698 | if ids ~= nil and ids.id ~= 0 then |
699 | local id = ids.id; |
700 | if useWindrowed then |
701 | return 0, 1; |
702 | end |
703 | |
704 | query:addRequiredCropType(ids.id, requiredMinGrowthState2+1, requiredMaxGrowthState2+1, 0, g_currentMission.numFruitStateChannels, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels); |
705 | end |
706 | end |
707 | if prohibitedFruitType ~= FruitUtil.FRUITTYPE_UNKNOWN then |
708 | local ids = g_currentMission.fruits[prohibitedFruitType]; |
709 | if ids ~= nil and ids.id ~= 0 then |
710 | query:addProhibitedCropType(ids.id, prohibitedMinGrowthState+1, prohibitedMaxGrowthState+1, 0, g_currentMission.numFruitStateChannels, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels); |
711 | end |
712 | end |
713 | |
714 | for _,valueRange in pairs(terrainDetailRequiredValueRanges) do |
715 | query:addRequiredGroundValue(valueRange[1], valueRange[2], valueRange[3], valueRange[4]); |
716 | end |
717 | for _,valueRange in pairs(terrainDetailProhibitValueRanges) do |
718 | query:addProhibitedGroundValue(valueRange[1], valueRange[2], valueRange[3], valueRange[4]); |
719 | end |
720 | local x,z, widthX,widthZ, heightX,heightZ = Utils.getXZWidthAndHeight(nil, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ); |
721 | return query:getParallelogram(x,z, widthX,widthZ, heightX,heightZ, true); |
722 | end |