LUADOC - Farming Simulator 17

Printable Version

AIVehicleUtil

Description
Util class for various ai vehicle functions
Functions

driveToPoint

Description
Drive vehicle to given point
Definition
driveToPoint(table self, float dt, float acceleration, boolean allowedToDrive, boolean moveForwards, float tX, float tY, float maxSpeed, boolean doNotSteer)
Arguments
tableselfobject of vehicle to move
floatdttime since last call in ms
floataccelerationacceleration
booleanallowedToDriveallowed to drive
booleanmoveForwardsmove forwards
floattXlocal space x position
floattYlocal space y position
floatmaxSpeedspeed limit
booleandoNotSteerdo not steer
Code
28function 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
98end

driveInDirection

Description
Drive in given direction
Definition
driveInDirection(table self, float dt, float steeringAngleLimit, float acceleration, float slowAcceleration, float slowAngleLimit, boolean allowedToDrive, boolean moveForwards, float lx, float lz, float maxSpeed, float slowDownFactor)
Arguments
tableselfobject of vehicle
floatdttime since last call in ms
floatsteeringAngleLimitlimit for steering angle
floataccelerationacceleration
floatslowAccelerationslow acceleration
floatslowAngleLimitlimit of slow angle
booleanallowedToDriveallow to drive
booleanmoveForwardsmove forwards
floatlxx direction
floatlzz direction
floatmaxSpeedmax speed
floatslowDownFactorslow down factor
Code
114function 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
171end

getDriveDirection

Description
Returns drive direction
Definition
getDriveDirection(integer refNode, float x, float y, float z)
Arguments
integerrefNodeid of ref node
floatxworld x
floatyworld y
floatzworld z
Return Values
floatlxx direction
floatlzz direction
Code
181function AIVehicleUtil.getDriveDirection(refNode, x, y, z)
182 local lx, _, lz = worldToLocal(refNode, x, y, z);
183
184 local length = Utils.vector2Length(lx, lz);
185 if length > 0.00001 then
186 length = 1/length;
187 lx = lx*length;
188 lz = lz*length;
189 end
190 return lx, lz;
191end

getAverageDriveDirection

Description
Returns average drive direction between 2 given vectors
Definition
getAverageDriveDirection(integer refNode, float x, float y, float z, float x2, float y2, float z2)
Arguments
integerrefNodeid of ref node
floatxworld x 1
floatyworld y 1
floatzworld z 1
floatx2world x 2
floaty2world y 2
floatz2world z 2
Return Values
floatlxaverage x direction
floatlzaverage z direction
Code
204function AIVehicleUtil.getAverageDriveDirection(refNode, x, y, z, x2, y2, z2)
205 local lx, _, lz = worldToLocal(refNode, (x+x2)*0.5, (y+y2)*0.5, (z+z2)*0.5);
206
207 local length = Utils.vector2Length(lx, lz);
208 if length > 0.00001 then
209 lx = lx/length;
210 lz = lz/length;
211 end
212 return lx, lz, length;
213end

getIsTrailerOrTrailerLowAttached

Description
Returns if trailer or trailer low is attached
Definition
getIsTrailerOrTrailerLowAttached(table vehicle)
Arguments
tablevehiclevehicle to check
Return Values
booleanisAttachedis attached
Code
219function AIVehicleUtil.getIsTrailerOrTrailerLowAttached(vehicle)
220 for _,implement in pairs(vehicle.attachedImplements) do
221 if implement.object ~= nil then
222 local jointDesc = implement.object.attacherVehicle.attacherJoints[implement.jointDescIndex];
223 if jointDesc.jointType == AttacherJoints.JOINTTYPE_TRAILER or jointDesc.jointType == AttacherJoints.JOINTTYPE_TRAILERLOW then
224 return true;
225 end
226 if AIVehicleUtil.getIsTrailerOrTrailerLowAttached(implement.object) then
227 return true;
228 end
229 end
230 end
231 return false;
232end

getAIToolReverserDirectionNode

Description
Returns reverser direction node of attached ai tool
Definition
getAIToolReverserDirectionNode(table vehicle)
Arguments
tablevehiclevehicle to check
Return Values
integeraiToolReverserDirectionNodereverser direction node of ai tool
Code
238function AIVehicleUtil.getAIToolReverserDirectionNode(vehicle)
239 for _,implement in pairs(vehicle.attachedImplements) do
240 if implement.object ~= nil then
241 if AIVehicleUtil.getAIToolReverserDirectionNode(implement.object) ~= nil then
242 if implement.object.aiToolReverserDirectionNode ~= nil then
243 return nil;
244 end
245 end
246 if implement.object.aiToolReverserDirectionNode ~= nil then
247 return implement.object.aiToolReverserDirectionNode;
248 end
249 end
250 end
251end

