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

planetUIPins.py (46930B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\planet\planetUIPins.py
      2 import math
      3 import random
      4 import evetypes
      5 import inventorycommon.typeHelpers
      6 import trinity
      7 import blue
      8 import uthread
      9 import geo2
     10 import utillib
     11 from carbon.common.script.sys.serviceConst import ROLE_GML
     12 from carbonui import uiconst
     13 from carbonui.uianimations import animations
     14 from carbonui.util.color import Color
     15 from eve.client.script.ui import eveColor
     16 from eve.client.script.ui.control.eveIcon import Icon
     17 from eve.client.script.ui.shared.planet import planetConst
     18 from eve.client.script.ui.shared.planet.planetUILinks import LinkBase
     19 from eve.common.lib import appConst
     20 import localization
     21 from eve.common.script.util.planetCommon import SurfacePoint
     22 import eve.common.script.util.planetCommon as planetCommon
     23 from fsdBuiltData.common.graphicIDs import GetGraphicFile
     24 from fsdBuiltData.common.planet import get_schematic_types
     25 from eve.client.script.ui.shared.planet import planetCommon as planetCommonUI
     26 from eveservices.menu import GetMenuService
     27 from menu import MenuLabel
     28 RADIUS_PIN = 0.006
     29 RADIUS_PIN_SELECTED = RADIUS_PIN * 1.2
     30 RADIUS_PINEXTENDED = RADIUS_PIN * 1.65
     31 RADIUS_CYCLE = RADIUS_PIN * 0.7
     32 RADIUS_CYCLEEXTENDED = RADIUS_PIN * 1.25
     33 RADIUS_LOGO = RADIUS_PIN * 0.5
     34 RADIUS_SHADOW = RADIUS_PIN * 1.2
     35 RADIUS_SHADOWEXTENDED = RADIUS_PINEXTENDED * 1.2
     36 RADIUS_BUILDPIN = RADIUS_PIN * 0.8
     37 RADIUS_PINOTHERS = RADIUS_PIN * 0.5
     38 RADIUS_EXTRACTIONHEAD = 0.003
     39 SCALE_PINBASE = 1.01
     40 SCALE_PINLIFTED = 1.0105
     41 SCALE_ONGROUND = 1.001
     42 SCALE_PINOTHERS = 1.005
     43 SCALE_HOLOGRAM = 1.026
     44 SCALE_HOLOGRAMMODEL = 0.025
     45 PINCOLORS = {appConst.groupCommandPins: planetCommonUI.PLANET_COLOR_ICON_COMMANDCENTER,
     46  appConst.groupExtractorPins: planetCommonUI.PLANET_COLOR_ICON_EXTRACTOR,
     47  appConst.groupStoragePins: planetCommonUI.PLANET_COLOR_ICON_STORAGE,
     48  appConst.groupSpaceportPins: planetCommonUI.PLANET_COLOR_ICON_SPACEPORT,
     49  appConst.groupProcessPins: planetCommonUI.PLANET_COLOR_ICON_PROCESSOR,
     50  appConst.groupExtractionControlUnitPins: planetCommonUI.PLANET_COLOR_ICON_EXTRACTOR}
     51 PINICONPATHS = {appConst.groupCommandPins: 'res:/UI/Texture/Planet/command.dds',
     52  appConst.groupExtractorPins: 'res:/UI/Texture/Planet/extractor.dds',
     53  appConst.groupStoragePins: 'res:/UI/Texture/Planet/storage.dds',
     54  appConst.groupSpaceportPins: 'res:/UI/Texture/Planet/spaceport.dds',
     55  appConst.groupProcessPins: 'res:/UI/Texture/Planet/process.dds',
     56  appConst.groupExtractionControlUnitPins: 'res:/UI/Texture/Planet/extractor.dds'}
     57 
     58 def GetPinIconPath(typeID):
     59     groupID = evetypes.GetGroupID(typeID)
     60     if groupID == appConst.groupProcessPins:
     61         if typeID in planetConst.TYPEIDS_PROCESSORS_HIGHTECH:
     62             return 'res:/UI/Texture/Planet/processHighTech.dds'
     63         elif typeID in planetConst.TYPEIDS_PROCESSORS_ADVANCED:
     64             return 'res:/UI/Texture/Planet/processAdvanced.dds'
     65         else:
     66             return 'res:/UI/Texture/Planet/process.dds'
     67     else:
     68         return PINICONPATHS[groupID]
     69 
     70 
     71 class SpherePinStack():
     72 
     73     def __init__(self, surfacePoint, maxRadius):
     74         self.spherePins = []
     75         self.transformsBySpherePins = {}
     76         self.surfacePoint = surfacePoint
     77         self.maxRadius = maxRadius
     78         self.destroyed = False
     79         self.hologramModel = None
     80 
     81     def CreateSpherePin(self, textureName, layer, radius, transform, isGauge = False, scale = 1.01, color = Color.WHITE, display = True, offsetScale = 1.0, xOffset = 0.0, yOffset = 0.0, maxRadius = None):
     82         if isGauge:
     83             shaderName = 'res:/Graphics/Effect/Managed/Space/UI/SpherePinThreshold.fx'
     84         else:
     85             shaderName = 'res:/Graphics/Effect/Managed/Space/UI/SpherePin1.fx'
     86         sp = trinity.EveSpherePin()
     87         transform.children.append(sp)
     88         self.spherePins.append(sp)
     89         self.transformsBySpherePins[sp] = transform
     90         sp.pinEffectResPath = shaderName
     91         sp.pinRadius = radius
     92         sp.pinMaxRadius = maxRadius or self.maxRadius
     93         sp.centerNormal = self.surfacePoint.GetAsXYZTuple()
     94         sp.scaling = (scale, scale, scale)
     95         sp.display = display
     96         sp.sortValueMultiplier = 1.0 - 0.01 * layer - 0.1 * scale
     97         sp.uvAtlasScaleOffset = (offsetScale,
     98          offsetScale,
     99          xOffset,
    100          yOffset)
    101         sm.GetService('planetUI').LoadSpherePinResources(sp, textureName)
    102         sp.pinColor = color
    103         return sp
    104 
    105     def CreateIconSpherePin(self, layer, radius, transform, typeID, scale = 1.01, color = Color.WHITE):
    106         iconFile = inventorycommon.typeHelpers.GetIcon(typeID).iconFile
    107         path = Icon.ConvertIconNoToResPath(None, iconFile)
    108         return self.CreateSpherePin(textureName=path, layer=layer, radius=radius, transform=transform, scale=scale, color=color, offsetScale=1.0, xOffset=0.0, yOffset=0.0)
    109 
    110     def SetLocation(self, surfacePoint):
    111         self.surfacePoint.Copy(surfacePoint)
    112         for spherePin in self.spherePins:
    113             centerNormal = self.surfacePoint.GetAsXYZTuple()
    114             spherePin.centerNormal = centerNormal
    115 
    116     def Remove(self):
    117         self.destroyed = True
    118         for spherePin, transform in self.transformsBySpherePins.iteritems():
    119             if spherePin in transform.children:
    120                 transform.children.remove(spherePin)
    121                 animations.StopAllAnimations(spherePin)
    122 
    123         self.transformsBySpherePins = {}
    124         self.HideHologramModel()
    125 
    126     def RemoveSpherePin(self, spherePin):
    127         if self.destroyed:
    128             return
    129         transform = self.transformsBySpherePins.pop(spherePin)
    130         transform.children.remove(spherePin)
    131 
    132     def ShowHologramModel(self):
    133         uthread.new(self._ShowHologramModel)
    134 
    135     def _ShowHologramModel(self):
    136         if not self.hologramModel:
    137             self.hologramModel = self.ConstructHologramModel()
    138             self.transform.children.append(self.hologramModel)
    139         scale = (SCALE_HOLOGRAMMODEL, SCALE_HOLOGRAMMODEL, SCALE_HOLOGRAMMODEL)
    140         self.hologramModel.scaling = scale
    141         self.hologramModel.sortValueMultiplier = 0.5
    142         self.hologramModel.translation = geo2.Vec3Scale(self.surfacePoint.GetAsXYZTuple(), SCALE_HOLOGRAM)
    143         animations.MorphVector3(self.hologramModel, 'scaling', (SCALE_HOLOGRAMMODEL * 2, 0.0, 0.0), scale, duration=0.3)
    144         uthread.new(self._Rotate3dModel)
    145 
    146     def ConstructHologramModel(self):
    147         pass
    148 
    149     def _Rotate3dModel(self):
    150         t = 0.0
    151         plnSurfRotMat = geo2.MatrixRotationAxis(geo2.Vec3Cross(geo2.Vec3Normalize(self.surfacePoint.GetAsXYZTuple()), (0.0, 1.0, 0.0)), -math.acos(geo2.Vec3Dot(geo2.Vec3Normalize(self.surfacePoint.GetAsXYZTuple()), (0.0, 1.0, 0.0))))
    152         while self.hologramModel:
    153             t += 0.5 / blue.os.fps
    154             zRotMat = geo2.MatrixRotationAxis((0.0, 1.0, 0.0), -t)
    155             rotation = geo2.MatrixMultiply(zRotMat, plnSurfRotMat)
    156             rotQuat = geo2.QuaternionRotationMatrix(rotation)
    157             self.hologramModel.rotation = rotQuat
    158             blue.pyos.synchro.Yield()
    159 
    160     def HideHologramModel(self):
    161         if not self.hologramModel:
    162             return
    163         if self.hologramModel in self.transform.children:
    164             uthread.new(self._HideHologramModel, self.hologramModel)
    165         self.hologramModel = None
    166 
    167     def _HideHologramModel(self, hologramModel):
    168         animations.MorphVector3(hologramModel, 'scaling', hologramModel.scaling, (0.5 * SCALE_HOLOGRAMMODEL, 0, 0), duration=0.15, sleep=True)
    169         self.transform.children.remove(hologramModel)
    170 
    171 
    172 class BasePlanetPin(SpherePinStack):
    173     __notifyevents__ = ['ProcessColonyDataSet']
    174     baseColor = planetCommonUI.PLANET_COLOR_STORAGE
    175 
    176     def __init__(self, surfacePoint, pin, transform, maxRadius = RADIUS_PINEXTENDED):
    177         SpherePinStack.__init__(self, surfacePoint, maxRadius)
    178         sm.RegisterNotify(self)
    179         self.destroyed = False
    180         self.renderState = utillib.KeyVal(mouseHover=False, asRoute=False, selected=False)
    181         self.pin = pin
    182         self.spherePins = []
    183         self.hologramModel = None
    184         self.producerCycleTime = 0.0
    185         self.transform = transform
    186         self.resourceIcons = []
    187         self.border = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/pin_base_y.dds', layer=0, radius=RADIUS_PINEXTENDED, transform=transform, scale=SCALE_PINBASE, color=(0.0, 0.0, 0.0, 0.0))
    188         self.border.display = False
    189         self.logo = self.CreateSpherePin(textureName=GetPinIconPath(self.pin.typeID), layer=2, radius=RADIUS_LOGO, transform=transform, scale=SCALE_PINBASE, color=self.GetPinColor())
    190         self.mainPin = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/pin_base.dds', layer=1, radius=RADIUS_PIN, transform=transform, scale=SCALE_PINBASE, color=(0.0, 0.0, 0.0, 0.4))
    191         self.gaugeUnderlay = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/gauge_15px.dds', layer=3, radius=RADIUS_PIN, transform=transform, scale=SCALE_PINLIFTED, color=self.baseColor)
    192         self.gauge = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/gauge_15px.dds', layer=4, radius=RADIUS_PIN, transform=transform, scale=SCALE_PINLIFTED, isGauge=True, color=planetCommonUI.PLANET_COLOR_USED_STORAGE)
    193         self.multiSelected = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/gauge_15px.dds', layer=12, radius=RADIUS_PIN_SELECTED, transform=transform, scale=SCALE_PINLIFTED, isGauge=True, color=eveColor.CRYO_BLUE, display=False)
    194         self.multiSelected.pinAlphaThreshold = 1.0
    195         self.cycle = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/cycle_10px.dds', layer=5, radius=RADIUS_CYCLE, transform=transform, scale=SCALE_PINLIFTED, isGauge=True, color=planetCommonUI.PLANET_COLOR_CYCLE)
    196         self.shadow = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/disc_shadow.dds', layer=0, radius=RADIUS_SHADOW, transform=transform, scale=SCALE_ONGROUND, color=(0.0, 0.0, 0.0, 0.3))
    197         self.needsAttentionIndicator = None
    198         self.CheckShowNeedsAttentionIndicator()
    199         self.SetResourceIcons()
    200         self.pinExpansions = [(self.mainPin, RADIUS_PIN, RADIUS_PINEXTENDED),
    201          (self.gauge, RADIUS_PIN, RADIUS_PINEXTENDED),
    202          (self.gaugeUnderlay, RADIUS_PIN, RADIUS_PINEXTENDED),
    203          (self.cycle, RADIUS_CYCLE, RADIUS_CYCLEEXTENDED),
    204          (self.shadow, RADIUS_SHADOW, RADIUS_SHADOWEXTENDED)]
    205         self.AssignIDsToPins()
    206         self.UpdateStorageGauge()
    207         self.UpdateEditModeColors()
    208         uthread.new(self.UpdateCycleTimer)
    209         uthread.new(self.UpdateResourceIcons)
    210 
    211     def ShowNeedsAttentionIndicator(self):
    212         if self.needsAttentionIndicator:
    213             if self.needsAttentionIndicator.display:
    214                 return
    215             self.needsAttentionIndicator.color = planetCommonUI.PLANET_COLOR_NEEDSATTENTION
    216             self.needsAttentionIndicator.pinRadius = RADIUS_PIN
    217             self.needsAttentionIndicator.display = True
    218         else:
    219             self._ConstructNeedsAttentionIndicator()
    220         animations.FadeTo(self.needsAttentionIndicator, 1.0, 0.5, duration=2.0, curveType=uiconst.ANIM_WAVE, loops=uiconst.ANIM_REPEAT, curveSet='piBlink')
    221         animations.MorphScalar(self.needsAttentionIndicator, 'pinRadius', self.needsAttentionIndicator.pinRadius, 1.2 * RADIUS_PIN, duration=2.0, loops=uiconst.ANIM_REPEAT, curveType=uiconst.ANIM_WAVE)
    222 
    223     def _ConstructNeedsAttentionIndicator(self):
    224         self.needsAttentionIndicator = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/gauge_20px.dds', layer=20, radius=RADIUS_PIN, transform=self.transform, scale=1.0106, color=planetCommonUI.PLANET_COLOR_NEEDSATTENTION)
    225         self.needsAttentionIndicator.name = ''
    226 
    227     def HideNeedsAttentionIndicator(self):
    228         if self.needsAttentionIndicator:
    229             uthread.new(self._HideNeedsAttentionIndicator)
    230 
    231     def _HideNeedsAttentionIndicator(self):
    232         self.needsAttentionIndicator.color = planetConst.LINK_COLOR_ROUTED
    233         duration = 1.0
    234         animations.FadeTo(self.needsAttentionIndicator, 1.0, 0.0, duration=duration)
    235         animations.MorphScalar(self.needsAttentionIndicator, 'pinRadius', self.needsAttentionIndicator.pinRadius, 4 * RADIUS_PIN, duration=duration, sleep=True)
    236         self.needsAttentionIndicator.display = False
    237 
    238     def GetPinColor(self):
    239         groupID = evetypes.GetGroupID(self.pin.typeID)
    240         return PINCOLORS[groupID]
    241 
    242     def SetResourceIcons(self):
    243         pass
    244 
    245     def UpdateResourceIcons(self):
    246         t = 0.0
    247         cycleTimeBase = 4.0
    248         while not getattr(self, 'destroyed', False):
    249             numIcons = len(self.resourceIcons)
    250             if numIcons > 1:
    251                 cycleTime = cycleTimeBase * numIcons
    252                 t += 1.0 / blue.os.fps
    253                 t = t % cycleTime
    254                 for i, icon in enumerate(self.resourceIcons):
    255                     icon.display = t > i * cycleTimeBase and t < (i + 1) * cycleTimeBase
    256                     x = t - i * cycleTimeBase
    257                     alpha = math.sin(math.pi * (2 * x / cycleTimeBase - 0.5)) / 2 + 0.5
    258                     icon.pinColor = (1.0,
    259                      1.0,
    260                      1.0,
    261                      alpha * 0.8)
    262 
    263             blue.pyos.synchro.Yield()
    264 
    265     def AssignIDsToPins(self):
    266         for pin in self.spherePins:
    267             if isinstance(self.pin.id, tuple):
    268                 pinType = planetCommonUI.PINTYPE_NORMALEDIT
    269                 pin.name = '%s,%s,%s' % (pinType, self.pin.id[0], self.pin.id[1])
    270             else:
    271                 pinType = planetCommonUI.PINTYPE_NORMAL
    272                 pin.name = '%s,%s' % (pinType, self.pin.id)
    273 
    274         self.border.name = self.shadow.name = ''
    275         if self.needsAttentionIndicator:
    276             self.needsAttentionIndicator.name = ''
    277 
    278     def UpdateEditModeColors(self):
    279         if self and self.pin:
    280             if self.pin.IsInEditMode():
    281                 self.mainPin.pinColor = planetCommonUI.PLANET_COLOR_PINEDITMODE
    282             else:
    283                 self.mainPin.pinColor = (0.0, 0.0, 0.0, 0.4)
    284 
    285     def UpdateStorageGauge(self):
    286         if self.pin.IsStorage():
    287             usage = self.pin.capacityUsed / self.pin.GetCapacity()
    288         else:
    289             usage = 0.0
    290         if usage > 0:
    291             self.gauge.display = True
    292         else:
    293             self.gauge.display = False
    294         self.gauge.pinAlphaThreshold = usage
    295 
    296     def UpdateCycleTimer(self):
    297         while not getattr(self, 'destroyed', False):
    298             if self.pin.GetCycleTime() and self.pin.GetNextRunTime() and self.pin.IsActive() and not self.pin.IsInEditMode():
    299                 self.cycle.display = True
    300                 self.cycle.pinColor = Color.WHITE
    301                 currCycle = self.pin.GetCycleTime() - (self.pin.GetNextRunTime() - blue.os.GetWallclockTime())
    302                 cycleProportion = currCycle / float(self.pin.GetCycleTime())
    303                 self.cycle.pinAlphaThreshold = cycleProportion
    304             elif self.pin.IsProducer() and getattr(self.pin, 'schematicID', False):
    305                 cycleLength = 3.0
    306                 elapsed = 1.0 / blue.os.fps
    307                 self.producerCycleTime += elapsed
    308                 if self.producerCycleTime > cycleLength:
    309                     self.producerCycleTime -= cycleLength
    310                 self.cycle.display = True
    311                 self.cycle.pinAlphaThreshold = 1.0
    312                 alpha = math.sin(math.pi * self.producerCycleTime / cycleLength)
    313                 self.cycle.pinColor = (1.0,
    314                  1.0,
    315                  1.0,
    316                  alpha)
    317             else:
    318                 self.cycle.display = False
    319             blue.pyos.synchro.Yield()
    320 
    321     def RenderAccordingToState(self):
    322         renderState = self.renderState
    323         if renderState.mouseHover:
    324             self.border.display = True
    325             self.border.pinColor = (1.0, 1.0, 1.0, 0.15)
    326         elif renderState.asRoute:
    327             self.border.display = True
    328             self.border.pinColor = (255.0 / 256,
    329              125.0 / 256,
    330              0.0 / 256,
    331              0.15)
    332         elif renderState.selected:
    333             pass
    334         else:
    335             self.border.display = False
    336         self.CheckShowNeedsAttentionIndicator()
    337 
    338     def CheckShowNeedsAttentionIndicator(self):
    339         colony = sm.GetService('planetUI').planet.GetColony(session.charid)
    340         if colony and colony.colonyData.IsPinNeedingAttention(self.pin.id):
    341             self.ShowNeedsAttentionIndicator()
    342         else:
    343             self.HideNeedsAttentionIndicator()
    344 
    345     def ResetPinData(self, newPin):
    346         self.pin = newPin
    347         self.UpdateEditModeColors()
    348 
    349     def GetMenu(self):
    350         ret = []
    351         if session.role & ROLE_GML == ROLE_GML:
    352             ret.append(('GM / WM Extras', self.GetGMMenu()))
    353         planetUISvc = sm.GetService('planetUI')
    354         eventManager = planetUISvc.eventManager
    355         ret.extend([(MenuLabel('UI/PI/Common/CreateLink'), eventManager.BeginCreateLink, [self.pin.id]), (MenuLabel('UI/Commands/ShowInfo'), sm.GetService('info').ShowInfo, [self.pin.typeID, self.pin.id])])
    356         if len(eventManager.selectedPinIDs) > 1:
    357             ret += planetUISvc.myPinManager.GetMultiPinMenu(self)
    358         return ret
    359 
    360     def GetGMMenu(self):
    361         ret = []
    362         ret.append(('PinID: %s' % (self.pin.id,), blue.pyos.SetClipboardData, [str(self.pin.id)]))
    363         return ret
    364 
    365     def OnRefreshPins(self):
    366         self.UpdateStorageGauge()
    367         self.SetResourceIcons()
    368         self.UpdateEditModeColors()
    369         self.RenderAccordingToState()
    370 
    371     def SetAsRoute(self):
    372         self.renderState.asRoute = True
    373         self.RenderAccordingToState()
    374 
    375     def ResetAsRoute(self):
    376         self.renderState.asRoute = False
    377         self.RenderAccordingToState()
    378 
    379     def PlacementAnimation(self):
    380         for pin, radius, expandedRadius in self.pinExpansions:
    381             pin.pinRadius = RADIUS_LOGO
    382             animations.MorphScalar(pin, 'pinRadius', endVal=radius, duration=0.25)
    383 
    384     def ConstructHologramModel(self):
    385         graphic = inventorycommon.typeHelpers.GetGraphic(self.pin.typeID)
    386         if graphic and graphic.graphicFile:
    387             graphicFile = str(graphic.graphicFile)
    388             graphicFile = graphicFile.replace(':/model', ':/dx9/model').replace('.blue', '.red')
    389             return trinity.Load(graphicFile)
    390         if not self.hologramModel or self.hologramModel.__bluetype__ != 'trinity.EveTransform':
    391             return trinity.Load('res:/dx9/model/structure/planetary/terrestrial/command/commt_t1/commt_t1.red')
    392 
    393     def SetSelected(self):
    394         for pin, radius, expandedRadius in self.pinExpansions:
    395             animations.MorphScalar(pin, 'pinRadius', endVal=expandedRadius, duration=0.25)
    396 
    397         self.ShowHologramModel()
    398         self.renderState.selected = True
    399         self.RenderAccordingToState()
    400 
    401     def SetDeselected(self):
    402         for pin, radius, expandedRadius in self.pinExpansions:
    403             animations.MorphScalar(pin, 'pinRadius', endVal=radius, duration=0.25)
    404 
    405         if self.hologramModel:
    406             self.HideHologramModel()
    407         self.renderState.selected = False
    408         self.RenderAccordingToState()
    409 
    410     def SetMultiSelectedDisplay(self, doDisplay):
    411         self.multiSelected.display = doDisplay
    412 
    413     def OnMouseEnter(self):
    414         self.renderState.mouseHover = True
    415         self.RenderAccordingToState()
    416         sm.GetService('audio').SendUIEvent('msg_pi_pininteraction_mouseover_play')
    417 
    418     def OnMouseExit(self):
    419         self.renderState.mouseHover = False
    420         self.RenderAccordingToState()
    421 
    422     def ProcessColonyDataSet(self, planetID):
    423         if sm.GetService('planetUI').planetID != planetID:
    424             return
    425         self.pin = sm.GetService('planetSvc').GetPlanet(planetID).GetPin(self.pin.id)
    426 
    427 
    428 class CommandCenterPin(BasePlanetPin):
    429     BasePlanetPin.__notifyevents__.append('OnEditModeBuiltOrDestroyed')
    430 
    431     def __init__(self, surfacePoint, pin, transform):
    432         BasePlanetPin.__init__(self, surfacePoint, pin, transform)
    433         gaugeRadius = 0.005
    434         gaugeRadiusExtended = 0.0082
    435         powerGauge = self.powerGauge = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/hash15px.dds', layer=11, radius=gaugeRadius, transform=transform, scale=SCALE_PINLIFTED, isGauge=True, color=planetCommonUI.PLANET_COLOR_POWER)
    436         powerGaugeUnderlay = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/hash15px.dds', layer=10, radius=gaugeRadius, transform=transform, scale=SCALE_PINLIFTED, isGauge=True, color=(0.35, 0, 0))
    437         powerGauge.name = powerGaugeUnderlay.name = '%s,%s' % (planetCommonUI.PINTYPE_NORMAL, self.pin.id)
    438         self.pinExpansions.append((powerGauge, gaugeRadius, gaugeRadiusExtended))
    439         self.pinExpansions.append((powerGaugeUnderlay, gaugeRadius, gaugeRadiusExtended))
    440         cpuGauge = self.cpuGauge = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/hash15px.dds', layer=11, radius=gaugeRadius, transform=transform, scale=SCALE_PINLIFTED, isGauge=True, color=planetCommonUI.PLANET_COLOR_CPU)
    441         cpuGaugeUnderlay = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/hash15px.dds', layer=10, radius=gaugeRadius, transform=transform, scale=SCALE_PINLIFTED, isGauge=True, color=(0.0, 0.329, 0.267, 1.0))
    442         cpuGauge.name = cpuGaugeUnderlay.name = '%s,%s' % (planetCommonUI.PINTYPE_NORMAL, self.pin.id)
    443         cpuGauge.pinRotation = cpuGaugeUnderlay.pinRotation = math.pi
    444         self.pinExpansions.append((cpuGauge, gaugeRadius, gaugeRadiusExtended))
    445         self.pinExpansions.append((cpuGaugeUnderlay, gaugeRadius, gaugeRadiusExtended))
    446         powerGaugeUnderlay.pinAlphaThreshold = 0.5
    447         cpuGaugeUnderlay.pinAlphaThreshold = 0.5
    448         self.AssignIDsToPins()
    449         self.UpdatePowerCPUGauge()
    450 
    451     def OnRefreshPins(self):
    452         BasePlanetPin.OnRefreshPins(self)
    453         self.UpdatePowerCPUGauge()
    454 
    455     def OnEditModeBuiltOrDestroyed(self, planetID):
    456         if sm.GetService('planetUI').planetID != planetID:
    457             return
    458         self.UpdatePowerCPUGauge()
    459 
    460     def UpdatePowerCPUGauge(self):
    461         colony = sm.GetService('planetUI').GetCurrentPlanet().GetColony(self.pin.ownerID)
    462         if colony is None or colony.colonyData is None:
    463             raise RuntimeError('Colony is gone but Command Pin window still open')
    464         if colony.colonyData.GetColonyPowerSupply() > 0:
    465             self.powerGauge.pinAlphaThreshold = min(1.0, float(colony.colonyData.GetColonyPowerUsage()) / colony.colonyData.GetColonyPowerSupply()) / 2.0
    466         else:
    467             self.powerGauge.pinAlphaThreshold = 0.0
    468         if colony.colonyData.GetColonyCpuSupply() > 0:
    469             self.cpuGauge.pinAlphaThreshold = min(1.0, float(colony.colonyData.GetColonyCpuUsage()) / float(colony.colonyData.GetColonyCpuSupply())) / 2.0
    470         else:
    471             self.cpuGauge.pinAlphaThreshold = 0.0
    472 
    473     def GetGMMenu(self):
    474         menu = []
    475         menu.extend(BasePlanetPin.GetGMMenu(self))
    476         if session.role & ROLE_GML == ROLE_GML and not sm.GetService('planetUI').GetCurrentPlanet().IsInEditMode():
    477             menu.append(('Convert Command Center', self.ConvertCommandCenter))
    478         return menu
    479 
    480     def ConvertCommandCenter(self):
    481         sm.GetService('planetUI').planet.GMConvertCommandCenter(self.pin.id)
    482 
    483 
    484 class ProcessorPin(BasePlanetPin):
    485 
    486     def __init__(self, surfacePoint, pin, transform):
    487         self.hopperGauges = []
    488         self.hopperGaugeUnderlays = []
    489         BasePlanetPin.__init__(self, surfacePoint, pin, transform)
    490         self.gauge.display = self.gaugeUnderlay.display = False
    491         for i in xrange(3):
    492             gauge = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/gauge_15px.dds', layer=11, radius=RADIUS_PIN, transform=transform, scale=SCALE_PINLIFTED, isGauge=True, color=planetCommonUI.PLANET_COLOR_USED_PROCESSOR)
    493             gaugeUnderlay = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/gauge_15px.dds', layer=10, radius=RADIUS_PIN, transform=transform, scale=SCALE_PINLIFTED, isGauge=True, color=self.GetPinColor())
    494             gauge.display = gaugeUnderlay.display = False
    495             self.hopperGauges.append(gauge)
    496             self.hopperGaugeUnderlays.append(gaugeUnderlay)
    497             self.pinExpansions.append((gauge, RADIUS_PIN, RADIUS_PINEXTENDED))
    498             self.pinExpansions.append((gaugeUnderlay, RADIUS_PIN, RADIUS_PINEXTENDED))
    499 
    500         self.AssignIDsToPins()
    501         self.UpdateStorageGauge()
    502 
    503     def GetPinColor(self):
    504         typeID = self.pin.typeID
    505         if typeID in planetConst.TYPEIDS_PROCESSORS_HIGHTECH:
    506             return planetCommonUI.PLANET_COLOR_ICON_PROCESSOR_HIGHTECH
    507         elif typeID in planetConst.TYPEIDS_PROCESSORS_ADVANCED:
    508             return planetCommonUI.PLANET_COLOR_ICON_PROCESSOR_ADVANCED
    509         else:
    510             return planetCommonUI.PLANET_COLOR_ICON_PROCESSOR
    511 
    512     def UpdateStorageGauge(self):
    513         if not self.hopperGauges:
    514             return
    515         proportions = []
    516         ingredients = []
    517         gapConst = 0.04
    518         for typeID, item in get_schematic_types(self.pin.schematicID, {}).iteritems():
    519             if item.isInput:
    520                 ingredients.append(utillib.KeyVal(typeID=typeID, quantity=item.quantity))
    521 
    522         numIngredients = len(ingredients)
    523         for i in xrange(3):
    524             if i > numIngredients - 1:
    525                 self.hopperGauges[i].display = False
    526                 self.hopperGaugeUnderlays[i].display = False
    527                 continue
    528             hopperFill = self.pin.contents.get(ingredients[i].typeID, 0) / float(ingredients[i].quantity)
    529             if hopperFill > 1.0:
    530                 hopperFill = 1.0
    531             if hopperFill > 0.0:
    532                 self.hopperGauges[i].display = True
    533             self.hopperGaugeUnderlays[i].display = True
    534             if numIngredients > 1:
    535                 gaugeThreshold = hopperFill / numIngredients * (1.0 - gapConst * numIngredients)
    536                 underlayThreshold = 1.0 / numIngredients * (1.0 - gapConst * numIngredients)
    537             else:
    538                 gaugeThreshold = hopperFill
    539                 underlayThreshold = 1.0
    540             rotation = 2 * math.pi * (float(i) / numIngredients + gapConst / 2.0)
    541             self.hopperGauges[i].pinAlphaThreshold = gaugeThreshold
    542             self.hopperGaugeUnderlays[i].pinAlphaThreshold = underlayThreshold
    543             self.hopperGauges[i].pinRotation = rotation
    544             self.hopperGaugeUnderlays[i].pinRotation = rotation
    545 
    546 
    547 class ExtractorPin(BasePlanetPin):
    548     baseColor = planetCommonUI.PLANET_COLOR_EXTRACTOR
    549 
    550     def __init__(self, surfacePoint, pin, transform):
    551         BasePlanetPin.__init__(self, surfacePoint, pin, transform)
    552 
    553     def GetMenu(self):
    554         menu = []
    555         menu.extend(BasePlanetPin.GetMenu(self))
    556         return menu
    557 
    558     def GetGMMenu(self):
    559         menu = []
    560         menu.extend(BasePlanetPin.GetGMMenu(self))
    561         return menu
    562 
    563 
    564 class EcuPin(BasePlanetPin):
    565     baseColor = planetCommonUI.PLANET_COLOR_EXTRACTOR
    566 
    567     def __init__(self, surfacePoint, pin, transform):
    568         BasePlanetPin.__init__(self, surfacePoint, pin, transform)
    569         self.rings = []
    570         self.extractionHeadsByNum = {}
    571         self.linksByHeadID = {}
    572         numRings = 6
    573         self.transform = transform
    574         self.isSurveying = False
    575         self.distanceFactor = 0.0
    576         for i in xrange(numRings):
    577             ring = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/gauge_15px.dds', layer=0, radius=0.0, transform=transform, color=Color(*planetCommonUI.PLANET_COLOR_EXTRACTOR).SetAlpha(0.3).GetRGBA())
    578             self.rings.append(ring)
    579 
    580         self.CreateSpherePin(textureName='res:/UI/Texture/Planet/pin_base.dds', layer=0, radius=RADIUS_PIN * 0.25, scale=SCALE_ONGROUND * 1.0005, transform=transform, color=planetCommonUI.PLANET_COLOR_EXTRACTOR)
    581         areaOfInfluence = pin.GetAreaOfInfluence()
    582         self.maxDistanceCircle = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/survey_ghost_512.dds', layer=0, radius=areaOfInfluence, scale=SCALE_ONGROUND * 1.0005, transform=transform, display=False)
    583         self.maxDistanceCircle.pinMaxRadius = areaOfInfluence
    584         self.RenderExtractionHeads()
    585         uthread.new(self.Animate)
    586 
    587     def EnterSurveyMode(self):
    588         self.isSurveying = True
    589         self.SetExtractionHeadRadius(self.pin.headRadius)
    590         self.UpdateMaxDistanceCircle()
    591 
    592     def ExitSurveyMode(self):
    593         self.isSurveying = False
    594         self.UpdateMaxDistanceCircle()
    595         self.ResetOverlapValues()
    596 
    597     def ShowMaxDistanceCircle(self):
    598         self.isSurveying = True
    599         self.UpdateMaxDistanceCircle()
    600 
    601     def HideMaxDistanceCircle(self):
    602         self.isSurveying = False
    603         self.UpdateMaxDistanceCircle()
    604 
    605     def SetDistanceFactor(self, distanceFactor):
    606         self.distanceFactor = distanceFactor
    607         self.UpdateMaxDistanceCircle()
    608 
    609     def UpdateMaxDistanceCircle(self):
    610         self.maxDistanceCircle.display = self.isSurveying or self.renderState.selected
    611         if self.maxDistanceCircle.display:
    612             self._UpdateDistanceCircleOpacity()
    613 
    614     def _UpdateDistanceCircleOpacity(self):
    615         STARTSHOWVALUE = 0.7
    616         MINALPHA = 0.15
    617         MAXALPHA = 0.25
    618         color = planetCommonUI.GetContrastColorForCurrPlanet()
    619         x = MINALPHA
    620         if self.distanceFactor > STARTSHOWVALUE:
    621             x += (MAXALPHA - MINALPHA) * (self.distanceFactor - STARTSHOWVALUE) / (1.0 - STARTSHOWVALUE)
    622         self.maxDistanceCircle.pinColor = Color(*color).SetAlpha(x).GetRGBA()
    623 
    624     def GetExtractionHead(self, headID):
    625         return self.extractionHeadsByNum.get(headID, None)
    626 
    627     def OnHeadsUnlocked(self):
    628         for head in self.extractionHeadsByNum.values():
    629             head.ShowUnlocked()
    630 
    631     def OnHeadsLocked(self):
    632         for head in self.extractionHeadsByNum.values():
    633             head.ShowLocked()
    634 
    635     def RenderExtractionHeads(self):
    636         self.RemoveAllHeads()
    637         for headID, phi, theta in self.pin.heads:
    638             surfacePoint = SurfacePoint(theta=theta, phi=phi)
    639             self.AddHead(headID, surfacePoint)
    640 
    641     def AddHead(self, headID, surfacePoint):
    642         extractionHead = ExtractionHeadPin(surfacePoint, self.transform, self.pin, headID, self.pin.headRadius or planetCommon.RADIUS_DRILLAREAMIN)
    643         self.extractionHeadsByNum[headID] = extractionHead
    644         link = LinkBase('linksExtraction', surfacePoint, self.surfacePoint, color=planetCommonUI.PLANET_COLOR_EXTRACTIONLINK)
    645         self.linksByHeadID[headID] = link
    646 
    647     def RemoveAllHeads(self):
    648         for headID in self.extractionHeadsByNum.keys():
    649             self.RemoveHead(headID)
    650 
    651     def RemoveHead(self, headID):
    652         head = self.extractionHeadsByNum.get(headID, None)
    653         if head:
    654             head.Remove()
    655             self.extractionHeadsByNum.pop(headID)
    656         link = self.linksByHeadID.get(headID, None)
    657         if link:
    658             link.Remove()
    659             self.linksByHeadID.pop(headID)
    660 
    661     def MoveExtractionHeadTo(self, headID, surfacePoint):
    662         head = self.extractionHeadsByNum.get(headID, None)
    663         if head:
    664             head.SetLocation(surfacePoint)
    665         link = self.linksByHeadID.get(headID, None)
    666         if link:
    667             link.Remove()
    668             link = LinkBase('linksExtraction', surfacePoint, self.surfacePoint, color=planetCommonUI.PLANET_COLOR_EXTRACTIONLINK)
    669         self.HideHologramModel()
    670         for head in self.extractionHeadsByNum.values():
    671             head.HideHologramModel()
    672 
    673     def ResetPinData(self, newPin):
    674         oldHeads = [ head for head in self.pin.heads ]
    675         newHeads = [ head for head in newPin.heads ]
    676         toRemove = [ head for head in oldHeads if head not in newHeads ]
    677         for headID, phi, theta in toRemove:
    678             self.RemoveHead(headID)
    679 
    680         toAdd = [ head for head in newHeads if head not in oldHeads ]
    681         for headID, phi, theta in toAdd:
    682             surfacePoint = SurfacePoint(theta=theta, phi=phi)
    683             self.AddHead(headID, surfacePoint)
    684 
    685         for headUI in self.extractionHeadsByNum.values():
    686             headUI.pin = self.pin
    687 
    688         BasePlanetPin.ResetPinData(self, newPin)
    689 
    690     def ResetOverlapValues(self):
    691         for headUI in self.extractionHeadsByNum.values():
    692             headUI.SetOverlapValue(0)
    693 
    694     def SetOverlapValues(self, overlapVals):
    695         for headID, overlapVal in overlapVals.iteritems():
    696             head = self.extractionHeadsByNum.get(headID, None)
    697             if head:
    698                 head.SetOverlapValue(overlapVal)
    699 
    700     def SetExtractionHeadRadius(self, radius, time = 1000.0):
    701         uthread.new(self._SetExtractionHeadRadius, radius, time)
    702 
    703     def _SetExtractionHeadRadius(self, radius, time):
    704         for head in self.extractionHeadsByNum.values():
    705             head.SetExtractionHeadRadius(radius, time)
    706             blue.pyos.synchro.SleepWallclock(100)
    707 
    708     def Remove(self):
    709         self.RemoveAllHeads()
    710         BasePlanetPin.Remove(self)
    711 
    712     def Animate(self):
    713         cycleTime = 10.0
    714         numRings = len(self.rings)
    715         scaleDiff = SCALE_PINLIFTED - 1.0
    716         elapsed = 0.0
    717         color = list(planetCommonUI.PLANET_COLOR_EXTRACTOR)
    718         while not getattr(self, 'destroyed', False):
    719             elapsed += 1.0 / blue.os.fps
    720             t = elapsed % cycleTime
    721             for i, ring in enumerate(self.rings):
    722                 x = (float(i + 1) / numRings + t / cycleTime) % 1
    723                 scale = x * scaleDiff + 1.0
    724                 ring.scaling = (scale, scale, scale)
    725                 ring.pinRadius = (x * 0.7 + 0.3) * self.mainPin.pinRadius
    726                 color[3] = x
    727                 ring.pinColor = color
    728 
    729             blue.pyos.synchro.Yield()
    730 
    731     def SetSelected(self):
    732         BasePlanetPin.SetSelected(self)
    733         self.UpdateMaxDistanceCircle()
    734         for head in self.extractionHeadsByNum.values():
    735             head.ShowHologramModel()
    736 
    737     def SetDeselected(self):
    738         BasePlanetPin.SetDeselected(self)
    739         self.UpdateMaxDistanceCircle()
    740         for head in self.extractionHeadsByNum.values():
    741             head.HideHologramModel()
    742 
    743     def GetMenu(self):
    744         menu = []
    745         menu.extend(BasePlanetPin.GetMenu(self))
    746         return menu
    747 
    748     def GetGMMenu(self):
    749         menu = []
    750         menu.extend(BasePlanetPin.GetGMMenu(self))
    751         if session.role & ROLE_GML == ROLE_GML and not sm.GetService('planetUI').GetCurrentPlanet().IsInEditMode():
    752             menu.append(('Deposit Designer', self.HotProgramInjection))
    753         return menu
    754 
    755     def HotProgramInjection(self):
    756         sm.GetService('planetUI').planet.GMInstallProgram(self.pin.id)
    757 
    758 
    759 class LaunchpadPin(BasePlanetPin):
    760     pass
    761 
    762 
    763 class StorageFacilityPin(BasePlanetPin):
    764 
    765     def __init__(self, surfacePoint, pin, transform):
    766         BasePlanetPin.__init__(self, surfacePoint, pin, transform)
    767 
    768 
    769 class BuildIndicatorPin(SpherePinStack):
    770 
    771     def __init__(self, surfacePoint, typeID, groupID, transform):
    772         areaOfInfluence = sm.GetService('godma').GetTypeAttribute2(typeID, appConst.attributeEcuAreaOfInfluence)
    773         SpherePinStack.__init__(self, surfacePoint, areaOfInfluence)
    774         self.surfacePin = self.CreateSpherePin(textureName=GetPinIconPath(typeID), layer=10, radius=RADIUS_LOGO, transform=transform, scale=SCALE_PINBASE, color=(1.0, 1.0, 1.0, 0.4))
    775         self.cannotBuild = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/pin_base.dds', layer=11, radius=RADIUS_PIN, transform=transform, scale=SCALE_PINBASE, color=(0.3, 0.0, 0.0, 0.5))
    776         self.cannotBuild.display = False
    777         self.shadow = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/disc_shadow.dds', layer=12, radius=RADIUS_SHADOW, transform=transform, scale=SCALE_ONGROUND, color=(0.0, 0.0, 0.0, 0.3))
    778         if groupID == appConst.groupExtractionControlUnitPins:
    779             color = planetCommonUI.GetContrastColorForCurrPlanet()
    780             color = Color(*color).SetAlpha(0.2).GetRGBA()
    781             self.maxDistanceCircle = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/survey_ghost_512.dds', layer=0, radius=areaOfInfluence, scale=SCALE_ONGROUND * 1.0005, transform=transform, color=color)
    782         sm.GetService('planetUI').planetNav.SetFocus()
    783 
    784     def SetCanBuildIndication(self, canBuild):
    785         self.cannotBuild.display = not canBuild
    786 
    787 
    788 class TemplatePins(SpherePinStack):
    789 
    790     def __init__(self, surfacePoint, typeID, groupID, transform):
    791         areaOfInfluence = sm.GetService('godma').GetTypeAttribute2(typeID, appConst.attributeEcuAreaOfInfluence)
    792         SpherePinStack.__init__(self, surfacePoint, areaOfInfluence)
    793         self.typeCircle = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/gauge_15px.dds', layer=10, radius=RADIUS_PIN, transform=transform, scale=SCALE_PINBASE, color=(1.0, 1.0, 1.0, 1.0))
    794         self.surfacePin = self.CreateSpherePin(textureName=GetPinIconPath(typeID), layer=11, radius=RADIUS_LOGO, transform=transform, scale=SCALE_PINBASE, color=(1.0, 1.0, 1.0, 0.4))
    795         self.shadow = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/disc_shadow.dds', layer=12, radius=RADIUS_SHADOW, transform=transform, scale=SCALE_ONGROUND, color=(0.0, 0.0, 0.0, 0.3))
    796         if groupID == appConst.groupExtractionControlUnitPins:
    797             color = planetCommonUI.GetContrastColorForCurrPlanet()
    798             color = Color(*color).SetAlpha(0.2).GetRGBA()
    799             self.maxDistanceCircle = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/survey_ghost_512.dds', layer=0, radius=areaOfInfluence, scale=SCALE_ONGROUND * 1.0005, transform=transform, color=color)
    800         sm.GetService('planetUI').planetNav.SetFocus()
    801         self.AssignIDsToPins()
    802 
    803     def SetCircleColor(self, color):
    804         self.typeCircle.pinColor = color
    805 
    806     def AssignIDsToPins(self):
    807         counter = 0
    808         for pin in self.spherePins:
    809             pinType = planetCommonUI.PINTYPE_NORMAL
    810             pin.name = '%s,%s,_temp' % (pinType, counter)
    811             counter += 1
    812 
    813 
    814 class OtherPlayersPin(SpherePinStack):
    815     HOVERCOLOR = (1.0, 1.0, 1.0, 0.9)
    816     DEFAULTCOLOR = (0.0, 1.0, 1.0, 0.3)
    817 
    818     def __init__(self, surfacePoint, pinID, typeID, ownerID, transform, isActive = False):
    819         SpherePinStack.__init__(self, surfacePoint, RADIUS_PINOTHERS)
    820         self.pinID = pinID
    821         self.typeID = typeID
    822         self.ownerID = ownerID
    823         groupID = evetypes.GetGroupID(typeID)
    824         pinIconPath = PINICONPATHS[groupID]
    825         col = PINCOLORS[groupID]
    826         self.ACTIVECOLOR = (col[0],
    827          col[1],
    828          col[2],
    829          0.6)
    830         self.spherePins = []
    831         if isActive:
    832             self.currColor = self.ACTIVECOLOR
    833         else:
    834             self.currColor = self.DEFAULTCOLOR
    835         self.surfacePin = self.CreateSpherePin(textureName=pinIconPath, layer=0, radius=RADIUS_PINOTHERS, transform=transform, scale=SCALE_PINOTHERS, color=self.currColor)
    836         self.surfacePin.name = '%s,%s' % (planetCommonUI.PINTYPE_OTHERS, pinID)
    837 
    838     def OnMouseEnter(self):
    839         self.surfacePin.pinColor = self.HOVERCOLOR
    840         sm.GetService('audio').SendUIEvent('msg_pi_pininteraction_mouseover_play')
    841 
    842     def OnMouseExit(self):
    843         self.surfacePin.pinColor = self.currColor
    844 
    845     def RenderAsActive(self):
    846         self.surfacePin.pinColor = self.currColor = self.ACTIVECOLOR
    847 
    848     def RenderAsDefault(self):
    849         self.surfacePin.pinColor = self.currColor = self.DEFAULTCOLOR
    850 
    851     def GetGMMenu(self):
    852         return None
    853 
    854     def GetMenu(self):
    855         charTypeID = cfg.eveowners.Get(self.ownerID).typeID
    856         charName = localization.GetByLabel('UI/PI/Common/OwnerName', ownerName=cfg.eveowners.Get(self.ownerID).name)
    857         charMenu = GetMenuService().GetMenuFromItemIDTypeID(self.ownerID, charTypeID)
    858         ret = [(MenuLabel('UI/Commands/ShowInfo'), sm.GetService('info').ShowInfo, [self.typeID, self.pinID]), None, (charName, charMenu)]
    859         return ret
    860 
    861 
    862 class ExtractionHeadPin(SpherePinStack):
    863     NUMWAVES = 2
    864 
    865     def __init__(self, surfacePoint, transform, ecuPin, headID, radius):
    866         SpherePinStack.__init__(self, surfacePoint, planetCommon.RADIUS_DRILLAREAMAX)
    867         self.pin = ecuPin
    868         self.headID = headID
    869         self.disturbanceVal = 0.0
    870         self.headRadius = radius
    871         self.hologramModel = None
    872         self.transform = transform
    873         self.surfacePin = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/drill_pin.png', layer=headID * 10 + 2, radius=RADIUS_PIN * 0.4, maxRadius=RADIUS_PIN * 0.4, transform=transform, scale=SCALE_ONGROUND * 1.001, color=planetCommonUI.PLANET_COLOR_EXTRACTOR)
    874         self.selectionArea = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/arrows_256.dds', layer=headID * 10 + 1, radius=RADIUS_PIN * 1.6, maxRadius=RADIUS_PIN * 1.6, transform=transform, scale=SCALE_ONGROUND * 1.001, color=Color(*planetCommonUI.PLANET_COLOR_EXTRACTOR).SetAlpha(0.7).SetSaturation(0.9).GetRGBA())
    875         self.selectionArea.display = False
    876         self.pinColor = Color(*planetCommonUI.PLANET_COLOR_EXTRACTOR).SetSaturation(0.4).GetRGBA()
    877         self.drillArea = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/drill_area.png', layer=headID * 10, radius=RADIUS_PIN * 0.4, transform=transform, scale=SCALE_ONGROUND, color=self.pinColor)
    878         self.shadow = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/disc_shadow.dds', layer=0, radius=RADIUS_PIN * 0.4, transform=transform, scale=SCALE_ONGROUND, color=(0.0, 0.0, 0.0, 0.25))
    879         self.SetExtractionHeadRadius(radius)
    880         self.waves = []
    881         for i in xrange(self.NUMWAVES):
    882             wave = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/donut_512.dds', layer=0, radius=0.0, transform=transform, scale=SCALE_ONGROUND, color=self.pinColor)
    883             wave.name = ''
    884             self.waves.append(wave)
    885 
    886         self.noisePin = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/white_noise_256.dds', layer=0, radius=RADIUS_PIN * 1.5, transform=transform, scale=SCALE_ONGROUND, color=Color.WHITE, display=False)
    887         self.pickArea = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/pin_base.dds', layer=headID * 10 + 2, radius=RADIUS_PIN * 1.9, maxRadius=RADIUS_PIN * 1.9, transform=transform, scale=SCALE_ONGROUND * 1.001, color=(0.0, 0.0, 0.0, 0.01))
    888         name = '%s,%s,%s' % (planetCommonUI.PINTYPE_EXTRACTIONHEAD, self.pin.id, headID)
    889         self.selectionArea.name = self.surfacePin.name = self.pickArea.name = name
    890         uthread.new(self.AnimateDrillArea)
    891         uthread.new(self.AnimateWaves)
    892         uthread.new(self.AnimateNoise)
    893 
    894     def ConstructHologramModel(self):
    895         if sm.GetService('planetUI').planet.planetTypeID == appConst.typePlanetGas:
    896             id = 20612
    897         else:
    898             id = 10097
    899         return trinity.Load(GetGraphicFile(id))
    900 
    901     def SetExtractionHeadRadius(self, radius, time = 250.0):
    902         if radius is None:
    903             return
    904         self.headRadius = radius
    905         animations.MorphScalar(self.drillArea, 'pinRadius', self.drillArea.pinRadius, radius, duration=time / 1000)
    906         animations.MorphScalar(self.shadow, 'pinRadius', self.shadow.pinRadius, radius * 1.1, duration=time / 1000)
    907 
    908     def SetOverlapValue(self, disturbanceVal):
    909         self.disturbanceVal = min(1.0, max(0.0, disturbanceVal))
    910 
    911     def OnMouseEnter(self):
    912         self.ShowSelectionArea()
    913         sm.GetService('audio').SendUIEvent('msg_pi_pininteraction_mouseover_play')
    914 
    915     def OnMouseExit(self):
    916         self.HideSelectionArea()
    917 
    918     def ShowUnlocked(self):
    919         self.surfacePin.color = Color(*planetCommonUI.PLANET_COLOR_EXTRACTOR).SetAlpha(2.5).GetRGBA()
    920 
    921     def ShowLocked(self):
    922         self.surfacePin.color = planetCommonUI.PLANET_COLOR_EXTRACTOR
    923 
    924     def ShowSelectionArea(self):
    925         self.selectionArea.display = True
    926 
    927     def HideSelectionArea(self):
    928         self.selectionArea.display = False
    929 
    930     def AnimateDrillArea(self):
    931         cycleLength = 3.0
    932         elapsed = 0.0
    933         while not getattr(self, 'destroyed', False):
    934             elapsed += 1.0 / blue.os.fps
    935             x = (math.sin(math.pi * elapsed / cycleLength) + 1.0) / 2.0
    936             brightness = x * 0.2 + 0.7
    937             alpha = x * 0.15 + 0.2
    938             self.drillArea.pinColor = Color(*self.pinColor).SetBrightness(brightness).SetAlpha(alpha).GetRGBA()
    939             blue.pyos.synchro.Yield()
    940 
    941     def AnimateWaves(self):
    942         elapsed = 0.0
    943         cycleLength = self.NUMWAVES * 6.0
    944         phaseDiff = cycleLength / self.NUMWAVES
    945         while not getattr(self, 'destroyed', False):
    946             if self.pin.IsActive():
    947                 elapsed += 1.0 / blue.os.fps
    948                 x = elapsed % cycleLength
    949                 for i, wave in enumerate(self.waves):
    950                     x = (elapsed + i * phaseDiff) % cycleLength / cycleLength
    951                     wave.pinColor = Color(*planetCommonUI.PLANET_COLOR_EXTRACTOR).SetHSB(0.5, 0.4, 0.7 + 0.3 * x ** 0.3, 0.5 * x).GetRGBA()
    952                     wave.pinRadius = (1.0 - x) * self.drillArea.pinRadius
    953 
    954             else:
    955                 for wave in self.waves:
    956                     wave.pinRadius = 0.0
    957 
    958             blue.pyos.synchro.Yield()
    959 
    960     def AnimateNoise(self):
    961         while not getattr(self, 'destroyed', False):
    962             if self.disturbanceVal > 0.0:
    963                 self.noisePin.display = True
    964                 self.noisePin.pinRotation = random.random() * math.pi * 2
    965                 scale = self.drillArea.pinRadius / planetCommon.RADIUS_DRILLAREAMAX
    966                 xVal = random.random() * 0.05 * scale
    967                 yVal = random.random() * 0.05 * scale
    968                 self.noisePin.uvAtlasScaleOffset = (scale,
    969                  scale,
    970                  xVal,
    971                  xVal)
    972                 self.noisePin.pinRadius = self.drillArea.pinRadius * 0.95
    973                 self.noisePin.pinColor = (1.0,
    974                  1.0,
    975                  1.0,
    976                  self.disturbanceVal * 1.0)
    977             else:
    978                 self.noisePin.display = False
    979             blue.pyos.synchro.SleepWallclock(10)
    980 
    981 
    982 class DepletionPin(SpherePinStack):
    983 
    984     def __init__(self, surfacePoint, index, transform):
    985         self.index = index
    986         SpherePinStack.__init__(self, surfacePoint, 0.1)
    987         self.surfacePin = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/drill_pin.png', layer=0, radius=RADIUS_PIN * 0.4, transform=transform, scale=SCALE_ONGROUND * 1.001, color=Color.OLIVE)
    988         self.pinColor = Color(*planetCommonUI.PLANET_COLOR_EXTRACTOR).SetSaturation(0.4).GetRGBA()
    989         self.drillArea = self.CreateSpherePin(textureName='res:/UI/Texture/Planet/survey_ghost_512.dds', layer=0, radius=planetCommon.RADIUS_DRILLAREAMAX, transform=transform, scale=SCALE_ONGROUND, color=(0.4, 0.4, 0.9, 0.75))
    990         self.surfacePin.name = '5,%d' % index
    991 
    992     def GetDuration(self):
    993         return getattr(self, 'duration', 1440)
    994 
    995     def GetAmount(self):
    996         return getattr(self, 'amount', 500)
    997 
    998     def GetHeadRadius(self):
    999         return getattr(self, 'headRadius', planetCommon.RADIUS_DRILLAREAMAX)