NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

Warp.py (29604B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\environment\effects\Warp.py
      2 from math import cos, pow, sqrt, pi, sin
      3 from eve.client.script.environment.effects import warp_signals
      4 import random
      5 import blue
      6 import destiny
      7 import evecamera
      8 import trinity
      9 import geo2
     10 import uthread
     11 import carbon.common.script.util.logUtil as log
     12 import carbon.common.script.util.mathCommon as mathCommon
     13 from fsdBuiltData.common.graphicIDs import GetGraphicFile
     14 from eve.client.script.environment.effects.GenericEffect import ShipEffect, STOP_REASON_DEFAULT
     15 from eve.client.script.parklife.sceneManagerConsts import SYSTEM_WIDE_CLOUD_NAME
     16 import eve.client.script.environment.effects.effectConsts as effectconsts
     17 import evecamera.shaker as shaker
     18 import evegraphics.settings as gfxsettings
     19 DYNAMIC_WARP_LIGHT_COLOR = (0.270588219165802, 0.6156862378120422, 1.0, 1.0)
     20 STATIC_WARP_LIGHT_COLOR = (0.5647059082984924, 0.9960784316062927, 1.0, 1.0)
     21 SMALL_SUN_TYPE_IDS = [3801,
     22  3799,
     23  45038,
     24  3802,
     25  45041,
     26  3803,
     27  45042]
     28 
     29 class Warping(ShipEffect):
     30     __guid__ = 'effects.Warping'
     31 
     32     def __init__(self, trigger, effect = None, graphicFile = None):
     33         super(Warping, self).__init__(trigger, effect, graphicFile)
     34         self.shipball = None
     35         self.shipModel = None
     36         self.destination = None
     37         self.warpSpeedModifier = 1.0
     38         self.isLegacyJumpTunnel = True
     39         self.systemWideCloud = None
     40 
     41     def Prepare(self):
     42         shipID = self.GetEffectShipID()
     43         if shipID != session.shipid:
     44             self.fxSequencer.OnSpecialFX(shipID, None, None, None, None, 'effects.Warping', 0, 0, 0)
     45             self.fxSequencer.OnSpecialFX(shipID, None, None, None, None, 'effects.WarpOut', 0, 1, 0)
     46             return
     47         if hasattr(cfg.mapSolarSystemContentCache[session.solarsystemid], 'warpTunnelOverwrite'):
     48             warpTunnelGID = cfg.mapSolarSystemContentCache[session.solarsystemid].warpTunnelOverwrite
     49             if warpTunnelGID > 0:
     50                 self.graphicFile = GetGraphicFile(warpTunnelGID)
     51                 self.isLegacyJumpTunnel = False
     52         if hasattr(cfg.mapSolarSystemContentCache[session.solarsystemid], 'systemWideCloud'):
     53             scene = self.fxSequencer.GetScene()
     54             self.systemWideCloud = scene.objects.FindByName(SYSTEM_WIDE_CLOUD_NAME)
     55         ShipEffect.Prepare(self)
     56         self.AlignToDirection()
     57 
     58     def ModelChangeNotify(self, newModel):
     59         if newModel is None:
     60             return
     61         self.shipModel = newModel
     62         for binding in self.curveSet.bindings:
     63             binding.sourceObject = self.shipModel.speed
     64 
     65     def Start(self, duration):
     66         if self.gfx is None:
     67             return
     68         self.gfx.display = False
     69         self.hasExploded = False
     70         self.hasWind = False
     71         self.hasMoreCollisions = True
     72         self.findNext = True
     73         ShipEffect.Start(self, duration)
     74         bp = sm.StartService('michelle').GetBallpark()
     75         shipID = self.GetEffectShipID()
     76         shipBall = bp.GetBall(shipID)
     77         self.shipBall = shipBall
     78         self.shipModel = getattr(shipBall, 'model', None)
     79         self.shipBall.RegisterModelChangeNotification(self.ModelChangeNotify)
     80         slimItem = bp.GetInvItem(shipID)
     81         self.warpSpeedModifier = sm.StartService('godma').GetTypeAttribute(slimItem.typeID, const.attributeWarpSpeedMultiplier)
     82         if self.warpSpeedModifier is None:
     83             self.warpSpeedModifier = 1.0
     84         egoball = bp.GetBall(bp.ego)
     85         self.destination = (egoball.gotoX, egoball.gotoY, egoball.gotoZ)
     86         if self.isLegacyJumpTunnel:
     87             self.SetupTunnelBindings()
     88             self.nextCollision = None
     89             self.insideSolid = False
     90             self.collisions = []
     91             self.collisions = self.GetWarpCollisions(shipBall)
     92             self.ControlFlow('NextCollision')
     93         uthread.worker('FxSequencer::WarpEffectLoop', self.WarpLoop, shipBall)
     94 
     95     def AddToScene(self, effect):
     96         scene = self.fxSequencer.GetScene()
     97         if self.isLegacyJumpTunnel:
     98             scene.warpTunnel = effect
     99             self._SetupLightingCurves(scene)
    100             return
    101         scene.objects.append(effect)
    102 
    103     def RemoveFromScene(self, effect):
    104         scene = self.fxSequencer.GetScene()
    105         if self.isLegacyJumpTunnel:
    106             self._RemoveLightingCurves(scene)
    107             scene.warpTunnel = None
    108             return
    109         scene.objects.fremove(effect)
    110 
    111     def _SetupLightingCurves(self, scene):
    112         self.lightingCurveSet = trinity.TriCurveSet()
    113         self.lights = []
    114         curve = trinity.Tr2CurveScalarExpression()
    115         curve.expression = 'input3 - input3 * min(max(input1 - input2, 0), 1)'
    116         curve.input1 = 1
    117         curve.input2 = 0
    118         curve.input3 = gfxsettings.SECONDARY_LIGHTING_INTENSITY
    119         self.lightingCurveSet.curves.append(curve)
    120 
    121         def FindBinding(curveSet, binding):
    122             cs = [ x for x in self.gfx.curveSets if x.name == curveSet ][0]
    123             return [ x for x in cs.bindings if x.name == binding ][0]
    124 
    125         trinity.CreateBinding(self.lightingCurveSet, FindBinding('FadeInCurveSet', 'FadeInBinding').sourceObject, 'value', curve, 'input1')
    126         trinity.CreateBinding(self.lightingCurveSet, FindBinding('FadeOutCurveSet', 'FadeOutBindin').sourceObject, 'value', curve, 'input2')
    127         trinity.CreateBinding(self.lightingCurveSet, curve, 'currentValue', scene.shLightingManager, 'secondaryIntensity')
    128         if scene.shLightingManager:
    129             light = self._SetupStaticLight(-1, self.lightingCurveSet)
    130             self.lights.append((light, None, None))
    131             scene.shLightingManager.lights.append(light)
    132             light = self._SetupStaticLight(1, self.lightingCurveSet)
    133             self.lights.append((light, None, None))
    134             scene.shLightingManager.lights.append(light)
    135             curve = trinity.Tr2CurveScalarExpression()
    136             curve.expression = 'input1 * min(max(input2 + 2 * min(max(min(max(input3, 0), 1) - min(max(input4, 0), 1), 0), 1), 0), 1)'
    137             curve.input1 = 1
    138             self.lightingCurveSet.curves.append(curve)
    139             trinity.CreateBinding(self.lightingCurveSet, FindBinding('_Setup_', 'brightness_tunnel').sourceObject, 'currentValue', curve, 'input1').scale = gfxsettings.SECONDARY_LIGHTING_INTENSITY
    140             trinity.CreateBinding(self.lightingCurveSet, FindBinding('SpeedModifier', 'additiveBinding').sourceObject, 'currentValue', curve, 'input2')
    141             trinity.CreateBinding(self.lightingCurveSet, FindBinding('FadeInCurveSet', 'FadeInBindingAdditive').sourceObject, 'value', curve, 'input3')
    142             trinity.CreateBinding(self.lightingCurveSet, FindBinding('FadeOutCurveSet', 'FadeOutBindingAdditive').sourceObject, 'value', curve, 'input4')
    143             trinity.CreateBinding(self.lightingCurveSet, curve, 'currentValue', scene.shLightingManager, 'primaryIntensity').scale = 2
    144         self.shLightingManager = scene.shLightingManager
    145         scene.curveSets.append(self.lightingCurveSet)
    146         self.lightingCurveSet.Play()
    147         uthread.new(self._AnimateLights, scene)
    148 
    149     def _AnimateLights(self, scene):
    150         while self.lightingCurveSet and scene.shLightingManager:
    151             if self.shLightingManager != scene.shLightingManager:
    152                 self._RemoveLightingCurves(scene)
    153                 if scene.shLightingManager:
    154                     self._SetupLightingCurves(scene)
    155                 return
    156             light = self._SetupDynamicLight(self.lightingCurveSet)
    157             self.lights.append(light)
    158             scene.shLightingManager.lights.append(light[0])
    159             remove = [ i for i, light in enumerate(self.lights) if light[0].position[2] < -5 ]
    160             for each in sorted(remove, reverse=True):
    161                 light, curve, binding = self.lights[each]
    162                 self.lightingCurveSet.curves.remove(curve)
    163                 self.lightingCurveSet.bindings.remove(binding)
    164                 try:
    165                     scene.shLightingManager.lights.remove(light)
    166                 except RuntimeError:
    167                     pass
    168 
    169                 del self.lights[each]
    170 
    171             blue.synchro.SleepSim(random.randint(100, 500))
    172 
    173     def _SetupStaticLight(self, offset, curveSet):
    174         light = trinity.Tr2PointLight()
    175         light.color = STATIC_WARP_LIGHT_COLOR
    176         light.position = (0, 0, offset)
    177         curve = trinity.TriPerlinCurve()
    178         curve.offset = 0.2
    179         curve.scale = 0.2
    180         curveSet.curves.append(curve)
    181         trinity.CreateBinding(curveSet, curve, 'value', light, 'radius')
    182         return light
    183 
    184     def _SetupDynamicLight(self, curveSet):
    185         angle = random.random() * 2 * pi
    186         light = trinity.Tr2PointLight()
    187         light.color = geo2.Vec3Lerp(DYNAMIC_WARP_LIGHT_COLOR, (1, 1, 1, 1), random.random())
    188         light.radius = 0.7
    189         light.position = (sin(angle) * 1.5, cos(angle) * 1.5, 2)
    190         curve = trinity.Tr2CurveScalar()
    191         curve.keys.append((curveSet.scaledTime,
    192          2,
    193          0,
    194          0,
    195          0,
    196          0,
    197          0))
    198         curve.keys.append((curveSet.scaledTime + 8.0 / 20.0,
    199          -6,
    200          0,
    201          0,
    202          0,
    203          0,
    204          0))
    205         curve.OnKeysChanged()
    206         curveSet.curves.append(curve)
    207         binding = trinity.CreateBinding(curveSet, curve, 'currentValue', light, 'position.z')
    208         return (light, curve, binding)
    209 
    210     def _RemoveLightingCurves(self, scene):
    211         try:
    212             scene.curveSets.remove(self.lightingCurveSet)
    213         except (RuntimeError, ValueError):
    214             pass
    215 
    216         self.lightingCurveSet = None
    217         if self.shLightingManager:
    218             self.shLightingManager.primaryIntensity = gfxsettings.SECONDARY_LIGHTING_INTENSITY
    219             self.shLightingManager.secondaryIntensity = gfxsettings.SECONDARY_LIGHTING_INTENSITY
    220             for each, _, _ in self.lights:
    221                 try:
    222                     self.shLightingManager.lights.remove(each)
    223                 except RuntimeError:
    224                     pass
    225 
    226         self.lights = []
    227 
    228     def RecycleOrLoad(self, resPath):
    229         return blue.resMan.LoadObject(resPath)
    230 
    231     def ControlFlow(self, event):
    232         if event == 'ExitPlanet':
    233             scene = self.fxSequencer.GetScene()
    234             for each in scene.lensflares:
    235                 each.display = True
    236 
    237             self.nextCollision[0].display = True
    238             self.exitPlanetBinding.scale = 0
    239             self.exitPlanetEventCurve.Stop()
    240             if self.hasMoreCollisions:
    241                 self.nextPlanetBinding.scale = 1
    242                 self.nextPlanetEventCurve.Play()
    243                 self.nextPlanetBinding.sourceObject.expression = '-input1 / input2'
    244         elif event == 'NextCollision':
    245             self.nextPlanetBinding.scale = 0
    246             self.nextPlanetEventCurve.Stop()
    247             res = self.SetupNextCollision()
    248             if res == False:
    249                 self.nextPlanetBinding.scale = 1
    250                 self.nextPlanetEventCurve.Play()
    251                 self.nextPlanetBinding.sourceObject.expression = 'input2 / input1'
    252             else:
    253                 self.enterPlanetBinding.scale = 1
    254                 self.enterPlanetEventCurve.Play()
    255         elif event == 'EnterPlanet':
    256             scene = self.fxSequencer.GetScene()
    257             for each in scene.lensflares:
    258                 each.display = False
    259 
    260             self.nextCollision[0].display = False
    261             if self.nextCollision[0].radius < 450000:
    262                 delta = 1
    263                 self.nextCollision = (self.nextCollision[0], delta)
    264                 self.collisionCurve.input1 = 1.1 * delta / 10000.0
    265             self.enterPlanetBinding.scale = 0
    266             self.enterPlanetEventCurve.Stop()
    267             self.exitPlanetBinding.scale = 1
    268             self.exitPlanetEventCurve.Play()
    269 
    270     def SetupTunnelBindings(self):
    271         self.curveSet = [ x for x in self.gfx.curveSets if x.name == 'SpeedBinding' ][0]
    272         for binding in self.curveSet.bindings:
    273             self.speedBinding = binding
    274             binding.sourceObject = self.shipModel.speed
    275             binding.scale *= 1.0 / (3.0 * const.AU * self.warpSpeedModifier)
    276 
    277         self.curveSet.Play()
    278         setup = [ x for x in self.gfx.curveSets if x.name == '_Setup_' ][0]
    279         self.setup = setup
    280         self.collisionCurve = [ x for x in setup.curves if x.name == '_global' ][0]
    281         self.xout = [ x for x in setup.curves if x.name == '_xPointOut' ][0]
    282         extra = [ x for x in self.gfx.curveSets if getattr(x, 'name', None) == '_Extra_' ][0]
    283         first = [ x for x in self.gfx.curveSets if getattr(x, 'name', None) == '_First_' ][0]
    284         self.distanceTracker = first.curves.Find('trinity.Tr2DistanceTracker')[0]
    285         self.distanceTraveled = [ x for x in extra.curves if getattr(x, 'name', None) == '_mov' ][0]
    286         self.fadeInLength = [ x for x in extra.curves if getattr(x, 'name', None) == '_fadeLength' ][0]
    287         self.eventb = [ x for x in self.gfx.curveSets if x.name == 'EventBindings' ][0]
    288         eventBindings = [ x for x in self.gfx.curveSets if x.name == 'EventBindings' ][0].bindings
    289         for binding in eventBindings:
    290             if binding.name == 'enterPlanetBinding':
    291                 self.enterPlanetBinding = binding
    292             elif binding.name == 'exitPlanetBinding':
    293                 self.exitPlanetBinding = binding
    294             elif binding.name == 'nextPlanetBinding':
    295                 self.nextPlanetBinding = binding
    296 
    297         self.enterPlanetEventCurve = [ x for x in self.gfx.curveSets if x.name == 'enterPlanet' ][0]
    298         self.exitPlanetEventCurve = [ x for x in self.gfx.curveSets if x.name == 'exitPlanet' ][0]
    299         self.nextPlanetEventCurve = [ x for x in self.gfx.curveSets if x.name == 'nextCollision' ][0]
    300         self.enterPlanetBinding.scale = 0
    301         self.exitPlanetBinding.scale = 0
    302         self.nextPlanetBinding.scale = 0
    303         self.enterPlanetEventCurve.Stop()
    304         self.exitPlanetEventCurve.Stop()
    305         self.nextPlanetEventCurve.Stop()
    306         self.exitPlanetEventCurve.curves[0].AddKey(0.0, u'Start')
    307         self.exitPlanetEventCurve.curves[0].AddCallableKey(1.0, self.ControlFlow, ('ExitPlanet',))
    308         self.enterPlanetEventCurve.curves[0].AddKey(0.0, u'Start')
    309         self.enterPlanetEventCurve.curves[0].AddCallableKey(1.0, self.ControlFlow, ('EnterPlanet',))
    310         self.nextPlanetEventCurve.curves[0].AddKey(0.0, u'Start')
    311         self.nextPlanetEventCurve.curves[0].AddCallableKey(1.0, self.ControlFlow, ('NextCollision',))
    312 
    313     def TeardownTunnelBindings(self):
    314         if getattr(self, 'speedBinding', None) is not None:
    315             self.speedBinding.sourceObject = self.shipModel.speed
    316         if getattr(self, 'distanceTracker', None) is not None:
    317             self.distanceTracker.targetObject = None
    318             self.distanceTracker = None
    319         if getattr(self, 'exitPlanetEventCurve', None) is not None:
    320             del self.exitPlanetEventCurve.curves[0]
    321             del self.enterPlanetEventCurve.curves[0]
    322             del self.nextPlanetEventCurve.curves[0]
    323 
    324     def GetCorrectModelRadius(self, ball):
    325         radius = ball.radius
    326         if ball in sm.GetService('space').planetManager.suns:
    327             radius *= 0.5
    328             if ball.typeID in SMALL_SUN_TYPE_IDS:
    329                 radius *= 0.5
    330         return radius
    331 
    332     def CalcEffectiveRadius(self, direction, planetPosition, planetRadius):
    333         distToMiddle = geo2.Vec3DotD(planetPosition, direction)
    334         if distToMiddle < 0:
    335             return None
    336         midPoint = geo2.Vec3ScaleD(direction, distToMiddle)
    337         distToCenter = geo2.Vec3DistanceD(planetPosition, midPoint)
    338         if distToCenter > planetRadius:
    339             return None
    340         return sqrt(planetRadius * planetRadius - distToCenter * distToCenter)
    341 
    342     def GetDistanceToTarget(self, direction, planetPosition):
    343         return geo2.Vec3DotD(planetPosition, direction)
    344 
    345     def GetWarpCollisions(self, ball):
    346         space = sm.GetService('space')
    347         planets = space.planetManager.planets + space.planetManager.suns
    348         destination = self.destination
    349         source = (ball.x, ball.y, ball.z)
    350         self.direction = geo2.Vec3SubtractD(destination, source)
    351         direction = self.direction
    352         warpDistance = geo2.Vec3LengthD(direction)
    353         normDirection = geo2.Vec3NormalizeD(direction)
    354         self.normDirection = normDirection
    355         ballpark = sm.GetService('michelle').GetBallpark()
    356         collisions = []
    357         for planet in planets:
    358             planetBall = ballpark.GetBall(planet.id)
    359             if planetBall is None:
    360                 continue
    361             planetPosition = (planetBall.x, planetBall.y, planetBall.z)
    362             planetDir = geo2.Vec3SubtractD(planetPosition, source)
    363             if geo2.Vec3LengthSqD(self.direction) < geo2.Vec3LengthSqD(planetDir):
    364                 continue
    365             effectiveRadius = self.CalcEffectiveRadius(normDirection, planetDir, self.GetCorrectModelRadius(planetBall))
    366             if effectiveRadius is None:
    367                 continue
    368             collisions.append((planetBall, effectiveRadius))
    369             blue.pyos.BeNice()
    370 
    371         return collisions
    372 
    373     def FindNextCollision(self, destination, candidates, popCollision = True):
    374         minDist = None
    375         time = blue.os.GetSimTime()
    376         position = self.shipBall.GetVectorAt(blue.os.GetSimTime())
    377         position = (position.x, position.y, position.z)
    378         nextCollision = None
    379         for each in candidates:
    380             collisionBall = each[0]
    381             collisionCenter = collisionBall.GetVectorAt(time)
    382             collisionCenter = (collisionCenter.x, collisionCenter.y, collisionCenter.z)
    383             projection = geo2.Vec3DotD(collisionCenter, self.normDirection)
    384             if minDist is None or projection < minDist:
    385                 minDist = projection
    386                 nextCollision = each
    387 
    388         if nextCollision is not None and popCollision:
    389             candidates.remove(nextCollision)
    390         return nextCollision
    391 
    392     def SetupNextCollision(self):
    393         self.hasMoreCollisions = False
    394         self.distanceTracker.direction = self.normDirection
    395         time = blue.os.GetSimTime()
    396         if self.findNext:
    397             lastCollision = self.nextCollision
    398             self.nextCollision = self.FindNextCollision(self.destination, self.collisions)
    399             if self.nextCollision is None:
    400                 self.nextCollision = lastCollision
    401             if self.nextCollision is None:
    402                 self.collisionCurve.input1 = 1.0
    403                 self.fadeInLength.input1 = 0.0
    404                 self.collisionCurve.input3 = 100000000
    405                 self.collisionCurve.input3 = 100000000
    406                 self.distanceTracker.targetObject = None
    407                 self.distanceTraveled.input1 = 100000000
    408                 self.distanceTracker.targetPosition = (0, 0, 100000000)
    409                 self.distanceTracker.direction = (0, 0, -1)
    410                 return True
    411             targetPosition = self.nextCollision[0].GetVectorAt(time)
    412             targetPosition = (targetPosition.x, targetPosition.y, targetPosition.z)
    413             furtherCollision = self.FindNextCollision(self.destination, self.collisions, False)
    414             if furtherCollision is not None:
    415                 self.hasMoreCollisions = True
    416                 furtherPosition = furtherCollision[0].GetVectorAt(time)
    417                 furtherPosition = (furtherPosition.x, furtherPosition.y, furtherPosition.z)
    418                 length = geo2.Vec3DistanceD(targetPosition, furtherPosition)
    419                 self.nextPlanetBinding.sourceObject.input2 = length / 2
    420         else:
    421             targetPosition = self.nextCollision[0].GetVectorAt(time)
    422             targetPosition = (targetPosition.x, targetPosition.y, targetPosition.z)
    423         distanceToCollision = self.GetDistanceToTarget(self.normDirection, targetPosition)
    424         returnValue = True
    425         warpSpeed = self.warpSpeedModifier * const.AU
    426         if distanceToCollision > warpSpeed:
    427             self.findNext = False
    428             returnValue = False
    429             self.nextPlanetBinding.sourceObject.input2 = warpSpeed
    430         else:
    431             self.findNext = True
    432         delta = self.CalcEffectiveRadius(self.normDirection, targetPosition, self.GetCorrectModelRadius(self.nextCollision[0]))
    433         if delta is None:
    434             delta = self.nextCollision[0].radius
    435         self.nextCollision = (self.nextCollision[0], delta)
    436         self.collisionCurve.input1 = 1.1 * delta / 10000.0
    437         self.fadeInLength.input1 = 80000 * self.warpSpeedModifier * 3
    438         self.collisionCurve.input3 = abs(distanceToCollision) / 10000.0
    439         self.distanceTracker.targetObject = self.nextCollision[0]
    440         self.distanceTraveled.input1 = abs(distanceToCollision) / 10000.0
    441         return returnValue
    442 
    443     def WarpLoop(self, ball):
    444         space = sm.GetService('space')
    445         michelle = sm.GetService('michelle')
    446         space.StartWarpIndication()
    447         warpToItemID, warpToTypeID = space.GetWarpDestinationItemIDAndTypeID()
    448         sm.ScatterEvent('OnWarpStarted', warpToItemID, warpToTypeID)
    449         warp_signals.on_warp_started(warpToItemID)
    450         self.shipBall = ball
    451         shipID = ball.id
    452         hasSentActiveWarpEvent = False
    453         hasSentArrivedWarpEvent = False
    454         lastSpeed = 0
    455         initialWarpDistance = 1.0
    456         currentProgress = 0.01
    457         warpSpeedMod = 1.0 / (3.0 * const.AU * self.warpSpeedModifier)
    458         while ball.mode == destiny.DSTBALL_WARP:
    459             if session.shipid != shipID:
    460                 self.hasExploded = True
    461             sm.GetService('space').IndicateCurrentShipManouveringAction()
    462             if ball.effectStamp > 0 and not hasSentActiveWarpEvent:
    463                 sm.ScatterEvent('OnWarpActive', warpToItemID, warpToTypeID)
    464                 warp_signals.on_warp_activated(warpToItemID)
    465                 if not self.isLegacyJumpTunnel:
    466                     self.gfx.SetControllerVariable('TravelTunnelProgress', 0.01)
    467                     self.gfx.SetControllerVariable('warpSpeedModifier', self.warpSpeedModifier)
    468                     threshold = const.minWarpDistance * 100.0
    469                     isShortWarp = geo2.Vec3Distance(michelle.GetMyPosition(), self.destination) < threshold
    470                     if isShortWarp:
    471                         self.gfx.SetControllerVariable('shortWarp', 1.0)
    472                 if self.systemWideCloud:
    473                     self.systemWideCloud.SetControllerVariable('isWarping', 1.0)
    474                 hasSentActiveWarpEvent = True
    475                 initialWarpDistance = geo2.Vec3DistanceSq(michelle.GetMyPosition(), self.destination)
    476             self.ShakeCamera(ball)
    477             if not self.hasExploded or self.hasWind:
    478                 if self.isLegacyJumpTunnel:
    479                     speedFraction = self.shipModel.speed.value * self.curveSet.bindings[0].scale
    480                 else:
    481                     speedFraction = self.shipModel.speed.value * warpSpeedMod
    482                 if not self.hasExploded and speedFraction > 0.005:
    483                     sm.StartService('audio').SendUIEvent('ship_warp_explosion_play')
    484                     sm.StartService('audio').SendUIEvent('ship_warp_wind_play')
    485                     self.hasExploded = True
    486                     self.hasWind = True
    487                     sm.ScatterEvent('OnWarpStarted2', warpToItemID, warpToTypeID)
    488                 elif self.hasWind and speedFraction < 1e-06:
    489                     sm.ScatterEvent('OnWarpDecelerate', warpToItemID, warpToTypeID)
    490                     warp_signals.on_warp_deceleration_started(warpToItemID)
    491                     self.hasWind = False
    492                 if hasSentActiveWarpEvent and not hasSentArrivedWarpEvent:
    493                     currentWarpDistance = space.GetWarpDistance()
    494                     if not self.isLegacyJumpTunnel:
    495                         if currentProgress > 0.5 and speedFraction < 1e-05:
    496                             currentProgress = 1.0
    497                         remainingDistance = geo2.Vec3DistanceSq(michelle.GetMyPosition(), self.destination)
    498                         distanceTraveled = 1 - remainingDistance / initialWarpDistance
    499                         currentProgress = max(currentProgress, distanceTraveled)
    500                         self.gfx.SetControllerVariable('TravelTunnelProgress', currentProgress)
    501                     if lastSpeed <= self.shipModel.speed.value:
    502                         lastSpeed = self.shipModel.speed.value
    503                     elif currentWarpDistance < 10000000:
    504                         if not self.isLegacyJumpTunnel:
    505                             self.gfx.SetControllerVariable('TravelTunnelProgress', 1.0)
    506                         sm.ScatterEvent('OnWarpArrived', warpToItemID, warpToTypeID)
    507                         if hasSentActiveWarpEvent:
    508                             warp_signals.on_warp_arrived_at(warpToItemID)
    509                         hasSentArrivedWarpEvent = True
    510                         if self.systemWideCloud:
    511                             self.systemWideCloud.SetControllerVariable('isWarping', 0.0)
    512             if self.isLegacyJumpTunnel:
    513                 blue.synchro.SleepSim(1000)
    514             else:
    515                 blue.synchro.SleepSim(500)
    516             if hasattr(self.gfx, 'display'):
    517                 self.gfx.display = True
    518 
    519         self.EndWarpShake()
    520         if not self.isLegacyJumpTunnel:
    521             self.gfx.SetControllerVariable('TravelTunnelProgress', 1.0)
    522         if self.systemWideCloud:
    523             self.systemWideCloud.SetControllerVariable('isWarping', 0.0)
    524         sm.StartService('audio').SendUIEvent('ship_warp_wind_stop')
    525         sm.StartService('FxSequencer').OnSpecialFX(ball.id, None, None, None, None, 'effects.Warping', 0, 0, 0)
    526         sm.ScatterEvent('OnWarpFinished', warpToItemID, warpToTypeID)
    527         if hasSentActiveWarpEvent:
    528             warp_signals.on_warp_finished(warpToItemID)
    529         sm.StartService('space').StopWarpIndication()
    530 
    531     def Stop(self, reason = STOP_REASON_DEFAULT):
    532         if self.isLegacyJumpTunnel:
    533             self.TeardownTunnelBindings()
    534         if self.shipBall is not None:
    535             self.shipBall.UnregisterModelChangeNotification(self.ModelChangeNotify)
    536         self.shipBall = None
    537         self.shipModel = None
    538         ShipEffect.Stop(self)
    539 
    540     def ShakeCamera(self, ball):
    541         ballpark = sm.GetService('michelle').GetBallpark()
    542         if ballpark is None:
    543             return
    544         speedVector = trinity.TriVector(ball.vx, ball.vy, ball.vz)
    545         speed = speedVector.Length()
    546         maxSpeed = ballpark.warpSpeed * const.AU - ball.maxVelocity
    547         speed = (speed - ball.maxVelocity) / maxSpeed
    548         speed = max(0.0, speed)
    549         rumbleFactor = 0.5 - 0.5 * cos(6.28 * pow(speed, 0.1))
    550         rumbleFactor = (rumbleFactor - 0.2) / 0.8
    551         rumbleFactor = max(rumbleFactor, 0.0)
    552         rumbleFactor = pow(rumbleFactor, 0.8)
    553         shakeFactor = 0.7 * rumbleFactor
    554         cam = self.GetCamera()
    555         noisescaleCurve = trinity.Tr2CurveScalar()
    556         noisescaleCurve.AddKey(0.0, cam.noiseScale, trinity.Tr2CurveInterpolation.LINEAR)
    557         noisescaleCurve.AddKey(0.5, shakeFactor * 2.0, trinity.Tr2CurveInterpolation.LINEAR)
    558         noisescaleCurve.AddKey(5.0, 0.0, trinity.Tr2CurveInterpolation.LINEAR)
    559         behavior = shaker.ShakeBehavior('Warp')
    560         behavior.scaleCurve = noisescaleCurve
    561         cam.shakeController.DoCameraShake(behavior)
    562 
    563     def GetCamera(self):
    564         return sm.GetService('sceneManager').GetActiveSpaceCamera()
    565 
    566     def EndWarpShake(self):
    567         camera = self.GetCamera()
    568         camera.shakeController.EndCameraShake('Warp')
    569 
    570     def AlignToDirection(self):
    571         ballPark = sm.StartService('michelle').GetBallpark()
    572         egoball = ballPark.GetBall(ballPark.ego)
    573         direction = [egoball.x - egoball.gotoX, egoball.y - egoball.gotoY, egoball.z - egoball.gotoZ]
    574         zaxis = direction
    575         if geo2.Vec3LengthSqD(zaxis) > 0.0:
    576             zaxis = geo2.Vec3NormalizeD(zaxis)
    577             xaxis = geo2.Vec3CrossD((0, 1, 0), zaxis)
    578             if geo2.Vec3LengthSqD(xaxis) == 0.0:
    579                 zaxis = geo2.Vec3AddD(zaxis, mathCommon.RandomVector(0.0001))
    580                 zaxis = geo2.Vec3NormalizeD(zaxis)
    581                 xaxis = geo2.Vec3CrossD((0, 1, 0), zaxis)
    582             xaxis = geo2.Vec3NormalizeD(xaxis)
    583             yaxis = geo2.Vec3CrossD(zaxis, xaxis)
    584         else:
    585             self.transformFlags = effectconsts.FX_TF_POSITION_BALL | effectconsts.FX_TF_ROTATION_BALL
    586             self.Prepare()
    587             return
    588         mat = ((xaxis[0],
    589           xaxis[1],
    590           xaxis[2],
    591           0.0),
    592          (yaxis[0],
    593           yaxis[1],
    594           yaxis[2],
    595           0.0),
    596          (zaxis[0],
    597           zaxis[1],
    598           zaxis[2],
    599           0.0),
    600          (0.0, 0.0, 0.0, 1.0))
    601         quat = geo2.QuaternionRotationMatrix(mat)
    602         self.gfxModel.rotationCurve = None
    603         if self.gfxModel and hasattr(self.gfxModel, 'modelRotationCurve'):
    604             self.gfxModel.modelRotationCurve = trinity.Tr2RotationAdapter()
    605             self.gfxModel.modelRotationCurve.value = quat
    606         self.debugAligned = True
    607         if not self.isLegacyJumpTunnel:
    608             if self.gfx is not None and self.gfx.modelRotationCurve is not None:
    609                 vect = geo2.QuaternionRotationGetYawPitchRoll(self.gfx.modelRotationCurve.value)
    610                 self.gfx.modelRotationCurve.value = geo2.QuaternionRotationSetYawPitchRoll(vect[0], vect[1] + pi, vect[2])
    611 
    612     def Repeat(self, duration):
    613         if self.gfx is None:
    614             return
    615         ShipEffect.Repeat(self, duration)