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

attributes.py (19448B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\neocom\attributes.py
      2 import blue
      3 from carbon.common.script.util.format import FmtDate
      4 from carbonui.control.scrollentries import SE_BaseClassCore
      5 from carbonui.primitives.containerAutoSize import ContainerAutoSize
      6 from characterskills.attribute import ATTRIBUTEBONUS_BY_ATTRIBUTEID
      7 from carbonui.primitives.container import Container
      8 from carbonui.primitives.layoutGrid import LayoutGrid
      9 from carbonui.primitives.line import Line
     10 from dogma.effects import IsBoosterSkillAccelerator
     11 from eve.client.script.ui.control import eveIcon, eveLabel
     12 from carbonui.button.group import ButtonGroup
     13 from carbonui.control.button import Button
     14 from eve.client.script.ui.control.clickableboxbar import ClickableBoxBar
     15 from eve.client.script.ui.control.eveLabel import EveLabelMedium
     16 from carbonui.control.window import Window
     17 from eve.client.script.ui.control.infoIcon import MoreInfoIcon
     18 from eve.client.script.ui.control.themeColored import SpriteThemeColored
     19 from eve.common.lib import appConst as const
     20 from eveexceptions import UserError
     21 from fsdBuiltData.common.iconIDs import GetIconFile
     22 import uthread
     23 import carbonui.const as uiconst
     24 import localization
     25 import evetypes
     26 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     27 
     28 class AttributeRespecWindow(Window):
     29     __guid__ = 'form.attributeRespecWindow'
     30     default_windowID = 'attributerespecification'
     31     default_iconNum = 'res:/ui/Texture/WindowIcons/attributes.png'
     32     default_minSize = (450, 450)
     33     default_captionLabelPath = 'UI/CharacterSheet/CharacterSheetWindow/Attributes/NeuralRemapping'
     34 
     35     def ApplyAttributes(self, attributes):
     36         super(AttributeRespecWindow, self).ApplyAttributes(attributes)
     37         self.readOnly = attributes.readOnly
     38         self.MakeUnResizeable()
     39         self.godma = sm.StartService('godma')
     40         self.skillHandler = sm.StartService('skills').GetSkillHandler()
     41         self.main_cont = ContainerAutoSize(parent=self.content, align=uiconst.TOTOP, callback=self._on_main_cont_size_changed, only_use_callback_when_size_changes=True)
     42         self.attributes = [const.attributePerception,
     43          const.attributeMemory,
     44          const.attributeWillpower,
     45          const.attributeIntelligence,
     46          const.attributeCharisma]
     47         self.implantTypes = [19540,
     48          19551,
     49          19553,
     50          19554,
     51          19555]
     52         self.attributeIcons = ['ui_22_32_5',
     53          'ui_22_32_4',
     54          'ui_22_32_2',
     55          'ui_22_32_3',
     56          'ui_22_32_1']
     57         self.attributeLabels = [localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/AttributePerception'),
     58          localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/AttributeMemory'),
     59          localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/AttributeWillpower'),
     60          localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/AttributeIntelligence'),
     61          localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/AttributeCharisma')]
     62         self.currentAttributes = {}
     63         self.implantModifier = {}
     64         self.unspentPts = 0
     65         self.ConstructLayout()
     66         self.Load()
     67 
     68     def Load(self, *args):
     69         if not session.charid or self.destroyed:
     70             return
     71         dogmaLM = sm.GetService('clientDogmaIM').GetDogmaLocation()
     72         skillSvc = sm.StartService('skills')
     73         dogmaStaticMgr = dogmaLM.dogmaStaticMgr
     74         attrDict = skillSvc.GetCharacterAttributes()
     75         unspentPts = const.respecTotalRespecPoints
     76         for x in xrange(0, 5):
     77             attr = self.attributes[x]
     78             if attr in attrDict:
     79                 attrValue = attrDict[attr]
     80                 implantBonus = 0
     81                 implants = skillSvc.GetImplants()
     82                 boosters = skillSvc.GetBoosters()
     83                 for implantSlot, implant in implants.iteritems():
     84                     implantBonus += dogmaStaticMgr.GetTypeAttribute2(implant.typeID, ATTRIBUTEBONUS_BY_ATTRIBUTEID[attr])
     85 
     86                 boosterBonus = 0
     87                 for boosterTypeID, boosterRecord in boosters.iteritems():
     88                     if IsBoosterSkillAccelerator(dogmaStaticMgr, boosterRecord):
     89                         boosterBonus += dogmaStaticMgr.GetTypeAttribute2(boosterRecord.boosterTypeID, ATTRIBUTEBONUS_BY_ATTRIBUTEID[attr])
     90 
     91                 attrValue -= implantBonus
     92                 attrValue -= boosterBonus
     93                 if attrValue > const.respecMaximumAttributeValue:
     94                     attrValue = const.respecMaximumAttributeValue
     95                 if attrValue < const.respecMinimumAttributeValue:
     96                     attrValue = const.respecMinimumAttributeValue
     97                 self.currentAttributes[attr] = attrValue
     98                 self.respecBar[x].SetValue(attrValue - const.respecMinimumAttributeValue)
     99                 unspentPts -= attrValue
    100             totalAttributesText = localization.formatters.FormatNumeric(int(self.currentAttributes[attr]) + implantBonus, decimalPlaces=0)
    101             self.totalLabels[x].text = totalAttributesText
    102             self.implantModifier[x] = implantBonus
    103             label, icon = self.implantLabels[x]
    104             if implantBonus == 0:
    105                 icon.SetAlpha(0.5)
    106                 label.text = localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/ImplantBonusZero')
    107                 label.SetAlpha(0.5)
    108             else:
    109                 label.text = localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/ImplantBonus', implantBonus=int(implantBonus))
    110 
    111         if not self.readOnly:
    112             self.unspentPts = unspentPts
    113             self.sr.unassignedBar.SetValue(unspentPts)
    114             unspentPtsText = localization.formatters.FormatNumeric(self.unspentPts, decimalPlaces=0)
    115             self.availableLabel.text = unspentPtsText
    116             if self.unspentPts <= 0:
    117                 self.sr.saveWarningText.state = uiconst.UI_HIDDEN
    118             else:
    119                 self.sr.saveWarningText.state = uiconst.UI_DISABLED
    120 
    121     def ConstructLayout(self):
    122         self.implantLabels = []
    123         self.respecBar = []
    124         self.totalLabels = []
    125         iconsize = 32
    126         buttonSize = 24
    127         boxWidth = 6
    128         boxHeight = 12
    129         boxMargin = 1
    130         boxSpacing = 1
    131         numBoxes = const.respecMaximumAttributeValue - const.respecMinimumAttributeValue
    132         barWidth = numBoxes * boxSpacing + 2 * boxMargin + numBoxes * boxWidth - 1
    133         barHeight = boxHeight + 2 * boxMargin
    134         backgroundColor = (0.0, 0.0, 0.0, 0.0)
    135         colorDict = {ClickableBoxBar.COLOR_UNSELECTED: (0.2, 0.2, 0.2, 1.0),
    136          ClickableBoxBar.COLOR_SELECTED: (0.2, 0.8, 0.2, 1.0)}
    137         MoreInfoIcon(parent=self.header.extra_content, align=uiconst.CENTERLEFT, hint=localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/CharacterRespecMessage'))
    138         if self.readOnly:
    139             columns = 7
    140         else:
    141             columns = 9
    142         gridParent = ContainerAutoSize(parent=self.main_cont, align=uiconst.TOTOP)
    143         self.mainGrid = LayoutGrid(parent=gridParent, align=uiconst.CENTERTOP, columns=columns, cellPadding=4, OnGridSizeChanged=self._on_main_grid_size_changed)
    144         for labelPath, colSpan in (('UI/CharacterSheet/CharacterSheetWindow/NavScroll/Attributes', 2),
    145          ('UI/CharacterSheet/CharacterSheetWindow/Attributes/BaseStatPoints', 1),
    146          ('UI/CharacterSheet/CharacterSheetWindow/Attributes/CharacterImplants', 2),
    147          ('UI/CharacterSheet/CharacterSheetWindow/Attributes/RemappableStat', 1 if self.readOnly else 3),
    148          ('UI/CharacterSheet/CharacterSheetWindow/Attributes/StatTotal', 1)):
    149             label = EveLabelMedium(text=localization.GetByLabel(labelPath), align=uiconst.CENTER)
    150             self.mainGrid.AddCell(cellObject=label, colSpan=colSpan, cellPadding=(10, 2, 10, 2))
    151 
    152         line = Line(align=uiconst.TOTOP)
    153         self.mainGrid.AddCell(cellObject=line, colSpan=self.mainGrid.columns)
    154         for x in xrange(5):
    155             eveIcon.Icon(parent=self.mainGrid, width=iconsize, height=iconsize, size=iconsize, icon=self.attributeIcons[x], align=uiconst.TOPLEFT)
    156             EveLabelMedium(text=self.attributeLabels[x], parent=self.mainGrid, state=uiconst.UI_DISABLED, align=uiconst.CENTERLEFT)
    157             minText = localization.formatters.FormatNumeric(const.respecMinimumAttributeValue, decimalPlaces=0)
    158             EveLabelMedium(text=minText, parent=self.mainGrid, state=uiconst.UI_DISABLED, align=uiconst.CENTER, bold=True)
    159             icon = eveIcon.Icon(parent=self.mainGrid, width=32, height=32, size=32, icon=GetIconFile(evetypes.GetIconID(self.implantTypes[x])), align=uiconst.TOPLEFT, ignoreSize=True)
    160             implantLabel = EveLabelMedium(text='0', parent=self.mainGrid, align=uiconst.CENTERLEFT)
    161             self.implantLabels.append((implantLabel, icon))
    162             if not self.readOnly:
    163                 minusText = localization.GetByLabel('UI/Common/Buttons/Minus')
    164                 Button(parent=self.mainGrid, label=minusText, fixedwidth=buttonSize, func=self.DecreaseAttribute, args=(x,), align=uiconst.CENTERRIGHT)
    165             bar = Container(parent=self.mainGrid, align=uiconst.CENTER, width=barWidth, height=barHeight, state=uiconst.UI_PICKCHILDREN)
    166             bar = ClickableBoxBar(parent=bar, numBoxes=numBoxes, boxWidth=boxWidth, boxHeight=boxHeight, boxMargin=boxMargin, boxSpacing=boxSpacing, backgroundColor=backgroundColor, colorDict=colorDict)
    167             bar.OnValueChanged = self.OnMemberBoxClick
    168             bar.OnAttemptBoxClicked = self.ValidateBoxClick
    169             self.respecBar.append(bar)
    170             if not self.readOnly:
    171                 plusText = localization.GetByLabel('UI/Common/Buttons/Plus')
    172                 Button(parent=self.mainGrid, label=plusText, fixedwidth=buttonSize, func=self.IncreaseAttribute, args=(x,), align=uiconst.CENTERLEFT)
    173             totalLabel = EveLabelMedium(text='0', parent=self.mainGrid, left=8, align=uiconst.CENTERRIGHT, bold=True)
    174             self.totalLabels.append(totalLabel)
    175 
    176         if not self.readOnly:
    177             line = Line(align=uiconst.TOTOP)
    178             self.mainGrid.AddCell(cellObject=line, colSpan=self.mainGrid.columns)
    179             textObj = EveLabelMedium(text=localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/UnassignedAttributePoints'))
    180             self.mainGrid.AddCell(cellObject=textObj, colSpan=6)
    181             numBoxes = const.respecTotalRespecPoints - const.respecMinimumAttributeValue * 5
    182             barWidth = numBoxes * boxSpacing + 2 * boxMargin + numBoxes * boxWidth - 1
    183             unassignedBarParent = Container(align=uiconst.TOPLEFT, width=barWidth, height=barHeight, state=uiconst.UI_PICKCHILDREN)
    184             self.mainGrid.AddCell(cellObject=unassignedBarParent, colSpan=2)
    185             self.sr.unassignedBar = ClickableBoxBar(parent=unassignedBarParent, numBoxes=numBoxes, boxWidth=boxWidth, boxHeight=boxHeight, boxMargin=boxMargin, boxSpacing=boxSpacing, backgroundColor=backgroundColor, colorDict=colorDict, readonly=True, hintFormat='UI/CharacterSheet/CharacterSheetWindow/Attributes/UnassignedPointsHint')
    186             self.availableLabel = EveLabelMedium(parent=self.mainGrid, align=uiconst.CENTERRIGHT, left=8)
    187             self.mainGrid.FillRow()
    188             self.sr.saveWarningText = EveLabelMedium(text=localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/CannotSaveUnassignedPoints'), color=(1.0, 0.0, 0.0, 0.9))
    189             self.mainGrid.AddCell(cellObject=self.sr.saveWarningText, colSpan=self.mainGrid.columns)
    190         if not self.readOnly:
    191             ButtonGroup(btns=[[localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/SaveStatChanges'),
    192               self.SaveChanges,
    193               (),
    194               None], [localization.GetByLabel('UI/Common/Buttons/Cancel'),
    195               self.CloseByUser,
    196               (),
    197               None]], parent=self.main_cont, align=uiconst.TOTOP)
    198 
    199     def OnMainGridSizeChanged(self, width, height, *args, **kwds):
    200         self.SetMinSize([width + 12, height + self.headerText.height + 110], refresh=1)
    201 
    202     def _on_main_cont_size_changed(self):
    203         _, height = self.GetWindowSizeForContentSize(height=self.main_cont.height)
    204         self.SetMinSize(size=(self.GetMinWidth(), height), refresh=True)
    205 
    206     def _on_main_grid_size_changed(self, width, height):
    207         width, _ = self.GetWindowSizeForContentSize(width=width)
    208         self.SetMinSize(size=(width, self.GetMinHeight()), refresh=True)
    209 
    210     def SaveChanges(self, *args):
    211         totalAttrs = 0
    212         newAttributes = {}
    213         for x in xrange(0, 5):
    214             newAttributes[self.attributes[x]] = const.respecMinimumAttributeValue + self.respecBar[x].GetValue()
    215 
    216         for attrValue in newAttributes.itervalues():
    217             if attrValue < const.respecMinimumAttributeValue:
    218                 raise UserError('RespecAttributesTooLow')
    219             elif attrValue > const.respecMaximumAttributeValue:
    220                 raise UserError('RespecAttributesTooHigh')
    221             totalAttrs += attrValue
    222 
    223         if totalAttrs != const.respecTotalRespecPoints or self.sr.unassignedBar.GetValue() > 0:
    224             self.sr.saveWarningText.state = uiconst.UI_DISABLED
    225             raise UserError('RespecAttributesMisallocated')
    226         allSame = True
    227         for attr in self.attributes:
    228             if int(self.currentAttributes[attr]) != int(newAttributes[attr]):
    229                 allSame = False
    230                 break
    231 
    232         if not allSame:
    233             respecInfo = sm.GetService('skills').GetRespecInfo()
    234             freeRespecs = respecInfo['freeRespecs']
    235             if respecInfo['nextTimedRespec'] is None or respecInfo['nextTimedRespec'] <= blue.os.GetWallclockTime():
    236                 if prompt_player_fsd_dialog('ConfirmRespec2', {'months': int(const.respecTimeInterval / const.MONTH30)}, uiconst.YESNO) != uiconst.ID_YES:
    237                     return
    238             elif freeRespecs > 0:
    239                 if prompt_player_fsd_dialog('ConfirmRespecFree', {'freerespecs': int(respecInfo['freeRespecs']) - 1}, uiconst.YESNO) != uiconst.ID_YES:
    240                     return
    241             else:
    242                 raise UserError('RespecTooSoon', {'nextTime': respecInfo['nextTimedRespec']})
    243             self.skillHandler.RespecCharacter(newAttributes)
    244         self.CloseByUser()
    245 
    246     def IncreaseAttribute(self, attribute, *args):
    247         if self.respecBar[attribute].GetValue() >= const.respecMaximumAttributeValue - const.respecMinimumAttributeValue:
    248             return
    249         if self.unspentPts <= 0:
    250             raise UserError('RespecCannotIncrementNotEnoughPoints')
    251         if not self.respecBar[attribute].Increment():
    252             raise UserError('RespecAttributesTooHigh')
    253 
    254     def DecreaseAttribute(self, attribute, *args):
    255         if self.respecBar[attribute].GetValue() <= 0:
    256             return
    257         if not self.respecBar[attribute].Decrement():
    258             raise UserError('RespecAttributesTooLow')
    259 
    260     def ValidateBoxClick(self, oldValue, newValue):
    261         if self.readOnly:
    262             return False
    263         if oldValue >= newValue:
    264             return True
    265         if self.unspentPts < newValue - oldValue:
    266             return False
    267         return True
    268 
    269     def OnMemberBoxClick(self, oldValue, newValue):
    270         if oldValue is None or oldValue == newValue:
    271             return
    272         if self.readOnly:
    273             return
    274         self.unspentPts -= newValue - oldValue
    275         self.sr.unassignedBar.SetValue(self.unspentPts)
    276         unspentPtsText = localization.formatters.FormatNumeric(self.unspentPts, decimalPlaces=0)
    277         self.availableLabel.text = unspentPtsText
    278         for x in xrange(0, 5):
    279             totalPts = const.respecMinimumAttributeValue + self.respecBar[x].GetValue() + self.implantModifier[x]
    280             totalPtsText = localization.formatters.FormatNumeric(int(totalPts), decimalPlaces=0)
    281             self.totalLabels[x].text = totalPtsText
    282 
    283         if self.unspentPts <= 0:
    284             self.sr.saveWarningText.state = uiconst.UI_HIDDEN
    285 
    286 
    287 class AttributeRespecEntry(SE_BaseClassCore):
    288     __guid__ = 'listentry.AttributeRespec'
    289     default_showHilite = False
    290 
    291     def Startup(self, *args):
    292         self.OnSelectCallback = None
    293         self.sr.label = eveLabel.EveLabelSmall(parent=self, left=8, top=4, text=localization.GetByLabel('UI/Neocom/NextDNAModification'), maxLines=1)
    294         self.sr.respecTime = eveLabel.EveLabelMedium(parent=self, left=8, top=18, text='', maxLines=1)
    295         self.sr.numberOfRemaps = eveLabel.EveLabelMedium(parent=self, state=uiconst.UI_HIDDEN, left=8, top=38, text='', maxLines=1)
    296         self.sr.respecButton = Button(parent=self, label=localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/RemapStatsNow'), align=uiconst.TOPRIGHT, func=self.OpenRespecWindow, args=(False,))
    297         self.hint = localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/CharacterSheetHint')
    298 
    299     def Load(self, node):
    300         self.sr.node = node
    301         freeRespecs = node.Get('freeRespecs', 0)
    302         nextRespecTime = node.Get('nextTimedRespec', None)
    303         canRemap = False
    304         if nextRespecTime is None or nextRespecTime <= blue.os.GetWallclockTime():
    305             self.sr.respecTime.text = localization.GetByLabel('UI/Generic/Now')
    306             canRemap = True
    307         else:
    308             self.sr.respecTime.text = FmtDate(node.nextTimedRespec)
    309             self.refreshThread = uthread.new(self.RefreshThread)
    310         if freeRespecs > 0:
    311             canRemap = True
    312             lbl = localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/BonusRemapsAvailable', remapsAvailable=freeRespecs)
    313             self.sr.numberOfRemaps.text = lbl
    314             if nextRespecTime is not None and nextRespecTime > blue.os.GetWallclockTime():
    315                 self.hint = localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/CharacterSheetHintFree')
    316             else:
    317                 self.hint = localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/CharacterSheetHintFreeTimed')
    318             self.sr.numberOfRemaps.state = uiconst.UI_DISABLED
    319         if not canRemap:
    320             self.sr.respecButton.SetLabel(localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/Attributes/AttributesOverview'))
    321             self.sr.respecButton.args = (True,)
    322 
    323     def OpenRespecWindow(self, readOnly, *args):
    324         wnd = AttributeRespecWindow.GetIfOpen()
    325         if wnd is not None and not wnd.destroyed:
    326             wnd.Maximize()
    327         else:
    328             AttributeRespecWindow.Open(readOnly=readOnly)
    329 
    330     def RefreshThread(self):
    331         if not self or self.destroyed:
    332             return
    333         sleepMsec = max(self.sr.node.nextTimedRespec - blue.os.GetWallclockTime(), 0) / 10000
    334         sleepMsec = min(sleepMsec, 60000)
    335         while sleepMsec > 0:
    336             blue.pyos.synchro.SleepWallclock(sleepMsec)
    337             if not self or self.destroyed:
    338                 return
    339             sleepMsec = max(self.sr.node.nextTimedRespec - blue.os.GetWallclockTime(), 0) / 10000
    340             sleepMsec = min(sleepMsec, 60000)
    341 
    342         if not self or self.destroyed:
    343             return
    344         self.sr.respecButton.state = uiconst.UI_NORMAL
    345         self.sr.respecTime.text = localization.GetByLabel('UI/Generic/Now')