412 | function RidgeMarker:getIsWorkAreaActive(superFunc, workArea) |
413 | |
414 | if workArea.type == WorkAreaType.RIDGEMARKER then |
415 | local spec = self.spec_ridgeMarker |
416 | local ridgeMarker = spec.workAreaToRidgeMarker[workArea.index] |
417 | |
418 | if ridgeMarker ~= nil then |
419 | local animTime = self:getAnimationTime(ridgeMarker.animName) |
420 | if animTime > ridgeMarker.maxWorkLimit or animTime < ridgeMarker.minWorkLimit then |
421 | return false |
422 | end |
423 | |
424 | if spec.onlyActiveWhenLowered and not self:getIsLowered(false) then |
425 | return false |
426 | end |
427 | end |
428 | end |
429 | |
430 | return superFunc(self, workArea) |
431 | end |
20 | function RidgeMarker.initSpecialization() |
21 | g_workAreaTypeManager:addWorkAreaType("ridgemarker", false) |
22 | |
23 | local schema = Vehicle.xmlSchema |
24 | schema:setXMLSpecializationType("RidgeMarker") |
25 | |
26 | schema:register(XMLValueType.STRING, "vehicle.ridgeMarker#inputButton", "Input action name", "IMPLEMENT_EXTRA4") |
27 | |
28 | schema:register(XMLValueType.STRING, "vehicle.ridgeMarker.marker(?)#animName", "Animation name") |
29 | schema:register(XMLValueType.FLOAT, "vehicle.ridgeMarker.marker(?)#minWorkLimit", "Min. work limit", 0.99) |
30 | schema:register(XMLValueType.FLOAT, "vehicle.ridgeMarker.marker(?)#maxWorkLimit", "Max. work limit", 1) |
31 | schema:register(XMLValueType.FLOAT, "vehicle.ridgeMarker.marker(?)#liftedAnimTime", "Lifted animation time") |
32 | schema:register(XMLValueType.INT, "vehicle.ridgeMarker.marker(?)#workAreaIndex", "Work area index") |
33 | |
34 | schema:register(XMLValueType.FLOAT, "vehicle.ridgeMarker#foldMinLimit", "Fold min. limit", 0) |
35 | schema:register(XMLValueType.FLOAT, "vehicle.ridgeMarker#foldMaxLimit", "Fold max. limit", 1) |
36 | schema:register(XMLValueType.INT, "vehicle.ridgeMarker#foldDisableDirection", "Fold disable direction") |
37 | schema:register(XMLValueType.BOOL, "vehicle.ridgeMarker#onlyActiveWhenLowered", "Only active while lowered", true) |
38 | schema:register(XMLValueType.NODE_INDEX, "vehicle.ridgeMarker#directionNode", "Direction node") |
39 | |
40 | RidgeMarker.registerRidgeMarkerAreaXMLPaths(schema, WorkArea.WORK_AREA_XML_KEY) |
41 | RidgeMarker.registerRidgeMarkerAreaXMLPaths(schema, WorkArea.WORK_AREA_XML_CONFIG_KEY) |
42 | |
43 | schema:register(XMLValueType.STRING, SpeedRotatingParts.SPEED_ROTATING_PART_XML_KEY .. "#ridgeMarkerAnim", "Ridge marker animation") |
44 | schema:register(XMLValueType.FLOAT, SpeedRotatingParts.SPEED_ROTATING_PART_XML_KEY .. "#ridgeMarkerAnimTimeMax", "Animation max. time for activation", 0.99) |
45 | |
46 | schema:setXMLSpecializationType() |
47 | |
48 | local schemaSavegame = Vehicle.xmlSchemaSavegame |
49 | schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).ridgeMarker#state", "Ridge marker state") |
50 | end |
211 | function RidgeMarker:loadRidgeMarker(xmlFile, key, ridgeMarker) |
212 | ridgeMarker.animName = xmlFile:getValue(key .. "#animName") |
213 | ridgeMarker.minWorkLimit = xmlFile:getValue(key .. "#minWorkLimit", 0.99) |
214 | ridgeMarker.maxWorkLimit = xmlFile:getValue(key .. "#maxWorkLimit", 1) |
215 | |
216 | ridgeMarker.liftedAnimTime = xmlFile:getValue(key .. "#liftedAnimTime") |
217 | ridgeMarker.workAreaIndex = xmlFile:getValue(key .. "#workAreaIndex") |
218 | |
219 | if ridgeMarker.workAreaIndex == nil then |
220 | Logging.xmlWarning(self.xmlFile, "Missing 'workAreaIndex' for ridgeMarker '%s'!", key) |
221 | return false |
222 | end |
223 | |
224 | return true |
225 | end |
327 | function RidgeMarker:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key) |
328 | local ridgeMarkerNode = xmlFile:getValue(key ..".ridgeMarkerArea#node", nil, self.components, self.i3dMappings) |
329 | |
330 | local ridgeMarkerSize = xmlFile:getValue(key ..".ridgeMarkerArea#size", 0.25) * 0.5 |
331 | local ridgeMarkerTestOffset = xmlFile:getValue(key ..".ridgeMarkerArea#testAreaOffset", 0.2) |
332 | |
333 | if ridgeMarkerNode ~= nil then |
334 | workArea.start = createTransformGroup("ridgeMarkerAreaStart") |
335 | link(ridgeMarkerNode, workArea.start) |
336 | setTranslation(workArea.start, ridgeMarkerSize, 0, ridgeMarkerSize) |
337 | |
338 | workArea.width = createTransformGroup("ridgeMarkerAreaWidth") |
339 | link(ridgeMarkerNode, workArea.width) |
340 | setTranslation(workArea.width, -ridgeMarkerSize, 0, ridgeMarkerSize) |
341 | |
342 | workArea.height = createTransformGroup("ridgeMarkerAreaHeight") |
343 | link(ridgeMarkerNode, workArea.height) |
344 | setTranslation(workArea.height, ridgeMarkerSize, 0, -ridgeMarkerSize) |
345 | |
346 | local testOffset = (ridgeMarkerTestOffset + 2 * ridgeMarkerSize) |
347 | workArea.testNode = createTransformGroup("ridgeMarkerTestNode") |
348 | link(ridgeMarkerNode, workArea.testNode) |
349 | setTranslation(workArea.testNode, 0, 0, ridgeMarkerSize + testOffset) |
350 | end |
351 | |
352 | if not superFunc(self, workArea, xmlFile, key) then |
353 | return false |
354 | end |
355 | |
356 | if workArea.type == WorkAreaType.RIDGEMARKER then |
357 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, key ..".testArea#startNode", key ..".ridgeMarkerArea#node") -- FS19 to FS22 |
358 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, key ..".testArea#widthNode", key ..".ridgeMarkerArea#node") -- FS19 to FS22 |
359 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, key ..".testArea#heightNode", key ..".ridgeMarkerArea#node") -- FS19 to FS22 |
360 | end |
361 | |
362 | if ridgeMarkerNode ~= nil then |
363 | if workArea.type == WorkAreaType.DEFAULT then |
364 | workArea.type = WorkAreaType.RIDGEMARKER |
365 | end |
366 | elseif workArea.type == WorkAreaType.RIDGEMARKER then |
367 | Logging.xmlWarning(self.xmlFile, "Missing ridge marker node for ridge marker area '%s'", key) |
368 | end |
369 | |
370 | return true |
371 | end |
104 | function RidgeMarker:onLoad(savegame) |
105 | local spec = self.spec_ridgeMarker |
106 | |
107 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.ridgeMarkers", "vehicle.ridgeMarker") -- FS17 to FS19 |
108 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.ridgeMarkers.ridgeMarker", "vehicle.ridgeMarker.marker") -- FS17 to FS19 |
109 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.ridgeMarker.ridgeMarker", "vehicle.ridgeMarker.marker") -- FS17 to FS19 |
110 | |
111 | local inputButtonStr = self.xmlFile:getValue("vehicle.ridgeMarker#inputButton") |
112 | if inputButtonStr ~= nil then |
113 | spec.ridgeMarkerInputButton = InputAction[inputButtonStr] |
114 | end |
115 | spec.ridgeMarkerInputButton = Utils.getNoNil(spec.ridgeMarkerInputButton, InputAction.IMPLEMENT_EXTRA4) |
116 | |
117 | spec.ridgeMarkers = {} |
118 | spec.workAreaToRidgeMarker = {} |
119 | local i = 0 |
120 | while true do |
121 | local key = string.format("vehicle.ridgeMarker.marker(%d)", i) |
122 | if not self.xmlFile:hasProperty(key) then |
123 | break |
124 | end |
125 | |
126 | if table.getn(spec.ridgeMarkers) >= RidgeMarker.MAX_NUM_RIDGEMARKERS-1 then |
127 | Logging.xmlError(self.xmlFile, "Too many ridgeMarker states. Only %d states are supported!", RidgeMarker.MAX_NUM_RIDGEMARKERS-1) |
128 | break |
129 | end |
130 | |
131 | local ridgeMarker = {} |
132 | if self:loadRidgeMarker(self.xmlFile, key, ridgeMarker) then |
133 | table.insert(spec.ridgeMarkers, ridgeMarker) |
134 | spec.workAreaToRidgeMarker[ridgeMarker.workAreaIndex] = ridgeMarker |
135 | end |
136 | |
137 | i = i + 1 |
138 | end |
139 | spec.numRigdeMarkers = #spec.ridgeMarkers |
140 | |
141 | spec.ridgeMarkerMinFoldTime = self.xmlFile:getValue("vehicle.ridgeMarker#foldMinLimit", 0) |
142 | spec.ridgeMarkerMaxFoldTime = self.xmlFile:getValue("vehicle.ridgeMarker#foldMaxLimit", 1) |
143 | spec.foldDisableDirection = self.xmlFile:getValue("vehicle.ridgeMarker#foldDisableDirection") |
144 | spec.onlyActiveWhenLowered = self.xmlFile:getValue("vehicle.ridgeMarker#onlyActiveWhenLowered", true) |
145 | spec.ridgeMarkerState = 0 |
146 | spec.directionNode = self.xmlFile:getValue("vehicle.ridgeMarker#directionNode", nil, self.components, self.i3dMappings) |
147 | |
148 | if not self.isClient then |
149 | SpecializationUtil.removeEventListener(self, "onUpdateTick", RidgeMarker) |
150 | end |
151 | end |
435 | function RidgeMarker:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection) |
436 | if self.isClient then |
437 | local spec = self.spec_ridgeMarker |
438 | self:clearActionEventsTable(spec.actionEvents) |
439 | |
440 | if isActiveForInputIgnoreSelection and spec.numRigdeMarkers > 0 then |
441 | local _, actionEventId = self:addPoweredActionEvent(spec.actionEvents, spec.ridgeMarkerInputButton, self, RidgeMarker.actionEventToggleRidgeMarkers, false, true, false, true, nil) |
442 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL) |
443 | g_inputBinding:setActionEventText(actionEventId, g_i18n:getText("action_toggleRidgeMarker")) |
444 | end |
445 | end |
446 | end |
451 | function RidgeMarker:onSetLowered(lowered) |
452 | local spec = self.spec_ridgeMarker |
453 | if lowered then |
454 | for _, ridgeMarker in pairs(spec.ridgeMarkers) do |
455 | if ridgeMarker.liftedAnimTime ~= nil then |
456 | local animTime = self:getAnimationTime(ridgeMarker.animName) |
457 | if animTime == ridgeMarker.liftedAnimTime then |
458 | self:playAnimation(ridgeMarker.animName, 1, animTime, true) |
459 | end |
460 | end |
461 | end |
462 | else |
463 | for _, ridgeMarker in pairs(spec.ridgeMarkers) do |
464 | if ridgeMarker.liftedAnimTime ~= nil then |
465 | local animTime = self:getAnimationTime(ridgeMarker.animName) |
466 | if animTime > ridgeMarker.liftedAnimTime then |
467 | self:setAnimationStopTime(ridgeMarker.animName, ridgeMarker.liftedAnimTime) |
468 | self:playAnimation(ridgeMarker.animName, -1, animTime, true) |
469 | end |
470 | end |
471 | end |
472 | end |
473 | end |
281 | function RidgeMarker:processRidgeMarkerArea(workArea, dt) |
282 | local spec = self.spec_ridgeMarker |
283 | |
284 | local mission = g_currentMission |
285 | local groundTypeMapId, groundTypeFirstChannel, groundTypeNumChannels = mission.fieldGroundSystem:getDensityMapData(FieldDensityMap.GROUND_TYPE) |
286 | |
287 | local densityBits = getDensityAtWorldPos(groundTypeMapId, getWorldTranslation(workArea.testNode)) |
288 | local densityType = bitAND(bitShiftRight(densityBits, groundTypeFirstChannel), 2^groundTypeNumChannels - 1) |
289 | |
290 | -- ignore non-field areas |
291 | if densityType ~= FieldGroundType.NONE then |
292 | local x, _, z = getWorldTranslation(workArea.start) |
293 | local x1, _, z1 = getWorldTranslation(workArea.width) |
294 | local x2, _, z2 = getWorldTranslation(workArea.height) |
295 | |
296 | local wx, wz = x1-x, z1-z |
297 | local hx, hz = x2-x, z2-z |
298 | |
299 | local worldToDensity = mission.terrainDetailMapSize / mission.terrainSize |
300 | x = math.floor(x * worldToDensity + 0.5)/worldToDensity |
301 | z = math.floor(z * worldToDensity + 0.5)/worldToDensity |
302 | |
303 | x1, z1 = x + wx, z + wz |
304 | x2, z2 = x + hx, z + hz |
305 | |
306 | local dx, _, dz = localDirectionToWorld(spec.directionNode or self.rootNode, 0, 0, 1) |
307 | local angle = FSDensityMapUtil.convertToDensityMapAngle(MathUtil.getYRotationFromDirection(dx, dz), mission.fieldGroundSystem:getGroundAngleMaxValue()) |
308 | |
309 | if densityType == FieldGroundType.PLOWED then |
310 | FSDensityMapUtil.updateCultivatorArea(x, z, x1, z1, x2, z2, false, true, angle, nil, nil, true) |
311 | else |
312 | FSDensityMapUtil.updatePlowArea(x, z, x1, z1, x2, z2, false, true, angle, false, true) |
313 | end |
314 | |
315 | FSDensityMapUtil.eraseTireTrack(x, z, x1, z1, x2, z2) |
316 | end |
317 | |
318 | return 0, 0 |
319 | end |
89 | function RidgeMarker.registerEventListeners(vehicleType) |
90 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", RidgeMarker) |
91 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", RidgeMarker) |
92 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", RidgeMarker) |
93 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", RidgeMarker) |
94 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", RidgeMarker) |
95 | SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", RidgeMarker) |
96 | SpecializationUtil.registerEventListener(vehicleType, "onSetLowered", RidgeMarker) |
97 | SpecializationUtil.registerEventListener(vehicleType, "onFoldStateChanged", RidgeMarker) |
98 | SpecializationUtil.registerEventListener(vehicleType, "onAIImplementStart", RidgeMarker) |
99 | end |
79 | function RidgeMarker.registerOverwrittenFunctions(vehicleType) |
80 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadWorkAreaFromXML", RidgeMarker.loadWorkAreaFromXML) |
81 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsWorkAreaActive", RidgeMarker.getIsWorkAreaActive) |
82 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadSpeedRotatingPartFromXML", RidgeMarker.loadSpeedRotatingPartFromXML) |
83 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsSpeedRotatingPartActive", RidgeMarker.getIsSpeedRotatingPartActive) |
84 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", RidgeMarker.getCanBeSelected) |
85 | end |
231 | function RidgeMarker:setRidgeMarkerState(state, noEventSend) |
232 | local spec = self.spec_ridgeMarker |
233 | |
234 | if spec.ridgeMarkerState ~= state then |
235 | RidgeMarkerSetStateEvent.sendEvent(self, state, noEventSend) |
236 | |
237 | -- fold last state |
238 | if spec.ridgeMarkerState ~= 0 then |
239 | local animTime = self:getAnimationTime(spec.ridgeMarkers[spec.ridgeMarkerState].animName) |
240 | self:playAnimation(spec.ridgeMarkers[spec.ridgeMarkerState].animName, -1, animTime, true) |
241 | end |
242 | spec.ridgeMarkerState = state |
243 | |
244 | -- unfold new state |
245 | if spec.ridgeMarkerState ~= 0 then |
246 | if spec.ridgeMarkers[spec.ridgeMarkerState].liftedAnimTime ~= nil and not self:getIsLowered(true) then |
247 | self:setAnimationStopTime(spec.ridgeMarkers[spec.ridgeMarkerState].animName, spec.ridgeMarkers[spec.ridgeMarkerState].liftedAnimTime) |
248 | end |
249 | |
250 | local animTime = self:getAnimationTime(spec.ridgeMarkers[spec.ridgeMarkerState].animName) |
251 | self:playAnimation(spec.ridgeMarkers[spec.ridgeMarkerState].animName, 1, animTime, true) |
252 | end |
253 | end |
254 | end |