skillRequirements.py (13135B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fittingScreen\skillRequirements.py 2 from collections import defaultdict 3 from carbon.common.script.sys.serviceConst import ROLE_GML 4 from carbonui.text.styles import TextHeader 5 from carbonui.util.sortUtil import SortListOfTuples 6 from dogma.items.characterDogmaItem import CharacterDogmaItem 7 from dogma.items.shipDogmaItem import ShipDogmaItem 8 from carbonui.control.button import Button 9 from eve.client.script.ui.control.eveLabel import EveLabelMedium, EveHeaderMedium 10 import evetypes 11 import carbonui.const as uiconst 12 from eve.client.script.ui.shared.fittingScreen.skillRequirementsUtil import GetAllSkillsAndLevels, _GetSkillTypeIDAndLevelRequired 13 from eve.client.script.ui.shared.industry.submitButton import PrimaryButton 14 from eve.client.script.ui.shared.neocom.skillConst import COLOR_SKILL_1, COLOR_SKILL_2 15 from eve.client.script.ui.shared.tooltip.itemObject import ItemObject 16 from eve.client.script.ui.shared.tooltip.skill_requirement import RequiredSkillRow, AddSkillActionForList, AddTrainingTime 17 from inventorycommon.const import categoryBlueprint 18 from localization import GetByLabel 19 import blue 20 from omega.client.clone_grade_svc import get_clone_grade_svc 21 22 def GetSkillTooltip(tooltipPanel, fittingController, fitName = None): 23 tooltipPanel.state = uiconst.UI_NORMAL 24 tooltipPanel.columns = 2 25 tooltipPanel.margin = (12, 8, 12, 12) 26 tooltipPanel.state = uiconst.UI_NORMAL 27 dogmaLocation = fittingController.GetDogmaLocation() 28 shipAndFitTypeIDs = _GetAllTypesForShipAndFit(dogmaLocation) 29 shipAndFitTypeIDsMissingSomeReq = GetMissingSkillsForTypeIDs(shipAndFitTypeIDs) 30 shipAndFitHighestLevelByTypeID, _ = GetMissingSkills_HighestLevelByTypeID(shipAndFitTypeIDsMissingSomeReq) 31 cargoholdTypeIDs = _GetAllTypesForCargoHold(dogmaLocation) 32 cargoholdTypeIDsMissingSomeReq = GetMissingSkillsForTypeIDs(cargoholdTypeIDs) 33 cargoholdTypeIDsMissingSomeReq -= shipAndFitTypeIDsMissingSomeReq 34 cargoholdHighestLevelByTypeID, _ = GetMissingSkills_HighestLevelByTypeID(cargoholdTypeIDsMissingSomeReq) 35 for typeID, lvl in cargoholdHighestLevelByTypeID.items(): 36 lvlForFit = shipAndFitHighestLevelByTypeID.get(typeID, 0) 37 if lvlForFit >= lvl: 38 cargoholdHighestLevelByTypeID.pop(typeID) 39 40 shipText = None 41 holdText = GetByLabel('UI/Fitting/FittingWindow/Warnings/CargoHold') 42 if shipAndFitTypeIDsMissingSomeReq and cargoholdTypeIDsMissingSomeReq: 43 shipText = GetByLabel('UI/Fitting/FittingWindow/Warnings/ShipAndFit') 44 if shipAndFitTypeIDs: 45 AddMissingSkillRequirements(tooltipPanel, shipAndFitHighestLevelByTypeID, True, shipText) 46 if cargoholdTypeIDsMissingSomeReq: 47 AddMissingSkillRequirements(tooltipPanel, cargoholdHighestLevelByTypeID, False, holdText) 48 allSkillLevelsByID = [] 49 for key in set(shipAndFitHighestLevelByTypeID.keys()) | set(cargoholdHighestLevelByTypeID.keys()): 50 valA = shipAndFitHighestLevelByTypeID.get(key, 0) 51 valB = cargoholdHighestLevelByTypeID.get(key, 0) 52 allSkillLevelsByID.append((key, max(valA, valB))) 53 54 skillSvc = sm.GetService('skills') 55 allSkillLevelsByID = skillSvc.GetSkillsMissingToUseAllSkillsFromListRecursiveAsList(allSkillLevelsByID) 56 allSkillLevelsByIDDict = dict(allSkillLevelsByID) 57 missingSkills = skillSvc.GetMissingSkillBooksFromList(allSkillLevelsByID) 58 totalTime = long(skillSvc.GetSkillTrainingTimeLeftForTypesAndLevels(allSkillLevelsByIDDict, includeBoosters=False)) 59 if totalTime <= 0: 60 return 61 isOmegaRestricted = False 62 for typeID, level in allSkillLevelsByID: 63 if not isOmegaRestricted: 64 isOmegaRestricted = ItemObject(typeID).NeedsOmegaUpgrade() 65 66 isOmega = get_clone_grade_svc().is_omega_with_grace_period() 67 AddTrainingTime(tooltipPanel, isOmega=isOmega, isOmegaRestricted=isOmegaRestricted, trainingTime=totalTime, activityText=GetByLabel('Tooltips/SkillPlanner/ActivityFlyFittedShip')) 68 if fitName: 69 skillPlanName = GetByLabel('Tooltips/SkillPlanner/SkillPlanNameStringWithType', typeName=fitName) 70 else: 71 skillPlanName = GetByLabel('UI/SkillPlan/DefaultCreateFitSkillPlanName') 72 AddSkillActionForList(tooltipPanel, allSkillLevelsByID, missingSkills, minWidth=300, skillPlanName=skillPlanName) 73 74 75 def GetMissingSkillsForTypeIDs(allTypeIDs): 76 skillsSvc = sm.GetService('skills') 77 missingReq = set() 78 for eachTypeID in allTypeIDs: 79 if not skillsSvc.IsSkillRequirementMet(eachTypeID): 80 missingReq.add(eachTypeID) 81 82 return missingReq 83 84 85 def GetAllTypeIDsMissingSkillsForShipAndContent(dogmaLocation): 86 allTypeIDs = _GetAllTypesForShipAndFit(dogmaLocation) 87 allTypeIDs.update(_GetAllTypesForCargoHold(dogmaLocation)) 88 return allTypeIDs 89 90 91 def _GetAllTypesForShipAndFit(dogmaLocation): 92 allTypeIDs = set() 93 ship = dogmaLocation.GetShipItem() 94 if ship is None: 95 return allTypeIDs 96 allTypeIDs.add(ship.typeID) 97 fittedItems = dogmaLocation.GetFittedItemsToShip() 98 for eachItem in fittedItems.itervalues(): 99 if isinstance(eachItem, (CharacterDogmaItem, ShipDogmaItem)): 100 continue 101 allTypeIDs.add(eachItem.typeID) 102 103 for flagID in [const.flagDroneBay, const.flagFighterBay] + const.fighterTubeFlags: 104 allTypeIDs.update(_GetTypesInFlag(dogmaLocation, flagID)) 105 106 return allTypeIDs 107 108 109 def _GetAllTypesForCargoHold(dogmaLocation): 110 return _GetTypesInFlag(dogmaLocation, const.flagCargo) 111 112 113 def _GetTypesInFlag(dogmaLocation, flagID): 114 holdItems = dogmaLocation.GetHoldItems(flagID) 115 typesInHold = {x.typeID for x in holdItems.itervalues()} 116 return typesInHold 117 118 119 def AddMissingSkillRequirements(tooltipPanel, highestLevelByTypeID, addHeaderLabel = True, text = None): 120 if not highestLevelByTypeID: 121 return 122 skillsSvc = sm.GetService('skills') 123 tooltipPanel.AddSpacer(width=250, colSpan=tooltipPanel.columns) 124 tooltipPanel.FillRow() 125 if addHeaderLabel: 126 headerText = GetByLabel('UI/Skills/RequiredSkills') 127 headerLabel = TextHeader(text=headerText) 128 tooltipPanel.AddCell(headerLabel, colSpan=tooltipPanel.columns, cellPadding=(0, 4, 0, 0)) 129 tooltipPanel.FillRow() 130 if text: 131 headerLabel = EveHeaderMedium(text=text, color=COLOR_SKILL_1) 132 topPadding = 8 if addHeaderLabel else 20 133 tooltipPanel.AddCell(headerLabel, colSpan=tooltipPanel.columns, cellPadding=(0, 134 topPadding, 135 0, 136 0)) 137 skillList = [] 138 for skillTypeID, skillLevel in highestLevelByTypeID.iteritems(): 139 name = evetypes.GetName(skillTypeID) 140 skillList.append((name, (skillTypeID, skillLevel))) 141 142 skillList = SortListOfTuples(skillList) 143 for skillID, level in skillList: 144 tooltipPanel.AddRow(rowClass=RequiredSkillRow, typeID=skillID, level=level, cellPadding=(0, 4, 0, 0), colSpan=tooltipPanel.columns) 145 146 147 def CopyAllSkills(typeIDs): 148 allSkillsAndLevels = GetAllSkillsAndLevels(typeIDs) 149 textList = [] 150 for eachSkillTypeID, skillLvl in allSkillsAndLevels: 151 name = evetypes.GetName(eachSkillTypeID) 152 textList.append('%s %d' % (name, skillLvl)) 153 154 text = '\r\n'.join(textList) 155 blue.pyos.SetClipboardData(text) 156 157 158 def AddSkillAction(tooltipPanel, typeIDs): 159 allMissingSkillbooks = GetMissingSkillbooksForTypeIDs(typeIDs) 160 areSomeTypesMissingSkillNotInQueue = bool(GetTypesWithMissingSkills(typeIDs)) 161 skillTypesAndLvlsToUse, _ = GetMissingSkills_HighestLevelByTypeID(typeIDs) 162 if allMissingSkillbooks: 163 AddBuyAndTrainForRequiredSkillbooksMissingRow(tooltipPanel, list(allMissingSkillbooks), skillTypesAndLvlsToUse, tooltipPanel.columns) 164 if areSomeTypesMissingSkillNotInQueue: 165 if _ShouldAddTrainNowBtn(skillTypesAndLvlsToUse.keys()): 166 AddTrainNowRow(tooltipPanel, skillTypesAndLvlsToUse) 167 if session.role & ROLE_GML == ROLE_GML: 168 skillsAndLevels, _ = GetMissingSkills_HighestLevelByTypeID(typeIDs) 169 if skillsAndLevels: 170 btn = Button(label='Give Skills', func=sm.GetService('info').DoGiveSkills, args=(skillsAndLevels, None), idx=0) 171 tooltipPanel.AddCell(cellObject=btn, colSpan=tooltipPanel.columns) 172 173 174 def _ShouldAddTrainNowBtn(skillTypesToUse): 175 for eachTypeID in skillTypesToUse: 176 if ItemObject(eachTypeID).CanTrainNow(): 177 return True 178 179 return False 180 181 182 def AddTrainNowRow(tooltipPanel, skillTypesAndLvlsToUse): 183 tooltipPanel.AddCell(cellPadding=(0, 12, 0, 0), colSpan=tooltipPanel.columns) 184 trainNowButton = TrainNowButtonManyTypes(align=uiconst.CENTER, fixedheight=30, fixedwidth=120, skillTypesAndLvlsToUse=skillTypesAndLvlsToUse) 185 tooltipPanel.AddCell(trainNowButton, colSpan=tooltipPanel.columns) 186 187 188 def AddBuyAndTrainForRequiredSkillbooksMissingRow(grid, missing, skillTypesAndLvlsToUse, colSpan): 189 grid.AddCell(cellPadding=(0, 12, 0, 0), colSpan=colSpan) 190 grid.FillRow() 191 available = [ x for x in missing if evetypes.IsSkillAvailableForPurchase(x) ] 192 numUnavailable = len(missing) - len(available) 193 text = GetByLabel('UI/SkillQueue/RequiredSkillBooksMissingWithNum', numBooks=len(missing)) 194 if available and numUnavailable: 195 text += '<br>%s' % GetByLabel('UI/SkillQueue/AvailableAndUnavailableSkillbooks', numAvailable=len(available), numUnavailable=numUnavailable) 196 label = EveLabelMedium(align=uiconst.CENTERLEFT, text=text, color=COLOR_SKILL_1) 197 grid.AddCell(label, colSpan=colSpan - 1) 198 btn = Button(align=uiconst.CENTERRIGHT, label=GetByLabel('UI/Skills/BuyAndTrain'), fixedheight=24, func=BuyAndTrain, args=(available, skillTypesAndLvlsToUse)) 199 if not available and numUnavailable: 200 btn.Disable() 201 if numUnavailable == 1: 202 btn.hint = GetByLabel('UI/Skills/ErrorRareSkill') 203 else: 204 btn.hint = GetByLabel('UI/Skills/ErrorRareSkills') 205 grid.AddCell(btn, cellPadding=(10, 0, 0, 0)) 206 207 208 def GetTypesWithMissingSkills(typeIDs): 209 typesWithMissingSkills = set() 210 for eachTypeID in typeIDs: 211 isMet = sm.GetService('skills').IsSkillRequirementMetIncludingSkillQueue(eachTypeID) 212 if not isMet: 213 typesWithMissingSkills.add(eachTypeID) 214 215 return typesWithMissingSkills 216 217 218 def GetMissingSkillbooksForTypeIDs(typeIDs): 219 allMissingSkillbooks = set() 220 for eachTypeID in typeIDs: 221 itemObject = ItemObject(eachTypeID) 222 missingSkillbooks = itemObject.GetMissingSkillBooks() 223 allMissingSkillbooks.update(missingSkillbooks) 224 225 return allMissingSkillbooks 226 227 228 def GetMissingSkills_HighestLevelByTypeID(typeIDs): 229 skillsSvc = sm.GetService('skills') 230 highestLevelByTypeID = defaultdict(int) 231 missingSkillsForTypeID = defaultdict(set) 232 for eachTypeID in typeIDs: 233 if not evetypes.Exists(eachTypeID) or evetypes.GetCategoryID(eachTypeID) == categoryBlueprint: 234 continue 235 allMissing = skillsSvc.GetSkillsMissingToUseItemRecursive(eachTypeID) 236 for skillTypeID, skillLevel in allMissing.iteritems(): 237 highestLevelByTypeID[skillTypeID] = int(max(skillLevel, highestLevelByTypeID[skillTypeID])) 238 missingSkillsForTypeID[eachTypeID].add(skillTypeID) 239 240 return (highestLevelByTypeID, missingSkillsForTypeID) 241 242 243 def GetSkillTypeIDAndLevelRequired(typeID): 244 ret = [] 245 _GetSkillTypeIDAndLevelRequired(typeID, ret) 246 return ret 247 248 249 class TrainNowButtonManyTypes(PrimaryButton): 250 default_name = 'TrainNowButton' 251 252 def ApplyAttributes(self, attributes): 253 super(TrainNowButtonManyTypes, self).ApplyAttributes(attributes) 254 self.skillTypesAndLvlsToUse = attributes.skillTypesAndLvlsToUse 255 self._isFinished = False 256 self.UpdateState() 257 258 def IsActive(self): 259 return not self._isFinished 260 261 def ClickFunc(self, *args): 262 self.Disable() 263 try: 264 for eachTypeID, eachLvl in self.skillTypesAndLvlsToUse.iteritems(): 265 sm.GetService('skillqueue').AddSkillAndRequirementsToQueue(eachTypeID, eachLvl) 266 267 self._isFinished = True 268 except Exception: 269 self.Enable() 270 271 self.UpdateState() 272 273 def GetColor(self): 274 if self._isFinished: 275 return (1.0, 1.0, 1.0, 0.3) 276 else: 277 return COLOR_SKILL_2 278 279 def GetText(self): 280 if self._isFinished: 281 return GetByLabel('UI/SkillQueue/SkillQueueUpdated') 282 else: 283 return GetByLabel('UI/SkillQueue/AddToQueue') 284 285 def GetTranslation(self): 286 return 0.1667 287 288 def Update_Size_(self): 289 PrimaryButton.Update_Size_(self) 290 self.width = max(self.fixedwidth, self.sr.label.width + 20) 291 292 293 def BuyAndTrain(availableForPurchase, skillTypesAndLvlsToUse): 294 skillSvc = sm.GetService('skills') 295 boughtSkills = skillSvc.PurchaseSkills(availableForPurchase) 296 if not boughtSkills: 297 return 298 skillSvc.WaitUntilSkillsAreAvailable(availableForPurchase) 299 skillqueueSvc = sm.GetService('skillqueue') 300 for eachTypeID, eachLvl in skillTypesAndLvlsToUse.iteritems(): 301 skillqueueSvc.AddSkillAndRequirementsToQueue(eachTypeID, eachLvl)