applySkillPointsWindow.py (16591B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\skilltrading\applySkillPointsWindow.py 2 import telemetry 3 import evetypes 4 import localization 5 import uthread2 6 from carbon.client.script.environment.AudioUtil import PlaySound 7 from carbon.common.script.util.format import IntToRoman 8 from carbon.common.script.util.timerstuff import AutoTimer 9 from carbonui import uiconst, fontconst 10 from carbonui.control.scrollContainer import ScrollContainer 11 from carbonui.control.scrollentries import SE_BaseClassCore 12 from carbonui.primitives.container import Container 13 from carbonui.primitives.containerAutoSize import ContainerAutoSize 14 from carbonui.primitives.frame import Frame 15 from carbonui.primitives.sprite import Sprite 16 from carbonui.uianimations import animations 17 from carbonui.util.color import Color 18 from characterskills import GetSPForLevelRaw 19 from characterskills.util import GetLevelProgress 20 from carbonui.button.group import ButtonGroup 21 from eve.client.script.ui.control.eveLabel import Label, EveLabelMedium 22 from carbonui.control.window import Window 23 from eve.client.script.ui.control.gauge import Gauge 24 from skills.skillConst import ICON_BY_GROUPID 25 from eve.client.script.ui.shared.neocom.skillConst import COLOR_UNALLOCATED_1 26 from gametime import GetWallclockTime 27 28 class ApplySkillPointsWindow(Window): 29 default_windowID = 'ApplySkillPointsWindow' 30 default_captionLabelPath = 'UI/SkillTrading/ApplySkillPointsWindowCaption' 31 default_iconNum = 'res:/UI/Texture/WindowIcons/augmentations.png' 32 default_width = 600 33 default_height = 350 34 default_fixedWidth = 600 35 default_minSize = (600, 200) 36 default_clipChildren = True 37 default_isCollapseable = False 38 default_isLightBackgroundConfigurable = False 39 default_isStackable = False 40 default_isLockable = False 41 default_isOverlayable = False 42 default_isMinimizable = False 43 __notifyevents__ = ['OnClientEvent_SkillAddedToQueue', 44 'OnClientEvent_SkillPrioritized', 45 'OnClientEvent_SkillsRemovedFromQueue', 46 'OnFreeSkillPointsChanged_Local', 47 'OnSkillsChanged'] 48 49 def ApplyAttributes(self, attributes): 50 super(ApplySkillPointsWindow, self).ApplyAttributes(attributes) 51 self.skillTypeIDsAndLevels = attributes.get('skillTypeIDsAndLevels', None) 52 self.mainArea = self.GetMainArea() 53 self.skillQueueSvc = sm.GetService('skillqueue') 54 self.skillSvc = sm.GetService('skills') 55 self.skillEntriesByTypeIDAndLevel = {} 56 self.isSaving = False 57 self.isApplying = False 58 self.isFinished = False 59 self.skillPointsToBeUsed = 0 60 self.SaveChanges(activate=self.IsTraining()) 61 self.ConstructLayout() 62 self.PopulateScroll() 63 self.SetDescriptionLabel() 64 65 def CloseByUser(self, *args): 66 if not self.skillQueueSvc.IsTransactionOpen(): 67 self.skillQueueSvc.BeginTransaction() 68 super(ApplySkillPointsWindow, self).CloseByUser() 69 70 def ConstructLayout(self): 71 self.HideHeader() 72 self.ConstructHeader() 73 self.ConstructFooter() 74 self.mainContainer = Container(name='MainContainer', parent=self.mainArea, padding=(4, 0, 4, 0)) 75 descriptionCont = Container(name='DescriptionCont', parent=self.mainContainer, align=uiconst.TOTOP, height=50) 76 self.descriptionLabel = EveLabelMedium(name='Description', parent=descriptionCont, align=uiconst.CENTER) 77 self.scrollContainer = ScrollContainer(name='SkillEntryScroll', parent=self.mainContainer, align=uiconst.TOALL) 78 79 def ConstructHeader(self): 80 headerContainer = Container(name='HeaderContainer', parent=self.mainArea, align=uiconst.TOTOP, height=35, bgColor=(0.133, 0.133, 0.141, 0.7), padding=(4, 4, 4, 0)) 81 iconContainer = Container(name='IconContainer', parent=headerContainer, align=uiconst.TOLEFT, width=32, height=32) 82 Sprite(name='ApplySkillsIcon', parent=iconContainer, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=26, height=26, left=5, opacity=0.7, texturePath='res:/UI/Texture/classes/skilltrading/applySkillpoints.png') 83 labelContainer = ContainerAutoSize(name='HeaderLabelContainer', parent=headerContainer, align=uiconst.TOLEFT, left=10) 84 Label(name='ApplySkillsWindowCaption', parent=labelContainer, align=uiconst.CENTERLEFT, text=localization.GetByLabel('UI/SkillTrading/ApplySkillPointsWindowCaption')) 85 86 def ConstructFooter(self): 87 footerContainer = Container(name='footerContainer', parent=self.mainArea, align=uiconst.TOBOTTOM, height=35, bgColor=(0.133, 0.133, 0.141, 0.7), padding=(4, 0, 4, 4)) 88 self.buttonGroup = ButtonGroup(name='buttonGroup', parent=footerContainer, align=uiconst.CENTER) 89 self.buttonGroup.AddButton(localization.GetByLabel('UI/SkillTrading/ConfirmInjectionLabel'), self.ApplySkillPoints, uiName='confirm_skill_injection') 90 self.buttonGroup.AddButton(localization.GetByLabel('UI/SkillTrading/CancelInjectionLabel'), self.CloseByUser, uiName='cancel_skill_injection') 91 92 def SetDescriptionLabel(self): 93 self.descriptionLabel.SetText(localization.GetByLabel('UI/SkillTrading/ApplySkillPointsDescription', color=Color.RGBtoHex(*COLOR_UNALLOCATED_1), points=self.skillPointsToBeUsed, amount=len(self.skillEntriesByTypeIDAndLevel))) 94 95 def _GetPointsBySkillTypeID(self): 96 handler = self.skillSvc.GetSkillHandler() 97 if self.skillTypeIDsAndLevels is None: 98 return handler.GetFreeSkillPointsAppliedToQueue() 99 return handler.GetFreeSkillPointsAppliedToSkills(self.skillTypeIDsAndLevels) 100 101 def _GetIterationSet(self): 102 if self.skillTypeIDsAndLevels is None: 103 return [ (s.trainingTypeID, s.trainingToLevel) for s in self.skillQueueSvc.GetQueue() ] 104 return self.skillTypeIDsAndLevels 105 106 def PopulateScroll(self): 107 pointsBySkillTypeID = self._GetPointsBySkillTypeID() 108 if not pointsBySkillTypeID: 109 self.buttonGroup.buttons[0].Disable() 110 else: 111 self.buttonGroup.buttons[0].Enable() 112 levelAndProgressBySkillTypeID = self.skillQueueSvc.GetSkillLevelAndProgressWithFreePoints(pointsBySkillTypeID) 113 self.skillPointsToBeUsed = sum(pointsBySkillTypeID.itervalues()) 114 queue = self.skillQueueSvc.GetQueue() 115 for skillID, skillLevel in self._GetIterationSet(): 116 levelReachedWithFreePoints, progressWithFreePoints = levelAndProgressBySkillTypeID[skillID] if skillID in levelAndProgressBySkillTypeID else (0, 0) 117 if (skillID, skillLevel) in self.skillEntriesByTypeIDAndLevel: 118 continue 119 entry = ApplySkillPointsListEntry(parent=self.scrollContainer, align=uiconst.TOTOP, skillTypeID=skillID, progressWithFreePoints=progressWithFreePoints, levelReachedWithFreePoints=levelReachedWithFreePoints, trainingToLevel=skillLevel) 120 self.skillEntriesByTypeIDAndLevel[skillID, skillLevel] = entry 121 122 @telemetry.ZONE_METHOD 123 def ApplySkillPoints(self, *args): 124 if self.isApplying: 125 return 126 self.isApplying = True 127 try: 128 self.AnimateBars() 129 isTraining = self.IsTraining() 130 self.SaveChanges(activate=isTraining) 131 if self.skillTypeIDsAndLevels is None: 132 self.skillQueueSvc.ApplyFreeSkillPointsToQueue() 133 else: 134 self.skillQueueSvc.ApplyFreeSkillPointsToSkills(self.skillTypeIDsAndLevels) 135 self.skillQueueSvc.BeginTransaction() 136 PlaySound('st_allocate_skillpoints_play') 137 finally: 138 self.isApplying = False 139 self.isFinished = True 140 animations.FadeOut(self.buttonGroup, callback=self.FlushButtonsAndCreateCloseButton) 141 142 def FlushButtonsAndCreateCloseButton(self): 143 self.buttonGroup.FlushButtons() 144 self.buttonGroup.AddButton(localization.GetByLabel('UI/SkillTrading/CloseInjectionLabel'), self.CloseByUser, uiName='close_skill_injection') 145 animations.FadeIn(self.buttonGroup) 146 147 def IsTraining(self): 148 return self.skillQueueSvc.SkillInTraining() is not None 149 150 def AnimateBars(self): 151 for entry in self.skillEntriesByTypeIDAndLevel.values(): 152 entry.OnSkillPointsApplied() 153 154 def Reconstruct(self): 155 if self.isApplying: 156 return 157 if self.isFinished: 158 return 159 self.skillEntriesByTypeIDAndLevel.clear() 160 self.scrollContainer.Flush() 161 self.PopulateScroll() 162 self.SetDescriptionLabel() 163 164 def OnClientEvent_SkillAddedToQueue(self, skillTypeID, skillLevel): 165 self.CloseByUser() 166 167 def OnClientEvent_SkillsRemovedFromQueue(self, skillRequirements): 168 self.CloseByUser() 169 170 def OnClientEvent_SkillPrioritized(self, skillTypeID): 171 self.CloseByUser() 172 173 def OnFreeSkillPointsChanged_Local(self): 174 if self.isApplying: 175 return 176 self.Reconstruct() 177 178 def OnSkillsChanged(self, skillInfo): 179 self.Reconstruct() 180 181 def SaveChanges(self, activate = True): 182 if self.isSaving: 183 return 184 self.isSaving = True 185 try: 186 self.skillQueueSvc.CommitTransaction(activate=activate) 187 finally: 188 self.isSaving = False 189 190 191 class ApplySkillPointsListEntry(SE_BaseClassCore): 192 default_name = 'ApplySkillPointsListEntry' 193 __guid__ = 'listentry.ApplySkillPointsListEntry' 194 default_height = 55 195 default_padTop = 10 196 default_padLeft = 5 197 default_padRight = 5 198 default_complete_color = (0.239, 0.647, 0.278, 0.7) 199 default_skillbook_green_color = (0.239, 0.647, 0.278, 1.0) 200 201 def ApplyAttributes(self, attributes): 202 super(ApplySkillPointsListEntry, self).ApplyAttributes(attributes) 203 self.skillTypeID = attributes.skillTypeID 204 self.levelReachedWithFreePoints = attributes.levelReachedWithFreePoints 205 self.trainingToLevel = attributes.trainingToLevel 206 self.progressWithFreePoints = attributes.progressWithFreePoints 207 self.applyingSkillPoints = False 208 self.skillSvc = sm.GetService('skills') 209 self.skillQueueSvc = sm.GetService('skillqueue') 210 self._progress = self.GetProgress() 211 self.AdjustProgressWithFreePoints() 212 self.ConstructLayout() 213 self.SetSkillName() 214 self.SetSkillGroupIcon() 215 self.SetGaugesToCurrentProgress() 216 self.Update() 217 self.timeSavedUpdateThread = AutoTimer(method=self.Update, interval=1000) 218 219 def AdjustProgressWithFreePoints(self): 220 if self.levelReachedWithFreePoints >= self.trainingToLevel: 221 self.progressWithFreePoints = 1.0 222 elif self.levelReachedWithFreePoints + 1 < self.trainingToLevel: 223 self.progressWithFreePoints = 0.0 224 225 def ConstructLayout(self): 226 iconCont = ContainerAutoSize(name='iconCont', parent=self, align=uiconst.TOLEFT) 227 self.skillGroupIcon = Sprite(name='SkillGroupIcon', parent=iconCont, align=uiconst.CENTERTOP, width=32, height=32) 228 skillBookIconCont = ContainerAutoSize(name='skillBookIconCont', parent=self, align=uiconst.TORIGHT) 229 self.skillBookIcon = Sprite(parent=skillBookIconCont, align=uiconst.CENTERTOP, width=32, height=32, texturePath='res:/UI/Texture/Classes/Skills/doNotHave.png') 230 middleCont = Container(name='MiddleContainer', parent=self, align=uiconst.TOALL, pos=(10, 0, 5, 0)) 231 gaugeCont = Container(name='GaugeContainer', parent=middleCont, align=uiconst.TOTOP, height=32) 232 Frame(parent=gaugeCont, texturePath='res:/UI/Texture/classes/skilltrading/frame.png', cornerSize=3, opacity=0.5) 233 self.skillName = Label(name='SkillName', parent=gaugeCont, align=uiconst.CENTER) 234 self.alreadyTrainedGauge = Gauge(name='alreadyTrainedGauge', parent=gaugeCont, align=uiconst.TOTOP_NOPUSH, state=uiconst.UI_DISABLED, height=30, gaugeHeight=30, top=1, color=COLOR_UNALLOCATED_1, opacity=0.7, backgroundColor=(1.0, 1.0, 0.0, 0.0)) 235 self.aboutToBeTrainedGauge = Gauge(name='aboutToBeTrainedGauge', parent=gaugeCont, align=uiconst.TOTOP_NOPUSH, state=uiconst.UI_DISABLED, height=30, gaugeHeight=30, top=1, color=(0.21, 0.62, 0.74, 0.4), backgroundColor=(1.0, 1.0, 0.0, 0.0)) 236 timeSavedContainer = Container(name='timeSavedContainer', parent=middleCont, align=uiconst.TOALL, top=3) 237 Frame(parent=timeSavedContainer, texturePath='res:/UI/Texture/classes/skilltrading/frame.png', cornerSize=3, opacity=0.5) 238 self.timeSavedLabel = Label(name='timeSavedLabel', parent=timeSavedContainer, align=uiconst.CENTER, fontsize=fontconst.EVE_SMALL_FONTSIZE, opacity=0.7) 239 self.percentageTrainedLabel = Label(name='percentageTrainedLabel', parent=timeSavedContainer, align=uiconst.CENTERRIGHT, fontsize=fontconst.EVE_SMALL_FONTSIZE, left=5) 240 241 @property 242 def progress(self): 243 if self.applyingSkillPoints: 244 return self._progress 245 else: 246 return self.GetProgress() 247 248 @progress.setter 249 def progress(self, value): 250 self._progress = value 251 self.UpdateProgressLabel() 252 253 def Close(self): 254 self.timeSavedUpdateThread = None 255 super(ApplySkillPointsListEntry, self).Close() 256 257 def Update(self): 258 self.UpdateLabels() 259 self.UpdateAlreadyTrainedGauge() 260 self.UpdateAboutToBeTrainedGauge() 261 262 def SetSkillGroupIcon(self): 263 self.skillGroupIcon.SetTexturePath(ICON_BY_GROUPID.get(evetypes.GetGroupID(self.skillTypeID))) 264 265 def SetSkillName(self): 266 self.skillName.SetText('%s %s' % (evetypes.GetName(self.skillTypeID), IntToRoman(self.trainingToLevel))) 267 268 def UpdateAboutToBeTrainedGauge(self): 269 self.aboutToBeTrainedGauge.SetValue(self.progressWithFreePoints, animate=False) 270 271 def UpdateAlreadyTrainedGauge(self): 272 self.alreadyTrainedGauge.SetValue(self.progress, animate=False) 273 274 def SetGaugesToCurrentProgress(self): 275 self.alreadyTrainedGauge.SetValue(self.progress, animate=False) 276 self.aboutToBeTrainedGauge.SetValue(self.progress, animate=False) 277 278 def GetProgress(self): 279 progress = 0 280 currentSkillLevel = self.skillSvc.MySkillLevel(self.skillTypeID) 281 if currentSkillLevel == self.trainingToLevel - 1 and self.skillQueueSvc.FindInQueue(self.skillTypeID, self.trainingToLevel) == 0: 282 currentPoints = self.skillQueueSvc.GetEstimatedSkillPointsTrained(self.skillTypeID) 283 rank = self.skillSvc.GetSkillRank(self.skillTypeID) 284 progress = GetLevelProgress(currentPoints, rank) 285 return progress 286 287 def OnSkillPointsApplied(self): 288 self.applyingSkillPoints = True 289 self.timeSavedUpdateThread = None 290 self.AlignGauges() 291 animations.MorphScalar(self, 'progress', startVal=self.progress, endVal=self.progressWithFreePoints, callback=lambda : setattr(self, 'progress', self.progressWithFreePoints)) 292 293 def AlignGauges(self): 294 self.alreadyTrainedGauge.SetValueTimed(value=self.aboutToBeTrainedGauge.value, duration=0.6, callback=self.OnGaugeProgressSet) 295 296 def OnGaugeProgressSet(self): 297 if self.progressWithFreePoints == 1.0: 298 self.alreadyTrainedGauge.SetColor(self.default_complete_color, animDuration=0.3) 299 self.skillBookIcon.SetTexturePath('res:/UI/Texture/Classes/Skills/skillTrainingComplete.png') 300 self.skillBookIcon.SetRGBA(*self.default_skillbook_green_color) 301 animations.FadeTo(self.alreadyTrainedGauge, startVal=1.0, endVal=1.0, curveType=uiconst.ANIM_OVERSHOT3) 302 303 def GetTimeSaved(self): 304 skill = self.skillSvc.GetSkill(self.skillTypeID) 305 trainingTimeCalculator = self.skillSvc.GetSkillTrainingTimeCalculator() 306 skillPointsPreviousLevel = GetSPForLevelRaw(skill.skillRank, self.trainingToLevel - 1) 307 _, totalTimeToTrain = trainingTimeCalculator.get_skill_points_and_time_to_train_given_existing_skill_points(self.skillTypeID, self.trainingToLevel, GetWallclockTime(), skillPointsPreviousLevel) 308 return (self.progressWithFreePoints - self.progress) * totalTimeToTrain 309 310 def UpdateLabels(self): 311 self.UpdateTimeSavedLabel() 312 self.UpdateProgressLabel() 313 314 def UpdateTimeSavedLabel(self): 315 text = localization.GetByLabel('UI/SkillTrading/EstimatedSkillTimeSaved', timeSaved=long(self.GetTimeSaved())) 316 self.timeSavedLabel.SetText(text) 317 318 def UpdateProgressLabel(self): 319 text = localization.GetByLabel('UI/SkillTrading/SkillProgressLabel', progress=round(self.progress * 100, 1), progressWithFreePoints=round(self.progressWithFreePoints * 100, 1)) 320 self.percentageTrainedLabel.SetText(text)