57 | function AnimatedObject:load(nodeId) |
58 | self.nodeId = nodeId |
59 | |
60 | local xmlFilename = getUserAttribute(nodeId, "xmlFilename") |
61 | |
62 | if xmlFilename == nil then |
63 | print("Error: Missing 'xmlFilename' user attribute for AnimatedObject node '"..getName(nodeId).."'!") |
64 | return false |
65 | end |
66 | |
67 | local baseDir = g_currentMission.loadingMapBaseDirectory |
68 | if baseDir == "" then |
69 | baseDir = Utils.getNoNil(self.baseDirectory, baseDir) |
70 | end |
71 | |
72 | local i18n = g_i18n; |
73 | if self.customEnvironment ~= nil then |
74 | i18n = _G[self.customEnvironment].g_i18n; |
75 | end |
76 | |
77 | self.xmlFilename = Utils.getFilename(xmlFilename, baseDir) |
78 | local success = true |
79 | local xmlFile = loadXMLFile("AnimatedObject", self.xmlFilename) |
80 | if xmlFile ~= 0 then |
81 | local index = getUserAttribute(nodeId, "index") |
82 | if index ~= nil then |
83 | local key = nil |
84 | local i = 0 |
85 | while true do |
86 | local objectKey = string.format("animatedObjects.animatedObject(%d)", i) |
87 | if not hasXMLProperty(xmlFile, objectKey) then |
88 | break |
89 | end |
90 | |
91 | local configIndex = getXMLString(xmlFile, objectKey.."#index") |
92 | if configIndex == index then |
93 | key = objectKey |
94 | break |
95 | end |
96 | i = i + 1 |
97 | end |
98 | |
99 | if key ~= nil then |
100 | self.saveId = getXMLString(xmlFile, key.."#saveId"); |
101 | if self.saveId == nil then |
102 | self.saveId = "AnimatedObject_"..getName(nodeId) |
103 | end |
104 | |
105 | local animKey = key .. ".animation" |
106 | |
107 | self.animation = {} |
108 | self.animation.parts = {} |
109 | self.animation.duration = Utils.getNoNil(getXMLFloat(xmlFile, animKey.."#duration"), 3) * 1000 |
110 | if self.animation.duration == 0 then |
111 | self.animation.duration = 1000 |
112 | end |
113 | self.animation.time = 0 |
114 | self.animation.direction = 0 |
115 | |
116 | local i = 0 |
117 | while true do |
118 | local partKey = string.format("%s.part(%d)", animKey, i) |
119 | if not hasXMLProperty(xmlFile, partKey) then |
120 | break |
121 | end |
122 | |
123 | local node = Utils.indexToObject(self.nodeId, getXMLString(xmlFile, partKey.."#node")) |
124 | if node ~= nil then |
125 | local part = {} |
126 | part.node = node |
127 | part.animCurve = AnimCurve:new(linearInterpolatorN) |
128 | local hasFrames = false |
129 | local j = 0 |
130 | while true do |
131 | local frameKey = string.format("%s.keyFrame(%d)", partKey, j) |
132 | if not hasXMLProperty(xmlFile, frameKey) then |
133 | break |
134 | end |
135 | |
136 | local keyTime = getXMLFloat(xmlFile, frameKey.."#time") |
137 | local values = {self:loadFrameValues(xmlFile, frameKey, node)} |
138 | part.animCurve:addKeyframe({ v=values, time = keyTime}) |
139 | hasFrames = true |
140 | |
141 | j = j + 1 |
142 | end |
143 | |
144 | if hasFrames then |
145 | table.insert(self.animation.parts, part) |
146 | end |
147 | end |
148 | i = i + 1 |
149 | end |
150 | |
151 | local initialTime = Utils.getNoNil(getXMLFloat(xmlFile, animKey.."#initialTime"), 0)*1000 |
152 | self:setAnimTime(initialTime/self.animation.duration) |
153 | |
154 | local startTime = getXMLFloat(xmlFile, key..".openingHours#startTime") |
155 | local endTime = getXMLFloat(xmlFile, key..".openingHours#endTime") |
156 | if startTime ~= nil and endTime ~= nil then |
157 | local disableIfClosed = Utils.getNoNil(getXMLBool(xmlFile, key..".openingHours#disableIfClosed"), false) |
158 | local closedText = getXMLString(xmlFile, key..".openingHours#closedText") |
159 | if closedText ~= nil then |
160 | if i18n:hasText(closedText) then |
161 | closedText = i18n:getText(closedText) |
162 | end |
163 | end |
164 | self.openingHours = {startTime=startTime, endTime=endTime, disableIfClosed=disableIfClosed, closedText=closedText} |
165 | g_currentMission.environment:addHourChangeListener(self) |
166 | end |
167 | |
168 | self.isEnabled = true |
169 | |
170 | |
171 | local triggerId = Utils.indexToObject(self.nodeId, getXMLString(xmlFile, key..".controls#triggerNode")) |
172 | if triggerId ~= nil then |
173 | self.controls = {} |
174 | self.controls.triggerId = triggerId |
175 | |
176 | addTrigger(self.controls.triggerId, "triggerCallback", self) |
177 | for i=0, getNumOfChildren(self.controls.triggerId)-1 do |
178 | addTrigger(getChildAt(self.controls.triggerId, i), "triggerCallback", self) |
179 | end |
180 | |
181 | local posKey = getXMLString(xmlFile, key..".controls#posKey") |
182 | if posKey ~= nil then |
183 | if InputBinding[posKey] ~= nil then |
184 | self.controls.posKey = InputBinding[posKey] |
185 | local posText = getXMLString(xmlFile, key..".controls#posText") |
186 | if posText ~= nil then |
187 | if i18n:hasText(posText) then |
188 | posText = i18n:getText(posText) |
189 | end |
190 | self.controls.posText = posText |
191 | end |
192 | local negText = getXMLString(xmlFile, key..".controls#negText") |
193 | if negText ~= nil then |
194 | if i18n:hasText(negText) then |
195 | negText = i18n:getText(negText) |
196 | end |
197 | self.controls.negText = negText |
198 | end |
199 | |
200 | local negKey = getXMLString(xmlFile, key..".controls#negKey") |
201 | if negKey ~= nil then |
202 | if InputBinding[negKey] ~= nil then |
203 | self.controls.negKey = InputBinding[negKey] |
204 | else |
205 | print("Warning: Negative direction key '"..negKey.."' not defined!") |
206 | end |
207 | end |
208 | else |
209 | print("Warning: Positive direction key '"..posKey.."' not defined!") |
210 | end |
211 | end |
212 | end |
213 | |
214 | if g_client ~= nil then |
215 | self.sampleMoving = SoundUtil.loadSample(xmlFile, {}, key..".sound", nil, baseDir, self.nodeId) |
216 | end |
217 | else |
218 | success = false |
219 | print("Error: index '"..index.."' not found in AnimatedObject xml '"..self.xmlFilename.."'!") |
220 | end |
221 | else |
222 | success = false |
223 | print("Error: Missing 'index' user attribute for AnimatedObject node '"..getName(nodeId).."'!") |
224 | end |
225 | |
226 | delete(xmlFile) |
227 | end |
228 | |
229 | self.animatedObjectDirtyFlag = self:getNextDirtyFlag(); |
230 | |
231 | |
232 | return success |
233 | end |
250 | function AnimatedObject:loadFrameValues(xmlFile, key, node) |
251 | local rx,ry,rz = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rotation")) |
252 | local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#translation")) |
253 | local sx,sy,sz = Utils.getVectorFromString(getXMLString(xmlFile, key.."#scale")) |
254 | local isVisible = Utils.getNoNil(getXMLBool(xmlFile, key.."#visibility"), true) |
255 | |
256 | local drx,dry,drz = getRotation(node) |
257 | rx = Utils.getNoNilRad(rx, drx) |
258 | ry = Utils.getNoNilRad(ry, dry) |
259 | rz = Utils.getNoNilRad(rz, drz) |
260 | local dx,dy,dz = getTranslation(node) |
261 | x = Utils.getNoNil(x, dx) |
262 | y = Utils.getNoNil(y, dy) |
263 | z = Utils.getNoNil(z, dz) |
264 | local dsx,dsy,dsz = getScale(node) |
265 | sx = Utils.getNoNil(sx, dsx) |
266 | sy = Utils.getNoNil(sy, dsy) |
267 | sz = Utils.getNoNil(sz, dsz) |
268 | |
269 | local visibility = 1 |
270 | if not isVisible then |
271 | visibility = 0 |
272 | end |
273 | |
274 | return x, y, z, rx, ry, rz, sx, sy, sz, visibility |
275 | end |
381 | function AnimatedObject:update(dt) |
382 | AnimatedObject:superClass().update(self, dt) |
383 | |
384 | if self.playerInRange then |
385 | if self.isEnabled then |
386 | if self.controls.posKey ~= nil and g_gui.currentGui == nil and not g_currentMission.isPlayerFrozen then |
387 | if self.controls.negKey == nil then |
388 | -- event based action |
389 | if InputBinding.hasEvent(self.controls.posKey) then |
390 | self.animation.direction = self.animation.direction * -1 |
391 | if self.animation.direction == 0 then |
392 | if self.animation.time > 0 then |
393 | self.animation.direction = -1 |
394 | else |
395 | self.animation.direction = 1 |
396 | end |
397 | end |
398 | if g_server == nil then |
399 | g_client:getServerConnection():sendEvent(AnimatedObjectEvent:new(self, self.animation.direction)) |
400 | end |
401 | end |
402 | |
403 | local text = nil |
404 | if self.animation.direction == 0 then |
405 | if self.animation.time > 0 then |
406 | text = self.controls.negText |
407 | else |
408 | text = self.controls.posText |
409 | end |
410 | else |
411 | if self.animation.direction == 1 then |
412 | text = self.controls.negText |
413 | else |
414 | text = self.controls.posText |
415 | end |
416 | end |
417 | |
418 | if text ~= nil then |
419 | g_currentMission:addHelpButtonText(text, self.controls.posKey, nil, GS_PRIO_VERY_HIGH); |
420 | end |
421 | else |
422 | -- move if key is pressed action |
423 | local changed = false |
424 | if InputBinding.isPressed(self.controls.posKey) then |
425 | self.wasPressed = true |
426 | if self.animation.direction ~= 1 and self.animation.time ~= 1 then |
427 | self.animation.direction = 1 |
428 | changed = true |
429 | end |
430 | elseif InputBinding.isPressed(self.controls.negKey) then |
431 | self.wasPressed = true |
432 | if self.animation.direction ~= -1 and self.animation.time ~= 0 then |
433 | self.animation.direction = -1 |
434 | changed = true |
435 | end |
436 | else |
437 | if self.animation.direction ~= 0 and self.wasPressed then |
438 | self.animation.direction = 0 |
439 | changed = true |
440 | end |
441 | end; |
442 | |
443 | if g_server == nil and changed then |
444 | g_client:getServerConnection():sendEvent(AnimatedObjectEvent:new(self, self.animation.direction)) |
445 | end |
446 | |
447 | if self.controls.posText ~= nil then |
448 | g_currentMission:addHelpButtonText(self.controls.posText, self.controls.posKey, nil, GS_PRIO_VERY_HIGH); |
449 | end; |
450 | if self.controls.negText ~= nil then |
451 | g_currentMission:addHelpButtonText(self.controls.negText, self.controls.negKey, nil, GS_PRIO_VERY_HIGH); |
452 | end; |
453 | end |
454 | end |
455 | else |
456 | if self.openingHours ~= nil and self.openingHours.closedText ~= nil then |
457 | g_currentMission:addExtraPrintText(self.openingHours.closedText) |
458 | end |
459 | end |
460 | end |
461 | end |
466 | function AnimatedObject:updateTick(dt) |
467 | AnimatedObject:superClass().updateTick(self, dt) |
468 | |
469 | if self.isServer then |
470 | if self.animation.direction ~= 0 then |
471 | local newAnimTime = Utils.clamp(self.animation.time + (self.animation.direction*dt)/self.animation.duration, 0, 1) |
472 | self:setAnimTime(newAnimTime) |
473 | if newAnimTime == 0 or newAnimTime == 1 then |
474 | self.animation.direction = 0 |
475 | end |
476 | |
477 | self:raiseDirtyFlags(self.animatedObjectDirtyFlag); |
478 | end |
479 | |
480 | self.isMoving = self.animation.direction ~= 0; |
481 | |
482 | if self.sendIsMoving ~= self.isMoving then |
483 | self:raiseDirtyFlags(self.animatedObjectDirtyFlag); |
484 | end; |
485 | end |
486 | |
487 | if self.isClient and self.sampleMoving ~= nil then |
488 | if self.isMoving then |
489 | if not self.sampleMoving.isPlaying then |
490 | SoundUtil.play3DSample(self.sampleMoving) |
491 | self.sampleMoving.isPlaying = true |
492 | end |
493 | else |
494 | if self.sampleMoving.isPlaying then |
495 | SoundUtil.stop3DSample(self.sampleMoving) |
496 | self.sampleMoving.isPlaying = false |
497 | end |
498 | end |
499 | end |
500 | end |