getMaxToolRadius

Description
Returns max tool turn radius
Definition
getMaxToolRadius(table implement)
Arguments
tableimplementimplement to check
Return Values
floatmaxTurnRadiusmax turn radius
Code
257function 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;
328end

updateInvertLeftRightMarkers

Description
Update invertation of ai left and right markers on vehicle
Definition
updateInvertLeftRightMarkers(table rootAttacherVehicle, table vehicle)
Arguments
tablerootAttacherVehicleroot attacher vehicle
tablevehiclevehicle
Code
334function AIVehicleUtil.updateInvertLeftRightMarkers(rootAttacherVehicle, vehicle)
335 if vehicle.aiLeftMarker ~= nil and vehicle.aiRightMarker ~= nil then
336 local lX, _, _ = localToLocal(vehicle.aiLeftMarker, rootAttacherVehicle.aiVehicleDirectionNode, 0,0,0);
337 local rX, _, _ = localToLocal(vehicle.aiRightMarker, rootAttacherVehicle.aiVehicleDirectionNode, 0,0,0);
338 if rX > lX then
339 vehicle.aiLeftMarker, vehicle.aiRightMarker = vehicle.aiRightMarker, vehicle.aiLeftMarker;
340 end
341 end
342end

invertsMarkerOnTurn

Description
Returns if ai markers should be turned on turn
Definition
invertsMarkerOnTurn(table vehicle, boolean turnLeft)
Arguments
tablevehiclevehicle
booleanturnLeftturn left
Return Values

getValidityOfTurnDirections

Description
Checks fruits on left and right side of vehicle to decide the turn direction
Definition
getValidityOfTurnDirections(table vehicle, float checkFrontDistance, table turnData)
Arguments
tablevehiclevehicle to check
floatcheckFrontDistancedistance to check in front of vehicle
tableturnDataproperties for turning
Return Values
floatleftAreaPercentageleft area percentage
floatrightAreaPercentageright area percentage
Code
369function 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;
461end

getImplementList

Description
Returns a list with ai implements attached to given vehicle
Definition
getImplementList(table vehicle, table implementList)
Arguments
tablevehiclevehicle
tableimplementListlist to fill in vehicles
Code
467function 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
499end

checkImplementListForValidGround

Description
Returns if valid ground to work on is found for ai vehicle
Definition
checkImplementListForValidGround(table vehicle, float lookAheadDist, float lookAheadSize)
Arguments
tablevehiclevehicle to check
floatlookAheadDistlook a head distance
floatlookAheadSizelook a head size

getAIAreaOfVehicle

Description
Returns amount of fruit to work for ai vehicle is in given area
Definition
getAIAreaOfVehicle(table vehicle, float startWorldX, float startWorldZ, float widthWorldX, float widthWorldZ, float heightWorldX, float heightWorldZ)
Arguments
tablevehiclevehicle
floatstartWorldXstart world x
floatstartWorldZstart world z
floatwidthWorldXwidth world x
floatwidthWorldZwidth world z
floatheightWorldXheight world x
floatheightWorldZheight world z
Return Values
floatareaarea found
floattotalAreatotal area checked
Code
545function 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;
660end

getAIArea

Description
Returns amount of fruit to work is in given area
Definition
getAIArea(float startWorldX, float startWorldZ, float widthWorldX, float widthWorldZ, float heightWorldX, float heightWorldZ, table terrainDetailRequiredValueRanges, table terrainDetailProhibitValueRanges, integer requiredfruittype, integer requiredMinGrowthState, integer requiredMaxGrowthState, integer prohibitedFruitType, integer prohibitedMinGrowthState, integer prohibitedMaxGrowthState, boolean useWindrowed)
Arguments
floatstartWorldXstart world x
floatstartWorldZstart world z
floatwidthWorldXwidth world x
floatwidthWorldZwidth world z
floatheightWorldXheight world x
floatheightWorldZheight world z
tableterrainDetailRequiredValueRangesterrain detail required value ranges
tableterrainDetailProhibitValueRangesterrain detail prohibit value ranges
integerrequiredfruittyperequired fruit type
integerrequiredMinGrowthStaterequired min growth state
integerrequiredMaxGrowthStaterequired max growth state
integerprohibitedFruitTypeprohibited fruit type
integerprohibitedMinGrowthStateprohibited min growth state
integerprohibitedMaxGrowthStateprohibited max growth state
booleanuseWindroweduse windrow
Return Values
floatareaarea found
floattotalAreatotal area checked
Code
681function 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);
722end