Script v1.7.1.0
- AI
- Animals
- Contracts
- Debug
- Economy
- Effects
- Events
- Farms
- GUI
- Handtools
- I3d
- Materials
- Misc
- Objects
- Placeables
- Player
- Shop
- Sounds
- Specializations
- Triggers
- Utils
- Vehicles
- AIVehicleUtil
- ConfigurationManager
- ConfigurationUtil
- SpecializationManager
- SpecializationUtil
- Vehicle
- VehicleCamera
- VehicleCharacter
- VehicleHudUtils
- VehicleMotor
- VehiclePlacementCallback
- VehicleTypeManager
- WheelsUtil
- WorkAreaTypeManager
- Weather
Engine v1.7.1.0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- XML
- general
Foundation Reference
AIVehicleUtil
DescriptionUtil class for various ai vehicle functionsFunctions
- driveInDirection
- driveToPoint
- getAIAreaOfVehicle
- getAIDensityHeightArea
- getAIFruitArea
- getAIToolReverserDirectionNode
- getAreaDimensions
- getAttachedImplementsAllowTurnBackward
- getAttachedImplementsBlockTurnBackward
- getAttachedImplementsMaxTurnRadius
- getAverageDriveDirection
- getDriveDirection
- getIsAreaOwned
- getMaxToolRadius
- getValidityOfTurnDirections
- updateInvertLeftRightMarkers
driveInDirection
DescriptionDrive in given directionDefinition
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
table | self | object of vehicle |
float | dt | time since last call in ms |
float | steeringAngleLimit | limit for steering angle |
float | acceleration | acceleration |
float | slowAcceleration | slow acceleration |
float | slowAngleLimit | limit of slow angle |
boolean | allowedToDrive | allow to drive |
boolean | moveForwards | move forwards |
float | lx | x direction |
float | lz | z direction |
float | maxSpeed | max speed |
float | slowDownFactor | slow down factor |
110 | function AIVehicleUtil.driveInDirection(self, dt, steeringAngleLimit, acceleration, slowAcceleration, slowAngleLimit, allowedToDrive, moveForwards, lx, lz, maxSpeed, slowDownFactor) |
111 | |
112 | local angle = 0 |
113 | if lx ~= nil and lz ~= nil then |
114 | local dot = lz |
115 | angle = math.deg(math.acos(dot)) |
116 | if angle < 0 then |
117 | angle = angle+180 |
118 | end |
119 | |
120 | local turnLeft = lx > 0.00001 |
121 | if not moveForwards then |
122 | turnLeft = not turnLeft |
123 | end |
124 | |
125 | local targetRotTime |
126 | if turnLeft then |
127 | --rotate to the left |
128 | targetRotTime = self.maxRotTime*math.min(angle/steeringAngleLimit, 1) |
129 | else |
130 | --rotate to the right |
131 | targetRotTime = self.minRotTime*math.min(angle/steeringAngleLimit, 1) |
132 | end |
133 | |
134 | if targetRotTime > self.rotatedTime then |
135 | self.rotatedTime = math.min(self.rotatedTime + dt*self:getAISteeringSpeed(), targetRotTime) |
136 | else |
137 | self.rotatedTime = math.max(self.rotatedTime - dt*self:getAISteeringSpeed(), targetRotTime) |
138 | end |
139 | end |
140 | |
141 | |
142 | if self.firstTimeRun then |
143 | local acc = acceleration |
144 | if maxSpeed ~= nil and maxSpeed ~= 0 then |
145 | if math.abs(angle) >= slowAngleLimit then |
146 | maxSpeed = maxSpeed * slowDownFactor |
147 | end |
148 | self.motor:setSpeedLimit(maxSpeed) |
149 | |
150 | if self.cruiseControl.state ~= Drivable.CRUISECONTROL_STATE_ACTIVE then |
151 | self:setCruiseControlState(Drivable.CRUISECONTROL_STATE_ACTIVE) |
152 | end |
153 | else |
154 | if math.abs(angle) >= slowAngleLimit then |
155 | acc = slowAcceleration |
156 | end |
157 | end |
158 | if not allowedToDrive then |
159 | acc = 0 |
160 | end |
161 | if not moveForwards then |
162 | acc = -acc |
163 | end |
164 | WheelsUtil.updateWheelsPhysics(self, dt, self.lastSpeedReal*self.movingDirection, acc, not allowedToDrive, true) |
165 | end |
166 | end |
driveToPoint
DescriptionDrive vehicle to given pointDefinition
driveToPoint(table self, float dt, float acceleration, boolean allowedToDrive, boolean moveForwards, float tX, float tY, float maxSpeed, boolean doNotSteer)Arguments
table | self | object of vehicle to move |
float | dt | time since last call in ms |
float | acceleration | acceleration |
boolean | allowedToDrive | allowed to drive |
boolean | moveForwards | move forwards |
float | tX | local space x position |
float | tY | local space y position |
float | maxSpeed | speed limit |
boolean | doNotSteer | do not steer |
27 | function AIVehicleUtil.driveToPoint(self, dt, acceleration, allowedToDrive, moveForwards, tX, tZ, maxSpeed, doNotSteer) |
28 | |
29 | if self.firstTimeRun then |
30 | |
31 | if allowedToDrive then |
32 | |
33 | local tX_2 = tX * 0.5 |
34 | local tZ_2 = tZ * 0.5 |
35 | |
36 | local d1X, d1Z = tZ_2, -tX_2 |
37 | if tX > 0 then |
38 | d1X, d1Z = -tZ_2, tX_2 |
39 | end |
40 | |
41 | local hit,_,f2 = MathUtil.getLineLineIntersection2D(tX_2,tZ_2, d1X,d1Z, 0,0, tX, 0) |
42 | |
43 | if doNotSteer == nil or not doNotSteer then |
44 | local rotTime = 0 |
45 | if hit and math.abs(f2) < 100000 then |
46 | local radius = tX * f2 |
47 | rotTime = self.wheelSteeringDuration * ( math.atan(1/radius) / math.atan(1/self.maxTurningRadius) ) |
48 | end |
49 | |
50 | local targetRotTime |
51 | if rotTime >= 0 then |
52 | targetRotTime = math.min(rotTime, self.maxRotTime) |
53 | else |
54 | targetRotTime = math.max(rotTime, self.minRotTime) |
55 | end |
56 | |
57 | if targetRotTime > self.rotatedTime then |
58 | self.rotatedTime = math.min(self.rotatedTime + dt*self:getAISteeringSpeed(), targetRotTime) |
59 | else |
60 | self.rotatedTime = math.max(self.rotatedTime - dt*self:getAISteeringSpeed(), targetRotTime) |
61 | end |
62 | |
63 | -- adjust maxSpeed |
64 | local steerDiff = targetRotTime - self.rotatedTime |
65 | local fac = math.abs(steerDiff) / math.max(self.maxRotTime, -self.minRotTime) |
66 | local speedReduction = 1.0 - math.pow(fac, 0.25) |
67 | |
68 | -- if the speed is decreased to less than 1.5km/h we do not accelrate anymore |
69 | if maxSpeed * speedReduction < 1.5 then |
70 | acceleration = 0 |
71 | speedReduction = 1.5 / maxSpeed |
72 | end |
73 | |
74 | maxSpeed = maxSpeed * speedReduction |
75 | end |
76 | end |
77 | |
78 | self:getMotor():setSpeedLimit(math.min(maxSpeed, self:getCruiseControlSpeed())) |
79 | if self:getCruiseControlState() ~= Drivable.CRUISECONTROL_STATE_ACTIVE then |
80 | self:setCruiseControlState(Drivable.CRUISECONTROL_STATE_ACTIVE) |
81 | end |
82 | |
83 | if not allowedToDrive then |
84 | acceleration = 0 |
85 | end |
86 | if not moveForwards then |
87 | acceleration = -acceleration |
88 | end |
89 | |
90 | WheelsUtil.updateWheelsPhysics(self, dt, self.lastSpeedReal*self.movingDirection, acceleration, not allowedToDrive, true) |
91 | |
92 | end |
93 | |
94 | end |
getAIAreaOfVehicle
DescriptionReturns amount of fruit to work for ai vehicle is in given areaDefinition
getAIAreaOfVehicle(table vehicle, float startWorldX, float startWorldZ, float widthWorldX, float widthWorldZ, float heightWorldX, float heightWorldZ)Arguments
table | vehicle | vehicle |
float | startWorldX | start world x |
float | startWorldZ | start world z |
float | widthWorldX | width world x |
float | widthWorldZ | width world z |
float | heightWorldX | height world x |
float | heightWorldZ | height world z |
float | area | area found |
float | totalArea | total area checked |
599 | function AIVehicleUtil.getAIAreaOfVehicle(vehicle, startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ) |
600 | local useDensityHeightMap, useWindrowFruitType = vehicle:getAIFruitExtraRequirements() |
601 | |
602 | if not useDensityHeightMap then |
603 | local query = vehicle:getFieldCropsQuery() |
604 | return AIVehicleUtil.getAIFruitArea(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, query) |
605 | else |
606 | local fruitRequirements = vehicle:getAIFruitRequirements() |
607 | return AIVehicleUtil.getAIDensityHeightArea(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, fruitRequirements, useWindrowFruitType) |
608 | end |
609 | end |
getAIDensityHeightArea
DescriptionReturns amount of density height to work is in given areaDefinition
getAIDensityHeightArea(float startWorldX, float startWorldZ, float widthWorldX, float widthWorldZ, float heightWorldX, float heightWorldZ, table fruitRequirements, boolean useWindrowed)Arguments
float | startWorldX | start world x |
float | startWorldZ | start world z |
float | widthWorldX | width world x |
float | widthWorldZ | width world z |
float | heightWorldX | height world x |
float | heightWorldZ | height world z |
table | fruitRequirements | table with all required fruit types |
boolean | useWindrowed | use windrow |
float | area | area found |
float | totalArea | total area checked |
639 | function AIVehicleUtil.getAIDensityHeightArea(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, fruitRequirements, useWindrowed) |
640 | -- first check if we are on a field |
641 | |
642 | local data = g_currentMission.densityMapModifiers.getAIDensityHeightArea |
643 | local modifier = data.modifier |
644 | local filter = data.filter |
645 | |
646 | modifier:setParallelogramWorldCoords(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, "ppp") |
647 | filter:setValueCompareParams("greater", 0) |
648 | |
649 | local _, detailArea, _ = modifier:executeGet(filter) |
650 | if detailArea == 0 then |
651 | return 0, 0 |
652 | end |
653 | |
654 | local retArea, retTotalArea = 0, 0 |
655 | for _, fruitRequirement in pairs(fruitRequirements) do |
656 | if fruitRequirement.fruitType ~= FruitType.UNKNOWN then |
657 | local fillType |
658 | if useWindrowed then |
659 | fillType = g_fruitTypeManager:getWindrowFillTypeIndexByFruitTypeIndex(fruitRequirement.fruitType) |
660 | else |
661 | fillType = g_fruitTypeManager:getFruitTypeIndexByFillTypeIndex(fruitRequirement.fruitType) |
662 | end |
663 | local _, area, totalArea = DensityMapHeightUtil.getFillLevelAtArea(fillType, startWorldX,startWorldZ, widthWorldX,widthWorldZ, heightWorldX,heightWorldZ) |
664 | retArea, retTotalArea = retArea+area, totalArea |
665 | end |
666 | end |
667 | |
668 | return retArea, retTotalArea |
669 | end |
getAIFruitArea
DescriptionReturns amount of fruit to work is in given areaDefinition
getAIFruitArea(float startWorldX, float startWorldZ, float widthWorldX, float widthWorldZ, float heightWorldX, float heightWorldZ, table query)Arguments
float | startWorldX | start world x |
float | startWorldZ | start world z |
float | widthWorldX | width world x |
float | widthWorldZ | width world z |
float | heightWorldX | height world x |
float | heightWorldZ | height world z |
table | query | field crops query of vehicle |
float | area | area found |
float | totalArea | total area checked |
622 | function AIVehicleUtil.getAIFruitArea(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ, query) |
623 | local x,z, widthX,widthZ, heightX,heightZ = MathUtil.getXZWidthAndHeight(startWorldX, startWorldZ, widthWorldX, widthWorldZ, heightWorldX, heightWorldZ) |
624 | return query:getParallelogram(x,z, widthX,widthZ, heightX,heightZ, false) |
625 | end |
getAIToolReverserDirectionNode
DescriptionReturns reverser direction node of attached ai toolDefinition
getAIToolReverserDirectionNode(table vehicle)Arguments
table | vehicle | vehicle to check |
integer | aiToolReverserDirectionNode | reverser direction node of ai tool |
302 | function AIVehicleUtil.getAIToolReverserDirectionNode(vehicle) |
303 | for _, implement in pairs(vehicle:getAttachedImplements()) do |
304 | if implement.object ~= nil then |
305 | local reverserNode = implement.object:getAIToolReverserDirectionNode() |
306 | |
307 | local attachedReverserNode = AIVehicleUtil.getAIToolReverserDirectionNode(implement.object) |
308 | reverserNode = reverserNode or attachedReverserNode |
309 | |
310 | if reverserNode ~= nil then |
311 | return reverserNode |
312 | end |
313 | end |
314 | end |
315 | end |
getAreaDimensions
DescriptionDefinitiongetAreaDimensions()Code
553 | function AIVehicleUtil.getAreaDimensions(directionX, directionZ, leftNode, rightNode, xOffset, zOffset, areaSize, invertXOffset) |
554 | local xOffsetLeft, xOffsetRight = xOffset, xOffset |
555 | if invertXOffset == nil or invertXOffset then |
556 | xOffsetLeft = -xOffsetLeft |
557 | end |
558 | local lX, _, lZ = localToWorld(leftNode, xOffsetLeft, 0, zOffset) |
559 | local rX, _, rZ = localToWorld(rightNode, xOffsetRight, 0, zOffset) |
560 | |
561 | local sX = lX - (0.5 * directionX) |
562 | local sZ = lZ - (0.5 * directionZ) |
563 | local wX = rX - (0.5 * directionX) |
564 | local wZ = rZ - (0.5 * directionZ) |
565 | local hX = lX + (areaSize * directionX) |
566 | local hZ = lZ + (areaSize * directionZ) |
567 | |
568 | return sX, sZ, wX, wZ, hX, hZ |
569 | end |
getAttachedImplementsAllowTurnBackward
DescriptionReturns if trailer or trailer low is attachedDefinition
getAttachedImplementsAllowTurnBackward(table vehicle)Arguments
table | vehicle | vehicle to check |
boolean | isAttached | is attached |
214 | function AIVehicleUtil.getAttachedImplementsAllowTurnBackward(vehicle) |
215 | if vehicle.getAIAllowTurnBackward ~= nil then |
216 | if not vehicle:getAIAllowTurnBackward() then |
217 | return false |
218 | end |
219 | end |
220 | |
221 | if vehicle.getAttachedImplements ~= nil then |
222 | for _, implement in pairs(vehicle:getAttachedImplements()) do |
223 | local object = implement.object |
224 | if object ~= nil then |
225 | if object.getAIAllowTurnBackward ~= nil then |
226 | if not object:getAIAllowTurnBackward() then |
227 | return false |
228 | end |
229 | end |
230 | |
231 | if not AIVehicleUtil.getAttachedImplementsAllowTurnBackward(object) then |
232 | return false |
233 | end |
234 | end |
235 | end |
236 | end |
237 | |
238 | return true |
239 | end |
getAttachedImplementsBlockTurnBackward
DescriptionReturns if one of the attached implements blocks reverse drivingDefinition
getAttachedImplementsBlockTurnBackward(table vehicle)Arguments
table | vehicle | vehicle to check |
boolean | doesBlock | implement does block |
245 | function AIVehicleUtil.getAttachedImplementsBlockTurnBackward(vehicle) |
246 | if vehicle.getAIBlockTurnBackward ~= nil then |
247 | if vehicle:getAIBlockTurnBackward() then |
248 | return true |
249 | end |
250 | end |
251 | |
252 | if vehicle.getAttachedImplements ~= nil then |
253 | for _, implement in pairs(vehicle:getAttachedImplements()) do |
254 | local object = implement.object |
255 | if object ~= nil then |
256 | if object.getAIBlockTurnBackward ~= nil then |
257 | if object:getAIBlockTurnBackward() then |
258 | return true |
259 | end |
260 | end |
261 | |
262 | if AIVehicleUtil.getAttachedImplementsBlockTurnBackward(object) then |
263 | return true |
264 | end |
265 | end |
266 | end |
267 | end |
268 | |
269 | return false |
270 | end |
getAttachedImplementsMaxTurnRadius
DescriptionDefinitiongetAttachedImplementsMaxTurnRadius()Code
274 | function AIVehicleUtil.getAttachedImplementsMaxTurnRadius(vehicle) |
275 | local maxRadius = -1 |
276 | if vehicle.getAttachedImplements ~= nil then |
277 | for _, implement in pairs(vehicle:getAttachedImplements()) do |
278 | local object = implement.object |
279 | if object ~= nil then |
280 | if object.getAITurnRadiusLimitation ~= nil then |
281 | local radius = object:getAITurnRadiusLimitation() |
282 | if radius ~= nil and radius > maxRadius then |
283 | maxRadius = radius |
284 | end |
285 | end |
286 | |
287 | local radius = AIVehicleUtil.getAttachedImplementsMaxTurnRadius(object) |
288 | if radius > maxRadius then |
289 | maxRadius = radius |
290 | end |
291 | end |
292 | end |
293 | end |
294 | |
295 | return maxRadius |
296 | end |
getAverageDriveDirection
DescriptionReturns average drive direction between 2 given vectorsDefinition
getAverageDriveDirection(integer refNode, float x, float y, float z, float x2, float y2, float z2)Arguments
integer | refNode | id of ref node |
float | x | world x 1 |
float | y | world y 1 |
float | z | world z 1 |
float | x2 | world x 2 |
float | y2 | world y 2 |
float | z2 | world z 2 |
float | lx | average x direction |
float | lz | average z direction |
199 | function AIVehicleUtil.getAverageDriveDirection(refNode, x, y, z, x2, y2, z2) |
200 | local lx, _, lz = worldToLocal(refNode, (x+x2)*0.5, (y+y2)*0.5, (z+z2)*0.5) |
201 | |
202 | local length = MathUtil.vector2Length(lx, lz) |
203 | if length > 0.00001 then |
204 | lx = lx/length |
205 | lz = lz/length |
206 | end |
207 | return lx, lz, length |
208 | end |
getDriveDirection
DescriptionReturns drive directionDefinition
getDriveDirection(integer refNode, float x, float y, float z)Arguments
integer | refNode | id of ref node |
float | x | world x |
float | y | world y |
float | z | world z |
float | lx | x direction |
float | lz | z direction |
176 | function AIVehicleUtil.getDriveDirection(refNode, x, y, z) |
177 | local lx, _, lz = worldToLocal(refNode, x, y, z) |
178 | |
179 | local length = MathUtil.vector2Length(lx, lz) |
180 | if length > 0.00001 then |
181 | length = 1/length |
182 | lx = lx*length |
183 | lz = lz*length |
184 | end |
185 | return lx, lz |
186 | end |
getIsAreaOwned
DescriptionDefinitiongetIsAreaOwned()Code
573 | function AIVehicleUtil.getIsAreaOwned(vehicle, sX, sZ, wX, wZ, hX, hZ) |
574 | local farmId = vehicle.spec_aiVehicle.startedFarmId |
575 | local centerX, centerZ = (sX + wX)*0.5, (sZ + wZ)*0.5 |
576 | if g_farmlandManager:getIsOwnedByFarmAtWorldPosition(farmId, centerX, centerZ) then |
577 | return true |
578 | end |
579 | |
580 | if g_missionManager:getIsMissionWorkAllowed(farmId, centerX, centerZ, nil) then |
581 | return true |
582 | end |
583 | |
584 | return false |
585 | end |
getMaxToolRadius
DescriptionReturns max tool turn radiusDefinition
getMaxToolRadius(table implement)Arguments
table | implement | implement to check |
float | maxTurnRadius | max turn radius |
321 | function AIVehicleUtil.getMaxToolRadius(implement) |
322 | local radius = 0 |
323 | |
324 | local _, rotationNode, wheels = implement.object:getAITurnRadiusLimitation() |
325 | |
326 | -- collect the max manual defined turn radius of all vehicles, not only valid ai implements |
327 | local rootVehicle = implement.object:getRootVehicle() |
328 | local retRadius = AIVehicleUtil.getAttachedImplementsMaxTurnRadius(rootVehicle) |
329 | |
330 | if retRadius ~= -1 then |
331 | radius = retRadius |
332 | end |
333 | |
334 | if rotationNode then |
335 | local activeInputAttacherJoint = implement.object:getActiveInputAttacherJoint() |
336 | local refNode = rotationNode |
337 | |
338 | -- If the refNode is any attacher joint, we always use the currently used attacher joint |
339 | for _, inputAttacherJoint in pairs(implement.object:getInputAttacherJoints()) do |
340 | if refNode == inputAttacherJoint.node then |
341 | refNode = activeInputAttacherJoint.node |
342 | break |
343 | end |
344 | end |
345 | |
346 | local rx,_,rz = localToLocal(refNode, implement.object.components[1].node, 0,0,0) |
347 | |
348 | for _, wheel in pairs(wheels) do |
349 | local nx,_,nz = localToLocal(wheel.repr, implement.object.components[1].node, 0,0,0) |
350 | |
351 | local x,z = nx-rx, nz-rz |
352 | local cx,cz = 0,0 |
353 | |
354 | -- get max rotation |
355 | local rotMax |
356 | if refNode == activeInputAttacherJoint.node then |
357 | local attacherVehicle = implement.object:getAttacherVehicle() |
358 | local jointDesc = attacherVehicle:getAttacherJointDescFromObject(implement.object) |
359 | rotMax = math.max(jointDesc.upperRotLimit[2], jointDesc.lowerRotLimit[2]) * activeInputAttacherJoint.lowerRotLimitScale[2] |
360 | else |
361 | for _,compJoint in pairs(implement.object.componentJoints) do |
362 | if refNode == compJoint.jointNode then |
363 | rotMax = compJoint.rotLimit[2] |
364 | break |
365 | end |
366 | end |
367 | end |
368 | |
369 | -- calc turning radius |
370 | local x1 = x*math.cos(rotMax) - z*math.sin(rotMax) |
371 | local z1 = x*math.sin(rotMax) + z*math.cos(rotMax) |
372 | |
373 | local dx = -z1 |
374 | local dz = x1 |
375 | if wheel.steeringAxleScale ~= 0 and wheel.steeringAxleRotMax ~= 0 then |
376 | local tmpx, tmpz = dx, dz |
377 | dx = tmpx*math.cos(wheel.steeringAxleRotMax) - tmpz*math.sin(wheel.steeringAxleRotMax) |
378 | dz = tmpx*math.sin(wheel.steeringAxleRotMax) + tmpz*math.cos(wheel.steeringAxleRotMax) |
379 | end |
380 | |
381 | local hit,f1,_ = MathUtil.getLineLineIntersection2D(cx,cz, 1,0, x1,z1, dx,dz) |
382 | if hit then |
383 | radius = math.max(radius, math.abs(f1)) |
384 | end |
385 | end |
386 | end |
387 | |
388 | return radius |
389 | end |
getValidityOfTurnDirections
DescriptionChecks fruits on left and right side of vehicle to decide the turn directionDefinition
getValidityOfTurnDirections(table vehicle, float checkFrontDistance, table turnData)Arguments
table | vehicle | vehicle to check |
float | checkFrontDistance | distance to check in front of vehicle |
table | turnData | properties for turning |
float | leftAreaPercentage | left area percentage |
float | rightAreaPercentage | right area percentage |
416 | function AIVehicleUtil.getValidityOfTurnDirections(vehicle, turnData) |
417 | -- let's check the area at/around the marker which is farest behind of vehicle |
418 | local directionNode = vehicle:getAIVehicleDirectionNode() |
419 | local attachedAIImplements = vehicle:getAttachedAIImplements() |
420 | local checkFrontDistance = 5 |
421 | |
422 | local leftAreaPercentage = 0 |
423 | local rightAreaPercentage = 0 |
424 | |
425 | local minZ = math.huge |
426 | local maxZ = -math.huge |
427 | for _,implement in pairs(attachedAIImplements) do |
428 | local leftMarker, rightMarker, backMarker = implement.object:getAIMarkers() |
429 | |
430 | local _,_,zl = localToLocal(leftMarker, directionNode, 0,0,0) |
431 | local _,_,zr = localToLocal(rightMarker, directionNode, 0,0,0) |
432 | local _,_,zb = localToLocal(backMarker, directionNode, 0,0,0) |
433 | |
434 | minZ = math.min(minZ, zl, zr, zb) |
435 | maxZ = math.max(maxZ, zl, zr, zb) |
436 | end |
437 | |
438 | local sideDistance |
439 | if turnData == nil then |
440 | local minAreaWidth = math.huge |
441 | for _,implement in pairs(attachedAIImplements) do |
442 | local leftMarker, rightMarker, _ = implement.object:getAIMarkers() |
443 | |
444 | local lx, _, _ = localToLocal(leftMarker, directionNode, 0,0,0) |
445 | local rx, _, _ = localToLocal(rightMarker, directionNode, 0,0,0) |
446 | minAreaWidth = math.min(minAreaWidth, math.abs(lx-rx)) |
447 | end |
448 | sideDistance = minAreaWidth |
449 | else |
450 | sideDistance = math.abs(turnData.sideOffsetRight - turnData.sideOffsetLeft) |
451 | end |
452 | |
453 | local dx, dz = vehicle.aiDriveDirection[1], vehicle.aiDriveDirection[2] |
454 | local sx, sz = -dz, dx |
455 | |
456 | for _,implement in pairs(attachedAIImplements) do |
457 | local leftMarker, rightMarker, _ = implement.object:getAIMarkers() |
458 | |
459 | local lx, ly, lz = localToLocal(leftMarker, directionNode, 0,0,0) |
460 | local rx, ry, rz = localToLocal(rightMarker, directionNode, 0,0,0) |
461 | |
462 | local width = math.abs(lx-rx) |
463 | 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) |
464 | |
465 | lx, _, lz = localToWorld(directionNode, lx,ly,maxZ + checkFrontDistance) |
466 | rx, _, rz = localToWorld(directionNode, rx,ry,maxZ + checkFrontDistance) |
467 | |
468 | local lSX = lx |
469 | local lSZ = lz |
470 | local lWX = lSX - sx * width |
471 | local lWZ = lSZ - sz * width |
472 | local lHX = lSX - dx * length |
473 | local lHZ = lSZ - dz * length |
474 | |
475 | local rSX = rx |
476 | local rSZ = rz |
477 | local rWX = rSX + sx * width |
478 | local rWZ = rSZ + sz * width |
479 | local rHX = rSX - dx * length |
480 | local rHZ = rSZ - dz * length |
481 | |
482 | local lArea, lTotal = AIVehicleUtil.getAIAreaOfVehicle(implement.object, lSX,lSZ, lWX,lWZ, lHX,lHZ, false) |
483 | local rArea, rTotal = AIVehicleUtil.getAIAreaOfVehicle(implement.object, rSX,rSZ, rWX,rWZ, rHX,rHZ, false) |
484 | |
485 | if lTotal > 0 then |
486 | leftAreaPercentage = leftAreaPercentage + (lArea / lTotal) |
487 | end |
488 | if rTotal > 0 then |
489 | rightAreaPercentage = rightAreaPercentage + (rArea / rTotal) |
490 | end |
491 | |
492 | -- just visual debuging |
493 | if VehicleDebug.state == VehicleDebug.DEBUG_AI then |
494 | local lSY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, lSX,0,lSZ)+2 |
495 | local lWY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, lWX,0,lWZ)+2 |
496 | local lHY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, lHX,0,lHZ)+2 |
497 | local rSY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, rSX,0,rSZ)+2 |
498 | local rWY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, rWX,0,rWZ)+2 |
499 | local rHY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, rHX,0,rHZ)+2 |
500 | |
501 | vehicle:addAIDebugLine({lSX,lSY,lSZ}, {lWX,lWY,lWZ}, {0.5, 0.5, 0.5}) |
502 | vehicle:addAIDebugLine({lSX,lSY,lSZ}, {lHX,lHY,lHZ}, {0.5, 0.5, 0.5}) |
503 | vehicle:addAIDebugLine({rSX,rSY,rSZ}, {rWX,rWY,rWZ}, {0.5, 0.5, 0.5}) |
504 | vehicle:addAIDebugLine({rSX,rSY,rSZ}, {rHX,rHY,rHZ}, {0.5, 0.5, 0.5}) |
505 | end |
506 | end |
507 | |
508 | leftAreaPercentage = leftAreaPercentage / table.getn(attachedAIImplements) |
509 | rightAreaPercentage = rightAreaPercentage / table.getn(attachedAIImplements) |
510 | |
511 | return leftAreaPercentage, rightAreaPercentage |
512 | end |
updateInvertLeftRightMarkers
DescriptionUpdate invertation of ai left and right markers on vehicleDefinition
updateInvertLeftRightMarkers(table rootAttacherVehicle, table vehicle)Arguments
table | rootAttacherVehicle | root attacher vehicle |
table | vehicle | vehicle |
395 | function AIVehicleUtil.updateInvertLeftRightMarkers(rootAttacherVehicle, vehicle) |
396 | if vehicle.getAIMarkers ~= nil then |
397 | local leftMarker, rightMarker, _ = vehicle:getAIMarkers() |
398 | if leftMarker ~= nil and rightMarker ~= nil then |
399 | local lX, _, _ = localToLocal(leftMarker, rootAttacherVehicle:getAIVehicleDirectionNode(), 0,0,0) |
400 | local rX, _, _ = localToLocal(rightMarker, rootAttacherVehicle:getAIVehicleDirectionNode(), 0,0,0) |
401 | |
402 | if rX > lX then |
403 | vehicle:setAIMarkersInverted() |
404 | end |
405 | end |
406 | end |
407 | end |