28 | function VariableWorkWidth.initSpecialization() |
29 | g_configurationManager:addConfigurationType("variableWorkWidth", g_i18n:getText("configuration_workingWidth"), "variableWorkWidth", nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION) |
30 | |
31 | local schema = Vehicle.xmlSchema |
32 | schema:setXMLSpecializationType("VariableWorkWidth") |
33 | |
34 | VariableWorkWidth.registerSectionPaths(schema, "vehicle.variableWorkWidth") |
35 | VariableWorkWidth.registerSectionPaths(schema, "vehicle.variableWorkWidth.variableWorkWidthConfigurations.variableWorkWidthConfiguration(?)") |
36 | |
37 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.variableWorkWidth.variableWorkWidthConfigurations.variableWorkWidthConfiguration(?)") |
38 | |
39 | schema:register(XMLValueType.INT, "vehicle.variableWorkWidth#widthReferenceWorkAreaIndex", "Width of this work area is used as reference for the HUD display", 1) |
40 | schema:register(XMLValueType.INT, "vehicle.variableWorkWidth#defaultStateLeft", "Default state on left side", "Max. possible state") |
41 | schema:register(XMLValueType.INT, "vehicle.variableWorkWidth#defaultStateRight", "Default state on right side", "Max. possible state") |
42 | |
43 | schema:register(XMLValueType.BOOL, "vehicle.variableWorkWidth#aiKeepCurrentWidth", "Defines if the ai should keep the current width or change it", false) |
44 | schema:register(XMLValueType.INT, "vehicle.variableWorkWidth#aiStateLeft", "AI state on left side", "Max. possible state") |
45 | schema:register(XMLValueType.INT, "vehicle.variableWorkWidth#aiStateRight", "AI state on right side", "Max. possible state") |
46 | |
47 | schema:register(XMLValueType.INT, WorkArea.WORK_AREA_XML_KEY .. ".section#index", "Section index (Section needs to be active to activate workArea)") |
48 | schema:register(XMLValueType.INT, WorkArea.WORK_AREA_XML_CONFIG_KEY .. ".section#index", "Section index (Section needs to be active to activate workArea)") |
49 | |
50 | schema:setXMLSpecializationType() |
51 | |
52 | local schemaSavegame = Vehicle.xmlSchemaSavegame |
53 | schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).variableWorkWidth#leftSide", "Left side section states", "Max. state") |
54 | schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).variableWorkWidth#rightSide", "Right side section states", "Max. state") |
55 | end |
113 | function VariableWorkWidth:onPostLoad(savegame) |
114 | local spec = self.spec_variableWorkWidth |
115 | |
116 | local configurationId = Utils.getNoNil(self.configurations["variableWorkWidth"], 1) |
117 | local configKey = string.format("vehicle.variableWorkWidth.variableWorkWidthConfigurations.variableWorkWidthConfiguration(%d)", configurationId - 1) |
118 | ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.variableWorkWidth.variableWorkWidthConfigurations.variableWorkWidthConfiguration", configurationId , self.components, self) |
119 | |
120 | if not self.xmlFile:hasProperty(configKey) then |
121 | configKey = "vehicle.variableWorkWidth" |
122 | end |
123 | |
124 | local deleteListener = function(section, effect) |
125 | for i=#section.effects, 1, -1 do |
126 | if section.effects[i] == effect then |
127 | section.effects[i] = nil |
128 | break |
129 | end |
130 | end |
131 | end |
132 | |
133 | local startRestriction = function(section) |
134 | return section.isActive |
135 | end |
136 | |
137 | spec.hasCenter = false |
138 | |
139 | spec.sections = {} |
140 | spec.sectionsLeft = {} |
141 | spec.sectionsRight = {} |
142 | self.xmlFile:iterate(configKey .. ".sections.section", function(index, key) |
143 | local section = {} |
144 | section.isLeft = self.xmlFile:getValue(key .. "#isLeft", false) |
145 | section.isCenter = self.xmlFile:getValue(key .. "#isCenter", false) |
146 | |
147 | section.maxWidthNode = self.xmlFile:getValue(key .. "#maxWidthNode", nil, self.components, self.i3dMappings) |
148 | section.width = self.xmlFile:getValue(key .. "#width") |
149 | |
150 | section.effects = {} |
151 | self.xmlFile:iterate(key .. ".effect", function(effectIndex, effectKey) |
152 | local effectNode = self.xmlFile:getValue(effectKey .. "#node", nil, self.components, self.i3dMappings) |
153 | if effectNode ~= nil then |
154 | local effect = self:getEffectByNode(effectNode) |
155 | if effect ~= nil then |
156 | effect:addDeleteListener(deleteListener, section, effect) |
157 | effect:addStartRestriction(startRestriction, section) |
158 | table.insert(section.effects, effect) |
159 | end |
160 | end |
161 | end) |
162 | |
163 | section.isActive = true |
164 | |
165 | if section.isLeft then |
166 | table.insert(spec.sectionsLeft, section) |
167 | elseif not section.isCenter then |
168 | table.insert(spec.sectionsRight, section) |
169 | else |
170 | spec.hasCenter = true |
171 | end |
172 | |
173 | table.insert(spec.sections, section) |
174 | end) |
175 | |
176 | spec.sectionNodes = {} |
177 | spec.sectionNodesLeft = {} |
178 | spec.sectionNodesRight = {} |
179 | self.xmlFile:iterate(configKey .. ".sectionNodes.sectionNode", function(index, key) |
180 | local sectionNode = {} |
181 | sectionNode.node = self.xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings) |
182 | if sectionNode.node ~= nil then |
183 | sectionNode.isLeft = self.xmlFile:getValue(key .. "#isLeft", false) |
184 | |
185 | sectionNode.startTrans = self.xmlFile:getValue(key .. "#minTrans", nil, true) |
186 | sectionNode.startTransX = self.xmlFile:getValue(key .. "#minTransX") |
187 | sectionNode.endTrans = self.xmlFile:getValue(key .. "#maxTrans", nil, true) |
188 | sectionNode.endTransX = self.xmlFile:getValue(key .. "#maxTransX") |
189 | sectionNode.startRot = self.xmlFile:getValue(key .. "#minRot", nil, true) |
190 | sectionNode.endRot = self.xmlFile:getValue(key .. "#endRot", nil, true) |
191 | |
192 | sectionNode.workAreaIndex = self.xmlFile:getValue(key .. "#workAreaIndex", 1) |
193 | |
194 | if sectionNode.isLeft then |
195 | table.insert(spec.sectionNodesLeft, sectionNode) |
196 | else |
197 | table.insert(spec.sectionNodesRight, sectionNode) |
198 | end |
199 | |
200 | table.insert(spec.sectionNodes, sectionNode) |
201 | end |
202 | end) |
203 | |
204 | for i=1, #spec.sections do |
205 | local section = spec.sections[i] |
206 | if section.maxWidthNode ~= nil then |
207 | if not section.isCenter then |
208 | for j=1, #spec.sectionNodes do |
209 | local sectionNode = spec.sectionNodes[j] |
210 | if sectionNode.isLeft == section.isLeft then |
211 | local x, _, _ = localToLocal(section.maxWidthNode, getParent(sectionNode.node), 0, 0, 0) |
212 | |
213 | local minX, maxX = sectionNode.startTransX or sectionNode.startTrans[1], sectionNode.endTransX or sectionNode.endTrans[1] |
214 | section.width = MathUtil.clamp(math.abs((x - minX) / (maxX - minX)), 0, 1) |
215 | section.widthAbs = x |
216 | break |
217 | end |
218 | end |
219 | end |
220 | else |
221 | section.width = 0 |
222 | end |
223 | |
224 | if section.width == nil then |
225 | Logging.xmlWarning(self.xmlFile, "Unable to get width for section 'vehicle.variableWorkWidth.sections.section(%d)'", i) |
226 | section.width = 0 |
227 | end |
228 | end |
229 | |
230 | local function sort(a, b) |
231 | return a.width < b.width |
232 | end |
233 | table.sort(spec.sectionsLeft, sort) |
234 | table.sort(spec.sectionsRight, sort) |
235 | |
236 | spec.widthReferenceWorkArea = self.xmlFile:getValue("vehicle.variableWorkWidth#widthReferenceWorkAreaIndex", 1) |
237 | |
238 | spec.leftSideMax = #spec.sectionsLeft |
239 | spec.leftSide = self.xmlFile:getValue("vehicle.variableWorkWidth#defaultStateLeft", spec.leftSideMax) |
240 | spec.rightSideMax = #spec.sectionsRight |
241 | spec.rightSide = self.xmlFile:getValue("vehicle.variableWorkWidth#defaultStateRight", spec.rightSideMax) |
242 | |
243 | spec.aiKeepCurrentWidth = self.xmlFile:getValue("vehicle.variableWorkWidth#aiKeepCurrentWidth", false) |
244 | spec.aiStateLeft = self.xmlFile:getValue("vehicle.variableWorkWidth#aiStateLeft", spec.leftSideMax) |
245 | spec.aiStateRight = self.xmlFile:getValue("vehicle.variableWorkWidth#aiStateRight", spec.rightSideMax) |
246 | |
247 | spec.minSideState = spec.hasCenter and 0 or 1 |
248 | |
249 | if savegame ~= nil and not savegame.resetVehicles then |
250 | spec.leftSide = math.min(savegame.xmlFile:getValue(savegame.key .. ".variableWorkWidth#leftSide", spec.leftSide), spec.leftSideMax) |
251 | spec.rightSide = math.min(savegame.xmlFile:getValue(savegame.key .. ".variableWorkWidth#rightSide", spec.rightSide), spec.rightSideMax) |
252 | end |
253 | |
254 | self:updateSections() |
255 | |
256 | spec.drawInputHelp = false |
257 | spec.hasSections = #spec.sections > 0 |
258 | |
259 | if not self.isClient or not spec.hasSections then |
260 | SpecializationUtil.removeEventListener(self, "onRegisterActionEvents", VariableWorkWidth) |
261 | end |
262 | end |
276 | function VariableWorkWidth:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection) |
277 | local spec = self.spec_variableWorkWidth |
278 | self:clearActionEventsTable(spec.actionEvents) |
279 | |
280 | if isActiveForInputIgnoreSelection then |
281 | local _, actionEventIdLeft = self:addActionEvent(spec.actionEvents, InputAction.VARIABLE_WORK_WIDTH_LEFT, self, VariableWorkWidth.actionEventWorkWidthLeft, false, true, false, true, nil) |
282 | g_inputBinding:setActionEventTextPriority(actionEventIdLeft, GS_PRIO_HIGH) |
283 | |
284 | local _, actionEventIdRight = self:addActionEvent(spec.actionEvents, InputAction.VARIABLE_WORK_WIDTH_RIGHT, self, VariableWorkWidth.actionEventWorkWidthRight, false, true, false, true, nil) |
285 | g_inputBinding:setActionEventTextPriority(actionEventIdRight, GS_PRIO_HIGH) |
286 | |
287 | local _, actionEventIdToggle = self:addActionEvent(spec.actionEvents, InputAction.VARIABLE_WORK_WIDTH_TOGGLE, self, VariableWorkWidth.actionEventWorkWidthToggle, false, true, false, true, nil) |
288 | g_inputBinding:setActionEventTextPriority(actionEventIdToggle, GS_PRIO_HIGH) |
289 | |
290 | spec.drawInputHelp = g_inputBinding:getActionEventsHasBinding(actionEventIdLeft) or g_inputBinding:getActionEventsHasBinding(actionEventIdRight) or g_inputBinding:getActionEventsHasBinding(actionEventIdToggle) |
291 | end |
292 | end |
59 | function VariableWorkWidth.registerSectionPaths(schema, basePath) |
60 | schema:register(XMLValueType.BOOL, basePath .. ".sections.section(?)#isLeft", "Section side", false) |
61 | schema:register(XMLValueType.BOOL, basePath .. ".sections.section(?)#isCenter", "Is center section", false) |
62 | schema:register(XMLValueType.FLOAT, basePath .. ".sections.section(?)#width", "Section max. width as percentage [0..1]", "Automatically calculated") |
63 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".sections.section(?)#maxWidthNode", "Position of this node defines max. width of this section") |
64 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".sections.section(?).effect(?)#node", "Effect to deactivate/activate") |
65 | |
66 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".sectionNodes.sectionNode(?)#node", "Section node") |
67 | schema:register(XMLValueType.BOOL, basePath .. ".sectionNodes.sectionNode(?)#isLeft", "Section node") |
68 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".sectionNodes.sectionNode(?)#minTrans", "Min. translation") |
69 | schema:register(XMLValueType.FLOAT, basePath .. ".sectionNodes.sectionNode(?)#minTransX", "Min. X translation") |
70 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".sectionNodes.sectionNode(?)#maxTrans", "Max. translation") |
71 | schema:register(XMLValueType.FLOAT, basePath .. ".sectionNodes.sectionNode(?)#maxTransX", "Max. X translation") |
72 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".sectionNodes.sectionNode(?)#minRot", "Min. rotation") |
73 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".sectionNodes.sectionNode(?)#endRot", "Max. rotation") |
74 | schema:register(XMLValueType.INT, basePath .. ".sectionNodes.sectionNode(?)#workAreaIndex", "Work area index", 1) |
75 | end |