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

fittingUtil.py (15758B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fitting\fittingUtil.py
      2 import blue
      3 import carbonui.const as uiconst
      4 import collections
      5 import dogma.attributes.groups as dogma_attr_groups
      6 import dogma.data as dogma_data
      7 import evetypes
      8 import inventorycommon.const as invConst
      9 from carbon.client.script.environment.AudioUtil import PlaySound
     10 from carbon.common.script.util.mathCommon import FloatCloseEnough
     11 from carbonui.uicore import uicore
     12 from contextlib2 import contextmanager
     13 from eve.client.script.environment import invControllers as invCtrl
     14 from eve.common.script.sys.eveCfg import GetActiveShip
     15 from inventorycommon.util import IsShipFittingFlag, IsFittingModule, IsModularShip
     16 from localization import GetByLabel
     17 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     18 from shipfitting.fittingDogmaLocationUtil import GetAlignTimeFromAgilityAndMass
     19 from utillib import KeyVal
     20 FONTCOLOR_DEFAULT2 = 3238002687L
     21 PASSIVESHIELDRECHARGE = 0
     22 SHIELDBOOSTRATEACTIVE = 1
     23 ARMORREPAIRRATEACTIVE = 2
     24 HULLREPAIRRATEACTIVE = 3
     25 PANEL_WIDTH_MIN = 280
     26 PANEL_WIDTH_DEFAULT = 400
     27 PANEL_WIDTH_MAX = 600
     28 PANEL_WIDTH_RIGHT = PANEL_WIDTH_MIN
     29 FTTING_PANEL_SETTING_LEFT_WIDTH = 'fitting_leftpanelwidth'
     30 FITKEYS = ('Hi', 'Med', 'Lo')
     31 NUM_SUBSYSTEM_SLOTS = 5
     32 GHOST_FITTABLE_CATEGORIES = (const.categoryModule,
     33  const.categorySubSystem,
     34  const.categoryStructureModule,
     35  const.categoryDrone,
     36  const.categoryFighter,
     37  const.categoryCharge)
     38 CLOSE_ENOUGH_TOLERANCE = 1e-07
     39 
     40 def GetTypeAttributesByID(typeID):
     41     if not typeID:
     42         return {}
     43     return {attribute.attributeID:attribute.value for attribute in dogma_data.get_type_attributes(typeID)}
     44 
     45 
     46 def GetAlignTimeForShip(dogmaLocation):
     47     shipID = dogmaLocation.GetCurrentShipID()
     48     agility = GetShipAttributeWithDogmaLocation(dogmaLocation, shipID, const.attributeAgility)
     49     mass = GetShipAttributeWithDogmaLocation(dogmaLocation, shipID, const.attributeMass)
     50     return GetAlignTimeFromAgilityAndMass(agility, mass)
     51 
     52 
     53 def GetShipAttributeWithDogmaLocation(dogmaLocation, shipID, attributeID):
     54     if session.shipid == shipID:
     55         ship = sm.GetService('godma').GetItem(shipID)
     56         attributeName = dogma_data.get_attribute_name(attributeID)
     57         return getattr(ship, attributeName)
     58     else:
     59         return dogmaLocation.GetAttributeValue(shipID, attributeID)
     60 
     61 
     62 def GetSensorStrengthAttribute(dogmaLocation, shipID):
     63     if session.shipid == shipID:
     64         return sm.GetService('godma').GetStateManager().GetSensorStrengthAttribute(shipID)
     65     else:
     66         maxAttributeID = None
     67         maxValue = None
     68         for attributeID in dogma_attr_groups.ecm_sensor_strength_attribute_ids:
     69             val = dogmaLocation.GetAttributeValue(shipID, attributeID)
     70             if val > maxValue:
     71                 maxValue, maxAttributeID = val, attributeID
     72 
     73         return (maxAttributeID, maxValue)
     74 
     75 
     76 def GetFittingDragData():
     77     fittingSvc = sm.StartService('fittingSvc')
     78     fitting = KeyVal()
     79     fitting.shipTypeID, fitting.fitData, _ = fittingSvc.GetFittingDictForCurrentFittingWindowShip()
     80     fitting.fittingID = None
     81     fitting.description = ''
     82     fitting.name = cfg.evelocations.Get(GetActiveShip()).locationName
     83     fitting.ownerID = 0
     84     if fittingSvc.IsShipSimulated():
     85         fitting.name = sm.GetService('ghostFittingSvc').GetShipName()
     86     else:
     87         fitting.name = cfg.evelocations.Get(GetActiveShip()).locationName
     88     entry = KeyVal()
     89     entry.fitting = fitting
     90     entry.label = fitting.name
     91     entry.displayText = fitting.name
     92     entry.__guid__ = 'listentry.FittingEntry'
     93     return [entry]
     94 
     95 
     96 def GetScaleFactor():
     97     dw = uicore.desktop.width
     98     minWidth = 1400
     99     return min(1.0, max(0.75, dw / float(minWidth)))
    100 
    101 
    102 def GetBaseShapeSize():
    103     return int(640 * GetScaleFactor())
    104 
    105 
    106 def GetBaseShapeYOffset():
    107     return -6
    108 
    109 
    110 def IsCharge(typeID):
    111     return evetypes.GetCategoryID(typeID) in (const.categoryCharge, const.groupFrequencyCrystal)
    112 
    113 
    114 def TryFit(invItems, shipID = None):
    115     if not shipID:
    116         shipID = GetActiveShip()
    117         if not shipID:
    118             return
    119     godma = sm.services['godma']
    120     invCache = sm.GetService('invCache')
    121     shipInv = invCache.GetInventoryFromId(shipID, locationID=session.stationid)
    122     shipTypeID = shipInv.typeID
    123     godmaSM = godma.GetStateManager()
    124     useRigs = None
    125     charges = set()
    126     drones = []
    127     subSystemGroupIDs = set()
    128     for invItem in invItems[:]:
    129         if IsFittingModule(invItem.categoryID):
    130             moduleEffects = dogma_data.get_type_effects(invItem.typeID)
    131             for mEff in moduleEffects:
    132                 if mEff.effectID == const.effectRigSlot:
    133                     if useRigs is None:
    134                         useRigs = True if RigFittingCheck(invItem, shipTypeID) else False
    135                     if not useRigs:
    136                         invItems.remove(invItem)
    137                         invCache.UnlockItem(invItem.itemID)
    138                         break
    139 
    140         if invItem.categoryID == const.categorySubSystem:
    141             if invItem.groupID in subSystemGroupIDs:
    142                 invItems.remove(invItem)
    143             else:
    144                 subSystemGroupIDs.add(invItem.groupID)
    145         elif invItem.categoryID == const.categoryCharge:
    146             charges.add(invItem)
    147             invItems.remove(invItem)
    148         elif invItem.categoryID == const.categoryDrone:
    149             drones.append(invItem)
    150             invItems.remove(invItem)
    151 
    152     if len(invItems) > 0:
    153         PlaySound(uiconst.SOUND_ADD_OR_USE)
    154         shipInv.moniker.MultiAdd([ invItem.itemID for invItem in invItems ], invItems[0].locationID, flag=const.flagAutoFit)
    155     if charges:
    156         shipStuff = shipInv.List()
    157         shipStuff.sort(key=lambda r: (r.flagID, isinstance(r.itemID, tuple)))
    158         loadedSlots = set()
    159     if drones:
    160         invCtrl.ShipDroneBay(shipID or GetActiveShip()).AddItems(drones)
    161     dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation()
    162     shipDogmaItem = dogmaLocation.dogmaItems.get(shipID, None)
    163     loadedSomething = False
    164     for DBRowInvItem in charges:
    165         invItem = KeyVal(DBRowInvItem)
    166         chargeDgmType = godmaSM.GetType(invItem.typeID)
    167         isCrystalOrScript = invItem.groupID in cfg.GetCrystalGroups()
    168         for row in shipStuff:
    169             if row in loadedSlots:
    170                 continue
    171             if not IsShipFittingFlag(row.flagID):
    172                 continue
    173             if dogmaLocation.IsInWeaponBank(row.locationID, row.itemID) and dogmaLocation.IsModuleSlave(row.itemID, row.locationID):
    174                 continue
    175             if row.categoryID == const.categoryCharge:
    176                 continue
    177             moduleDgmType = godmaSM.GetType(row.typeID)
    178             desiredSize = getattr(moduleDgmType, 'chargeSize', None)
    179             for x in xrange(1, 5):
    180                 chargeGroup = getattr(moduleDgmType, 'chargeGroup%d' % x, False)
    181                 if not chargeGroup:
    182                     continue
    183                 if chargeDgmType.groupID != chargeGroup:
    184                     continue
    185                 if desiredSize and getattr(chargeDgmType, 'chargeSize', -1) != desiredSize:
    186                     continue
    187                 for i, squatter in enumerate([ i for i in shipStuff if i.flagID == row.flagID ]):
    188                     if isCrystalOrScript and i > 0:
    189                         break
    190                     if shipDogmaItem is None:
    191                         continue
    192                     subLocation = dogmaLocation.GetSubLocation(shipID, squatter.flagID)
    193                     if subLocation is None:
    194                         continue
    195                     chargeVolume = chargeDgmType.volume * dogmaLocation.GetAttributeValue(subLocation, const.attributeQuantity)
    196                     if godmaSM.GetType(row.typeID).capacity <= chargeVolume:
    197                         break
    198                 else:
    199                     moduleCapacity = godmaSM.GetType(row.typeID).capacity
    200                     numCharges = moduleCapacity / chargeDgmType.volume
    201                     subLocation = dogmaLocation.GetSubLocation(shipID, row.flagID)
    202                     if subLocation:
    203                         numCharges -= dogmaLocation.GetAttributeValue(subLocation, const.attributeQuantity)
    204                     dogmaLocation.LoadAmmo(shipID, row.itemID, invItem.itemID, invItem.locationID)
    205                     loadedSomething = True
    206                     invItem.stacksize -= numCharges
    207                     loadedSlots.add(row)
    208                     blue.pyos.synchro.SleepWallclock(100)
    209                     break
    210 
    211             else:
    212                 continue
    213 
    214             if invItem.stacksize <= 0:
    215                 break
    216         else:
    217             if not loadedSomething:
    218                 prompt_player_fsd_dialog('NoSuitableModules')
    219 
    220 
    221 def CanFitFromSourceLocation(dragNodes):
    222     from eve.client.script.ui.shared.inventory.invContainers import AssetSafetyContainer, AssetSafetyCorpContainer
    223     if not isinstance(dragNodes, collections.Iterable):
    224         dragNodes = [dragNodes]
    225     for node in dragNodes:
    226         container = getattr(node, 'container', None)
    227         if isinstance(container, (AssetSafetyContainer, AssetSafetyCorpContainer)):
    228             return False
    229 
    230     return True
    231 
    232 
    233 def RigFittingCheck(invItem, shipTypeID):
    234     if IsModularShip(shipTypeID):
    235         return True
    236     moduleEffects = dogma_data.get_type_effects(invItem.typeID)
    237     for mEff in moduleEffects:
    238         if mEff.effectID == const.effectRigSlot:
    239             if prompt_player_fsd_dialog('RigFittingInfo', {}, uiconst.OKCANCEL) != uiconst.ID_OK:
    240                 return False
    241 
    242     return True
    243 
    244 
    245 def IsSurveyProbeLauncherFitted():
    246     dogmaLoc = sm.GetService('clientDogmaIM').GetDogmaLocation()
    247     fittedModules = dogmaLoc.SafeGetDogmaItem(session.shipid).GetFittedItems()
    248     for module in fittedModules.values():
    249         if module.groupID == invConst.groupSurveyProbeLauncher:
    250             return True
    251 
    252     return False
    253 
    254 
    255 class ModifiedAttribute(object):
    256 
    257     def __init__(self, value, multiplier = 1.0, addition = 0.0, higherIsBetter = True, oldValue = None, attributeID = None):
    258         self.baseValue = value
    259         self.multiplier = multiplier
    260         self.addition = addition
    261         self.higherIsBetter = higherIsBetter
    262         self.oldValue = oldValue
    263         self.attributeID = attributeID
    264 
    265     @property
    266     def value(self):
    267         return (self.baseValue + self.addition) * self.multiplier
    268 
    269     @value.setter
    270     def value(self, value):
    271         self.baseValue = value
    272 
    273     @property
    274     def diff(self):
    275         return self.value - self.baseValue
    276 
    277     @property
    278     def diffNormalized(self):
    279         if not self.higherIsBetter:
    280             return -self.diff
    281         else:
    282             return self.diff
    283 
    284     @property
    285     def isBetterThanBefore(self):
    286         if self.oldValue is None or FloatCloseEnough(self.value, self.oldValue, CLOSE_ENOUGH_TOLERANCE) or self.higherIsBetter is None:
    287             return
    288         else:
    289             currentIsHigher = self.value > self.oldValue
    290             if self.higherIsBetter:
    291                 return currentIsHigher
    292             return not currentIsHigher
    293 
    294     @property
    295     def isSame(self):
    296         return FloatCloseEnough(self.value, self.baseValue)
    297 
    298 
    299 def GetDefensiveLayersInfo(controller):
    300     shieldResistanceInfo = {'em': controller.GetShieldEmDamageResonance(),
    301      'explosive': controller.GetShieldExplosiveDamageResonance(),
    302      'kinetic': controller.GetShieldKineticDamageResonance(),
    303      'thermal': controller.GetShieldThermalDamageResonance()}
    304     armorResistanceInfo = {'em': controller.GetArmorEmDamageResonance(),
    305      'explosive': controller.GetArmorExplosiveDamageResonance(),
    306      'kinetic': controller.GetArmorKineticDamageResonance(),
    307      'thermal': controller.GetArmorThermalDamageResonance()}
    308     structureResistanceInfo = {'em': controller.GetStructureEmDamageResonance(),
    309      'explosive': controller.GetStructureExplosiveDamageResonance(),
    310      'kinetic': controller.GetStructureKineticDamageResonance(),
    311      'thermal': controller.GetStructureThermalDamageResonance()}
    312     allLayersInfo = {'shield': KeyVal(resistances=shieldResistanceInfo, hpInfo=controller.GetShieldHp(), isRechargable=True),
    313      'armor': KeyVal(resistances=armorResistanceInfo, hpInfo=controller.GetArmorHp(), isRechargable=False),
    314      'structure': KeyVal(resistances=structureResistanceInfo, hpInfo=controller.GetStructureHp(), isRechargable=False)}
    315     return allLayersInfo
    316 
    317 
    318 def GetEffectiveHp(controller):
    319     effectiveHp = 0.0
    320     allDefensiveLayersInfo = GetDefensiveLayersInfo(controller)
    321     for whatLayer, layerInfo in allDefensiveLayersInfo.iteritems():
    322         layerResistancesInfo = layerInfo.resistances
    323         total = sum((valueInfo.value for valueInfo in layerResistancesInfo.itervalues()))
    324         avgResistance = total / len(layerResistancesInfo)
    325         layerHp = layerInfo.hpInfo.value
    326         if avgResistance:
    327             effectiveHpForLayer = layerHp / avgResistance
    328             effectiveHp += effectiveHpForLayer
    329 
    330     return effectiveHp
    331 
    332 
    333 def GetTypeIDForController(itemID):
    334     if isinstance(itemID, basestring):
    335         typeID = int(itemID.split('_')[1])
    336         return typeID
    337     item = sm.GetService('godma').GetItem(itemID)
    338     if item:
    339         return item.typeID
    340 
    341 
    342 def CanDeleteFit(ownerID):
    343     if ownerID == session.charid:
    344         return True
    345     if not session.corprole & const.corpRoleFittingManager:
    346         return False
    347     if ownerID == session.corpid:
    348         return True
    349     if session.allianceid and ownerID == session.allianceid:
    350         if sm.GetService('alliance').GetAlliance().executorCorpID == session.corpid:
    351             return True
    352     return False
    353 
    354 
    355 def GetDeletableNodes(nodes):
    356     canDelete = []
    357     for eachNode in nodes:
    358         if CanDeleteFit(eachNode.ownerID):
    359             canDelete.append(eachNode)
    360 
    361     return canDelete
    362 
    363 
    364 def DeleteFittings(selectedNodes):
    365     fittingSvc = sm.GetService('fittingSvc')
    366     if len(selectedNodes) > 1:
    367         fittingsByOwnerID = collections.defaultdict(list)
    368         for node in selectedNodes:
    369             fittingsByOwnerID[node.ownerID].append(node.fittingID)
    370 
    371         if len(fittingsByOwnerID) == 1:
    372             ownerText = cfg.eveowners.Get(fittingsByOwnerID.keys()[0]).name
    373             msgName = 'DeleteFittingsManyOneOwner'
    374         else:
    375             ownerText = _GetDeleteWarningText(fittingsByOwnerID)
    376             msgName = 'DeleteFittingsMany'
    377         if prompt_player_fsd_dialog(msgName, {'ownerText': ownerText,
    378          'numFittings': len(selectedNodes)}, uiconst.YESNO) != uiconst.ID_YES:
    379             return False
    380         fittingSvc.DeleteManyFittings(fittingsByOwnerID)
    381     else:
    382         node = selectedNodes[0]
    383         if prompt_player_fsd_dialog('DeleteFitting', {}, uiconst.YESNO, suppress=uiconst.ID_YES) != uiconst.ID_YES:
    384             return False
    385         fittingID = node.fittingID
    386         ownerID = node.ownerID
    387         fittingSvc.DeleteFitting(ownerID, fittingID)
    388     return True
    389 
    390 
    391 def _GetDeleteWarningText(fittingsByOwnerID):
    392     textList = []
    393     myOwners = [session.charid, session.corpid, session.allianceid]
    394     for ownerID in myOwners:
    395         if not ownerID:
    396             continue
    397         fittingIDs = fittingsByOwnerID.get(ownerID, [])
    398         if fittingIDs:
    399             ownerName = cfg.eveowners.Get(ownerID).name
    400             t = GetByLabel('UI/Fitting/FittingWindow/OwnerAndFittingNum', ownerName=ownerName, numFittings=len(fittingIDs))
    401             t = u'  \u2022 ' + t
    402             textList.append(t)
    403 
    404     text = '<br>'.join(textList)
    405     return text
    406 
    407 
    408 @contextmanager
    409 def EatSignalChangingErrors(errorMsg):
    410     try:
    411         yield
    412     except Exception as e:
    413         import log
    414         log.LogError('Failed at changing signal connections, %s e = %s ' % (errorMsg, e))