142 | function SupportVehicle:addSupportVehicle(filename, inputAttacherJointIndex, attacherJointIndex) |
143 | local spec = self.spec_supportVehicle |
144 | if spec.filename ~= nil then |
145 | if spec.supportVehicle == nil then |
146 | -- make sure below the vehicle is enough space to place the support vehicle |
147 | local component = self.components[1].node |
148 | for _, check in ipairs(spec.heightChecks) do |
149 | local x, y, z = localToWorld(component, check.x, 0, check.z) |
150 | local height = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, y, z) |
151 | local difference = y - height |
152 | if difference < spec.minTerrainDistance then |
153 | for _, comp in ipairs(self.components) do |
154 | local cx, cy, cz = getWorldTranslation(comp.node) |
155 | setWorldTranslation(comp.node, cx, cy + spec.minTerrainDistance - difference, cz) |
156 | end |
157 | end |
158 | end |
159 | |
160 | local storeItem = g_storeManager:getItemByXMLFilename(filename) |
161 | if storeItem ~= nil then |
162 | local inputAttacherJoint = self:getInputAttacherJoints()[inputAttacherJointIndex] |
163 | if inputAttacherJoint ~= nil then |
164 | local x, y, z = localToWorld(inputAttacherJoint.node, 0, 0, 0) |
165 | local dirX, _, dirZ = localDirectionToWorld(inputAttacherJoint.node, 1, 0, 0) |
166 | local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ) |
167 | local location = {x=x, y=y, z=z, yRot=yRot} |
168 | self:removeFromPhysics() |
169 | local vehicle = VehicleLoadingUtil.loadVehicle(storeItem.xmlFilename, location, false, 0, Vehicle.PROPERTY_STATE_NONE, self:getActiveFarm(), spec.configurations, nil, SupportVehicle.supportVehicleLoaded, self, {attacherJointIndex, inputAttacherJointIndex, inputAttacherJoint.node}) |
170 | if vehicle ~= nil then |
171 | vehicle:setIsSupportVehicle() |
172 | end |
173 | end |
174 | else |
175 | Logging.xmlWarning(self.xmlFile, "Unable to find support vehicle '%s'.", filename) |
176 | end |
177 | end |
178 | end |
179 | end |
21 | function SupportVehicle.initSpecialization() |
22 | local schema = Vehicle.xmlSchema |
23 | schema:setXMLSpecializationType("SupportVehicle") |
24 | |
25 | schema:register(XMLValueType.STRING, "vehicle.supportVehicle#filename", "Path to support vehicle xml") |
26 | schema:register(XMLValueType.INT, "vehicle.supportVehicle#attacherJointIndex", "Attacher joint index on support vehicle", 1) |
27 | schema:register(XMLValueType.INT, "vehicle.supportVehicle#inputAttacherJointIndex", "Input attacher joint index on own vehicle", 1) |
28 | schema:register(XMLValueType.FLOAT, "vehicle.supportVehicle#minTerrainDistance", "Min. distance from vehicle root to ground (To have enough space for support vehicle)", 0.75) |
29 | schema:register(XMLValueType.FLOAT, "vehicle.supportVehicle#attachedMass", "Mass of vehicle components if attached to support vehicle (kg)", 10) |
30 | |
31 | schema:register(XMLValueType.STRING, "vehicle.supportVehicle.configuration(?)#name", "Configuration name") |
32 | schema:register(XMLValueType.INT, "vehicle.supportVehicle.configuration(?)#id", "Configuration id") |
33 | |
34 | schema:setXMLSpecializationType() |
35 | end |
62 | function SupportVehicle:onLoad(savegame) |
63 | local spec = self.spec_supportVehicle |
64 | |
65 | local baseKey = "vehicle.supportVehicle" |
66 | |
67 | local filename = self.xmlFile:getValue(baseKey.."#filename") |
68 | if filename ~= nil then |
69 | spec.filename = Utils.getFilename(filename, self.customEnvironment) |
70 | end |
71 | spec.attacherJointIndex = self.xmlFile:getValue(baseKey.."#attacherJointIndex", 1) |
72 | spec.inputAttacherJointIndex = self.xmlFile:getValue(baseKey.."#inputAttacherJointIndex", 1) |
73 | |
74 | spec.minTerrainDistance = self.xmlFile:getValue(baseKey.."#minTerrainDistance", 0.75) |
75 | |
76 | spec.attachedMass = self.xmlFile:getValue(baseKey.."#attachedMass", 10) / 1000 |
77 | |
78 | spec.heightChecks = {} |
79 | table.insert(spec.heightChecks, {x= self.size.width / 2 + self.size.widthOffset, z= self.size.length / 2 + self.size.lengthOffset}) |
80 | table.insert(spec.heightChecks, {x=-self.size.width / 2 + self.size.widthOffset, z= self.size.length / 2 + self.size.lengthOffset}) |
81 | table.insert(spec.heightChecks, {x= self.size.width / 2 + self.size.widthOffset, z=-self.size.length / 2 + self.size.lengthOffset}) |
82 | table.insert(spec.heightChecks, {x=-self.size.width / 2 + self.size.widthOffset, z=-self.size.length / 2 + self.size.lengthOffset}) |
83 | |
84 | spec.configurations = {} |
85 | local i = 0 |
86 | while true do |
87 | local configurationKey = string.format("%s.configuration(%d)", baseKey, i) |
88 | if not self.xmlFile:hasProperty(configurationKey) then |
89 | break |
90 | end |
91 | |
92 | local name = self.xmlFile:getValue(configurationKey.."#name") |
93 | local id = self.xmlFile:getValue(configurationKey.."#id") |
94 | if name ~= nil and id ~= nil then |
95 | spec.configurations[name] = id |
96 | end |
97 | |
98 | i = i + 1 |
99 | end |
100 | |
101 | spec.firstRun = true |
102 | |
103 | if not self.isServer then |
104 | SpecializationUtil.removeEventListener(self, "onDelete", SupportVehicle) |
105 | SpecializationUtil.removeEventListener(self, "onUpdate", SupportVehicle) |
106 | SpecializationUtil.removeEventListener(self, "onPostDetach", SupportVehicle) |
107 | end |
108 | end |
225 | function SupportVehicle:removeSupportVehicle() |
226 | local spec = self.spec_supportVehicle |
227 | if spec.supportVehicle ~= nil then |
228 | spec.supportVehicle:delete() |
229 | spec.supportVehicle = nil |
230 | end |
231 | |
232 | if self.isServer and self.components ~= nil then |
233 | for i=1, #self.components do |
234 | local component = self.components[i] |
235 | setMass(component.node, component.defaultMass) |
236 | end |
237 | end |
238 | end |
183 | function SupportVehicle:supportVehicleLoaded(vehicle, vehicleLoadState, asyncCallbackArguments) |
184 | if vehicleLoadState == VehicleLoadingUtil.VEHICLE_LOAD_OK and vehicle ~= nil then |
185 | local attacherVehicle = self:getAttacherVehicle() |
186 | -- check again if vehicle is already attached (async loading of support vehicle can have a delay |
187 | self:addToPhysics() |
188 | |
189 | local spec = self.spec_supportVehicle |
190 | for i=1, #self.components do |
191 | setMass(self.components[i].node, spec.attachedMass) |
192 | end |
193 | |
194 | if not self.isDeleted and attacherVehicle == nil then |
195 | local offset = {0, 0, 0} |
196 | local dirOffset = {0, 0, 0} |
197 | if vehicle.getAttacherJoints ~= nil then |
198 | local attacherJoints = vehicle:getAttacherJoints() |
199 | if attacherJoints[asyncCallbackArguments[1]] ~= nil then |
200 | offset = attacherJoints[asyncCallbackArguments[1]].jointOrigOffsetComponent |
201 | dirOffset = attacherJoints[asyncCallbackArguments[1]].jointOrigDirOffsetComponent |
202 | end |
203 | end |
204 | |
205 | local x, y, z = localToWorld(asyncCallbackArguments[3], unpack(offset)) |
206 | local dirX, _, dirZ = localDirectionToWorld(asyncCallbackArguments[3], unpack(dirOffset)) |
207 | local yRot = MathUtil.getYRotationFromDirection(dirX, dirZ) |
208 | |
209 | vehicle:setAbsolutePosition(x, y, z, 0, yRot, 0) |
210 | vehicle:attachImplement(self, asyncCallbackArguments[2], asyncCallbackArguments[1], true, nil, nil, true) |
211 | |
212 | self.rootVehicle:updateSelectableObjects() |
213 | self.rootVehicle:setSelectedVehicle(self) |
214 | |
215 | spec.supportVehicle = vehicle |
216 | else |
217 | -- if the parent vehicle was deleted while loading the support vehicle we remove also the support vehicle |
218 | vehicle:delete() |
219 | end |
220 | end |
221 | end |