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

controller.py (13695B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\crate\controller.py
      2 from crates import CratesStaticData
      3 from crates.const import MAX_MULTI_OPEN
      4 from player_messaging.client.ui_message import message_player
      5 from eve.client.script.ui.crate.lootItem import LootItemFromType, SkillBundleLootItem, FittingLootItem, InsuranceLootItem
      6 from localization import GetByMessageID, GetByLabel
      7 from log import LogException
      8 from random import shuffle
      9 from signals import Signal
     10 
     11 class Texture(object):
     12 
     13     def __init__(self, data):
     14         self.width = data.width
     15         self.height = data.height
     16         self.resPath = data.resPath
     17         self.color = getattr(data, 'color', None)
     18 
     19 
     20 class HackingCrateController(object):
     21     __notifyevents__ = ['ProcessSessionChange']
     22 
     23     def __init__(self, typeID, itemID, stacksize):
     24         self.typeID = typeID
     25         self.itemID = itemID
     26         self.stacksize = stacksize
     27         self.isOpening = False
     28         self.loot = None
     29         self.specialLoot = None
     30         self.destinationID = None
     31         self.destinationFlagID = None
     32         self.onFinish = Signal(signalName='onFinish')
     33         self.onOpen = Signal(signalName='onOpen')
     34         self.onSkip = Signal(signalName='onSkip')
     35         self.onCrateMultiHackEnded = Signal(signalName='onCrateMultiHackEnded')
     36         sm.RegisterNotify(self)
     37 
     38     @property
     39     def staticData(self):
     40         return CratesStaticData().get_crate_by_type_id(self.typeID)
     41 
     42     @property
     43     def caption(self):
     44         return GetByMessageID(self.staticData.nameID)
     45 
     46     @property
     47     def description(self):
     48         return GetByMessageID(self.staticData.descriptionID)
     49 
     50     @property
     51     def animatedSplash(self):
     52         if self.staticData.animatedSplash:
     53             return Texture(self.staticData.animatedSplash)
     54 
     55     @property
     56     def staticSplash(self):
     57         if self.staticData.staticSplash:
     58             return Texture(self.staticData.staticSplash)
     59 
     60     def LoadLootFromTypes(self, loot):
     61         shuffle(loot)
     62         return [ LootItemFromType(itemID, typeID, quantity, self.destinationID, self.destinationFlagID) for itemID, typeID, quantity in loot ]
     63 
     64     def LoadSpecialLoot(self):
     65         specialLoot = []
     66         fitting_ids = getattr(self.staticData, 'fittings', []) or []
     67         for fitting_id in fitting_ids:
     68             name, icon, ship_type_id, insurance = sm.RemoteSvc('ship').GetShipFittingInfo(fitting_id)
     69             if insurance:
     70                 specialLoot.append(InsuranceLootItem(self.itemID, ship_type_id, insurance))
     71             specialLoot.append(FittingLootItem(self.itemID, fitting_id, name, icon))
     72 
     73         skillBundleID = getattr(self.staticData, 'skillBundleID', None)
     74         if skillBundleID:
     75             specialLoot.append(SkillBundleLootItem(self.itemID, skillBundleID))
     76         return specialLoot
     77 
     78     def OpenCrate(self):
     79         if self.stacksize <= 0:
     80             raise RuntimeError('No more crates')
     81         self.isOpening = True
     82         self.stacksize -= 1
     83         try:
     84             self.destinationID, self.destinationFlagID = sm.RemoteSvc('crateService').GetCrateLocation(self.itemID)
     85             loot = sm.RemoteSvc('crateService').OpenCrate(self.itemID)
     86             sm.ScatterEvent('OnClientEvent_CrateOpen', self.typeID)
     87             self.loot = self.LoadLootFromTypes(loot)
     88             self.specialLoot = self.LoadSpecialLoot()
     89             self.onOpen()
     90         except Exception:
     91             self.stacksize += 1
     92             self.isOpening = False
     93             raise
     94 
     95     def OpenMultipleCrates(self):
     96         qty = min(MAX_MULTI_OPEN, self.stacksize)
     97         cratesOpened = 0
     98         numCratesToOpen = qty
     99         try:
    100             cratesOpened, numCratesToOpen = sm.RemoteSvc('crateService').ClaimLootFromCrateStack(self.itemID, qty)
    101         except UserError as e:
    102             if e.msg in ('MultipleCrateOpenAbortedDueToTidiCratesOpened', 'MultipleCrateOpenAbortedDueToTidiCratesOpened'):
    103                 if e.msg == 'MultipleCrateOpenAbortedDueToTidiCratesOpened':
    104                     cratesOpened = e.dict['numCratesOpened']
    105                     self.stacksize -= cratesOpened
    106             elif e.msg == 'FailedOpeningMultiCrate':
    107                 cratesOpened = e.dict['numCratesOpened']
    108                 self.stacksize -= cratesOpened
    109             raise
    110         finally:
    111             self.onCrateMultiHackEnded(cratesOpened, numCratesToOpen)
    112 
    113         self.ShowResultMessage(cratesOpened, numCratesToOpen)
    114         self.stacksize -= cratesOpened
    115         if cratesOpened:
    116             sm.ScatterEvent('OnClientEvent_CrateOpen', self.typeID)
    117 
    118     def ShowResultMessage(self, cratesOpened, numCratesToOpen):
    119         if cratesOpened == numCratesToOpen:
    120             message_player(GetByLabel('UI/Crate/NumCratesSuccessfullyHacked', numCrates=cratesOpened))
    121         else:
    122             message_player(GetByLabel('UI/Crate/NumCratesHacked', numCrates=cratesOpened, numCratesToOpen=numCratesToOpen))
    123 
    124     def IsAnyLootLeft(self):
    125         return self.loot or self.specialLoot
    126 
    127     def ClaimLoot(self):
    128         if not self.IsAnyLootLeft():
    129             raise ValueError('No loot to claim')
    130         item = None
    131         if self.loot:
    132             item = self.loot.pop()
    133             item.claim()
    134         elif self.specialLoot:
    135             item = self.specialLoot.pop()
    136             item.claim()
    137         if not self.IsAnyLootLeft():
    138             self.isOpening = False
    139         return item
    140 
    141     def ClaimAllLoot(self):
    142         while self.loot:
    143             item = self.loot.pop()
    144             try:
    145                 item.claim()
    146             except Exception:
    147                 LogException('Error claiming loot item %s' % item.get_name())
    148 
    149         while self.specialLoot:
    150             item = self.specialLoot.pop()
    151             try:
    152                 item.claim()
    153             except Exception:
    154                 LogException('Error claiming special loot item %s' % item.get_name())
    155 
    156     def Finish(self):
    157         self.onFinish()
    158 
    159     def Close(self):
    160         sm.UnregisterNotify(self)
    161         self.ClaimAllLoot()
    162         self.onFinish.clear()
    163         self.onOpen.clear()
    164 
    165     def ProcessSessionChange(self, isremote, session, change):
    166         self.Finish()
    167 
    168     def GetSortedLoot(self):
    169         return self.loot
    170 
    171     def GetSpecialLoot(self):
    172         return self.specialLoot
    173 
    174 
    175 class FixedCrateStackController(object):
    176 
    177     def __init__(self, crate_stack_list):
    178         self.lootByType = {}
    179         self.controllers = []
    180         self.loot = None
    181         self.specialLoot = None
    182         self.crate_stack_list = crate_stack_list
    183         self.crate_list_index = 0
    184         self.onFinish = Signal(signalName='onFinish')
    185         self.onOpen = Signal(signalName='onOpen')
    186         self.onSkip = Signal(signalName='onSkip')
    187         self.destinationID = None
    188         self.destinationFlagID = None
    189         self.onCrateMultiOpenEnded = Signal(signalName='onCrateMultiOpenEnded')
    190 
    191     @property
    192     def staticData(self):
    193         typeID, itemID, stacksize = self.crate_stack_list[self.crate_list_index]
    194         return CratesStaticData().get_crate_by_type_id(typeID)
    195 
    196     @property
    197     def lootViewDescription(self):
    198         return GetByMessageID(self.staticData.lootDescriptionID)
    199 
    200     @property
    201     def caption(self):
    202         return GetByMessageID(self.staticData.nameID)
    203 
    204     @property
    205     def description(self):
    206         return GetByMessageID(self.staticData.descriptionID)
    207 
    208     @property
    209     def animatedSplash(self):
    210         if self.staticData.animatedSplash:
    211             return Texture(self.staticData.animatedSplash)
    212 
    213     @property
    214     def staticSplash(self):
    215         if self.staticData.staticSplash:
    216             return Texture(self.staticData.staticSplash)
    217 
    218     @property
    219     def stacksize(self):
    220         return sum((stacksize for typeID, itemID, stacksize in self.crate_stack_list))
    221 
    222     def LoadLootFromTypes(self, loot):
    223         return [ LootItemFromType(itemID, typeID, quantity, self.destinationID, self.destinationFlagID) for itemID, typeID, quantity in loot ]
    224 
    225     def LoadSpecialLoot(self, itemID):
    226         specialLoot = []
    227         skillBundleID = getattr(self.staticData, 'skillBundleID', None)
    228         if skillBundleID:
    229             specialLoot.append(SkillBundleLootItem(itemID, skillBundleID))
    230         fitting_ids = getattr(self.staticData, 'fittings', []) or []
    231         for fitting_id in fitting_ids:
    232             name, icon, ship_type_id, insurance = sm.RemoteSvc('ship').GetShipFittingInfo(fitting_id)
    233             specialLoot.append(FittingLootItem(itemID, fitting_id, name, icon))
    234             if insurance:
    235                 specialLoot.append(InsuranceLootItem(itemID, ship_type_id, insurance))
    236 
    237         return specialLoot
    238 
    239     def OpenCrate(self):
    240         if self.stacksize <= 0:
    241             raise RuntimeError('No more crates')
    242         self.isOpening = True
    243         itemID = self.crate_stack_list[self.crate_list_index][1]
    244         typeID = self.crate_stack_list[self.crate_list_index][0]
    245         self.DecreaseStackSize()
    246         try:
    247             self.destinationID, self.destinationFlagID = sm.RemoteSvc('crateService').GetCrateLocation(itemID)
    248             loot = sm.RemoteSvc('crateService').OpenCrate(itemID)
    249             sm.ScatterEvent('OnClientEvent_CrateOpen', typeID)
    250             self.loot = self.LoadLootFromTypes(loot)
    251             self.specialLoot = self.LoadSpecialLoot(itemID)
    252             self.ClaimSpecialLoot()
    253             if self.crate_stack_list[self.crate_list_index][2] <= 0:
    254                 self.crate_list_index = min(self.crate_list_index + 1, len(self.crate_stack_list) - 1)
    255             self.onOpen()
    256         except Exception:
    257             self.IncreaseStackSize()
    258             self.isOpening = False
    259             raise
    260 
    261     def OpenMultipleCrates(self):
    262         crateEntry = self.crate_stack_list[self.crate_list_index]
    263         typeID = crateEntry[0]
    264         itemID = crateEntry[1]
    265         stacksize = crateEntry[2]
    266         qty = min(MAX_MULTI_OPEN, stacksize)
    267         cratesOpened = 0
    268         numCratesToOpen = qty
    269         try:
    270             cratesOpened, numCratesToOpen = sm.RemoteSvc('crateService').ClaimLootFromCrateStack(itemID, qty)
    271         except UserError as e:
    272             if e.msg in ('MultipleCrateOpenAbortedDueToTidiCratesOpened', 'MultipleCrateOpenAbortedDueToTidiCratesOpened'):
    273                 if e.msg == 'MultipleCrateOpenAbortedDueToTidiCratesOpened':
    274                     cratesOpened = e.dict['numCratesOpened']
    275                     self.DecreaseStackSize(cratesOpened)
    276             elif e.msg == 'FailedOpeningMultiCrate':
    277                 cratesOpened = e.dict['numCratesOpened']
    278                 self.DecreaseStackSize(cratesOpened)
    279             raise
    280         finally:
    281             self.DecreaseStackSize(cratesOpened)
    282             self.onCrateMultiOpenEnded(cratesOpened, numCratesToOpen)
    283 
    284         self.ShowResultMessage(cratesOpened, numCratesToOpen)
    285         if cratesOpened:
    286             sm.ScatterEvent('OnClientEvent_CrateOpen', typeID)
    287 
    288     def ShowResultMessage(self, cratesOpened, numCratesToOpen):
    289         if cratesOpened == numCratesToOpen:
    290             message_player(GetByLabel('UI/Crate/NumCratesSuccessfullyOpened', numCrates=cratesOpened))
    291         else:
    292             message_player(GetByLabel('UI/Crate/NumCratesOpened', numCrates=cratesOpened, numCratesToOpen=numCratesToOpen))
    293 
    294     def ClaimSpecialLoot(self):
    295         specialLoot = self.specialLoot[:]
    296         while specialLoot:
    297             item = specialLoot.pop()
    298             try:
    299                 item.claim()
    300             except Exception:
    301                 LogException('Error claiming special loot item %s' % item.get_name())
    302 
    303     def Finish(self):
    304         self.onFinish()
    305 
    306     def DecreaseStackSize(self, amount = 1):
    307         entry = self.crate_stack_list[self.crate_list_index]
    308         self.crate_stack_list[self.crate_list_index] = (entry[0], entry[1], entry[2] - amount)
    309         if entry[2] <= 1:
    310             self.crate_list_index = min(self.crate_list_index + 1, len(self.crate_stack_list) - 1)
    311 
    312     def IncreaseStackSize(self):
    313         entry = self.crate_stack_list[self.crate_list_index]
    314         self.crate_stack_list[self.crate_list_index] = (entry[0], entry[1], entry[2] + 1)
    315 
    316     def Skip(self):
    317         self.DecreaseStackSize()
    318         self.onSkip()
    319 
    320     def GetSortedLoot(self):
    321         return self.LoadLootFromTypes(self.PeekInsideFixedCrate())
    322 
    323     def GetSpecialLoot(self):
    324         return self.specialLoot or []
    325 
    326     def PeekInsideFixedCrate(self):
    327         typeID = self.crate_stack_list[self.crate_list_index][0]
    328         if typeID not in self.lootByType:
    329             itemID = self.crate_stack_list[self.crate_list_index][1]
    330             peekResult = sm.RemoteSvc('crateService').PeekInsideFixedCrate(itemID)
    331             self.lootByType[typeID] = [ (None, typeID_quantity_customInfo[0], typeID_quantity_customInfo[1]) for typeID_quantity_customInfo in peekResult ]
    332             self.specialLoot = self.LoadSpecialLoot(itemID)
    333         return self.lootByType[typeID]
    334 
    335     def Close(self):
    336         self.onFinish.clear()
    337         self.onOpen.clear()
    338 
    339 
    340 def CreateController(typeID, itemID, stacksize):
    341     crate = CratesStaticData().get_crate_by_type_id(typeID)
    342     if crate.lootPresentationType == 'fixed':
    343         return FixedCrateStackController([typeID, itemID, stacksize])
    344     if crate.lootPresentationType == 'hacking':
    345         return HackingCrateController(typeID, itemID, stacksize)
    346     raise RuntimeError("Unknown crate presentation type '%s'" % crate.lootPresentationType)
    347 
    348 
    349 def __SakeReloadHook():
    350     try:
    351         from eve.client.script.ui.crate.window import CrateWindow
    352         instance = CrateWindow.GetIfOpen()
    353         if instance:
    354             CrateWindow.Reload(instance)
    355     except Exception:
    356         import log
    357         log.LogException()