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

slotsContainer.py (30782B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\inflight\shipHud\slotsContainer.py
      2 import random
      3 import telemetry
      4 import carbonui.const as uiconst
      5 import evetypes
      6 import uthread
      7 from carbon.client.script.environment.AudioUtil import PlaySound
      8 from carbon.common.script.util.timerstuff import AutoTimer
      9 from carbonui.primitives.container import Container
     10 from carbonui.uianimations import animations
     11 from eve.client.script.ui.control.eveIcon import Icon
     12 from eve.client.script.ui.control.eveLabel import EveLabelSmall
     13 from eve.client.script.ui.inflight.moondefencebutton import DefenceStructureButton
     14 from eve.client.script.ui.inflight.shipHud import GetSlotOrder
     15 from eve.client.script.ui.inflight.shipHud.groupAllIcon import GroupAllButton
     16 from eve.client.script.ui.inflight.shipHud.overloadBtn import OverloadBtn
     17 from eve.client.script.ui.inflight.shipHud.shipSlot import ShipSlot
     18 from eve.client.script.ui.inflight.shipModuleButton.shipmodulebutton import ModuleButton
     19 from eve.client.script.ui.shared.fitting.fittingUtil import FITKEYS
     20 from eve.common.script.sys.dbrow import LookupConstValue
     21 from inventorycommon.util import IsShipFittingFlag
     22 from localization import GetByLabel
     23 from carbonui.uicore import uicore
     24 import eve.client.script.ui.shared.pointerTool.pointerToolConst as pConst
     25 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     26 from uihider import UiHiderMixin
     27 ICONSIZE = 32
     28 
     29 class SlotsContainer(UiHiderMixin, Container):
     30     default_name = 'slotsContainer'
     31     uniqueUiName = pConst.UNIQUE_NAME_MODULE_SLOTS
     32     __notifyevents__ = ['OnMapShortcut',
     33      'OnRestoreDefaultShortcuts',
     34      'ProcessShipEffect',
     35      'OnAttributes',
     36      'OnWeaponGroupsChanged',
     37      'OnRefreshModuleBanks']
     38 
     39     def ApplyAttributes(self, attributes):
     40         super(SlotsContainer, self).ApplyAttributes(attributes)
     41         sm.RegisterNotify(self)
     42         self.invCookie = sm.GetService('inv').Register(self)
     43         self.controller = attributes.controller
     44         self.slotsByFlag = {}
     45         self.slotsByOrder = {}
     46         self.modulesByID = {}
     47         self.checkingoverloadrackstate = 0
     48         self.totalSlaves = 0
     49         self.myHarpointFlags = []
     50         self.groupAllButton = None
     51 
     52     def Close(self):
     53         Container.Close(self)
     54         sm.GetService('inv').Unregister(self.invCookie)
     55 
     56     def AnimateReveal(self):
     57         PlaySound('onboarding_ui_sfx_play')
     58         self.opacity = 0
     59         self.Show()
     60         animations.BlinkIn(self, startVal=0.2, endVal=1.0, loops=3)
     61 
     62     def Hide(self, *args):
     63         super(SlotsContainer, self).Hide(*args)
     64         self.opacity = 0
     65 
     66     def Show(self, *args, **kwargs):
     67         super(SlotsContainer, self).Show(*args, **kwargs)
     68         self.opacity = 1.0
     69 
     70     def GetPosFromFlag(self, slotFlag):
     71         return self.slotsByFlag[slotFlag].sr.slotPos
     72 
     73     def ChangeSlots(self, toFlag, fromFlag):
     74         toModule = self.GetModuleType(toFlag)
     75         fromModule = self.GetModuleType(fromFlag)
     76         shift = uicore.uilib.Key(uiconst.VK_SHIFT)
     77         if toModule and fromModule and toModule[0] == fromModule[0]:
     78             self.LinkWeapons(toModule, fromModule, toFlag, fromFlag, merge=not shift)
     79             if not sm.GetService('clientDogmaIM').GetDogmaLocation().IsModuleMaster(toModule[1], session.shipid):
     80                 self.SwapSlots(fromFlag, toFlag)
     81         else:
     82             self.SwapSlots(toFlag, fromFlag)
     83 
     84     def SwapSlots(self, slotFlag1, slotFlag2):
     85         module1 = self.GetModuleType(slotFlag1)
     86         module2 = self.GetModuleType(slotFlag2)
     87         shift = uicore.uilib.Key(uiconst.VK_SHIFT)
     88         if shift and module1 is None and module2 is not None:
     89             dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation()
     90             if dogmaLocation.IsInWeaponBank(session.shipid, module2[1]):
     91                 moduleID = dogmaLocation.UngroupModule(session.shipid, module2[1])
     92                 slotFlag2 = dogmaLocation.GetItem(moduleID).flagID
     93         current = GetSlotOrder()[:]
     94         flag1Idx = current.index(slotFlag1)
     95         flag2Idx = current.index(slotFlag2)
     96         current[flag1Idx] = slotFlag2
     97         current[flag2Idx] = slotFlag1
     98         all = settings.user.ui.Get('slotOrder', {})
     99         all[session.shipid] = current
    100         settings.user.ui.Set('slotOrder', all)
    101         self.InitSlots()
    102 
    103     def LinkWeapons(self, master, slave, slotFlag1, slotFlag2, merge = False):
    104         dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation()
    105         groupID = evetypes.GetGroupID(master[0])
    106         areTurrets = groupID in const.dgmGroupableGroupIDs
    107         slaves = dogmaLocation.GetSlaveModules(slave[1], session.shipid)
    108         swapSlots = 0
    109         if slaves:
    110             swapSlots = 1
    111         if not areTurrets:
    112             prompt_player_fsd_dialog('CustomNotify', {'notify': GetByLabel('UI/Inflight/WeaponGroupingRule')})
    113             return
    114         weaponLinked = dogmaLocation.LinkWeapons(session.shipid, master[1], slave[1], merge=merge)
    115         if weaponLinked and swapSlots:
    116             self.SwapSlots(slotFlag1, slotFlag2)
    117 
    118     def GetModuleType(self, flag):
    119         if flag not in self.slotsByFlag:
    120             return None
    121         module = self.slotsByFlag[flag].sr.module
    122         if not module:
    123             return None
    124         return module.GetModuleType()
    125 
    126     def GetModuleFromID(self, moduleID):
    127         return self.modulesByID.get(moduleID, None)
    128 
    129     def GetModule(self, moduleID):
    130         return self.modulesByID.get(moduleID, None)
    131 
    132     @telemetry.ZONE_METHOD
    133     def InitDrawSlots(self, xstep, ystep, vgridrange, hgridrange, grid, myOrder, slotType = None):
    134         for r in xrange(vgridrange):
    135             x, y = grid[r]
    136             for i in xrange(hgridrange):
    137                 slotFlag = myOrder[r * hgridrange + i]
    138                 if slotType == 'shipslot':
    139                     slot = ShipSlot(parent=self, pos=(0,
    140                      int(ystep * y),
    141                      64,
    142                      64), name='slot', state=uiconst.UI_HIDDEN, align=uiconst.TOPLEFT)
    143                 else:
    144                     slot = Container(name='defenceslot', parent=self, width=64, height=128 + 60, align=uiconst.TOPLEFT, state=uiconst.UI_HIDDEN, top=0)
    145                 slot.left = int((x + i) * xstep - 40)
    146                 slot.sr.module = None
    147                 slot.sr.slotFlag = slotFlag
    148                 slot.sr.slotPos = (r, i)
    149                 self.slotsByFlag[slotFlag] = slot
    150                 self.slotsByOrder[r, i] = slot
    151                 slot.sr.shortcutHint = EveLabelSmall(text='<center>-', parent=slot, width=64, color=(1.0, 1.0, 1.0, 0.25), shadowOffset=(0, 0), state=uiconst.UI_DISABLED, idx=0)
    152                 slot.sr.shortcutHint.top = 30
    153                 if self.controller.IsControllingTurret():
    154                     slot.sr.shortcutHint.top -= 4
    155 
    156         self.RefreshShortcuts()
    157 
    158     def RefreshShortcuts(self):
    159         for (r, i), slot in self.slotsByOrder.iteritems():
    160             hiMedLo = ('High', 'Medium', 'Low')[r]
    161             slotno = i + 1
    162             txt = uicore.cmd.GetShortcutStringByFuncName('CmdActivate%sPowerSlot%i' % (hiMedLo, slotno))
    163             if not txt:
    164                 txt = '_'
    165             slot.sr.shortcutHint.text = '<center>' + txt
    166 
    167     def OnMapShortcut(self, *blah):
    168         self.RefreshShortcuts()
    169 
    170     def OnRestoreDefaultShortcuts(self):
    171         self.RefreshShortcuts()
    172 
    173     def ProcessShipEffect(self, godmaStm, effectState):
    174         dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation()
    175         masterID = dogmaLocation.IsInWeaponBank(session.shipid, effectState.itemID)
    176         if masterID:
    177             module = self.GetModule(masterID)
    178         else:
    179             module = self.GetModule(effectState.itemID)
    180         if module:
    181             uthread.new(module.Update, effectState)
    182             uthread.new(self.CheckOverloadRackBtnState)
    183 
    184     def OnAttributes(self, ch):
    185         for each in ch:
    186             if each[0] != 'damage':
    187                 continue
    188             masterID, damage = sm.GetService('godma').GetStateManager().GetMaxDamagedModuleInGroup(session.shipid, each[1].itemID)
    189             module = self.GetModule(masterID)
    190             if module is None:
    191                 continue
    192             module.SetDamage(damage / module.moduleinfo.hp)
    193 
    194     def OnInvChange(self, item, change):
    195         if const.ixFlag in change or const.ixLocationID in change and item[const.ixItemID] in self.modulesByID:
    196             if IsShipFittingFlag(item.flagID) or IsShipFittingFlag(change[const.ixFlag]):
    197                 uthread.new(self.InitSlotsDelayed)
    198 
    199     def IsItemHere(self, rec):
    200         return rec.locationID == session.shipid and rec.categoryID in (const.categoryModule, const.categoryStructureModule) and rec.flagID not in (const.flagCargo, const.flagDroneBay)
    201 
    202     def InitStructureSlots(self):
    203         currentControl = sm.GetService('pwn').GetCurrentControl()
    204         shipmodules = []
    205         charges = {}
    206         if currentControl:
    207             for k, v in currentControl.iteritems():
    208                 shipmodules.append(sm.services['godma'].GetItem(k))
    209 
    210         xstep = int(ICONSIZE * 2.0)
    211         ystep = int(ICONSIZE * 1.35)
    212         vgridrange = 1
    213         hgridrange = 5
    214         grid = [[1.0, 0.1]]
    215         myOrder = [0,
    216          1,
    217          2,
    218          3,
    219          4]
    220         for i, moduleInfo in enumerate(shipmodules):
    221             if moduleInfo is None:
    222                 continue
    223             myOrder[i] = moduleInfo.itemID
    224             if moduleInfo.itemID in currentControl:
    225                 item = sm.services['godma'].GetItem(moduleInfo.itemID)
    226                 if item.groupID == const.groupMobileLaserSentry and len(item.modules):
    227                     charges[moduleInfo.itemID] = item.modules[0]
    228                 elif len(item.sublocations):
    229                     charges[moduleInfo.itemID] = item.sublocations[0]
    230 
    231         self.InitDrawSlots(xstep, ystep, vgridrange, hgridrange, grid, myOrder, slotType='structure')
    232         for moduleInfo in shipmodules:
    233             if moduleInfo:
    234                 self._FitStructureSlot(moduleInfo, charges)
    235 
    236         self.CheckButtonVisibility(3, ['hiSlots'], 5, myOrder)
    237 
    238     @telemetry.ZONE_METHOD
    239     def InitSlots(self, animate = False):
    240         self.initSlotsDelayedTimer = None
    241         if self.destroyed:
    242             return
    243         if animate:
    244             self.AnimateModulesOut()
    245         else:
    246             self.Flush()
    247         self.modulesByID = {}
    248         self.totalSlaves = 0
    249         self.passiveFiltered = []
    250         if self.controller.IsControllingTurret():
    251             self.InitStructureSlots()
    252         else:
    253             charges = {}
    254             for charge in self.controller.GetCharges():
    255                 charges[charge.flagID] = charge
    256                 if charge.stacksize == 0:
    257                     sm.services['godma'].LogError('InitSlots.no quantity', charge, charge.flagID)
    258 
    259             for module in self.controller.GetModules():
    260                 if module.categoryID == const.categoryCharge:
    261                     charges[module.flagID] = module
    262 
    263             xstep = int(ICONSIZE * 1.6)
    264             ystep = int(ICONSIZE * 1.4)
    265             vgridrange = 3
    266             hgridrange = 8
    267             grid = [[1.0, 0.0], [1.5, 1.0], [1.0, 2.0]]
    268             myOrder = GetSlotOrder()
    269             self.InitDrawSlots(xstep, ystep, vgridrange, hgridrange, grid, myOrder, slotType='shipslot')
    270             if not self.controller.IsControllingStructure():
    271                 self.InitOverloadBtns()
    272             self.InitGroupAllButtons()
    273             dogmaLocation = sm.StartService('clientDogmaIM').GetDogmaLocation()
    274             IsSlave = lambda itemID: dogmaLocation.IsModuleSlave(itemID, session.shipid)
    275             for moduleInfo in self.controller.GetModules():
    276                 if IsSlave(moduleInfo.itemID):
    277                     self.totalSlaves += 1
    278                     continue
    279                 self._FitSlot(moduleInfo, charges)
    280 
    281             self.CheckButtonVisibility(0, ['hiSlots', 'medSlots', 'lowSlots'], None, myOrder)
    282             if animate:
    283                 self.AnimateModulesIn()
    284 
    285     def InitSlotsDelayed(self):
    286         self.initSlotsDelayedTimer = AutoTimer(200, self.InitSlots)
    287 
    288     def CloseSlots_Delayed(self, toClose):
    289         self.closeSlotsDelayedTimer = None
    290         for child in toClose:
    291             child.Close()
    292 
    293     def AnimateModulesOut(self):
    294         toClose = self.children[:]
    295         for module in self.modulesByID.itervalues():
    296             module.ShowOffline()
    297             module.isInActiveState = False
    298 
    299         maxDuration = 1.0
    300         fadeTime = 0.1
    301         for child in toClose:
    302             child.opacity = 0.999
    303             fadeDelay = (maxDuration - fadeTime) * random.random()
    304             uicore.animations.FadeOut(child, duration=fadeTime, curveType=uiconst.ANIM_LINEAR, timeOffset=fadeDelay)
    305 
    306         self.closeSlotsDelayedTimer = AutoTimer(maxDuration, self.CloseSlots_Delayed, toClose)
    307 
    308     def AnimateModulesIn(self):
    309         for child in self.children[:]:
    310             if child.opacity < 1.0:
    311                 continue
    312             child.opacity = 0
    313             uicore.animations.FadeIn(child, duration=1.0, timeOffset=1.0, curveType=uiconst.ANIM_OVERSHOT)
    314 
    315     @telemetry.ZONE_METHOD
    316     def InitGroupAllButtons(self):
    317         self.groupAllButton = GroupAllButton(parent=self, idx=0)
    318 
    319     def CheckGroupAllButton(self):
    320         if self.groupAllButton:
    321             self.groupAllButton.CheckGroupAllButton()
    322 
    323     @telemetry.ZONE_METHOD
    324     def InitOverloadBtns(self):
    325         overloadEffectsByRack = {}
    326         modulesByRack = {}
    327         for module in self.controller.GetModules():
    328             for key in module.effects.iterkeys():
    329                 effect = module.effects[key]
    330                 if effect.effectID in (const.effectHiPower, const.effectMedPower, const.effectLoPower):
    331                     if effect.effectID not in modulesByRack:
    332                         modulesByRack[effect.effectID] = []
    333                     modulesByRack[effect.effectID].append(module)
    334                     for key in module.effects.iterkeys():
    335                         effect2 = module.effects[key]
    336                         if effect2.effectCategory == const.dgmEffOverload:
    337                             if effect.effectID not in overloadEffectsByRack:
    338                                 overloadEffectsByRack[effect.effectID] = []
    339                             overloadEffectsByRack[effect.effectID].append(effect2)
    340 
    341         grid = [[13, 52], [20, 66], [13, 80]]
    342         for i, each in enumerate(FITKEYS):
    343             x, y = grid[i]
    344             par = OverloadBtn(name='overloadBtn' + each, parent=self, left=x, top=y, fitKey=each, powerEffectID=getattr(const, 'effect%sPower' % each, None), activationID=None)
    345 
    346         self.CheckOverloadRackBtnState()
    347 
    348     def OverloadRackBtnMouseDown(self, btn, *args):
    349         btn.top = btn.orgPos + 1
    350 
    351     def OverloadRackBtnMouseUp(self, btn, *args):
    352         btn.top = btn.orgPos
    353 
    354     def OverloadRackBtnMouseExit(self, btn, *args):
    355         btn.top = btn.orgPos
    356 
    357     @telemetry.ZONE_METHOD
    358     def CheckOverloadRackBtnState(self):
    359         if self.controller.IsControllingTurret() or self.controller.IsControllingStructure():
    360             return
    361         if self.destroyed or not self:
    362             return
    363         if self.checkingoverloadrackstate:
    364             self.checkingoverloadrackstate = 2
    365             return
    366         self.checkingoverloadrackstate = 1
    367         overloadEffectsByRack = {}
    368         modulesByRack = {}
    369         for module in self.controller.GetModules():
    370             for key in module.effects.iterkeys():
    371                 effect = module.effects[key]
    372                 if effect.effectID in (const.effectHiPower, const.effectMedPower, const.effectLoPower):
    373                     if effect.effectID not in modulesByRack:
    374                         modulesByRack[effect.effectID] = []
    375                     modulesByRack[effect.effectID].append(module)
    376                     for key in module.effects.iterkeys():
    377                         effect2 = module.effects[key]
    378                         if effect2.effectCategory == const.dgmEffOverload:
    379                             if effect.effectID not in overloadEffectsByRack:
    380                                 overloadEffectsByRack[effect.effectID] = []
    381                             overloadEffectsByRack[effect.effectID].append(effect2)
    382 
    383         i = 0
    384         for each in FITKEYS:
    385             btn = self.GetChild('overloadBtn' + each)
    386             btn.activationID = None
    387             btn.active = False
    388             btn.children[0].LoadTexture('res:/UI/Texture/classes/ShipUI/overloadBtn%sOff.png' % each)
    389             btn.hint = GetByLabel('UI/Inflight/OverloadRack')
    390             btn.state = uiconst.UI_DISABLED
    391             if btn.powerEffectID in modulesByRack:
    392                 btn.activationID = modulesByRack[btn.powerEffectID][0].itemID
    393             if btn.powerEffectID in overloadEffectsByRack:
    394                 sumInactive = sum([ 1 for olEffect in overloadEffectsByRack[btn.powerEffectID] if not olEffect.isActive ])
    395                 if not sumInactive:
    396                     btn.children[0].LoadTexture('res:/UI/Texture/classes/ShipUI/overloadBtn%sOn.png' % each)
    397                     btn.active = True
    398                     btn.hint = GetByLabel('UI/Inflight/StopOverloadingRack')
    399             btn.state = uiconst.UI_NORMAL
    400 
    401         if self.checkingoverloadrackstate == 2:
    402             self.checkingoverloadrackstate = 0
    403             return self.CheckOverloadRackBtnState()
    404         self.checkingoverloadrackstate = 0
    405 
    406     @telemetry.ZONE_METHOD
    407     def CheckButtonVisibility(self, gidx, sTypes, totalslot, myOrder):
    408         lastType = ''
    409         showEmptySlots = settings.user.ui.Get('showEmptySlots', 0)
    410         slotUIID = 0
    411         totalslots = 0
    412         ignoredSlots = 0
    413         for sType in sTypes:
    414             if totalslot is None:
    415                 totalslots = self.GetNumSlots(sType)
    416             for sidx in xrange(totalslots):
    417                 if sidx == 8:
    418                     break
    419                 flagTypes = ['Hi',
    420                  'Med',
    421                  'Lo',
    422                  'Stuct']
    423                 if not self.controller.IsControllingTurret():
    424                     if gidx < len(flagTypes):
    425                         slotFlag = getattr(const, 'flag%sSlot%s' % (flagTypes[gidx], sidx), None)
    426                     slot = self.slotsByFlag.get(slotFlag, None)
    427                 else:
    428                     slotFlag = myOrder[sidx]
    429                     slot = self.slotsByFlag.get(slotFlag, None)
    430                 typeNames = ['High',
    431                  'Medium',
    432                  'Low',
    433                  'Stuct']
    434                 slotUIID += 1
    435                 if gidx < len(typeNames):
    436                     currType = typeNames[gidx]
    437                     if currType != lastType:
    438                         slotUIID = 1
    439                     lastType = currType
    440                     if slot:
    441                         slot.name = 'inFlight%sSlot%s' % (typeNames[gidx], slotUIID)
    442                 if showEmptySlots and not self.controller.IsControllingTurret():
    443                     if slot and slot.sr.module is None and slotFlag not in self.passiveFiltered:
    444                         slot.showAsEmpty = 1
    445                         if gidx == 0:
    446                             if ignoredSlots < self.totalSlaves:
    447                                 ignoredSlots += 1
    448                                 slot.ignored = 1
    449                                 continue
    450                         slot.hint = [GetByLabel('UI/Inflight/EmptyHighSlot'), GetByLabel('UI/Inflight/EmptyMediumSlot'), GetByLabel('UI/Inflight/EmptyLowSlot')][gidx]
    451                         slot.state = uiconst.UI_NORMAL
    452                         iconpath = ['ui_8_64_11',
    453                          'ui_8_64_10',
    454                          'ui_8_64_9',
    455                          'ui_44_64_14'][gidx]
    456                         icon = Icon(icon=iconpath, parent=slot, pos=(13, 13, 24, 24), align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED, idx=0, ignoreSize=True)
    457                         icon.left = (slot.width - icon.width) / 2
    458                         icon.opacity = 0.25
    459 
    460             gidx += 1
    461 
    462     def GetNumSlots(self, slotType):
    463         if slotType == 'hiSlots':
    464             return self.controller.GetNumHiSlots()
    465         if slotType == 'medSlots':
    466             return self.controller.GetNumMedSlots()
    467         if slotType == 'lowSlots':
    468             return self.controller.GetNumLowSlots()
    469 
    470     def _FitStructureSlot(self, moduleInfo, charges):
    471         showPassive = settings.user.ui.Get('showPassiveModules', 1)
    472         if moduleInfo.categoryID != const.categoryStarbase:
    473             return
    474         if not showPassive and self.GetDefaultEffect(moduleInfo) is None:
    475             self.passiveFiltered.append(moduleInfo.flagID)
    476             return
    477         slot = self.slotsByFlag.get(moduleInfo.itemID, None)
    478         if slot is None:
    479             return
    480         if slot.sr.module is not None:
    481             return
    482         self.FitStructureSlot(slot, moduleInfo, charges.get(moduleInfo.itemID, None))
    483 
    484     @telemetry.ZONE_METHOD
    485     def _FitSlot(self, moduleInfo, charges, grey = 0, slotUIID = 'slot'):
    486         showPassive = settings.user.ui.Get('showPassiveModules', 1)
    487         if moduleInfo.categoryID == const.categoryCharge:
    488             return
    489         if not showPassive and self.GetDefaultEffect(moduleInfo) is None:
    490             self.passiveFiltered.append(moduleInfo.flagID)
    491             return
    492         slot = self.slotsByFlag.get(moduleInfo.flagID, None)
    493         if slot is None:
    494             return
    495         if slot.sr.module is not None:
    496             return
    497         self.FitSlot(slot, moduleInfo, charges.get(moduleInfo.flagID, None), grey=grey, slotUIID=slotUIID)
    498 
    499     def GetDefaultEffect(self, moduleInfo):
    500         for key in moduleInfo.effects.iterkeys():
    501             effect = moduleInfo.effects[key]
    502             if self.IsEffectActivatible(effect):
    503                 return effect
    504 
    505     def IsEffectActivatible(self, effect):
    506         return effect.isDefault and effect.effectName != 'online' and effect.effectCategory in (const.dgmEffActivation, const.dgmEffTarget)
    507 
    508     def FitSlot(self, slot, moduleInfo, charge = None, grey = 0, slotUIID = 'slot'):
    509         pos = (slot.width - 48) / 2
    510         module = ModuleButton(name='ModuleButton_%s' % moduleInfo.typeID, parent=slot, align=uiconst.TOPLEFT, width=48, height=48, top=pos, left=pos, idx=0, state=uiconst.UI_NORMAL)
    511         module.Setup(moduleInfo, grey=grey)
    512         self.modulesByID[moduleInfo.itemID] = module
    513         slot.sr.module = module
    514         slot.state = uiconst.UI_NORMAL
    515         slot.sr.shortcutHint.state = uiconst.UI_HIDDEN
    516         slot.name = slotUIID
    517         if charge:
    518             module.SetCharge(charge)
    519         if moduleInfo.flagID in [const.flagHiSlot0,
    520          const.flagHiSlot1,
    521          const.flagHiSlot2,
    522          const.flagHiSlot3,
    523          const.flagHiSlot4,
    524          const.flagHiSlot5,
    525          const.flagHiSlot6,
    526          const.flagHiSlot7]:
    527             self.myHarpointFlags.append(moduleInfo.flagID)
    528 
    529     def FitStructureSlot(self, slot, moduleInfo, charge = None):
    530         pos = (slot.width - 48) / 2
    531         module = DefenceStructureButton(parent=slot, align=uiconst.TOPLEFT, width=64, height=250, top=0, left=0, idx=1, state=uiconst.UI_DISABLED)
    532         module.Setup(moduleInfo)
    533         self.modulesByID[moduleInfo.itemID] = module
    534         slot.sr.module = module
    535         slot.state = uiconst.UI_NORMAL
    536         if charge:
    537             module.SetCharge(charge)
    538 
    539     def OnReloadAmmo(self):
    540         modulesByCharge = {}
    541         for module in self.modulesByID.itervalues():
    542             if not cfg.IsChargeCompatible(module.moduleinfo):
    543                 continue
    544             chargeTypeID, chargeQuantity, roomForReload = module.GetChargeReloadInfo()
    545             if chargeTypeID in modulesByCharge:
    546                 modulesByCharge[chargeTypeID].append(module)
    547             else:
    548                 modulesByCharge[chargeTypeID] = [module]
    549 
    550         dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation()
    551         for chargeTypeID, modules in modulesByCharge.iteritems():
    552             ammoList = {}
    553             for typeID, ammoInfo in dogmaLocation.GetMatchingAmmo(session.shipid, modules[0].moduleinfo.itemID).iteritems():
    554                 if typeID != chargeTypeID:
    555                     continue
    556                 for item in ammoInfo.singletons:
    557                     ammoList[item.itemID] = item.stacksize
    558 
    559                 for item in ammoInfo.nonSingletons:
    560                     ammoList[item.itemID] = item.stacksize
    561 
    562             for module in modules:
    563                 maxItemID = 0
    564                 chargeTypeID, chargeQuantity, roomForReload = module.GetChargeReloadInfo()
    565                 bestItemID = None
    566                 for itemID, quant in ammoList.iteritems():
    567                     if quant >= roomForReload:
    568                         if not bestItemID or quant < ammoList[bestItemID]:
    569                             bestItemID = itemID
    570                     if not maxItemID or quant > ammoList[maxItemID]:
    571                         maxItemID = itemID
    572 
    573                 bestItemID = bestItemID or maxItemID
    574                 if bestItemID:
    575                     quant = min(roomForReload, ammoList[maxItemID])
    576                     uthread.new(module.AutoReload, 1, bestItemID, quant)
    577                     ammoList[bestItemID] -= quant
    578 
    579     def BlinkButton(self, key):
    580         btn = self.sr.Get(key.lower(), None) or self.sr.Get('%sBtn' % key.lower(), None)
    581         if not btn:
    582             for each in self.modulesByID:
    583                 if getattr(each, 'locationFlag', None) == LookupConstValue('flag%s' % key, 'no'):
    584                     btn = each
    585                     break
    586 
    587         if not btn:
    588             return
    589         if hasattr(btn.sr, 'icon'):
    590             sm.GetService('ui').BlinkSpriteA(btn.sr.icon, 1.0, 1000, None, passColor=0)
    591         else:
    592             sm.GetService('ui').BlinkSpriteA(btn, 1.0, 1000, None, passColor=0)
    593 
    594     def ChangeOpacityForRange(self, currentRange, *args):
    595         curveSet = None
    596         for module in self.modulesByID.itervalues():
    597             maxRange, falloffDist, bombRadius, _ = sm.GetService('tactical').FindMaxRange(module.moduleinfo, module.charge)
    598             if maxRange == 0:
    599                 continue
    600             animationDuration = 0.1
    601             if currentRange <= maxRange + falloffDist:
    602                 if round(module.opacity, 3) != 1.5:
    603                     curveSet = uicore.animations.MorphScalar(module, 'opacity', startVal=module.opacity, endVal=1.5, duration=animationDuration, curveSet=curveSet)
    604             elif round(module.opacity, 3) != 1.0:
    605                 curveSet = uicore.animations.MorphScalar(module, 'opacity', startVal=module.opacity, endVal=1.0, duration=animationDuration, curveSet=curveSet)
    606 
    607     def ResetModuleButtonOpacity(self, *args):
    608         for module in self.modulesByID.itervalues():
    609             module.StopAnimations()
    610             module.opacity = 1.0
    611 
    612     def ProcessPendingOverloadUpdate(self, moduleIDs):
    613         for moduleID in moduleIDs:
    614             moduleButton = self.modulesByID.get(moduleID, None)
    615             if moduleButton is not None:
    616                 moduleButton.UpdateOverloadState()
    617 
    618     def ResetSwapMode(self):
    619         for each in self.children:
    620             each.opacity = 1.0
    621             if each.sr.get('module', -1) == -1:
    622                 continue
    623             if each.sr.module is None and not getattr(each, 'showAsEmpty', 0) or getattr(each, 'ignored', 0):
    624                 each.state = uiconst.UI_HIDDEN
    625             if getattr(each.sr, 'module', None):
    626                 if getattr(each, 'linkDragging', None):
    627                     each.linkDragging = 0
    628                     each.sr.module.CheckOverload()
    629                     each.sr.module.CheckOnline()
    630                     each.sr.module.CheckMasterSlave()
    631                     each.sr.module.StopShowingGroupHighlight()
    632                     each.sr.module.CheckOnline()
    633                 each.sr.module.blockClick = 0
    634 
    635     def OnWeaponGroupsChanged(self):
    636         uthread.new(self.InitSlots)
    637 
    638     def OnRefreshModuleBanks(self):
    639         uthread.new(self.InitSlots)
    640 
    641     def GetModuleForFKey(self, key):
    642         slot = int(key[1:])
    643         gidx = (slot - 1) / 8
    644         sidx = (slot - 1) % 8
    645         slot = self.slotsByOrder.get((gidx, sidx), None)
    646         if slot and slot.sr.module and slot.sr.module.state == uiconst.UI_NORMAL:
    647             return slot.sr.module
    648 
    649     def OnF(self, sidx, gidx):
    650         slot = self.slotsByOrder.get((gidx, sidx), None)
    651         if slot and slot.sr.module and slot.sr.module.state == uiconst.UI_NORMAL:
    652             uthread.new(slot.sr.module.Click)
    653         else:
    654             uthread.new(prompt_player_fsd_dialog, 'Disabled')
    655 
    656     def OnFKeyOverload(self, sidx, gidx):
    657         slot = self.slotsByOrder.get((gidx, sidx), None)
    658         if slot and slot.sr.module and slot.sr.module.state == uiconst.UI_NORMAL:
    659             if hasattr(slot.sr.module, 'ToggleOverload'):
    660                 uthread.new(slot.sr.module.ToggleOverload)
    661         else:
    662             uthread.new(prompt_player_fsd_dialog, 'Disabled')
    663 
    664     def ToggleRackOverload(self, slotName):
    665         if slotName not in FITKEYS or self.destroyed or self.controller.IsControllingStructure():
    666             return
    667         btn = self.FindChild('overloadBtn' + slotName)
    668         if btn:
    669             if btn.activationID:
    670                 uthread.new(btn.OnClick)
    671             else:
    672                 uthread.new(prompt_player_fsd_dialog, 'Disabled')
    673 
    674     def StartDragMode(self, itemID, typeID):
    675         for slot in self.children:
    676             if not hasattr(slot, 'sr') or not hasattr(slot.sr, 'module'):
    677                 continue
    678             if slot.name.startswith('overload') or slot.name == 'groupAllIcon':
    679                 continue
    680             if slot.sr.module is None:
    681                 slot.opacity = 0.7
    682             slot.state = uiconst.UI_NORMAL
    683             if typeID is None:
    684                 continue
    685             if getattr(slot.sr, 'module', None) is not None:
    686                 moduleType = slot.sr.module.GetModuleType()
    687                 isGroupable = slot.sr.module.moduleinfo.groupID in const.dgmGroupableGroupIDs
    688                 if isGroupable:
    689                     slot.linkDragging = 1
    690                     if slot.sr.module.moduleinfo.itemID == itemID:
    691                         slot.sr.module.icon.SetAlpha(0.2)
    692                         continue
    693                     elif moduleType and moduleType[0] == typeID:
    694                         slot.sr.module.ShowGroupHighlight()
    695 
    696     def ToggleShowPassive(self):
    697         settings.user.ui.Set('showPassiveModules', not settings.user.ui.Get('showPassiveModules', 1))
    698         self.InitSlots()
    699 
    700     def ToggleShowEmpty(self):
    701         settings.user.ui.Set('showEmptySlots', not settings.user.ui.Get('showEmptySlots', 0))
    702         self.InitSlots()