infoUtil.py (14403B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\info\infoUtil.py 2 import sys 3 from collections import defaultdict 4 import dogma.const 5 import dogma.data 6 import eveformat 7 import evetypes 8 import localization 9 from carbon.common.script.util.mathCommon import FloatCloseEnough 10 from carbonui import uiconst 11 from dogma.attributes.format import GetFormattedAttributeAndValue 12 from eve.client.script.ui import eveColor 13 from eve.client.script.ui.shared.fittingScreen.fittingUtil import allPowerEffects 14 from eve.client.script.ui.shared.info.attribute import IsModified, IsMutated 15 from eve.client.script.ui.shared.dynamicItem.mutationBar import MutationBar 16 import inventorycommon.const as invConst 17 from dogma.attributes.groups import fitting_attribute_ids 18 OVERLOAD_ATTRIBUTE = 'overLoadAttribute' 19 attributesWithUnknownHighIsGood = (dogma.const.attributeMass, dogma.const.attributeDrawback) 20 21 def GetAttributeTooltipTitleAndDescription(attributeID): 22 if attributeID: 23 attributeInfo = dogma.data.get_attribute(attributeID) 24 tooltipTitleID = getattr(attributeInfo, 'tooltipTitleID', None) 25 if tooltipTitleID: 26 tooltipDescriptionID = attributeInfo.tooltipDescriptionID 27 return (localization.GetByMessageID(tooltipTitleID), localization.GetByMessageID(tooltipDescriptionID)) 28 return (None, None) 29 30 31 def GetColoredText(attribute, text): 32 return GetColoredTextWithCustomColors(attribute, text, positiveChange=eveColor.SUCCESS_GREEN, negativeChange=eveColor.DANGER_RED, unknown=eveColor.SAND_YELLOW) 33 34 35 def GetColoredTextWithCustomColors(attribute, text, positiveChange, negativeChange, unknown): 36 if IsModified(attribute) and _IsValidValue(attribute.value) and _IsValidValue(attribute.baseValue): 37 if attribute.isSame and IsMutated(attribute): 38 if attribute.isMutationPositive: 39 color = positiveChange 40 else: 41 color = negativeChange 42 elif attribute.isSame: 43 color = unknown 44 elif attribute.isBetter and IsMutated(attribute): 45 if attribute.isMutationPositive: 46 color = positiveChange 47 else: 48 color = negativeChange 49 elif attribute.attributeID in attributesWithUnknownHighIsGood: 50 color = unknown 51 elif attribute.isBetter: 52 color = positiveChange 53 else: 54 color = negativeChange 55 elif IsMutated(attribute): 56 if attribute.isMutationPositive: 57 color = positiveChange 58 else: 59 color = negativeChange 60 else: 61 return text 62 return eveformat.color(text, color) 63 64 65 def _IsValidValue(value): 66 return value is not None and not isinstance(value, basestring) 67 68 69 def PrepareInfoTextForAttributeHint(textLabel, attribute, itemID = None, extraModifyingAttrIDs = None, extraModifyingFactors = None): 70 if not attribute: 71 return 72 if textLabel.state == uiconst.UI_DISABLED: 73 textLabel.state = uiconst.UI_NORMAL 74 textLabel.LoadTooltipPanel = LoadAttributeTooltipPanel 75 textLabel.modifiedAttribute = attribute 76 textLabel.itemID = itemID 77 textLabel.extraModifyingAttrIDs = extraModifyingAttrIDs or [] 78 textLabel.extraModifyingFactors = extraModifyingFactors or [] 79 80 81 def LoadAttributeTooltipPanel(panel, owner): 82 panel.margin = (8, 8, 8, 0) 83 attribute = getattr(owner, 'modifiedAttribute', None) 84 itemID = getattr(owner, 'itemID', None) 85 extraModifyingAttrIDs = getattr(owner, 'extraModifyingAttrIDs', None) or [] 86 extraModifyingFactors = getattr(owner, 'extraModifyingFactors', None) or [] 87 if attribute is None: 88 return 89 if IsMutated(attribute): 90 text = localization.GetByLabel('UI/InfoWindow/AttributeIsMutated') 91 panel.AddLabelMedium(text=text) 92 MutationBar(parent=panel, align=uiconst.TOPLEFT, top=4, attribute=attribute, barWidth=60) 93 if IsModified(attribute): 94 panel.margin = (8, 8, 8, 8) 95 if attribute.baseValue is None: 96 text = localization.GetByLabel('UI/InfoWindow/AttributeModified') 97 panel.AddLabelMedium(text=text) 98 else: 99 affectedByTextList = GetAffectedByTextList(attribute.attributeID, itemID) 100 for mAttrID in extraModifyingAttrIDs: 101 affectedByTextList += GetAffectedByTextList(mAttrID, itemID) 102 103 affectedByTextList += GetExtraModifyingFactorsList(extraModifyingFactors) 104 affectedByText = GetAffectedByText(affectedByTextList) or '' 105 if affectedByText: 106 text = localization.GetByLabel('UI/InfoWindow/AttributeModifiedByWithBaseValue', affectedByText=affectedByText, baseAttributeValue=attribute.displayBaseValue) 107 else: 108 text = localization.GetByLabel('UI/InfoWindow/AttributeModifiedWithBaseValue', baseAttributeValue=attribute.displayBaseValue) 109 panel.AddLabelMedium(text=text) 110 111 112 def GetAffectedByText(textList): 113 if textList: 114 return '<br>'.join(textList) 115 116 117 def GetAffectedByTextList(attributeID, itemID): 118 if not itemID: 119 return [] 120 infoSvc = sm.GetService('info') 121 dogmaLocation = infoSvc.GetDogmaLocation(itemID) 122 dogmaItem = dogmaLocation.SafeGetDogmaItem(itemID) 123 if not dogmaItem: 124 return [] 125 itemAttributes = dogmaItem.attributes 126 attribRoot = None 127 if attributeID in itemAttributes: 128 attribRoot = itemAttributes[attributeID] 129 if not attribRoot: 130 return [] 131 makesHigher = defaultdict(list) 132 makesLower = defaultdict(list) 133 textList = [] 134 externalFactorsMakeHigher = False 135 externalFactorsMakeLower = False 136 if not infoSvc.IsItemSimulated(itemID): 137 try: 138 clientValue = dogmaLocation.GetAttributeValue(itemID, attributeID) 139 attrName = dogma.data.get_attribute_name(attributeID) 140 godmaVal = sm.GetService('godma').GetStateManager().GetAttribute(itemID, attrName) 141 if not FloatCloseEnough(godmaVal, clientValue): 142 externalFactorsMakeHigher = godmaVal > clientValue 143 externalFactorsMakeLower = clientValue > godmaVal 144 except (KeyError, RuntimeError, ZeroDivisionError): 145 sys.exc_clear() 146 147 HarvestModifiers(attribRoot, makesHigher, makesLower) 148 for direction, dictToUse, externalFactorsActive in [(u'\u2191', makesHigher, externalFactorsMakeHigher), (u'\u2193', makesLower, externalFactorsMakeLower)]: 149 if dictToUse: 150 for what, typeList in dictToUse.iteritems(): 151 countDict = defaultdict(int) 152 for typeID in typeList: 153 countDict[typeID] += 1 154 155 for typeID, typeCount in countDict.iteritems(): 156 if what == OVERLOAD_ATTRIBUTE: 157 cat = localization.GetByLabel('UI/InfoWindow/OverloadedModule') 158 else: 159 cat = evetypes.GetCategoryName(typeID) 160 typeText = ' %s %s: %s%s ' % (direction, 161 cat, 162 '%sx ' % typeCount if typeCount > 1 else '', 163 evetypes.GetName(typeID)) 164 textList.append(typeText) 165 166 if externalFactorsActive: 167 textList.append(' %s %s' % (direction, localization.Get('UI/InfoWindow/ExternalFactors'))) 168 169 return textList 170 171 172 def HarvestModifiers(curAttrib, makesHigher, makesLower): 173 modifiers = curAttrib.GetIncomingModifiers() 174 if not modifiers: 175 return 176 for opIdx, attrib in modifiers: 177 val = attrib.GetValue() 178 dictToUse = None 179 if opIdx in (dogma.const.dgmAssPreMul, dogma.const.dgmAssPostMul): 180 if val > 1.0: 181 dictToUse = makesHigher 182 elif val < 1.0: 183 dictToUse = makesLower 184 elif opIdx == dogma.const.dgmAssPostPercent: 185 if val > 0.0: 186 dictToUse = makesHigher 187 elif val < 0.0: 188 dictToUse = makesLower 189 elif opIdx in (dogma.const.dgmAssPreDiv, dogma.const.dgmAssPostDiv): 190 if val < 1.0: 191 dictToUse = makesHigher 192 elif val > 1.0: 193 dictToUse = makesLower 194 elif opIdx == dogma.const.dgmAssModAdd: 195 if val > 0.0: 196 dictToUse = makesHigher 197 elif val < 0.0: 198 dictToUse = makesLower 199 elif opIdx == dogma.const.dgmAssModSub: 200 if val < 0.0: 201 dictToUse = makesHigher 202 elif val > 0.0: 203 dictToUse = makesLower 204 if dictToUse is None: 205 continue 206 skills = getattr(attrib, 'skills', []) 207 if skills: 208 dictToUse[attrib.__class__.__name__].extend(skills) 209 else: 210 invItem = getattr(attrib, 'invItem', None) 211 if invItem: 212 typeID = attrib.invItem.typeID 213 if IsOverloadAttribute(attrib, typeID): 214 dictToUse[OVERLOAD_ATTRIBUTE].append(typeID) 215 else: 216 dictToUse[attrib.__class__.__name__].append(typeID) 217 HarvestModifiers(attrib, makesHigher, makesLower) 218 219 return (makesHigher, makesLower) 220 221 222 def GetExtraModifyingFactorsList(extraModifyingFactors): 223 ret = [] 224 for factorText, direction in extraModifyingFactors: 225 text = '' 226 if direction > 0: 227 text = u'\u2191 ' 228 elif direction < 0: 229 text = u'\u2193 ' 230 text += factorText 231 ret.append(text) 232 233 return ret 234 235 236 overloadingAttributesByTypeID = {} 237 238 def IsOverloadAttribute(attrib, typeID): 239 if getattr(attrib, 'attribID', None): 240 overloadingAttributes = overloadingAttributesByTypeID.get(typeID, None) 241 if overloadingAttributes is None: 242 overloadingAttributes = GetOverloadingAttributes(typeID) 243 overloadingAttributesByTypeID[typeID] = overloadingAttributes 244 if attrib.attribID in overloadingAttributes: 245 return True 246 return False 247 248 249 def GetOverloadingAttributes(typeID): 250 overloadingAttributes = set() 251 for e in dogma.data.get_type_effects(typeID): 252 if dogma.data.get_effect_category(e.effectID) != dogma.const.dgmEffOverload: 253 continue 254 effect = dogma.data.get_effect(e.effectID) 255 for m in effect.modifierInfo: 256 if m.modifyingAttributeID: 257 overloadingAttributes.add(m.modifyingAttributeID) 258 259 return overloadingAttributes 260 261 262 hybridTexturePath = 'res:/UI/Texture/classes/ShipTree/attributes/hybridTurrets.png' 263 projectileTexturePath = 'res:/UI/Texture/classes/ShipTree/attributes/projectileTurrets.png' 264 energyTexturePath = 'res:/UI/Texture/classes/ShipTree/attributes/energyTurrets.png' 265 precursorTexturePath = 'res:/UI/Texture/classes/ShipTree/attributes/precursor.png' 266 missileTexturePath = 'res:/UI/Texture/classes/ShipTree/attributes/missiles.png' 267 iconPathsForGroupIDs = {invConst.groupHybridWeapon: hybridTexturePath, 268 invConst.groupProjectileWeapon: projectileTexturePath, 269 invConst.groupEnergyWeapon: energyTexturePath, 270 invConst.groupPrecursorTurret: precursorTexturePath, 271 invConst.groupHybridAmmo: hybridTexturePath, 272 invConst.groupAdvancedRailgunCharge: hybridTexturePath, 273 invConst.groupAdvancedBlasterCharge: hybridTexturePath, 274 invConst.groupProjectileAmmo: projectileTexturePath, 275 invConst.groupAdvancedArtilleryAmmo: projectileTexturePath, 276 invConst.groupAdvancedAutocannonAmmo: projectileTexturePath, 277 invConst.groupFrequencyCrystal: energyTexturePath, 278 invConst.groupAdvancedBeamLaserCrystal: energyTexturePath, 279 invConst.groupAdvancedPulseLaserCrystal: energyTexturePath, 280 invConst.groupChargeBottle: precursorTexturePath, 281 invConst.groupAdvancedChargeBottle: precursorTexturePath} 282 iconPathForChargeSizes = {1: 'res:/UI/Texture/classes/Fitting/Small.png', 283 2: 'res:/UI/Texture/classes/Fitting/Medium.png', 284 3: 'res:/UI/Texture/classes/Fitting/Large.png', 285 4: 'res:/UI/Texture/classes/Fitting/XLarge.png'} 286 287 def GetWeaonSystemIconForTypeID(typeID): 288 groupID = evetypes.GetGroupID(typeID) 289 iconPath = iconPathsForGroupIDs.get(groupID, None) 290 if iconPath: 291 return iconPath 292 typeEffects = dogma.data.get_type_effects(typeID) 293 usesMissiles = any((x for x in typeEffects if x.effectID in (dogma.const.effectUseMissiles, dogma.const.effectDotMissileLaunching))) 294 if usesMissiles: 295 return missileTexturePath 296 isMissile = any((x for x in typeEffects if x.effectID in (dogma.const.effectMissileLaunching, dogma.const.effectFofMissileLaunching))) 297 if isMissile: 298 return missileTexturePath 299 300 301 def GetIconAndLabelForChargeSize(typeID): 302 chargeAttributeValue = dogma.data.get_type_attribute(typeID, dogma.const.attributeChargeSize) 303 if not chargeAttributeValue: 304 return (None, '') 305 groupID = evetypes.GetGroupID(typeID) 306 if groupID not in iconPathsForGroupIDs: 307 return (None, '') 308 texturePath = iconPathForChargeSizes.get(int(chargeAttributeValue), None) 309 formattedInfo = GetFormattedAttributeAndValue(dogma.const.attributeChargeSize, chargeAttributeValue) 310 label = '%s: %s' % (formattedInfo.displayName, formattedInfo.value) 311 return (texturePath, label) 312 313 314 def GetEffectIconIdAndLabelID(typeID): 315 for effect in dogma.data.get_type_effects(typeID): 316 if effect.effectID in allPowerEffects: 317 powerType = effect.effectID 318 effectInfo = dogma.data.get_effect(powerType) 319 break 320 else: 321 return (None, '') 322 323 return (effectInfo.iconID, effectInfo.displayNameID) 324 325 326 usedWithAttributes = [dogma.const.attributeChargeGroup1, 327 dogma.const.attributeChargeGroup2, 328 dogma.const.attributeChargeGroup3, 329 dogma.const.attributeChargeGroup4, 330 dogma.const.attributeChargeGroup5, 331 dogma.const.attributeLauncherGroup, 332 dogma.const.attributeLauncherGroup2, 333 dogma.const.attributeLauncherGroup3, 334 dogma.const.attributeLauncherGroup4, 335 dogma.const.attributeLauncherGroup5, 336 dogma.const.attributeLauncherGroup6] 337 338 def GetUsedWithText(typeID): 339 textList = [] 340 for eachAttribute in usedWithAttributes: 341 usedWithGroup = dogma.data.get_type_attribute(typeID, eachAttribute, None) 342 if usedWithGroup: 343 textList.append('- %s' % evetypes.GetGroupNameByGroup(int(usedWithGroup))) 344 345 if textList: 346 textList.insert(0, '%s:' % localization.GetByLabel('UI/InfoWindow/TabNames/UsedWith')) 347 return '<br>'.join(textList)