GenericEffect.py (13744B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\environment\effects\GenericEffect.py 2 import blue 3 import trinity 4 import audio2 5 from uthread2 import call_after_simtime_delay 6 from fsdBuiltData.common.graphicIDs import GetGraphicFile 7 import eve.client.script.environment.spaceObject.ship as ship 8 import eve.client.script.environment.effects.effectConsts as effectConst 9 STOP_REASON_DEFAULT = 'STOP_REASON_DEFAULT' 10 STOP_REASON_BALL_REMOVED = 'STOP_REASON_BALL_REMOVED' 11 12 class GenericEffect(object): 13 __guid__ = 'effects.GenericEffect' 14 15 def __init__(self, trigger, effect = None, graphicFile = None): 16 self.ballIDs = [trigger.shipID, trigger.targetID] 17 self.gfx = None 18 self.gfxModel = None 19 self.graphicFile = graphicFile 20 self.transformFlags = [0] if effect is None else effect.transformFlags 21 self.mergeFlags = [0] if effect is None else effect.mergeFlags 22 if trigger.duration is not None and trigger.duration > 0: 23 self.duration = trigger.duration 24 else: 25 self.duration = getattr(effect, 'duration', 10000) 26 if effect and effect.secondaryGraphicID is not None: 27 self.secondaryGraphicFile = GetGraphicFile(effect.secondaryGraphicID) 28 else: 29 self.secondaryGraphicFile = None 30 self.scaleTime = effect.timeScale if effect and effect.timeScale is not None else False 31 self.sourceOffset = 0 if effect is None else effect.sourceOffset 32 self.destinationOffset = 0 if effect is None else effect.destinationOffset 33 self.animationName = None if effect is None else effect.animationName 34 self.graphicInfo = trigger.graphicInfo 35 self.graphicRadius = getattr(self.graphicInfo, 'graphicRadius', None) 36 self.lingerOnDeathTimer = 0 37 if self.graphicInfo is not None and hasattr(self.graphicInfo, 'get'): 38 self.lingerOnDeathTimer = self.graphicInfo.get('lingerOnDeathTimer') or 0.0 39 self.startTime = trigger.startTime 40 self.timeFromStart = trigger.timeFromStart 41 self.moduleID = trigger.moduleID 42 self.fxSequencer = sm.GetService('FxSequencer') 43 self.observer = None 44 45 def Prepare(self, addToScene = True): 46 pass 47 48 def Start(self, duration): 49 pass 50 51 def Stop(self, reason = STOP_REASON_DEFAULT): 52 pass 53 54 def Repeat(self, duration): 55 pass 56 57 def UpdateGraphicInfo(self, newGraphicInfo): 58 pass 59 60 def GetBalls(self): 61 return self.ballIDs 62 63 def GetBallPositionCurve(self, ball): 64 if hasattr(ball, 'GetPositionCurve'): 65 return ball.GetPositionCurve() 66 return ball 67 68 def GetEffectShipID(self): 69 try: 70 return self.ballIDs[0] 71 except IndexError: 72 return None 73 74 def GetEffectShipBall(self): 75 return self.fxSequencer.GetBall(self.GetEffectShipID()) 76 77 def GetEffectTargetID(self): 78 try: 79 return self.ballIDs[1] 80 except IndexError: 81 return None 82 83 def GetEffectTargetBall(self): 84 return self.fxSequencer.GetBall(self.GetEffectTargetID()) 85 86 def PlayNamedAnimations(self, model, animName): 87 if not model: 88 return 89 for each in model.curveSets: 90 if each.name == animName: 91 each.Play() 92 93 def PlayNamedChildAnimations(self, model, animName): 94 if not model: 95 return 96 for each in model.effectChildren: 97 for curve in getattr(each, 'curveSets', []): 98 if curve.name == animName: 99 curve.Play() 100 101 def GetEffectRadius(self): 102 srcRadius = 35 103 if self.gfx: 104 effectBall = self.GetEffectShipBall() 105 if effectBall is not None: 106 srcRadius = effectBall.radius 107 return srcRadius 108 109 def ScaleEffectAudioEmitter(self, entity, scaler = 1.0): 110 srcRadius = self.GetEffectRadius() 111 if srcRadius < 0: 112 return 113 attenuation = pow(srcRadius, 0.95) * 33 * scaler 114 if entity is not None: 115 entity.SetAttenuationScalingFactor(attenuation) 116 117 def AttachObserverToTriEventCurve(self): 118 if self.gfx is None: 119 return 120 for curve in self.gfx.Find('trinity.TriEventCurve'): 121 if curve.name == 'audioEvents': 122 curve.eventListener = self.observer.observer 123 124 def CheckForExistingObserver(self, location, name): 125 if location is not None: 126 for observer in location.Find('trinity.TriObserverLocal'): 127 if getattr(observer, 'observer', None) is not None: 128 if observer.observer.name == name: 129 self.observer = observer 130 return 131 132 if self.gfx is None: 133 return 134 for observer in self.gfx.Find('trinity.TriObserverLocal'): 135 if getattr(observer, 'observer', None) is not None: 136 if 'booster' not in observer.observer.name: 137 self.observer = observer 138 return 139 140 def AddSoundToEffect(self, scaler = 1.0, model = None, guidOverride = ''): 141 shipID = self.GetEffectShipID() 142 emitter_name = 'effect_' + str(shipID) + '_' + (guidOverride or self.__guid__) 143 self.CheckForExistingObserver(model, emitter_name) 144 if self.observer is None: 145 self.CreateNewAudioEmitter(emitter_name) 146 model = model or self.gfx 147 self.AttachObserverToModel(model) 148 self.AttachObserverToTriEventCurve() 149 if hasattr(self.observer, 'observer') and self.observer.observer is not None: 150 self.ScaleEffectAudioEmitter(self.observer.observer, scaler) 151 152 def CreateNewAudioEmitter(self, emitter_name): 153 self.observer = trinity.TriObserverLocal() 154 entity = audio2.AudEmitter(emitter_name) 155 self.observer.observer = entity 156 157 def SetupEffectEmitter(self): 158 if self.observer is None: 159 self.AddSoundToEffect(scaler=1.0) 160 161 def SendAudioEvent(self, eventName): 162 triObserver = self.observer 163 if hasattr(triObserver, 'observer') and triObserver.observer is not None: 164 triObserver.observer.SendEvent(eventName) 165 166 def AttachObserverToModel(self, model): 167 model.observers.append(self.observer) 168 169 def AddToScene(self, effect): 170 scene = self.fxSequencer.GetScene() 171 if scene is not None: 172 scene.objects.append(effect) 173 174 def RemoveFromScene(self, effect): 175 scene = self.fxSequencer.GetScene() 176 if scene is not None: 177 scene.objects.fremove(effect) 178 179 def RecycleOrLoad(self, resPath): 180 return trinity.Load(resPath) 181 182 def _SpawnClientBall(self, position): 183 bp = self.fxSequencer.GetBallpark() 184 if bp is None: 185 return 186 egopos = bp.GetCurrentEgoPos() 187 ballPosition = (position[0] + egopos[0], position[1] + egopos[1], position[2] + egopos[2]) 188 return bp.AddClientSideBall(ballPosition) 189 190 def _DestroyClientBall(self, ball): 191 bp = self.fxSequencer.GetBallpark() 192 if bp is not None: 193 bp.RemoveBall(ball.id) 194 195 196 class ShipEffect(GenericEffect): 197 __guid__ = 'effects.ShipEffect' 198 199 def _CleanUp(self, model): 200 self.RemoveFromScene(model) 201 self.gfx = None 202 if model: 203 model.translationCurve = None 204 model.rotationCurve = None 205 self.gfxModel = None 206 self.observer = None 207 208 def Stop(self, reason = STOP_REASON_DEFAULT): 209 if self.gfx is None: 210 raise RuntimeError('ShipEffect: no effect defined:' + self.__guid__) 211 if self.lingerOnDeathTimer > 0.0 and reason != STOP_REASON_BALL_REMOVED: 212 if hasattr(self.gfx, 'controllers'): 213 self.gfx.SetControllerVariable('isOn', 0.0) 214 call_after_simtime_delay(self._CleanUp, self.lingerOnDeathTimer, self.gfxModel) 215 else: 216 self._CleanUp(self.gfxModel) 217 218 def Prepare(self, addToScene = True): 219 shipBall = self.GetEffectShipBall() 220 if shipBall is None: 221 raise RuntimeError('ShipEffect: no ball found:' + self.__guid__) 222 self.gfx = self.RecycleOrLoad(self.graphicFile) 223 if self.gfx is None: 224 raise RuntimeError('ShipEffect: no effect found:' + self.__guid__) 225 if type(self.gfx) == trinity.EveTransform: 226 self.gfxModel = trinity.EveRootTransform() 227 self.gfxModel.children.append(self.gfx) 228 elif isinstance(self.gfx, trinity.EveChildContainer): 229 self.gfxModel = trinity.EveEffectRoot2() 230 self.gfxModel.effectChildren.append(self.gfx) 231 else: 232 self.gfxModel = self.gfx 233 self.gfxModel.modelRotationCurve = getattr(shipBall.model, 'modelRotationCurve', None) 234 self.gfxModel.modelTranslationCurve = getattr(shipBall.model, 'modelTranslationCurve', None) 235 effectBall = shipBall 236 if effectConst.FX_TF_POSITION_BALL in self.transformFlags: 237 self.gfxModel.translationCurve = self.GetBallPositionCurve(shipBall) 238 if effectConst.FX_TF_POSITION_MODEL in self.transformFlags: 239 behavior = trinity.EveLocalPositionBehavior.centerBounds 240 self.gfxModel.translationCurve = trinity.EveLocalPositionCurve(behavior) 241 self.gfxModel.translationCurve.parent = shipBall.model 242 if effectConst.FX_TF_POSITION_TARGET in self.transformFlags: 243 effectBall = self.GetEffectTargetBall() 244 self.gfxModel.translationCurve = self.GetBallPositionCurve(effectBall) 245 if effectConst.FX_TF_ELLIPSOID in self.transformFlags: 246 if hasattr(effectBall.model, 'shapeEllipsoidCenter'): 247 radius = effectBall.model.shapeEllipsoidRadius 248 self.gfxModel.scaling = radius 249 position = effectBall.model.shapeEllipsoidCenter 250 curve = trinity.Tr2TranslationAdapter() 251 curve.value = position 252 self.gfxModel.modelTranslationCurve = curve 253 self.gfxModel.name = 'THIS ONE' 254 else: 255 self.transformFlags.append(effectConst.FX_TF_SCALE_BOUNDING) 256 if self.graphicRadius is not None: 257 self.gfxModel.scaling = (self.graphicRadius, self.graphicRadius, self.graphicRadius) 258 elif effectConst.FX_TF_SCALE_BOUNDING in self.transformFlags: 259 shipBBoxMin, shipBBoxMax = effectBall.model.GetLocalBoundingBox() 260 bBox = (max(-shipBBoxMin[0], shipBBoxMax[0]) * 1.2, max(-shipBBoxMin[1], shipBBoxMax[1]) * 1.2, max(-shipBBoxMin[2], shipBBoxMax[2]) * 1.2) 261 self.gfxModel.scaling = bBox 262 elif effectConst.FX_TF_SCALE_SYMMETRIC in self.transformFlags: 263 if effectBall.model is not None: 264 radius = effectBall.model.GetBoundingSphereRadius() 265 self.gfxModel.scaling = (radius, radius, radius) 266 self.gfx.translation = (0, 0, 0) 267 elif effectConst.FX_TF_SCALE_RADIUS in self.transformFlags: 268 if effectBall.model is not None: 269 radius = effectBall.model.GetBoundingSphereRadius() 270 self.gfxModel.scaling = (radius, radius, radius) 271 if effectConst.FX_TF_ROTATION_BALL in self.transformFlags: 272 self.gfxModel.rotationCurve = effectBall 273 self.gfxModel.name = self.__guid__ 274 self.AddSoundToEffect(2) 275 if addToScene: 276 self.AddToScene(self.gfxModel) 277 278 def Start(self, duration): 279 if self.gfx is None: 280 raise RuntimeError('ShipEffect: no effect defined:' + self.__guid__) 281 curveSets = self.gfx.curveSets 282 if len(curveSets) > 0: 283 if self.scaleTime: 284 length = self.gfx.curveSets[0].GetMaxCurveDuration() 285 if length > 0.0: 286 scaleValue = length / (duration / 1000.0) 287 self.gfx.curveSets[0].scale = scaleValue 288 curveSets[0].PlayFrom(self.timeFromStart / float(const.SEC)) 289 if hasattr(self.gfx, 'controllers'): 290 secondsFromStart = self.timeFromStart / float(const.SEC) 291 self.gfx.SetControllerVariable('elapsedTime', secondsFromStart) 292 self.gfx.SetControllerVariable('isOn', 1.0) 293 self.gfx.StartControllers() 294 295 def Repeat(self, duration): 296 if self.gfx is None: 297 return 298 curveSets = [] 299 if self.gfxModel is not None: 300 if hasattr(self.gfxModel, 'children'): 301 gfxModelChildren = self.gfxModel.children 302 if len(gfxModelChildren): 303 curveSets = gfxModelChildren[0].curveSets 304 elif isinstance(self.gfxModel, trinity.EveEffectRoot2): 305 curveSets = self.gfxModel.curveSets 306 if len(curveSets): 307 curveSets[0].Play() 308 309 310 def GetBoundingBox(shipBall, scale = 1.0): 311 if not isinstance(shipBall, ship.Ship): 312 return (shipBall.radius, shipBall.radius, shipBall.radius) 313 if hasattr(shipBall, 'GetModel'): 314 model = shipBall.GetModel() 315 else: 316 model = getattr(shipBall, 'model', None) 317 if model is None: 318 return (shipBall.radius, shipBall.radius, shipBall.radius) 319 if hasattr(model, 'GetLocalBoundingBox'): 320 shipBBoxMin, shipBBoxMax = model.GetLocalBoundingBox() 321 if shipBBoxMin is None or shipBBoxMax is None: 322 raise RuntimeError('StretchEffect: invalid LocalBoundingBox') 323 else: 324 return (scale * max(-shipBBoxMin[0], shipBBoxMax[0]), scale * max(-shipBBoxMin[1], shipBBoxMax[1]), scale * max(-shipBBoxMin[2], shipBBoxMax[2])) 325 else: 326 raise RuntimeError('StretchEffect: needs GetLocalBoundingBox')