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()