Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1 | -- |
2 | -- Steerable |
3 | -- Specialization class for steerables |
4 | -- |
5 | -- @author Stefan Geiger |
6 | -- @date 30/11/08 |
7 | -- |
8 | -- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved. |
9 | |
10 | Steerable = {}; |
11 | source("dataS/scripts/vehicles/specializations/SteerableToggleLightEvent.lua"); |
12 | |
13 | function Steerable.prerequisitesPresent(specializations) |
14 | return true; --SpecializationUtil.hasSpecialization(Attachable, specializations); |
15 | end; |
16 | |
17 | function Steerable:load(xmlFile) |
18 | |
19 | self.isSteerable = true; |
20 | self.isAttachable = SpecializationUtil.hasSpecialization(Attachable, self.specializations); |
21 | |
22 | self.onEnter = SpecializationUtil.callSpecializationsFunction("onEnter"); |
23 | self.onLeave = SpecializationUtil.callSpecializationsFunction("onLeave"); |
24 | self.setLights = SpecializationUtil.callSpecializationsFunction("setLights"); |
25 | |
26 | self.addToolCameras = Steerable.addToolCameras; |
27 | self.removeToolCameras = Steerable.removeToolCameras; |
28 | |
29 | self.setCharacterVisibility = Steerable.setCharacterVisibility; |
30 | self.drawUIInfo = Utils.overwrittenFunction(self.drawUIInfo, Steerable.drawUIInfo); |
31 | self.getIsActiveForInput = Utils.overwrittenFunction(self.getIsActiveForInput, Steerable.getIsActiveForInput); |
32 | |
33 | self.isControlled = false; |
34 | |
35 | Steerable.loadSettingsFromXML(self, xmlFile); |
36 | |
37 | self.numCameras = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.cameras#count"), 0); |
38 | self.cameras = {}; |
39 | for i=1, self.numCameras do |
40 | local cameraKey = string.format("vehicle.cameras.camera%d", i); |
41 | local camera = VehicleCamera:new(self); |
42 | if camera:loadFromXML(xmlFile, cameraKey) then |
43 | table.insert(self.cameras, camera); |
44 | end; |
45 | end; |
46 | self.numCameras = table.getn(self.cameras); |
47 | if self.numCameras == 0 then |
48 | print("Error: No cameras in xml file: ".. self.configFileName); |
49 | end; |
50 | |
51 | self.camIndex = 1; |
52 | |
53 | self.isEntered = false; |
54 | |
55 | self.controllerName = "Unknown"; |
56 | |
57 | self.disableCharacterOnLeave = true; |
58 | self.deactivateOnLeave = true; |
59 | |
60 | self.deactivateLightsOnLeave = true; |
61 | |
62 | self.lightsState = 0; |
63 | |
64 | self.numLightsStates = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.lights#numLightsStates"), self.numLightTypes); |
65 | |
66 | self.showWaterWarning = false; |
67 | self.waterSplashSample = nil; |
68 | |
69 | self.steerableGroundFlag = self:getNextDirtyFlag(); |
70 | end; |
71 | |
72 | function Steerable:loadSettingsFromXML(xmlFile) |
73 | self.enterReferenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.enterReferenceNode#index")); |
74 | self.exitPoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.exitPoint#index")); |
75 | |
76 | self.characterNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.characterNode#index")); |
77 | if self.characterNode ~= nil then |
78 | self.characterCameraMinDistance = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.characterNode#cameraMinDistance"), 1.5); |
79 | self.characterDistanceRefNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.characterNode#distanceRefNode")); |
80 | if self.characterDistanceRefNode == nil then |
81 | self.characterDistanceRefNode = self.characterNode; |
82 | end; |
83 | setVisibility(self.characterNode, false); |
84 | |
85 | local skinBasenode = self.components; |
86 | local filename = getXMLString(xmlFile, "vehicle.characterNode#filename"); |
87 | if filename ~= nil then |
88 | filename = Utils.getFilename(filename, self.baseDirectory); |
89 | local i3dNode = Utils.loadSharedI3DFile(filename); |
90 | if i3dNode ~= 0 then |
91 | self.characterSkin = Utils.indexToObject(i3dNode, getXMLString(xmlFile, "vehicle.characterNode#characterSkin")); |
92 | self.characterMesh = Utils.indexToObject(i3dNode, getXMLString(xmlFile, "vehicle.characterNode#characterMesh")); |
93 | self.characterGloves = Utils.indexToObject(i3dNode, getXMLString(xmlFile, "vehicle.characterNode#characterGloves")); |
94 | self.characterSpineNode = Utils.indexToObject(i3dNode, getXMLString(xmlFile, "vehicle.characterNode#spineNode")); |
95 | local x,y,z = Utils.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, "vehicle.characterNode#skinOffset"), "0 0.14 0")); |
96 | setClipDistance(self.characterMesh, 150); |
97 | setClipDistance(self.characterGloves, 50); |
98 | link(self.characterNode, self.characterSkin); |
99 | setTranslation(self.characterSkin, x,y,z); |
100 | link(self.characterNode, self.characterMesh); |
101 | if self.characterGloves ~= nil then |
102 | link(self.characterNode, self.characterGloves); |
103 | setVisibility(self.characterGloves, false); |
104 | end; |
105 | skinBasenode = self.characterNode; |
106 | delete(i3dNode); |
107 | end; |
108 | self.characterFilename = filename; |
109 | end; |
110 | |
111 | local i = 0; |
112 | while true do |
113 | local key = string.format("vehicle.characterNode.ikChains.ikChain(%d)", i); |
114 | if not hasXMLProperty(xmlFile, key) then |
115 | break; |
116 | end; |
117 | local chain = IKUtil.loadIKChain(xmlFile, key, self.components, skinBasenode, self.ikChains, self.ikChainsById, self.getParentComponent, self); |
118 | if chain ~= nil then |
119 | self.characterIsSkinned = true; |
120 | end; |
121 | i = i + 1; |
122 | end; |
123 | |
124 | self.characterLeftArmIKChainId = getXMLString(xmlFile, "vehicle.characterNode#leftArmIKChainId"); |
125 | self.characterRightArmIKChainId = getXMLString(xmlFile, "vehicle.characterNode#rightArmIKChainId"); |
126 | if self.characterSpineNode == nil then |
127 | self.characterSpineNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.characterNode#spineNode")); |
128 | end; |
129 | local rot = Utils.getRadiansFromString(getXMLString(xmlFile, "vehicle.characterNode#spineRotation"), 3); |
130 | if rot ~= nil and self.characterSpineNode ~= nil then |
131 | setRotation(self.characterSpineNode, unpack(rot)); |
132 | end; |
133 | self.characterSpineSpeedDepended = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.characterNode#speedDependedSpine"), false); |
134 | self.characterSpineNodeMinRot = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.characterNode#spineNodeMinRot"), 10)); |
135 | self.characterSpineNodeMaxRot = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.characterNode#spineNodeMaxRot"), -10)); |
136 | self.characterSpineNodeMinAcc = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.characterNode#spineNodeMinAcc"), -1)/(1000*1000); |
137 | self.characterSpineNodeMaxAcc = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.characterNode#spineNodeMaxAcc"), 1)/(1000*1000); |
138 | self.characterSpineNodeAccDeadZone = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.characterNode#spineNodeAccDeadZone"), 0.2)/(1000*1000); |
139 | self.characterSpineLastRotation = 0; |
140 | |
141 | self:setCharacterVisibility(false); |
142 | end; |
143 | |
144 | self.nicknameRenderNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.nicknameRenderNode#index")); |
145 | self.nicknameRenderNodeOffset = Utils.getVectorNFromString(getXMLString(xmlFile, "vehicle.nicknameRenderNode#offset"), 3); |
146 | if self.nicknameRenderNode == nil then |
147 | if self.characterDistanceRefNode ~= nil then |
148 | self.nicknameRenderNode = self.characterDistanceRefNode; |
149 | if self.nicknameRenderNodeOffset == nil then |
150 | self.nicknameRenderNodeOffset = {0,1.5,0}; |
151 | end; |
152 | else |
153 | self.nicknameRenderNode = self.components[1].node; |
154 | end; |
155 | end; |
156 | if self.nicknameRenderNodeOffset == nil then |
157 | self.nicknameRenderNodeOffset = {0,4,0}; |
158 | end; |
159 | |
160 | self.enterAnimation = getXMLString(xmlFile, "vehicle.enterAnimation#name"); |
161 | end; |
162 | |
163 | function Steerable:postLoad(xmlFile) |
164 | if self.steering ~= nil then |
165 | self.steeringSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.steering#rotationSpeed"), 0); |
166 | local indoorRotation = getXMLFloat(xmlFile, "vehicle.steering#indoorRotation"); |
167 | if indoorRotation ~= nil then |
168 | self.steeringIndoorRotation = math.rad(indoorRotation); |
169 | end; |
170 | local outdoorRotation = getXMLFloat(xmlFile, "vehicle.steering#outdoorRotation"); |
171 | if outdoorRotation ~= nil then |
172 | self.steeringOutdoorRotation = math.rad(outdoorRotation); |
173 | end; |
174 | _, self.steeringLastRotation, _ = getRotation(self.steering); |
175 | end; |
176 | |
177 | if self.characterMesh ~= nil then |
178 | link(getRootNode(), self.characterMesh); |
179 | if self.characterGloves ~= nil then |
180 | link(getRootNode(), self.characterGloves); |
181 | end; |
182 | else |
183 | if self.characterNode ~= nil and self.characterIsSkinned then |
184 | link(getRootNode(), self.characterNode); |
185 | end; |
186 | end; |
187 | end; |
188 | |
189 | function Steerable:delete() |
190 | if self.characterNode ~= nil then |
191 | if self.characterFilename ~= nil then |
192 | delete(self.characterMesh); |
193 | if self.characterGloves ~= nil then |
194 | delete(self.characterGloves); |
195 | end; |
196 | Utils.releaseSharedI3DFile(self.characterFilename, self.baseDirectory, true); |
197 | elseif self.characterIsSkinned then -- if character is skinned but not shared |
198 | delete(self.characterNode); |
199 | end; |
200 | end; |
201 | |
202 | for _, camera in ipairs(self.cameras) do |
203 | camera:delete(); |
204 | end; |
205 | end; |
206 | |
207 | function Steerable:readStream(streamId, connection) |
208 | local isControlled = streamReadBool(streamId); |
209 | if isControlled then |
210 | self.controllerName = streamReadString(streamId); |
211 | self:onEnter(false); |
212 | end; |
213 | end; |
214 | |
215 | function Steerable:writeStream(streamId, connection) |
216 | if streamWriteBool(streamId, self.isControlled) then |
217 | streamWriteString(streamId, self.controllerName); |
218 | end; |
219 | end; |
220 | |
221 | function Steerable:readUpdateStream(streamId, timestamp, connection) |
222 | end; |
223 | |
224 | function Steerable:writeUpdateStream(streamId, connection, dirtyMask) |
225 | end; |
226 | |
227 | function Steerable:getXMLStatsAttributes() |
228 | if self.isControlled and self.controllerName ~= nil then |
229 | return string.format('controller="%s"', Utils.encodeToHTML(tostring(self.controllerName))); |
230 | end |
231 | return nil; |
232 | end |
233 | |
234 | function Steerable:mouseEvent(posX, posY, isDown, isUp, button) |
235 | self.cameras[self.camIndex]:mouseEvent(posX, posY, isDown, isUp, button); |
236 | end; |
237 | |
238 | function Steerable:keyEvent(unicode, sym, modifier, isDown) |
239 | end; |
240 | |
241 | function Steerable:update(dt) |
242 | if self:getIsActive() then |
243 | if self.isClient then |
244 | if self.steering ~= nil then |
245 | local rotTime = self.rotatedTime; |
246 | local baseRotation = self.steeringSpeed; |
247 | |
248 | if g_currentMission.controlledVehicle ~= self or not self.cameras[self.camIndex].isInside then |
249 | baseRotation = Utils.getNoNil(self.steeringOutdoorRotation, self.steeringSpeed); |
250 | else |
251 | baseRotation = Utils.getNoNil(self.steeringIndoorRotation, self.steeringSpeed); |
252 | end; |
253 | |
254 | if self.steeringOutdoorRotation ~= nil or self.steeringIndoorRotation ~= nil then |
255 | if self.rotatedTime > 0 then |
256 | rotTime = self.rotatedTime/math.abs(self.maxRotTime); |
257 | else |
258 | rotTime = self.rotatedTime/math.abs(self.minRotTime); |
259 | end; |
260 | end; |
261 | |
262 | local rotation = baseRotation * rotTime; |
263 | |
264 | if self.steeringLastRotation ~= rotation then |
265 | self.steeringLastRotation = rotation; |
266 | setRotation(self.steering, 0, rotation, 0); |
267 | |
268 | if self.characterLeftArmIKChainId ~= nil then |
269 | IKUtil.setIKChainDirty(self.ikChainsById, self.characterLeftArmIKChainId); |
270 | end; |
271 | if self.characterRightArmIKChainId ~= nil then |
272 | IKUtil.setIKChainDirty(self.ikChainsById, self.characterRightArmIKChainId); |
273 | end; |
274 | end; |
275 | end; |
276 | |
277 | if self.isEntered then |
278 | if self.characterSpineNode ~= nil and self.characterSpineSpeedDepended then |
279 | local acc = 0; |
280 | if math.abs(self.lastSpeedAcceleration) > self.characterSpineNodeAccDeadZone then |
281 | acc = self.lastSpeedAcceleration; |
282 | end; |
283 | local alpha = Utils.clamp((acc - self.characterSpineNodeMinAcc)/(self.characterSpineNodeMaxAcc - self.characterSpineNodeMinAcc), 0, 1); |
284 | local rotation = Utils.lerp(self.characterSpineNodeMinRot, self.characterSpineNodeMaxRot, alpha); |
285 | if rotation ~= self.characterSpineLastRotation then |
286 | self.characterSpineLastRotation = self.characterSpineLastRotation * 0.95 + rotation * 0.05; |
287 | |
288 | setRotation(self.characterSpineNode, self.characterSpineLastRotation, 0, 0); |
289 | |
290 | if self.characterLeftArmIKChainId ~= nil then |
291 | IKUtil.setIKChainDirty(self.ikChainsById, self.characterLeftArmIKChainId); |
292 | end; |
293 | if self.characterRightArmIKChainId ~= nil then |
294 | IKUtil.setIKChainDirty(self.ikChainsById, self.characterRightArmIKChainId); |
295 | end; |
296 | end; |
297 | end; |
298 | end; |
299 | end; |
300 | end; |
301 | |
302 | if self.isEntered and self.isClient then |
303 | if not g_currentMission.hasSpecialCamera then |
304 | setCamera(self.cameras[self.camIndex].cameraNode); |
305 | end; |
306 | self.cameras[self.camIndex]:update(dt); |
307 | |
308 | -- do all the input handling |
309 | local activeForInput = true; |
310 | if g_gui.currentGui ~= nil or g_currentMission.isPlayerFrozen then |
311 | activeForInput = false; |
312 | end; |
313 | |
314 | if activeForInput then --self:getIsActiveForInput(false) then |
315 | |
316 | if InputBinding.hasEvent(InputBinding.CAMERA_SWITCH) then |
317 | self.cameras[self.camIndex]:onDeactivate(); |
318 | self.camIndex = self.camIndex + 1; |
319 | if self.camIndex > self.numCameras then |
320 | self.camIndex = 1; |
321 | end; |
322 | self.cameras[self.camIndex]:onActivate(); |
323 | if self.setMirrorVisible ~= nil and self.mirrorAvailable == true then |
324 | if self.cameras[self.camIndex].useMirror then |
325 | self:setMirrorVisible(true); |
326 | else |
327 | self:setMirrorVisible(false); |
328 | end; |
329 | end; |
330 | end; |
331 | |
332 | -- camera zoom is handled here, otherwise the controls are laggy or don't work at all |
333 | if self.cameras[self.camIndex].allowTranslation then |
334 | if InputBinding.isPressed(InputBinding.CAMERA_ZOOM_IN) then |
335 | if InputBinding.getInputTypeOfDigitalAction(InputBinding.CAMERA_ZOOM_IN) == InputBinding.INPUTTYPE_MOUSE_WHEEL then |
336 | self.cameras[self.camIndex]:zoomSmoothly(-0.6); |
337 | else |
338 | self.cameras[self.camIndex]:zoomSmoothly(-0.005*dt); |
339 | end; |
340 | elseif InputBinding.isPressed(InputBinding.CAMERA_ZOOM_OUT) then |
341 | if InputBinding.getInputTypeOfDigitalAction(InputBinding.CAMERA_ZOOM_OUT) == InputBinding.INPUTTYPE_MOUSE_WHEEL then |
342 | self.cameras[self.camIndex]:zoomSmoothly(0.6); |
343 | else |
344 | self.cameras[self.camIndex]:zoomSmoothly(0.005*dt); |
345 | end; |
346 | end; |
347 | end; |
348 | |
349 | if self:canToggleLight() then |
350 | |
351 | if self.numLightTypes >= 1 and InputBinding.hasEvent(InputBinding.TOGGLE_LIGHT_FRONT) then |
352 | playSample(g_currentMission.toggleLightsSound, 1, 1.0, 0); |
353 | local lightsTypesMask = bitXOR(self.lightsTypesMask, 2^0); |
354 | self:setLightsTypesMask(lightsTypesMask); |
355 | elseif InputBinding.hasEvent(InputBinding.TOGGLE_LIGHTS) then |
356 | Steerable.setNextLightsState(self); |
357 | end; |
358 | |
359 | if self.numLightTypes >= 2 then |
360 | -- work light back has light type 1 |
361 | if InputBinding.hasEvent(InputBinding.TOGGLE_WORK_LIGHT_BACK) then |
362 | playSample(g_currentMission.toggleLightsSound, 1, 1.0, 0); |
363 | local lightsTypesMask = bitXOR(self.lightsTypesMask, 2^1); |
364 | self:setLightsTypesMask(lightsTypesMask); |
365 | end |
366 | |
367 | if self.numLightTypes >= 3 then |
368 | -- work light front has light type 2 |
369 | if InputBinding.hasEvent(InputBinding.TOGGLE_WORK_LIGHT_FRONT) then |
370 | playSample(g_currentMission.toggleLightsSound, 1, 1.0, 0); |
371 | local lightsTypesMask = bitXOR(self.lightsTypesMask, 2^2); |
372 | self:setLightsTypesMask(lightsTypesMask); |
373 | end |
374 | |
375 | if self.numLightTypes >= 4 then |
376 | -- work light has light type 3 |
377 | if InputBinding.hasEvent(InputBinding.TOGGLE_HIGH_BEAM_LIGHT) then |
378 | playSample(g_currentMission.toggleLightsSound, 1, 1.0, 0); |
379 | local lightsTypesMask = bitXOR(self.lightsTypesMask, 2^3); |
380 | self:setLightsTypesMask(lightsTypesMask); |
381 | end |
382 | end |
383 | end |
384 | end |
385 | |
386 | end; |
387 | |
388 | end; |
389 | |
390 | -- update character visiblity |
391 | if self.characterNode ~= nil then |
392 | local cx, cy, cz = getWorldTranslation(self.characterDistanceRefNode); |
393 | local x,y,z = getWorldTranslation(getCamera()); |
394 | local dist = Utils.vector3Length(cx-x, cy-y, cz-z); |
395 | local visible = dist >= self.characterCameraMinDistance; |
396 | self:setCharacterVisibility(visible); |
397 | end; |
398 | end; |
399 | end; |
400 | |
401 | function Steerable:updateTick(dt) |
402 | end; |
403 | |
404 | function Steerable:draw() |
405 | if not self.isEntered then |
406 | return; |
407 | end; |
408 | |
409 | -- new in console version: show common commands (toggle lights, honk, etc) in button help |
410 | if GS_IS_CONSOLE_VERSION then |
411 | g_currentMission:addHelpButtonText(g_i18n:getText("ExitVehicle"), InputBinding.ENTER); |
412 | end; |
413 | |
414 | if self:canToggleLight() and not self.isAttachable then |
415 | if g_currentMission.environment.currentHour > 20 or g_currentMission.environment.currentHour < 7 then |
416 | g_currentMission:addHelpButtonText(g_i18n:getText("TOGGLE_LIGHTS"), InputBinding.TOGGLE_LIGHTS); |
417 | end; |
418 | end; |
419 | end; |
420 | |
421 | function Steerable:drawUIInfo(superFunc) |
422 | if superFunc ~= nil then |
423 | superFunc(self); |
424 | end; |
425 | |
426 | if not self.isEntered and self.isClient and self:getIsActive() and self.isControlled and g_gui.currentGui == nil and g_currentMission.showHudEnv then |
427 | local x,y,z = getWorldTranslation(self.nicknameRenderNode); |
428 | local x1,y1,z1 = getWorldTranslation(getCamera()) |
429 | local distSq = Utils.vector3LengthSq(x-x1,y-y1,z-z1); |
430 | if distSq <= 100*100 then |
431 | x = x + self.nicknameRenderNodeOffset[1]; |
432 | y = y + self.nicknameRenderNodeOffset[2]; |
433 | z = z + self.nicknameRenderNodeOffset[3]; |
434 | local sx,sy,sz = project(x,y,z); |
435 | if sz <= 1 then |
436 | setTextAlignment(RenderText.ALIGN_CENTER); |
437 | setTextBold(false); |
438 | setTextColor(0.0, 0.0, 0.0, 0.75); |
439 | renderText(sx, sy-0.0015, getCorrectTextSize(0.02), self.controllerName); |
440 | |
441 | setTextColor(0.5, 1.0, 0.5, 1.0); |
442 | renderText(sx, sy, getCorrectTextSize(0.02), self.controllerName); |
443 | |
444 | setTextAlignment(RenderText.ALIGN_LEFT); |
445 | end; |
446 | end; |
447 | end; |
448 | end; |
449 | |
450 | function Steerable:onEnter(isControlling) |
451 | self.isControlled = true; |
452 | if isControlling then |
453 | self.isEntered = true; |
454 | |
455 | self.camIndex = 1; |
456 | self.cameras[self.camIndex]:onActivate(); |
457 | end; |
458 | |
459 | for _, chain in pairs(self.ikChains) do |
460 | IKUtil.setIKChainDirty(self.ikChainsById, chain.id); |
461 | end; |
462 | |
463 | self:setCharacterVisibility(true); |
464 | |
465 | if self.enterAnimation ~= nil and self.playAnimation ~= nil then |
466 | self:playAnimation(self.enterAnimation, 1, nil, true); |
467 | end; |
468 | |
469 | g_currentMission.controlledVehicles[self] = self; |
470 | end; |
471 | |
472 | function Steerable:onLeave() |
473 | self.isControlled = false; |
474 | self.cameras[self.camIndex]:onDeactivate(); |
475 | |
476 | self:setCharacterVisibility(not self.disableCharacterOnLeave); |
477 | |
478 | if self.deactivateOnLeave then |
479 | self:onDeactivate(); |
480 | if self.enterAnimation ~= nil and self.playAnimation ~= nil then |
481 | self:playAnimation(self.enterAnimation, -1, nil, true); |
482 | end; |
483 | else |
484 | self:onDeactivateSounds(); |
485 | self:onDeactivateLights(); |
486 | end; |
487 | |
488 | self.isEntered = false; |
489 | g_currentMission.controlledVehicles[self] = nil; |
490 | end; |
491 | |
492 | function Steerable:setCharacterVisibility(isVisible) |
493 | if self.characterNode ~= nil then |
494 | setVisibility(self.characterNode, isVisible); |
495 | if self.characterMesh ~= nil then |
496 | setVisibility(self.characterMesh, isVisible); |
497 | end; |
498 | end; |
499 | end; |
500 | |
501 | function Steerable:loadFromAttributesAndNodes(xmlFile, key, resetVehicles) |
502 | return BaseMission.VEHICLE_LOAD_OK; |
503 | end; |
504 | |
505 | function Steerable:getSaveAttributesAndNodes(nodeIdent) |
506 | local attributes = ""; |
507 | local nodes = ""; |
508 | return attributes, nodes; |
509 | end; |
510 | |
511 | function Steerable:setLightsTypesMask(lightsTypesMask) |
512 | self.lightsState = 0; |
513 | end |
514 | |
515 | function Steerable.setNextLightsState(self) |
516 | -- loop through light types and keep first light enabled |
517 | |
518 | if self.numLightsStates > 0 then |
519 | playSample(g_currentMission.toggleLightsSound, 1, 1.0, 0); |
520 | local lightsState = self.lightsState + 1; |
521 | if lightsState > self.numLightsStates or (self.lightsState == 0 and self.lightsTypesMask > 0) then |
522 | lightsState = 0; |
523 | end |
524 | |
525 | local lightsTypesMask = 0; |
526 | if lightsState > 0 then |
527 | lightsTypesMask = bitOR(1, 2^(lightsState-1)); |
528 | end |
529 | |
530 | if self.isAttachable and lightsState > 0 then |
531 | lightsState = math.max(lightsState, 2); |
532 | local stdLights = 0; |
533 | if self.attacherVehicle ~= nil then |
534 | stdLights = bitAND(self.attacherVehicle.lightsTypesMask, 1); |
535 | end; |
536 | lightsTypesMask = bitOR(stdLights, 2^(lightsState-1)); |
537 | end; |
538 | |
539 | self:setLightsTypesMask(lightsTypesMask); |
540 | self.lightsState = lightsState; |
541 | end |
542 | end |
543 | |
544 | function Steerable:getIsActiveForInput(superFunc, onlyTrueIfSelected) |
545 | if not self.isAttachable then |
546 | return superFunc(self, onlyTrueIfSelected); |
547 | else |
548 | if g_gui.currentGui ~= nil or g_currentMission.isPlayerFrozen then |
549 | return false; |
550 | end; |
551 | if self.isEntered then |
552 | if self.attacherVehicle ~= nil then |
553 | return true; |
554 | else |
555 | return false; |
556 | end; |
557 | end; |
558 | return false; |
559 | end; |
560 | end; |
561 | |
562 | function Steerable:addToolCameras(cameras) |
563 | for i,toolCamera in pairs(cameras) do |
564 | table.insert(self.cameras, toolCamera); |
565 | end; |
566 | self.numCameras = #self.cameras; |
567 | end; |
568 | |
569 | function Steerable:removeToolCameras(cameras) |
570 | self.cameras[self.camIndex]:onDeactivate(); |
571 | for i,toolCamera in pairs(cameras) do |
572 | for j,camera in pairs(self.cameras) do |
573 | if toolCamera == camera then |
574 | table.remove(self.cameras, j); |
575 | break; |
576 | end; |
577 | end; |
578 | end; |
579 | self.numCameras = #self.cameras; |
580 | if self.camIndex > self.numCameras then |
581 | self.camIndex = 1; |
582 | end; |
583 | self.cameras[self.camIndex]:onActivate(); |
584 | end;
|
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de