shipTreeSvc.py (29029B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\shipTree\shipTreeSvc.py 2 from collections import defaultdict 3 import evetypes 4 import geo2 5 import shipgroup 6 import uthread 7 from carbon.common.script.sys.service import Service 8 from clonegrade.const import CLONE_STATE_ALPHA 9 from eve.client.script.ui.shared.shipTree import shipTreeConst 10 from eve.client.script.ui.shared.shipTree.shipTreeConst import NODETYPE_CONNECTOR, NODETYPE_GROUP, NODETYPE_OTHERFACTIONGROUP, NODETYPE_ROOT 11 from eve.client.script.ui.control.treeData import TreeData 12 from eve.common.lib import appConst as const 13 from omega.client.clone_grade_svc import get_clone_grade_svc 14 K2 = 1.0 / 2 15 K3 = 1.0 / 3 16 K4 = 1.0 / 4 17 K8 = 1.0 / 8 18 K12 = 1.0 / 12 19 K24 = 1.0 / 24 20 21 class ShipTree(Service): 22 __guid__ = 'svc.shipTree' 23 __servicename__ = 'Ship tree service' 24 __displayname__ = 'Ship tree service' 25 26 def Run(self, *args): 27 self.shipTypeIDsByFactionIDAndGroupID = None 28 self.shipGroupIDsByTypeIDs = None 29 self._recentlyChangedSkills = None 30 31 def _InitShipTypeIDDict(self): 32 self.shipTypeIDsByFactionIDAndGroupID = defaultdict(list) 33 for groupID in evetypes.GetGroupIDsByCategory(const.categoryShip): 34 if not evetypes.IsGroupPublishedByGroup(groupID): 35 continue 36 for typeID in evetypes.GetTypeIDsByGroup(groupID): 37 try: 38 if evetypes.IsPublished(typeID): 39 key = (evetypes.GetFactionID(typeID), evetypes.GetShipGroupID(typeID)) 40 self.shipTypeIDsByFactionIDAndGroupID[key].append(typeID) 41 except (KeyError, AttributeError): 42 pass 43 44 def GetShipTypeIDs(self, factionID, isisGroupID): 45 if not self.shipTypeIDsByFactionIDAndGroupID: 46 self._InitShipTypeIDDict() 47 if (factionID, isisGroupID) in self.shipTypeIDsByFactionIDAndGroupID: 48 return self.shipTypeIDsByFactionIDAndGroupID[factionID, isisGroupID] 49 return [] 50 51 def GetShipTypeIDsByGroupID(self, isisGroupID): 52 if not self.shipTypeIDsByFactionIDAndGroupID: 53 self._InitShipTypeIDDict() 54 results = set() 55 for factionID, groupID in self.shipTypeIDsByFactionIDAndGroupID: 56 if groupID == isisGroupID: 57 results.update(self.shipTypeIDsByFactionIDAndGroupID[factionID, isisGroupID]) 58 59 return results 60 61 def GetShipGroupID(self, typeID): 62 if not self.shipGroupIDsByTypeIDs: 63 self._InitShipGroupIDDict() 64 return self.shipGroupIDsByTypeIDs.get(typeID, None) 65 66 def _InitShipGroupIDDict(self): 67 if not self.shipTypeIDsByFactionIDAndGroupID: 68 self._InitShipTypeIDDict() 69 self.shipGroupIDsByTypeIDs = {} 70 for (_, isisGroupID), typeIDs in self.shipTypeIDsByFactionIDAndGroupID.iteritems(): 71 for typeID in typeIDs: 72 self.shipGroupIDsByTypeIDs[typeID] = isisGroupID 73 74 def GetRootNode(self, factionID): 75 if factionID == const.factionORE: 76 return self._GetOREData(factionID) 77 if factionID == const.factionTriglavian: 78 return self._GetTriglavianData(factionID) 79 if factionID == const.factionEDENCOM: 80 return self._GetEdenComData(factionID) 81 if factionID == const.factionCONCORDAssembly: 82 return self._GetConcordData(factionID) 83 if factionID == const.factionSocietyOfConsciousThought: 84 return self._GetSoctData(factionID) 85 if factionID == const.factionSistersOfEVE: 86 return self._GetSoeData(factionID) 87 if factionID in (const.factionGuristasPirates, 88 const.factionSanshasNation, 89 const.factionTheBloodRaiderCovenant, 90 const.factionAngelCartel, 91 const.factionSerpentis, 92 const.factionMordusLegion, 93 const.factionDeathless): 94 root, _ = self._GetPirateFactionData(factionID) 95 return root 96 return self._GetFactionData(factionID) 97 98 def _GetFactionData(self, factionID): 99 100 def Grp(parent, position, shipGroupID, iconsPerRow = 3): 101 return GroupNode(parent=parent, position=position, shipGroupID=shipGroupID, iconsPerRow=iconsPerRow, factionID=factionID, treeID=factionID) 102 103 def Con(parent, position): 104 return ConnectorNode(parent=parent, position=position, treeID=factionID) 105 106 root = RootNode(parent=None, position=(0, 0)) 107 c = Grp(root, (K2, 0), shipgroup.groupRookie) 108 cIndustr = Con(c, (0, 3 * K4)) 109 c = Con(c, (3 * K4, 0)) 110 c = Con(c, (K12, -K12)) 111 c = Grp(c, (0, -K2), shipgroup.groupFrigate) 112 c2 = Grp(c, (0, -K2), shipgroup.groupNavyFrigate, 4) 113 c2 = Con(c2, (0, -K3)) 114 Grp(c2, (K3, -K3), shipgroup.groupInterceptor, 6) 115 c2 = Con(c2, (0, -K2)) 116 Grp(c2, (K3, -K3), shipgroup.groupAssault, 6) 117 c2 = Con(c2, (0, -K2)) 118 Grp(c2, (K3, -K3), shipgroup.groupCovertOps, 6) 119 c2 = Con(c2, (0, -K2)) 120 Grp(c2, (K3, -K3), shipgroup.groupElectronicAttack, 6) 121 c2 = Con(c2, (0, -K2)) 122 Grp(c2, (K3, -K3), shipgroup.groupLogisticsFrigates, 6) 123 c = Grp(c, (5 * K4, 0), shipgroup.groupDestroyer) 124 c2 = Grp(c, (0, -K2), shipgroup.groupNavyDestroyers, 4) 125 c2 = Con(c2, (0, -K3)) 126 Grp(c2, (K3, -K3), shipgroup.groupInterdictor) 127 c2 = Con(c2, (0, -K2)) 128 Grp(c2, (K3, -K3), shipgroup.groupCommandDestroyers) 129 c2 = Con(c2, (0, -K2)) 130 Grp(c2, (K3, -K3), shipgroup.groupTacticalDestroyer) 131 c = Grp(c, (5 * K4, 0), shipgroup.groupCruiser) 132 c2 = Grp(c, (0, -K2), shipgroup.groupNavyCruiser, 4) 133 c2 = Con(c2, (0, -K3)) 134 Grp(c2, (K3, -K3), shipgroup.groupRecon, 6) 135 c2 = Con(c2, (0, -K2)) 136 Grp(c2, (K3, -K3), shipgroup.groupHeavyAssault, 6) 137 c2 = Con(c2, (0, -K2)) 138 Grp(c2, (K3, -K3), shipgroup.groupHeavyInterdictor, 6) 139 c2 = Con(c2, (0, -K2)) 140 Grp(c2, (K3, -K3), shipgroup.groupLogistics, 6) 141 c2 = Con(c2, (0, -K2)) 142 Grp(c2, (K2, -K2), shipgroup.groupStrategicCruiser, 6) 143 c = Grp(c, (3 * K2, 0), shipgroup.groupBattlecruiser) 144 c2 = Grp(c, (0, -K2), shipgroup.groupNavyBattlecruiser) 145 c2 = Con(c2, (0, -K3)) 146 Grp(c2, (K3, -K3), shipgroup.groupCommandship) 147 c = Grp(c, (6 * K4, 0), shipgroup.groupBattleship) 148 c2 = Grp(c, (0, -K2), shipgroup.groupNavyBattleship) 149 c2 = Con(c2, (0, -3 * K8)) 150 Grp(c2, (K3, -K3), shipgroup.groupBlackOps) 151 c2 = Con(c2, (0, -K2)) 152 Grp(c2, (K3, -K3), shipgroup.groupMarauder) 153 c = Con(c, (7 * K4, 0)) 154 c2 = Grp(c, (K4, 0), shipgroup.groupDreadnought) 155 c2 = Grp(c2, (0, -K3 * 2), shipgroup.groupNavyDreadnoughts, 4) 156 c2 = Con(c2, (0, -K3 * 1.5)) 157 Grp(c2, (K3, -K3), shipgroup.groupLancerDreadnought, 4) 158 c2 = Con(c, (0, -K3 * 6)) 159 Grp(c2, (K3, -K3), shipgroup.groupCarrier) 160 c2 = Con(c2, (0, -K3 * 2.5)) 161 Grp(c2, (K3, -K3), shipgroup.groupCommandCarrier) 162 c2 = Con(c2, (0, -K3 * 2.5)) 163 Grp(c2, (K3, -K3), shipgroup.groupTitan) 164 c = Con(cIndustr, (K12, K12)) 165 c = Grp(c, (K2, 0), shipgroup.groupShuttle) 166 c = Grp(c, (17 * K4, 0), shipgroup.groupIndustrial) 167 c2 = Con(c, (0, -K3)) 168 Grp(c2, (K4, -K4), shipgroup.groupTransport) 169 c = Grp(c, (3.0, 0), shipgroup.groupFreighter) 170 c2 = Con(c, (0, -K8)) 171 Grp(c2, (K2, -K2), shipgroup.groupJumpFreighter) 172 return root 173 174 def _GetTriglavianData(self, factionID): 175 176 def Grp(parent, position, shipGroupID, iconsPerRow = 3): 177 return GroupNode(parent=parent, position=position, shipGroupID=shipGroupID, iconsPerRow=iconsPerRow, factionID=factionID, treeID=factionID) 178 179 def Con(parent, position): 180 return ConnectorNode(parent=parent, position=position, treeID=factionID) 181 182 root = RootNode(parent=None, position=(0, 0)) 183 c = Grp(root, (K2, 0), shipgroup.groupFrigate) 184 c2 = Con(c, (0, -K3)) 185 Grp(c2, (K3, -K3), shipgroup.groupAssault, 6) 186 c = Grp(c, (5 * K4, 0), shipgroup.groupDestroyer) 187 c2 = Con(c, (0, -K3)) 188 Grp(c2, (K3, -K3), shipgroup.groupCommandDestroyers) 189 c = Grp(c, (5 * K4, 0), shipgroup.groupCruiser) 190 c2 = Con(c, (0, -K3)) 191 Grp(c2, (K3, -K3), shipgroup.groupHeavyAssault) 192 c2 = Con(c, (0, -K2)) 193 c2 = Con(c2, (0, -K3)) 194 Grp(c2, (K3, -K3), shipgroup.groupLogistics) 195 c = Grp(c, (5 * K4, 0), shipgroup.groupBattlecruiser) 196 c = Grp(c, (5 * K4, 0), shipgroup.groupBattleship) 197 c2 = Con(c, (0, -K3)) 198 Grp(c2, (K3, -K3), shipgroup.groupMarauder) 199 c = Con(c, (5 * K4, 0)) 200 Grp(c, (K4, 0), shipgroup.groupDreadnought) 201 return root 202 203 def _GetEdenComData(self, factionID): 204 205 def Grp(parent, position, shipGroupID, iconsPerRow = 3): 206 return GroupNode(parent=parent, position=position, shipGroupID=shipGroupID, iconsPerRow=iconsPerRow, factionID=factionID, treeID=factionID) 207 208 def Con(parent, position): 209 return ConnectorNode(parent=parent, position=position, treeID=factionID) 210 211 root = RootNode(parent=None, position=(0, 0)) 212 c = Con(root, (K2, 0)) 213 cLeft = Con(c, (0, 0)) 214 cRight = Con(c, (0, 1.0)) 215 c = Grp(cLeft, (K2, 0), shipgroup.groupFrigate) 216 c = Grp(c, (5 * K4, 0), shipgroup.groupCruiser) 217 c = Grp(c, (5 * K4, 0), shipgroup.groupBattleship) 218 c = Grp(cRight, (3 * K4, 0), shipgroup.groupIndustrial) 219 c2 = Con(c, (0, -K3)) 220 c3 = Grp(c2, (K4, -K4), shipgroup.groupTransport) 221 c = Grp(c, (4 * K2, 0), shipgroup.groupFreighter) 222 return root 223 224 def _GetOREData(self, factionID): 225 226 def Grp(parent, position, shipGroupID, iconsPerRow = 3): 227 return GroupNode(parent=parent, position=position, shipGroupID=shipGroupID, iconsPerRow=iconsPerRow, factionID=factionID, treeID=factionID) 228 229 def Con(parent, position): 230 return ConnectorNode(parent=parent, position=position, treeID=factionID) 231 232 root = RootNode(parent=None, position=(0, 0)) 233 c = Con(root, (K2, 0)) 234 cLeft = Con(c, (0, 1.0)) 235 cRight = Con(c, (0, 1.0)) 236 c = Grp(c, (K2, 0), shipgroup.groupMiningFrigate) 237 c1 = Grp(c, (0, -K2), shipgroup.groupNavyMiningFrigate, 4) 238 c1 = Con(c1, (0, -K4)) 239 Grp(c1, (K4, -K4), shipgroup.groupExpeditionFrigate, 6) 240 c = Grp(c, (2.5 * K2, 0), shipgroup.groupMiningDestroyer) 241 c2 = Grp(c, (0, -K2), shipgroup.groupNavyMiningDestroyer) 242 c2 = Con(c2, (0, -K4)) 243 Grp(c2, (K4, -K4), shipgroup.groupMiningCommandDestroyer) 244 c = Grp(c, (1.0, 0), shipgroup.groupMiningBarge) 245 c3 = Con(c, (0, -K4)) 246 Grp(c3, (K4, -K4), shipgroup.groupExhumers) 247 c = Grp(cRight, (5 * K2, 0), shipgroup.groupOreIndustrial) 248 cDown = Con(c, (0, 1.0)) 249 c4 = Grp(cDown, (4 * K2, 0), shipgroup.groupFreighter) 250 c = Grp(c, (1.0, 0), shipgroup.groupIndustrialCommand) 251 c = Grp(c, (1.0, 0), shipgroup.groupCapitalIndustrial) 252 return root 253 254 def _GetPirateFactionData(self, factionID): 255 256 def Grp(parent, position, shipGroupID, facID, showLinksTo, iconsPerRow = 3): 257 return GroupNode(parent=parent, position=position, shipGroupID=shipGroupID, factionID=facID, showLinksTo=showLinksTo, treeID=factionID, iconsPerRow=iconsPerRow) 258 259 def OtherGrp(parent, position, shipGroupID, facID, showLinksTo, iconsPerRow = 3): 260 return OtherFactionGroupNode(parent=parent, position=position, shipGroupID=shipGroupID, factionID=facID, showLinksTo=showLinksTo, treeID=factionID, iconsPerRow=iconsPerRow) 261 262 def Con(parent, position): 263 return ConnectorNode(parent=parent, position=position, treeID=factionID) 264 265 factionID1, factionID2 = shipTreeConst.PARENT_FACTIONIDS_BY_FACTIONID[factionID] 266 root = RootNode(parent=None, position=(0, 0)) 267 c = firstConnectionNode = Con(root, (K4, 0)) 268 shipTreeSvc = sm.GetService('shipTree') 269 i = 0 270 for shipGroupID in (shipgroup.groupFrigate, 271 shipgroup.groupDestroyer, 272 shipgroup.groupCruiser, 273 shipgroup.groupBattlecruiser, 274 shipgroup.groupBattleship): 275 if shipTreeSvc.GetShipTypeIDs(factionID, shipGroupID): 276 x = K4 if i == 0 else 3 * K4 277 c = Grp(c, (x, 0), shipGroupID, factionID, False) 278 top = OtherGrp(root, (K2 + i * x, -0.5), shipGroupID, factionID1, True) 279 Grp(top, (0, 0.5), shipGroupID, factionID, False) 280 bottom = OtherGrp(root, (K2 + i * x, 0.5), shipGroupID, factionID2, True) 281 Grp(bottom, (0, -0.5), shipGroupID, factionID, False) 282 i += 1 283 284 i = 0 285 for shipGroupID in (shipgroup.groupDreadnought, shipgroup.groupCarrier, shipgroup.groupTitan): 286 if shipTreeSvc.GetShipTypeIDs(factionID, shipGroupID): 287 h = 0.0 if i == 0 else -0.8 288 c = Con(c, (K2, h)) 289 g = Grp(c, (K2, 0), shipGroupID, factionID, False) 290 top = OtherGrp(g, (0, -K2), shipGroupID, factionID1, True) 291 Grp(top, (0, K2), shipGroupID, factionID, False) 292 bottom = OtherGrp(g, (0, K2), shipGroupID, factionID2, True) 293 Grp(bottom, (0, -K2), shipGroupID, factionID, False) 294 i += 1 295 296 return (root, firstConnectionNode) 297 298 def _GetSoeData(self, factionID): 299 root, firstConnectionNode = self._GetPirateFactionData(factionID) 300 shipGroupID = shipgroup.groupExpeditionCommandShip 301 if not self.GetShipTypeIDs(factionID, shipGroupID): 302 return root 303 304 def Grp(parent, position, shipGroupID, facID, showLinksTo, iconsPerRow = 3): 305 return GroupNode(parent=parent, position=position, shipGroupID=shipGroupID, factionID=facID, showLinksTo=showLinksTo, treeID=factionID, iconsPerRow=iconsPerRow) 306 307 def OtherGrp(parent, position, shipGroupID, facID, showLinksTo, iconsPerRow = 3): 308 return OtherFactionGroupNode(parent=parent, position=position, shipGroupID=shipGroupID, factionID=facID, showLinksTo=showLinksTo, treeID=factionID, iconsPerRow=iconsPerRow) 309 310 factionID1, factionID2 = shipTreeConst.PARENT_FACTIONIDS_BY_FACTIONID[factionID] 311 c = ConnectorNode(parent=firstConnectionNode, position=(0, 1.0), treeID=factionID) 312 c = ConnectorNode(parent=c, position=(2 * K2, 0.0), treeID=factionID) 313 g = Grp(c, (K2, 0), shipGroupID, factionID, False) 314 top = OtherGrp(g, (0, -K2), shipGroupID, factionID1, True) 315 Grp(top, (0, K2), shipGroupID, factionID, False) 316 bottom = OtherGrp(g, (0, K2), shipGroupID, factionID2, True) 317 Grp(bottom, (0, -K2), shipGroupID, factionID, False) 318 return root 319 320 def _GetConcordData(self, factionID): 321 322 def Grp(parent, position, shipGroupID, iconsPerRow = 3): 323 return GroupNode(parent=parent, position=position, shipGroupID=shipGroupID, iconsPerRow=iconsPerRow, factionID=factionID, treeID=factionID) 324 325 def Con(parent, position): 326 return ConnectorNode(parent=parent, position=position, treeID=factionID) 327 328 root = RootNode(parent=None, position=(0, 0)) 329 c = Grp(root, (K2, 0), shipgroup.groupShuttle) 330 c = Grp(c, (2 * K2, 0), shipgroup.groupCovertOps) 331 c = Grp(c, (5 * K4, 0), shipgroup.groupRecon) 332 c2 = Con(c, (0, -K3)) 333 Grp(c2, (K3, -K3), shipgroup.groupFlagCruiser) 334 c = Grp(c, (5 * K4, 0), shipgroup.groupBlackOps) 335 return root 336 337 def _GetSoctData(self, factionID): 338 339 def Grp(parent, position, shipGroupID, iconsPerRow = 3): 340 return GroupNode(parent=parent, position=position, shipGroupID=shipGroupID, iconsPerRow=iconsPerRow, factionID=factionID, treeID=factionID) 341 342 root = RootNode(parent=None, position=(0, 0)) 343 c = Grp(root, (K2, 0), shipgroup.groupShuttle) 344 c = Grp(c, (K2 * 2, 0), shipgroup.groupFrigate) 345 c = Grp(c, (K2 * 2, 0), shipgroup.groupDestroyer) 346 c = Grp(c, (K2 * 2, 0), shipgroup.groupBattlecruiser) 347 c = Grp(c, (K2 * 2, 0), shipgroup.groupBattleship) 348 return root 349 350 def IsInShipTree(self, typeID): 351 hasShipGroup = evetypes.GetShipGroupID(typeID) is not None 352 return hasShipGroup and evetypes.GetGroupID(typeID) != const.groupCapsule 353 354 def GetRecentlyChangedSkills(self): 355 if self._recentlyChangedSkills is not None: 356 return self._recentlyChangedSkills 357 uthread.Lock(self, 'GetRecentlyChangedSkills') 358 try: 359 if self._recentlyChangedSkills is None: 360 self._recentlyChangedSkills = sm.GetService('skills').GetRecentlyTrainedSkills() 361 finally: 362 uthread.UnLock(self, 'GetRecentlyChangedSkills') 363 364 return self._recentlyChangedSkills 365 366 def IsShipMasteryRecentlyIncreased(self, typeID): 367 masteryLevel = sm.GetService('certificates').GetCurrCharMasteryLevel(typeID) 368 certs = sm.GetService('certificates').GetCertificatesForShipByMasteryLevel(typeID, masteryLevel) 369 changed = self.GetRecentlyChangedSkills() 370 for cert in certs: 371 for skillTypeID, level in changed.iteritems(): 372 if skillTypeID in cert.skills: 373 currCertSkillLevel = cert.skills[skillTypeID][cert.currentLevel] 374 if currCertSkillLevel > level: 375 return True 376 377 return False 378 379 def IsGroupsRecentlyUnlocked(self, factionID): 380 factionData = self.GetRootNode(factionID) 381 shipGroups = [ node for node in factionData.GetDescendants().values() if isinstance(node, GroupNode) ] 382 for shipGroup in shipGroups: 383 if shipGroup.IsRecentlyUnlocked(): 384 return True 385 386 return False 387 388 def EmptyRecentlyChangedSkillsCache(self): 389 self._recentlyChangedSkills = {} 390 391 def FlushRecentlyChangedSkillsCache(self): 392 self._recentlyChangedSkills = None 393 394 395 class ShipTreeNodeBase(TreeData): 396 __guid__ = 'shipTree.NodeBase' 397 nodeType = None 398 399 def __init__(self, treeID = None, showLinksTo = True, iconsPerRow = 3, *args, **kw): 400 TreeData.__init__(self, *args, **kw) 401 self._isLocked = None 402 self._isRestricted = None 403 self._isPathToElite = None 404 self.showLinksTo = showLinksTo 405 self.treeID = treeID 406 self._boundingBox = None 407 self._position = (0, 0) 408 self._iconsPerRow = iconsPerRow 409 410 def GetNodeType(self): 411 return self.nodeType 412 413 def GetDimensions(self): 414 p0, p1 = self.GetBoundingBox() 415 return geo2.Vec2Subtract(p1, p0) 416 417 def GetCenter(self): 418 p0, p1 = self.GetBoundingBox() 419 return geo2.Vec3Lerp(p0, p1, 0.5) 420 421 def GetPosition(self): 422 return self._position 423 424 def GetPositionProportional(self): 425 rootNode = self.GetRootNode() 426 (minX, minY), (maxX, maxY) = rootNode.GetBoundingBox() 427 x, y = self.GetPosition() 428 if minX == maxX: 429 x = 0.0 430 else: 431 x = (x - minX) / (maxX - minX) 432 if minY == maxY: 433 y = 0.0 434 else: 435 y = (y - minY) / (maxY - minY) 436 return (x, y) 437 438 def SetPosition(self, position): 439 self._position = position 440 441 def GetBoundingBox(self): 442 if self._boundingBox: 443 return self._boundingBox 444 minX, minY = self.GetPosition() 445 maxX, maxY = self.GetPosition() 446 children = self.GetChildren() 447 if not children: 448 return (self.GetPosition(), self.GetPosition()) 449 for child in self.GetChildren(): 450 (x1, y1), (x2, y2) = child.GetBoundingBox() 451 minX = min(minX, x1, x2) 452 minY = min(minY, y1, y2) 453 maxX = max(maxX, x1, x2) 454 maxY = max(maxY, y1, y2) 455 456 self._boundingBox = ((minX, minY), (maxX, maxY)) 457 return self._boundingBox 458 459 def GetGroupNodesByLevel(self): 460 nodes = [] 461 self._GetGroupNodesByLevel(nodes, 0) 462 return nodes 463 464 def GetIconsPerRow(self): 465 return self._iconsPerRow 466 467 def IsAllChildrenElite(self): 468 if not self.children: 469 return self.IsElite() 470 for child in self.children: 471 if child.nodeType == NODETYPE_OTHERFACTIONGROUP: 472 continue 473 if not child._IsAllChildrenElite(child): 474 return False 475 476 return True 477 478 def _IsAllChildrenElite(self, node): 479 if not node.IsElite(): 480 return False 481 for child in node.children: 482 if not child._IsAllChildrenElite(child): 483 return False 484 485 return True 486 487 def IsElite(self): 488 return True 489 490 def FlushCache(self): 491 self._isLocked = None 492 self._isRestricted = None 493 self._isPathToElite = None 494 for child in self.children: 495 child.FlushCache() 496 497 def IsPathToElite(self): 498 if self._isPathToElite is not None: 499 return self._isPathToElite 500 parNode = self 501 while True: 502 childNode = parNode 503 parNode = parNode.parent 504 if parNode is None or parNode.nodeType != NODETYPE_CONNECTOR: 505 if childNode.nodeType == NODETYPE_CONNECTOR: 506 self._isPathToElite = childNode.IsAllChildrenElite() 507 else: 508 self._isPathToElite = childNode.IsElite() and childNode.IsAllChildrenElite() 509 return self._isPathToElite 510 511 def IsRestricted(self): 512 if self._isRestricted is None: 513 self._isRestricted = self._IsRestricted() 514 return self._isRestricted 515 516 def _IsRestricted(self): 517 return False 518 519 520 class GroupNode(ShipTreeNodeBase): 521 nodeType = NODETYPE_GROUP 522 523 def __init__(self, shipGroupID, factionID, position, *args, **kw): 524 ShipTreeNodeBase.__init__(self, *args, **kw) 525 self.shipGroupID = shipGroupID 526 self.factionID = factionID 527 if self.parent: 528 self.SetPosition(geo2.Add(self.parent.GetPosition(), position)) 529 else: 530 self.SetPosition(position) 531 532 def GetID(self): 533 return self.shipGroupID 534 535 def IsLocked(self): 536 if self._isLocked is not None: 537 return self._isLocked 538 mySkills = sm.GetService('skills').GetSkill 539 for skillTypeID, data in self._LoopInfoBubbleGroupsPreReqSkills(): 540 mySkill = mySkills(skillTypeID) 541 if mySkill is None or mySkill.effectiveSkillLevel < data['level']: 542 self._isLocked = True 543 return self._isLocked 544 545 self._isLocked = False 546 return self._isLocked 547 548 def IsLockedWithoutExpertSystem(self): 549 mySkills = sm.GetService('skills').GetSkill 550 for skillTypeID, data in self._LoopInfoBubbleGroupsPreReqSkills(): 551 mySkill = mySkills(skillTypeID) 552 if mySkill is None or mySkill.trainedSkillLevel < data['level']: 553 return True 554 555 return False 556 557 def IsRecentlyUnlocked(self): 558 if self.IsLocked(): 559 return False 560 oldSkills = sm.GetService('shipTree').GetRecentlyChangedSkills() 561 for skillTypeID, data in self._LoopInfoBubbleGroupsPreReqSkills(): 562 myOldLevel = oldSkills.get(skillTypeID, None) 563 if myOldLevel is not None and myOldLevel < data['level']: 564 return True 565 566 return False 567 568 def IsBeingTrained(self): 569 skillQueue = sm.GetService('skillqueue').GetQueue() 570 requiredSkills = self.GetRequiredSkills() 571 for trainingRecord in skillQueue: 572 if trainingRecord.trainingTypeID in requiredSkills: 573 return True 574 575 return False 576 577 def GetSkillLevel(self): 578 lowest = 5 579 skillSvc = sm.GetService('skills') 580 for skillTypeID, _ in self._LoopInfoBubbleGroupsPreReqSkills(): 581 mySkill = skillSvc.GetSkill(skillTypeID) 582 if not mySkill: 583 return 0 584 if mySkill.skillLevel < lowest: 585 lowest = mySkill.skillLevel 586 587 return lowest 588 589 def GetRequiredSkills(self, onlyVisible = False): 590 skillsWithLevel = {} 591 for skillTypeID, data in self._LoopInfoBubbleGroupsPreReqSkills(): 592 if onlyVisible and not data['display']: 593 continue 594 skillsWithLevel[skillTypeID] = data['level'] 595 596 return skillsWithLevel 597 598 def GetRequiredSkillsSorted(self, onlyVisible = False): 599 600 def Compare(x, y): 601 typeID1, level1 = x 602 typeID2, level2 = y 603 if level1 != level2: 604 return level2 - level1 605 typeName1 = evetypes.GetName(typeID1) 606 typeName2 = evetypes.GetName(typeID2) 607 if typeName1 > typeName2: 608 return 1 609 else: 610 return -1 611 612 skills = self.GetRequiredSkills(onlyVisible) 613 skills = [ (typeID, level) for typeID, level in skills.iteritems() ] 614 return sorted(skills, cmp=Compare) 615 616 def _LoopInfoBubbleGroupsPreReqSkills(self): 617 infoBubbleGroupPreReqSkills = {int(k):v for k, v in cfg.infoBubbleGroups[self.shipGroupID]['preReqSkills'].items()} 618 if self.factionID in infoBubbleGroupPreReqSkills: 619 skillData = {int(k):v for k, v in infoBubbleGroupPreReqSkills[self.factionID]['skills'].items()} 620 for skillTypeID, data in skillData.iteritems(): 621 yield (skillTypeID, data) 622 623 def GetBonusSkills(self): 624 return self.GetRequiredSkills(onlyVisible=True) 625 626 def GetBonusSkillsSorted(self): 627 return self.GetRequiredSkillsSorted(onlyVisible=True) 628 629 def _GetGroupNodesByLevel(self, nodes, level): 630 if len(nodes) <= level: 631 nodes.append([]) 632 nodes[level].append(self) 633 for child in self.GetChildren(): 634 child._GetGroupNodesByLevel(nodes, level + 1) 635 636 def GetIconSize(self): 637 if self.shipGroupID in (shipgroup.groupJumpFreighter, shipgroup.groupFreighter): 638 rigSize = 4 639 else: 640 typeIDs = self.GetShipTypeIDs() 641 if typeIDs: 642 rigSize = sm.GetService('godma').GetType(typeIDs[0]).rigSize 643 else: 644 rigSize = 0 645 return 82 + 16 * rigSize 646 647 def IsElite(self): 648 if self.IsLocked(): 649 return False 650 for typeID in self.GetShipTypeIDs(): 651 masteryLevel = sm.GetService('certificates').GetCurrCharMasteryLevel(typeID) 652 if masteryLevel != 5: 653 return False 654 655 return True 656 657 def GetShipTypeIDs(self): 658 return sm.GetService('shipTree').GetShipTypeIDs(self.factionID, self.shipGroupID) 659 660 def GetTimeToUnlock(self): 661 typeIDs = self.GetShipTypeIDs() 662 if typeIDs: 663 return sm.GetService('skills').GetSkillTrainingTimeLeftToUseType(typeIDs[0], includeBoosters=False) 664 return 0 665 666 def GetGroupWidth(self): 667 numIcons = min(len(self.GetShipTypeIDs()), self.GetIconsPerRow()) 668 return (self.GetIconSize() + 1) * numIcons 669 670 def _IsRestricted(self): 671 requiredSkills = self.GetRequiredSkills() 672 for skillID, requiredLevel in requiredSkills.iteritems(): 673 if get_clone_grade_svc().get_max_skill_level(skillID, CLONE_STATE_ALPHA) < requiredLevel: 674 return True 675 676 return super(GroupNode, self)._IsRestricted() 677 678 679 class OtherFactionGroupNode(GroupNode): 680 nodeType = NODETYPE_OTHERFACTIONGROUP 681 682 683 class ConnectorNode(ShipTreeNodeBase): 684 nodeType = NODETYPE_CONNECTOR 685 686 def __init__(self, position, *args, **kw): 687 ShipTreeNodeBase.__init__(self, *args, **kw) 688 self._skillLevel = None 689 if self.parent: 690 self.SetPosition(geo2.Add(self.parent.GetPosition(), position)) 691 else: 692 self.SetPosition(position) 693 694 def GetID(self): 695 return '%s_%s' % self.GetPosition() 696 697 def IsLocked(self): 698 if self._isLocked is not None: 699 return self._isLocked 700 for child in self.GetChildren(): 701 if not child.IsLocked(): 702 self._isLocked = False 703 return self._isLocked 704 705 self._isLocked = True 706 return self._isLocked 707 708 def GetSkillLevel(self): 709 if self._skillLevel is not None: 710 return self._skillLevel 711 self._skillLevel = max([ child.GetSkillLevel() for child in self.GetChildren() ]) 712 return self._skillLevel 713 714 def _GetGroupNodesByLevel(self, nodes, level): 715 for child in self.GetChildren(): 716 child._GetGroupNodesByLevel(nodes, level) 717 718 def _IsRestricted(self): 719 return all((c.IsRestricted() for c in self.GetChildren())) 720 721 722 class RootNode(ConnectorNode): 723 nodeType = NODETYPE_ROOT 724 725 def _IsRestricted(self): 726 return False