407 | function VehicleActionController:drawDebugRendering() |
408 | local renderTextVAC = function(x, y, height, text, color) |
409 | setTextColor(0.0, 0.0, 0.0, 0.75) |
410 | renderText(x, y-0.0015, height, text) |
411 | |
412 | color = color or {1,1,1,1} |
413 | setTextColor(unpack(color)) |
414 | renderText(x, y, height, text) |
415 | end |
416 | |
417 | local drawActions = function(name, sequenceActions, highlightIndex, posX, posY) |
418 | if sequenceActions ~= nil and #sequenceActions > 0 then |
419 | setTextBold(false) |
420 | setTextAlignment(RenderText.ALIGN_CENTER) |
421 | local textHeight = 0.012 |
422 | local lineSpacing = 0.002 |
423 | local lineHeight = textHeight + lineSpacing |
424 | |
425 | local currentHeight = 0 |
426 | for i=#sequenceActions, 1, -1 do |
427 | local actions = sequenceActions[i] |
428 | |
429 | setTextBold(highlightIndex == i) |
430 | local color |
431 | if i < highlightIndex then |
432 | color = {0,1,0,1} |
433 | elseif i == highlightIndex then |
434 | color = {1,0.5,0,1} |
435 | end |
436 | |
437 | for _, action in ipairs(actions) do |
438 | renderTextVAC(posX, posY+currentHeight, textHeight, action:getDebugText(), color) |
439 | currentHeight = currentHeight + lineHeight |
440 | end |
441 | |
442 | renderTextVAC(posX, posY+currentHeight+lineHeight*0.5, textHeight, "__________________________") |
443 | currentHeight = currentHeight + lineHeight |
444 | end |
445 | |
446 | renderTextVAC(posX, posY+currentHeight+lineHeight*0.5, textHeight*1.5, name) |
447 | |
448 | setTextBold(false) |
449 | setTextAlignment(RenderText.ALIGN_LEFT) |
450 | end |
451 | end |
452 | |
453 | -- all actions |
454 | drawActions("Controlled Actions", self.sortedActions, -1, 0.2, 0.3) |
455 | |
456 | -- current action sequence |
457 | local directionText = self.lastDirection == 1 and "TurnOn" or "TurnOff" |
458 | drawActions(string.format("Current Action Sequence (%s)", directionText), self.currentSequenceActions, self.currentSequenceIndex, 0.4, 0.3) |
459 | end |
54 | function VehicleActionController:load(savegame) |
55 | if savegame ~= nil then |
56 | self.lastDirection = savegame.xmlFile:getValue(savegame.key..".actionController#lastDirection", self.lastDirection) |
57 | self.loadedNumActions = savegame.xmlFile:getValue(savegame.key..".actionController#numActions", 0) |
58 | self.loadTime = g_time |
59 | |
60 | local needsToApply = false |
61 | |
62 | self.loadedActions = {} |
63 | local i = 0 |
64 | while true do |
65 | local baseKey = string.format("%s.actionController.action(%d)", savegame.key, i) |
66 | if not savegame.xmlFile:hasProperty(baseKey) then |
67 | break |
68 | end |
69 | |
70 | local action = {} |
71 | action.name = savegame.xmlFile:getValue(baseKey.."#name") |
72 | action.identifier = savegame.xmlFile:getValue(baseKey.."#identifier") |
73 | action.lastDirection = savegame.xmlFile:getValue(baseKey.."#lastDirection") |
74 | if action.lastDirection > 0 then |
75 | needsToApply = true |
76 | end |
77 | |
78 | table.insert(self.loadedActions, action) |
79 | |
80 | i = i + 1 |
81 | end |
82 | if not needsToApply then |
83 | self.loadedNumActions = 0 |
84 | self.loadedActions = {} |
85 | end |
86 | end |
87 | end |
164 | function VehicleActionController:registerActionEvents(isActiveForInput, isActiveForInputIgnoreSelection) |
165 | if #self.actions > 0 and self.vehicle.rootVehicle == self.vehicle then |
166 | self.vehicle:clearActionEventsTable(self.actionEvents) |
167 | for _, action in ipairs(self.actions) do |
168 | action:registerActionEvents(self, self.vehicle, self.actionEvents, isActiveForInput, isActiveForInputIgnoreSelection) |
169 | end |
170 | |
171 | if self.actionEventId ~= nil then |
172 | g_inputBinding:removeActionEvent(self.actionEventId) |
173 | end |
174 | |
175 | local _, actionEventId, _ = g_inputBinding:registerActionEvent(InputAction.VEHICLE_ACTION_CONTROL, self, VehicleActionController.actionSequenceEvent, false, true, false, true) |
176 | self.actionEventId = actionEventId |
177 | end |
178 | end |
463 | function VehicleActionController.registerXMLPaths(schema, basePath) |
464 | schema:register(XMLValueType.INT, basePath .. "#lastDirection", "Last action controller direction") |
465 | schema:register(XMLValueType.INT, basePath .. "#numActions", "Action controller actions") |
466 | schema:register(XMLValueType.STRING, basePath .. ".action(?)#name", "Action name") |
467 | schema:register(XMLValueType.STRING, basePath .. ".action(?)#identifier", "Action identifier") |
468 | schema:register(XMLValueType.INT, basePath .. ".action(?)#lastDirection", "Last action direction") |
469 | end |
34 | function VehicleActionController:saveToXMLFile(xmlFile, key, usedModNames) |
35 | if #self.actions > 0 then |
36 | xmlFile:setValue(key.."#lastDirection", self.lastDirection) |
37 | xmlFile:setValue(key.."#numActions", #self.actions) |
38 | |
39 | local i = 0 |
40 | for _, action in ipairs(self.actions) do |
41 | if action:getIsSaved() then |
42 | local actionKey = string.format("%s.action(%d)", key, i) |
43 | xmlFile:setValue(actionKey.."#name", action.name) |
44 | xmlFile:setValue(actionKey.."#identifier", action.identifier) |
45 | xmlFile:setValue(actionKey.."#lastDirection", action:getLastDirection()) |
46 | i = i + 1 |
47 | end |
48 | end |
49 | end |
50 | end |
220 | function VehicleActionController:startActionSequence(force) |
221 | local direction = -self.lastDirection |
222 | |
223 | self.currentSequenceActions = self.sortedActionsRev |
224 | if direction > 0 then |
225 | self.currentSequenceActions = self.sortedActions |
226 | end |
227 | |
228 | if not force then |
229 | local alreadyFinished = true |
230 | for _, actions in ipairs(self.currentSequenceActions) do |
231 | for _, action in ipairs(actions) do |
232 | local finished = action.lastValidDirection == direction |
233 | alreadyFinished = alreadyFinished and finished |
234 | end |
235 | end |
236 | |
237 | -- if we are already in the target state we restart the sequence to flip the direction |
238 | if alreadyFinished then |
239 | self.lastDirection = direction |
240 | self:startActionSequence(true) |
241 | return |
242 | end |
243 | end |
244 | |
245 | if self.currentSequenceIndex ~= nil then |
246 | self.currentSequenceIndex = self.currentMaxSequenceIndex - (self.currentSequenceIndex - 1) |
247 | else |
248 | self.currentSequenceIndex = 1 |
249 | self.currentMaxSequenceIndex = #self.currentSequenceActions |
250 | end |
251 | |
252 | self.lastDirection = direction |
253 | if not self:doAction(self.currentSequenceIndex, self.currentSequenceActions, self.lastDirection) then |
254 | self:continueActionSequence() |
255 | end |
256 | end |
317 | function VehicleActionController:update(dt) |
318 | if self.currentSequenceIndex ~= nil then |
319 | if self.currentSequenceIndex <= self.currentMaxSequenceIndex then |
320 | local actions = self:getActionsByIndex(self.currentSequenceIndex, self.currentSequenceActions) |
321 | if actions ~= nil then |
322 | local allFinished = true |
323 | for _, action in ipairs(actions) do |
324 | if not action:getIsFinished(self.lastDirection) then |
325 | allFinished = false |
326 | break |
327 | end |
328 | end |
329 | |
330 | if allFinished then |
331 | if self.currentSequenceIndex < self.currentMaxSequenceIndex then |
332 | self:continueActionSequence() |
333 | else |
334 | self:stopActionSequence() |
335 | end |
336 | end |
337 | end |
338 | end |
339 | end |
340 | |
341 | for _, action in ipairs(self.actions) do |
342 | action:update(dt) |
343 | end |
344 | |
345 | -- apply the loaded state from savegame to the actions |
346 | if self.loadedNumActions ~= 0 and self.loadedNumActions == #self.actions and self.loadTime + 500 < g_time then |
347 | if self.vehicle.startMotor ~= nil then |
348 | if not self.vehicle:getIsMotorStarted() then |
349 | self.vehicle:startMotor() |
350 | end |
351 | end |
352 | |
353 | local isStarted = true |
354 | if self.vehicle.startMotor ~= nil then |
355 | isStarted = self.vehicle:getIsMotorStarted(true) |
356 | end |
357 | |
358 | if isStarted then |
359 | for _, loadedAction in ipairs(self.loadedActions) do |
360 | for _, actionToCheck in ipairs(self.actions) do |
361 | if actionToCheck.name == loadedAction.name then |
362 | if actionToCheck.identifier == loadedAction.identifier then |
363 | if actionToCheck:getLastDirection() ~= loadedAction.lastDirection then |
364 | actionToCheck:doAction() |
365 | end |
366 | end |
367 | end |
368 | end |
369 | end |
370 | self.loadedNumActions = 0 |
371 | end |
372 | end |
373 | |
374 | -- if a new action was added we check if the action has a different direction than the controller and if so, we execute the action |
375 | if self.actionsDirty and self.loadedNumActions == 0 then |
376 | for _, action in ipairs(self.actions) do |
377 | if action:getLastDirection() ~= self.lastDirection then |
378 | action:doAction() |
379 | end |
380 | end |
381 | |
382 | self.actionsDirty = nil |
383 | end |
384 | end |
138 | function VehicleActionController:updateSortedActions() |
139 | local prioToActionTable = {} |
140 | self.actionsByPrio = {} |
141 | for _, action in ipairs(self.actions) do |
142 | if prioToActionTable[action.priority] == nil then |
143 | local prioTable = {action} |
144 | table.insert(self.actionsByPrio, prioTable) |
145 | |
146 | prioToActionTable[action.priority] = prioTable |
147 | else |
148 | table.insert(prioToActionTable[action.priority], action) |
149 | end |
150 | end |
151 | |
152 | |
153 | local sortFunc = function(a, b) return a[1].priority > b[1].priority end |
154 | self.sortedActions = table.copy(self.actionsByPrio) |
155 | table.sort(self.sortedActions, sortFunc) |
156 | |
157 | local sortFuncRev = function(a, b) return a[1].priority < b[1].priority end |
158 | self.sortedActionsRev = table.copy(self.actionsByPrio) |
159 | table.sort(self.sortedActionsRev, sortFuncRev) |
160 | end |