hacking.py (33399B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\crate\view\hacking.py 2 import blue 3 import uthread2 4 from carbonui import const as uiconst, ButtonVariant, TextAlign, TextColor 5 from carbonui.text.styles import TextHeadline, TextBody 6 from carbonui.button.group import ButtonGroup 7 from carbonui.control.button import Button 8 from carbonui.primitives.container import Container 9 from carbonui.primitives.containerAutoSize import ContainerAutoSize 10 from carbonui.primitives.sprite import Sprite, StreamingVideoSprite 11 from carbonui.primitives.vectorline import VectorLine 12 from carbonui.uianimations import animations 13 from carbonui.util import color 14 from crates.const import MAX_MULTI_OPEN 15 from eve.client.script.ui.control.eveIcon import Icon 16 from eve.client.script.ui.control.eveLabel import EveCaptionMedium 17 from eve.client.script.ui.control.themeColored import GradientThemeColored 18 from eve.client.script.ui.control.tooltips import TooltipPersistentPanel 19 from eve.client.script.ui.control.pointerPanel import FadeOutPanelAndClose, RefreshPanelPosition 20 import geo2 21 import itertools 22 import localization 23 import log 24 import math 25 import random 26 import trinity 27 import uthread 28 from carbonui.uicore import uicore 29 from eveexceptions import ExceptionEater 30 ACTIVE_CONNECTION_ANIM_DURATION = 0.15 31 HINT_TOOLTIP_SETTINGS_KEY = 'CrateWindowLootHintEnabled' 32 33 def res(filename): 34 return 'res:/UI/Texture/classes/ItemPacks/{}'.format(filename) 35 36 37 def center(text): 38 return u'<center>{}</center>'.format(text) 39 40 41 def getColorUIHighlight(alpha = 1.0): 42 elementColor = sm.GetService('uiColor').GetUIColor(uiconst.COLORTYPE_UIHILIGHT) 43 return color.GetColor(elementColor, alpha=alpha) 44 45 46 class HackingView(Container): 47 default_clipChildren = True 48 49 def ApplyAttributes(self, attributes): 50 super(HackingView, self).ApplyAttributes(attributes) 51 self.controller = attributes.controller 52 self._claimedLootCount = 0 53 self.processingMultiHackTasklet = None 54 self.controller.onCrateMultiHackEnded.connect(self.OnMultiHackEnded) 55 self.Layout() 56 uthread.new(self.AnimEntry) 57 58 def Layout(self): 59 self.overlayCont = Container(parent=self, align=uiconst.VERTICALLY_CENTERED, padLeft=380, height=80, opacity=0.0) 60 GradientThemeColored(bgParent=self.overlayCont, padding=(1, 0, 1, 0), rgbData=[(0, (0.5, 0.5, 0.5))], alphaData=[(0, 0.0), (0.4, 0.7), (0.6, 0.8)], rotation=0) 61 VectorLine(parent=self.overlayCont, align=uiconst.TOPLEFT, translationTo=(0, 0), translationFrom=(600, 0), widthTo=5, widthFrom=5, colorTo=(1.0, 1.0, 1.0, 0.0), texturePath=res('Hacking_HatchPattern.png'), spriteEffect=trinity.TR2_SFX_COPY, textureWidth=8) 62 VectorLine(parent=self.overlayCont, align=uiconst.BOTTOMLEFT, translationTo=(0, 0), translationFrom=(600, 0), widthTo=5, widthFrom=5, colorTo=(1.0, 1.0, 1.0, 0.0), texturePath=res('Hacking_HatchPattern.png'), spriteEffect=trinity.TR2_SFX_COPY, textureWidth=8) 63 labelCont = Container(parent=self.overlayCont, align=uiconst.TOALL, padding=(180, 30, 20, 20)) 64 self.hackingLabel = TextHeadline(parent=self.overlayCont, align=uiconst.VERTICALLY_CENTERED, text=localization.GetByLabel('UI/Crate/HackingInProgress'), textAlign=TextAlign.CENTER) 65 self.gridCont = Container(parent=self, align=uiconst.TOALL, padLeft=380) 66 self.grid = HackingGrid(parent=self.gridCont, align=uiconst.TOALL, loot=self.controller.loot, specialLoot=self.controller.specialLoot, onLootClaimed=self.OnLootClaimed) 67 self.back = StreamingVideoSprite(parent=self, align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED, width=800, height=550, top=-25, videoPath='res:/video/hacking/bgLoop_alpha.webm', spriteEffect=trinity.TR2_SFX_COPY, disableAudio=True) 68 buttonGroupCont = ContainerAutoSize(parent=self, align=uiconst.BOTTOMRIGHT, minWidth=400, idx=0, top=8) 69 self.buttonGroup = ButtonGroup(parent=buttonGroupCont, align=uiconst.CENTER) 70 71 def AnimEntry(self): 72 animations.FadeTo(self) 73 uthread.new(self.AnimBackground) 74 uthread.new(self.grid.AnimObstacles) 75 uthread.new(self.grid.AnimEntry) 76 77 def AnimBackground(self): 78 animations.FadeTo(self.back, startVal=self.back.opacity, endVal=0.4, duration=0.3, sleep=True) 79 animations.FadeTo(self.back, startVal=0.4, endVal=0.2, duration=6.0, loops=uiconst.ANIM_REPEAT, curveType=uiconst.ANIM_WAVE) 80 81 def AnimBackgroundPulse(self): 82 animations.FadeTo(self.back, startVal=0.6, endVal=0.4, duration=0.15, loops=3) 83 blue.synchro.SleepWallclock(450) 84 uthread.new(self.AnimBackground) 85 86 def OnLootClaimed(self): 87 item = None 88 try: 89 item = self.controller.ClaimLoot() 90 except Exception: 91 log.LogException('Error claiming loot item') 92 93 if not self.controller.loot and not self.controller.specialLoot: 94 self.RevealButtons() 95 uthread.new(self.AnimBackgroundPulse) 96 return item 97 98 def RevealButtons(self): 99 self.buttonGroup.FlushButtons() 100 if self.controller.stacksize > 0: 101 if self.controller.stacksize > MAX_MULTI_OPEN: 102 text = localization.GetByLabel('UI/Crate/HackMultiple', quantity=MAX_MULTI_OPEN) 103 else: 104 text = localization.GetByLabel('UI/Crate/HackAll', quantity=self.controller.stacksize) 105 Button(parent=self.buttonGroup, label=text, func=self.HackMultiple, variant=ButtonVariant.GHOST) 106 text = localization.GetByLabel('UI/Crate/HackNext', quantity=self.controller.stacksize) 107 Button(parent=self.buttonGroup, label=text, func=self.OpenAnotherCrate) 108 else: 109 Button(parent=self.buttonGroup, label=localization.GetByLabel('UI/Crate/Finish'), func=self.controller.Finish, args=()) 110 for button in self.buttonGroup.buttons: 111 animations.FadeTo(button) 112 113 def DisableButtons(self, *args): 114 for button in self.buttonGroup.buttons: 115 button.Disable() 116 117 def OpenAnotherCrate(self, button): 118 self.DisableButtons() 119 self.controller.OpenCrate() 120 121 def HackMultiple(self, button): 122 self.DisableButtons() 123 try: 124 self._KillMultiHackTasklet() 125 self.processingMultiHackTasklet = uthread.new(self.ShowProcessingMultiHack) 126 self.controller.OpenMultipleCrates() 127 except Exception: 128 self.RevealButtons() 129 raise 130 131 self.RevealButtons() 132 133 def ShowProcessingMultiHack(self): 134 self.hackingLabel.SetText(localization.GetByLabel('UI/Crate/HackingInProgress')) 135 animations.FadeIn(self.overlayCont) 136 self.gridCont.Flush() 137 self.grid = HackingGrid(parent=self.gridCont, align=uiconst.TOALL, loot=[], specialLoot=[], onLootClaimed=self.OnLootClaimed) 138 self.grid.ShowContiniousCellAnimation() 139 140 def OnMultiHackEnded(self, cratesOpened, numCratesToOpen): 141 self._KillMultiHackTasklet() 142 self.hackingLabel.opacity = 0.0 143 if cratesOpened == 0: 144 text = localization.GetByLabel('UI/Crate/HackingFailed') 145 elif cratesOpened != numCratesToOpen: 146 text = localization.GetByLabel('UI/Crate/HackingPartiallyCompleted', numCratesOpened=cratesOpened, numCratesToOpen=numCratesToOpen) 147 else: 148 text = localization.GetByLabel('UI/Crate/HackingCompleted') 149 self.hackingLabel.SetText(text) 150 animations.FadeTo(self.hackingLabel, endVal=TextColor.NORMAL[3], timeOffset=0.1) 151 152 def _KillMultiHackTasklet(self): 153 if self.processingMultiHackTasklet: 154 self.processingMultiHackTasklet.kill() 155 self.processingMultiHackTasklet = None 156 157 def Close(self): 158 with ExceptionEater(): 159 self._KillMultiHackTasklet() 160 self.controller.onCrateMultiHackEnded.disconnect(self.OnMultiHackEnded) 161 super(HackingView, self).Close() 162 163 164 def weighted_choice(choices): 165 total = sum((w for c, w in choices)) 166 r = random.uniform(0, total) 167 upto = 0 168 for c, w in choices: 169 if upto + w >= r: 170 return c 171 upto += w 172 173 174 class HackingGrid(Container): 175 gridWidth = 5 176 gridHeight = 8 177 gridTop = 55 178 gridLeft = 22 179 columnSpacing = 78.6 180 rowSpacing = 46 181 _neighborOffsetsOdd = ((-1, -1), 182 (0, -1), 183 (1, 0), 184 (0, 1), 185 (-1, 1), 186 (-1, 0)) 187 _neighborOffsetsEven = ((0, -1), 188 (1, -1), 189 (1, 0), 190 (1, 1), 191 (0, 1), 192 (-1, 0)) 193 _bleedHorizontalTexturePaths = ['res:/UI/Texture/classes/hacking/lineBleed/horiz01.png', 194 'res:/UI/Texture/classes/hacking/lineBleed/horiz02.png', 195 'res:/UI/Texture/classes/hacking/lineBleed/horiz03.png', 196 'res:/UI/Texture/classes/hacking/lineBleed/horiz04.png', 197 'res:/UI/Texture/classes/hacking/lineBleed/horiz05.png', 198 'res:/UI/Texture/classes/hacking/lineBleed/horiz06.png', 199 'res:/UI/Texture/classes/hacking/lineBleed/horiz07.png', 200 'res:/UI/Texture/classes/hacking/lineBleed/horiz08.png', 201 'res:/UI/Texture/classes/hacking/lineBleed/horiz09.png', 202 'res:/UI/Texture/classes/hacking/lineBleed/horiz10.png', 203 'res:/UI/Texture/classes/hacking/lineBleed/horiz11.png', 204 'res:/UI/Texture/classes/hacking/lineBleed/horiz12.png', 205 'res:/UI/Texture/classes/hacking/lineBleed/horiz13.png', 206 'res:/UI/Texture/classes/hacking/lineBleed/horiz14.png', 207 'res:/UI/Texture/classes/hacking/lineBleed/horiz15.png', 208 'res:/UI/Texture/classes/hacking/lineBleed/horiz16.png', 209 'res:/UI/Texture/classes/hacking/lineBleed/horiz17.png'] 210 _bleedDiagonalTexturePaths = ['res:/UI/Texture/classes/hacking/lineBleed/diag01.png', 211 'res:/UI/Texture/classes/hacking/lineBleed/diag02.png', 212 'res:/UI/Texture/classes/hacking/lineBleed/diag03.png', 213 'res:/UI/Texture/classes/hacking/lineBleed/diag04.png', 214 'res:/UI/Texture/classes/hacking/lineBleed/diag05.png', 215 'res:/UI/Texture/classes/hacking/lineBleed/diag06.png', 216 'res:/UI/Texture/classes/hacking/lineBleed/diag07.png', 217 'res:/UI/Texture/classes/hacking/lineBleed/diag08.png', 218 'res:/UI/Texture/classes/hacking/lineBleed/diag09.png', 219 'res:/UI/Texture/classes/hacking/lineBleed/diag10.png', 220 'res:/UI/Texture/classes/hacking/lineBleed/diag11.png'] 221 222 def ApplyAttributes(self, attributes): 223 super(HackingGrid, self).ApplyAttributes(attributes) 224 self.loot = attributes.loot 225 self.specialLoot = attributes.specialLoot 226 self.onLootClaimed = attributes.onLootClaimed 227 self._showHint = settings.user.ui.Get(HINT_TOOLTIP_SETTINGS_KEY, True) 228 self._hint = None 229 self._lootCells = [] 230 self.cellObjects = {} 231 self.path = self.GeneratePath() 232 self.DistributeLootOnPath() 233 self.SprinkleObstacles() 234 self.PunchHolesInGrid() 235 for cell in self.cells: 236 if cell in self.cellObjects: 237 continue 238 x, y = self.getCellPosition(cell) 239 self.cellObjects[cell] = RegularCell(parent=self, align=uiconst.RELATIVE, left=x, top=y) 240 241 self.DrawCellConnections() 242 243 def DistributeLootOnPath(self): 244 remainingLoot = self.loot + self.specialLoot 245 lootChancePerCell = len(remainingLoot) / float(len(self.path) - 2) 246 accumulatedLootChance = lootChancePerCell 247 for cell in self.path: 248 if remainingLoot: 249 if accumulatedLootChance >= 1.0: 250 remainingLoot.pop() 251 x, y = self.getCellPosition(cell) 252 self.cellObjects[cell] = ItemCell(parent=self, align=uiconst.RELATIVE, left=x - ItemCell.default_width / 2.0, top=y - ItemCell.default_height / 2.0, onClaimed=self.OnLootClaimed) 253 self._lootCells.append(cell) 254 accumulatedLootChance -= 1.0 255 accumulatedLootChance += lootChancePerCell 256 else: 257 break 258 259 def SprinkleObstacles(self): 260 self.obstacles = [] 261 candidates = set(self.cells) 262 candidates = list(candidates.difference(self.path)) 263 candidates = filter(lambda c: 0 < c[1] < self.gridHeight - 1, candidates) 264 for i in xrange(random.randint(5, 7)): 265 if not candidates: 266 break 267 cell = random.choice(candidates) 268 x, y = self.getCellPosition(cell) 269 obstacle = Obstacle(parent=self, align=uiconst.RELATIVE, left=x, top=y) 270 self.cellObjects[cell] = obstacle 271 self.obstacles.append(obstacle) 272 candidates.remove(cell) 273 for c in self.getCellNeighbors(cell): 274 if c in candidates: 275 candidates.remove(c) 276 277 def PunchHolesInGrid(self): 278 candidates = set(self.cells) 279 candidates = candidates.difference(self.path) 280 candidates = list(candidates.difference(self.cellObjects.iterkeys())) 281 for i in xrange(random.randint(5, 7)): 282 if not candidates: 283 break 284 cell = random.choice(candidates) 285 self.cellObjects[cell] = None 286 candidates.remove(cell) 287 288 def OnLootClaimed(self): 289 item = self.onLootClaimed() 290 self._showHint = False 291 settings.user.ui.Set(HINT_TOOLTIP_SETTINGS_KEY, False) 292 if self._hint: 293 FadeOutPanelAndClose(self._hint) 294 return item 295 296 def AnimObstacles(self): 297 298 def RevealThread(cell, timeOffset): 299 blue.synchro.SleepWallclock(timeOffset * 1000) 300 self.cellObjects[cell].AnimReveal() 301 302 x_center, y_center = self.getCellPosition((0, 0)) 303 x_extent, y_extent = self.getCellPosition((self.gridWidth, self.gridHeight)) 304 extent = math.sqrt((x_extent - x_center) ** 2 + (y_extent - y_center) ** 2) 305 timeFactor = 1.5 / extent 306 for cell in self.cells: 307 if self.cellObjects[cell] is None: 308 continue 309 x, y = self.getCellPosition(cell) 310 x_offset = abs(x - x_center) 311 y_offset = abs(y - y_center) 312 timeOffset = timeFactor * math.sqrt(x_offset ** 2 + y_offset ** 2) 313 uthread.new(RevealThread, cell, timeOffset) 314 315 def AnimEntry(self): 316 for i, cell in enumerate(self.path): 317 if i == 0: 318 self.DrawActiveFringeConnection(cell, self.getCellNeighbors(cell)[0]) 319 else: 320 self.DrawActiveConnection(self.path[i - 1], cell) 321 uthread.new(self.cellObjects[cell].AnimExplore) 322 blue.synchro.SleepWallclock(ACTIVE_CONNECTION_ANIM_DURATION * 1000) 323 324 lastCell = self.getCellNeighbors(self.path[-1])[3] 325 self.DrawActiveFringeConnection(self.path[-1], lastCell, inbound=False) 326 uthread.new(self.RevealHint) 327 328 def ShowContiniousCellAnimation(self): 329 x_center, y_center = self.getCellPosition((0, 0)) 330 x_extent, y_extent = self.getCellPosition((self.gridWidth, self.gridHeight)) 331 extent = math.sqrt((x_extent - x_center) ** 2 + (y_extent - y_center) ** 2) 332 timeFactor = 1.5 / extent 333 while True: 334 if self.destroyed: 335 break 336 self.AnimObstacles() 337 uthread2.Sleep(1.5) 338 339 def RevealHint(self): 340 blue.synchro.SleepWallclock(5000) 341 if self._showHint: 342 cell = random.choice(self._lootCells) 343 node = self.cellObjects[cell] 344 self._hint = uicore.uilib.tooltipHandler.LoadPersistentTooltip(node, customTooltipClass=HintTooltip) 345 346 def Close(self): 347 if self._hint: 348 FadeOutPanelAndClose(self._hint) 349 super(HackingGrid, self).Close() 350 351 def GeneratePath(self): 352 path = [] 353 354 def weight(c): 355 return self.gridWidth / 2.0 - abs(c - (self.gridWidth - 1) / 2.0) 356 357 weightedColumns = [ (c, weight(c)) for c in xrange(self.gridWidth) ] 358 column = weighted_choice(weightedColumns) 359 path.append((column, 0)) 360 while True: 361 horizontalMult = 0.0 if len(path) == 1 else 2.0 362 weights = (0 + max(0, 2 - path[-1][0]) * horizontalMult, 363 1 + max(0, 2 - path[-1][0]) * 0.5, 364 1 + max(0, path[-1][0] - 2) * 0.5, 365 0 + max(0, path[-1][0] - 2) * horizontalMult) 366 neighbors = self.getCellNeighbors(path[-1])[2:] 367 weightedNeighbors = zip(neighbors, weights) 368 candidates = filter(lambda x: self.IsCellInsideGrid(x[0]), weightedNeighbors) 369 nextCell = weighted_choice(candidates) 370 path.append(nextCell) 371 if nextCell[1] == self.gridHeight - 1: 372 break 373 374 return path 375 376 def DrawCellConnections(self): 377 for cell in self.cells: 378 if self.cellObjects[cell] is None: 379 continue 380 neighbors = filter(self.IsCellInsideGrid, self.getCellNeighbors(cell)[:3]) 381 for neighbor in neighbors: 382 if self.cellObjects[neighbor] is None: 383 continue 384 x_origin, y_origin = self.getCellPosition(cell) 385 x, y = self.getCellPosition(neighbor) 386 VectorLine(parent=self, translationFrom=(x_origin, y_origin), translationTo=(x, y), colorFrom=(1, 1, 1, 0.3), colorTo=(1, 1, 1, 0.8), widthFrom=0.3, widthTo=0.3) 387 388 self.DrawFringePaths() 389 390 def DrawActiveConnection(self, fromCell, toCell): 391 x_origin, y_origin = self.getCellPosition(fromCell) 392 x, y = self.getCellPosition(toCell) 393 line = VectorLine(parent=self, translationFrom=(x_origin, y_origin), translationTo=(x, y), colorFrom=getColorUIHighlight(alpha=0.5), colorTo=getColorUIHighlight(alpha=0.5), widthFrom=1, widthTo=1, blendMode=trinity.TR2_SBM_ADDX2) 394 midpoint = geo2.Vec2Lerp((x_origin, y_origin), (x, y), 0.5) 395 if y_origin == y: 396 texturePath = random.choice(self._bleedHorizontalTexturePaths) 397 height = 50 398 left = midpoint[0] - 48 399 top = midpoint[1] - height / 2.0 400 else: 401 texturePath = random.choice(self._bleedDiagonalTexturePaths) 402 height = 72 403 left = midpoint[0] - 32 404 top = midpoint[1] - height / 2.0 405 if y_origin < y and x_origin > x or y_origin > y and x_origin < x: 406 top += height 407 height *= -1 408 bleed = Sprite(parent=self, align=uiconst.RELATIVE, state=uiconst.UI_DISABLED, left=left, top=top, width=64, height=height, texturePath=texturePath, color=getColorUIHighlight(), blendMode=trinity.TR2_SBM_ADDX2) 409 410 def BleedAnimation(): 411 animations.FadeTo(bleed, startVal=bleed.opacity, endVal=0.2, duration=5.0, loops=uiconst.ANIM_REPEAT, curveType=uiconst.ANIM_WAVE) 412 413 animations.FadeTo(bleed, endVal=0.5, duration=0.1, loops=3, timeOffset=random.random() * 0.6, callback=BleedAnimation) 414 glow = VectorLine(parent=self, translationFrom=(x_origin, y_origin), translationTo=(x, y), colorFrom=color.GetColor(getColorUIHighlight(), alpha=1.0), colorTo=color.GetColor(getColorUIHighlight(), alpha=1.0), widthFrom=30, widthTo=30, texturePath=res('Hacking_ConnectionGlow.png'), spriteEffect=trinity.TR2_SFX_COPY) 415 animations.MorphVector2(line, 'translationTo', startVal=(x_origin, y_origin), endVal=(x, y), duration=ACTIVE_CONNECTION_ANIM_DURATION) 416 animations.MorphVector2(glow, 'translationTo', startVal=(x_origin, y_origin), endVal=(x, y), duration=ACTIVE_CONNECTION_ANIM_DURATION) 417 animations.SpColorMorphTo(line, attrName='colorTo', startColor=color.GetColor(getColorUIHighlight(), alpha=0.0), endColor=color.GetColor(getColorUIHighlight(), alpha=1.0), duration=ACTIVE_CONNECTION_ANIM_DURATION, timeOffset=ACTIVE_CONNECTION_ANIM_DURATION) 418 animations.SpColorMorphTo(glow, attrName='colorTo', startColor=color.GetColor(getColorUIHighlight(), alpha=0.0), endColor=color.GetColor(getColorUIHighlight(), alpha=1.0), duration=ACTIVE_CONNECTION_ANIM_DURATION) 419 animations.MorphScalar(glow, 'widthTo', endVal=30, duration=ACTIVE_CONNECTION_ANIM_DURATION) 420 421 def DrawActiveFringeConnection(self, insideCell, outsideCell, inbound = True): 422 x_origin, y_origin = self.getCellPosition(insideCell) 423 x, y = self.getCellPosition(outsideCell) 424 line = VectorLine(parent=self, translationFrom=(x_origin, y_origin), translationTo=(x, y), colorFrom=getColorUIHighlight(alpha=0.5), colorTo=color.GetColor(getColorUIHighlight(), alpha=0.0), widthFrom=1, widthTo=1, blendMode=trinity.TR2_SBM_ADDX2) 425 VectorLine(parent=self, translationFrom=(x_origin, y_origin), translationTo=(x, y), colorFrom=getColorUIHighlight(alpha=0.5), colorTo=color.GetColor(getColorUIHighlight(), alpha=0.0), widthFrom=30, widthTo=30, texturePath=res('Hacking_ConnectionGlow.png'), spriteEffect=trinity.TR2_SFX_COPY, blendMode=trinity.TR2_SBM_ADDX2) 426 if inbound: 427 animations.MorphVector2(line, 'translationFrom', startVal=(x, y), endVal=(x_origin, y_origin), duration=ACTIVE_CONNECTION_ANIM_DURATION) 428 else: 429 animations.MorphVector2(line, 'translationTo', startVal=(x_origin, y_origin), endVal=(x, y), duration=ACTIVE_CONNECTION_ANIM_DURATION) 430 animations.MorphScalar(line, 'opacity', startVal=0.0, endVal=1.0, duration=ACTIVE_CONNECTION_ANIM_DURATION) 431 432 def IsCellOutsideGrid(self, cell): 433 col, row = cell 434 return col < 0 or self.gridWidth <= col or row < 0 or self.gridHeight <= row 435 436 def IsCellInsideGrid(self, cell): 437 return not self.IsCellOutsideGrid(cell) 438 439 def DrawFringePaths(self): 440 for cell in self.cells: 441 if self.cellObjects[cell] is None: 442 continue 443 outsideCells = filter(self.IsCellOutsideGrid, self.getCellNeighbors(cell)) 444 for col, row in outsideCells: 445 if 0 <= col < self.gridWidth and 0 <= row < self.gridHeight: 446 continue 447 x_origin, y_origin = self.getCellPosition(cell) 448 x, y = self.getCellPosition((col, row)) 449 VectorLine(parent=self, translationFrom=(x_origin, y_origin), translationTo=(x, y), colorFrom=(1, 1, 1, 0.2), colorTo=(1, 1, 1, 0.0), widthFrom=0.5, widthTo=0.5) 450 451 @property 452 def cells(self): 453 return itertools.product(xrange(self.gridWidth), xrange(self.gridHeight)) 454 455 def getCellPosition(self, coord): 456 x, y = coord 457 rowOffset = self.columnSpacing / 2.0 if y % 2 == 0 else 0 458 return (x * self.columnSpacing + rowOffset + self.gridLeft, y * self.rowSpacing + self.gridTop) 459 460 def getCellNeighbors(self, coord): 461 column, row = coord 462 if row % 2 == 0: 463 neighborOffsets = self._neighborOffsetsEven 464 else: 465 neighborOffsets = self._neighborOffsetsOdd 466 return [ (column + c, row + r) for c, r in neighborOffsets ] 467 468 469 class RegularCell(Container): 470 default_clipChildren = False 471 default_state = uiconst.UI_DISABLED 472 default_width = 1 473 default_height = 1 474 475 def ApplyAttributes(self, attributes): 476 super(RegularCell, self).ApplyAttributes(attributes) 477 self.Layout() 478 479 def Layout(self): 480 self.closed = Sprite(parent=self, align=uiconst.CENTER, width=64, height=64, texturePath='res:/UI/Texture/classes/hacking/tileUnflipped.png', color=(0.3, 0.3, 0.3)) 481 482 def AnimReveal(self): 483 animations.SpGlowFadeOut(self.closed, duration=0.3) 484 animations.MorphScalar(self.closed, 'glowExpand', startVal=0.5, endVal=10.0, duration=0.3) 485 486 def AnimExplore(self): 487 opened = Sprite(parent=self, align=uiconst.CENTER, width=40, height=40, texturePath='res:/UI/Texture/classes/hacking/tileExplored.png', color=getColorUIHighlight(), opacity=2.0, idx=0) 488 offset = ACTIVE_CONNECTION_ANIM_DURATION / 2.0 489 animations.FadeOut(self.closed, timeOffset=offset) 490 animations.FadeIn(opened, duration=0.1, timeOffset=offset) 491 animations.SpGlowFadeOut(opened, duration=0.3, timeOffset=offset + 0.1) 492 animations.MorphScalar(opened, 'glowExpand', startVal=0.5, endVal=10.0, duration=0.3, timeOffset=offset + 0.1) 493 494 495 class ItemCell(Container): 496 default_clipChildren = False 497 default_state = uiconst.UI_DISABLED 498 default_width = 64 499 default_height = 64 500 501 def ApplyAttributes(self, attributes): 502 super(ItemCell, self).ApplyAttributes(attributes) 503 self.onClaimed = attributes.onClaimed 504 self._claimed = False 505 self.Layout() 506 507 def Layout(self): 508 self.nodeSprite = Sprite(parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=64, height=64, texturePath='res:/UI/Texture/classes/hacking/tileUnflipped.png', color=(0.3, 0.3, 0.3)) 509 self.frame = StreamingVideoSprite(parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=72, height=72, videoPath=res('nodeIntro_R4.webm'), spriteEffect=trinity.TR2_SFX_COPY, disableAudio=True, color=getColorUIHighlight(1.5)) 510 self.frame.Pause() 511 self.nodeSpinner = StreamingVideoSprite(parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=64, height=64, videoPath=res('baseNodeLoop.webm'), videoLoop=True, spriteEffect=trinity.TR2_SFX_COPY, blendMode=trinity.TR2_SBM_ADDX2, disableAudio=True, opacity=0.0, color=getColorUIHighlight()) 512 self.nodeSpinner.Pause() 513 self.node = Sprite(parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=32, height=32, texturePath=res('itemNodeCenter.png'), blendMode=trinity.TR2_SBM_ADDX2, color=(0, 0, 0, 0)) 514 self.back = Sprite(parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=64, height=64, texturePath=res('itemNodeBack.png'), color=getColorUIHighlight(), opacity=0.0) 515 516 def AnimReveal(self): 517 animations.FadeOut(self.nodeSprite, duration=0.1) 518 animations.FadeIn(self.node, endVal=1.0, duration=0.1) 519 animations.SpGlowFadeOut(self.node, duration=0.3, timeOffset=0.1) 520 animations.MorphScalar(self.node, 'glowExpand', startVal=0.5, endVal=10.0, duration=0.3, timeOffset=0.1) 521 522 def AnimExplore(self): 523 self.frame.Play() 524 animations.FadeOut(self.nodeSprite, duration=0.1) 525 animations.FadeIn(self.nodeSpinner, duration=0.5, callback=self.Enable) 526 self.nodeSpinner.Play() 527 animations.FadeIn(self.back, endVal=0.1, duration=0.2) 528 animations.FadeIn(self.node, endVal=1.0, duration=0.25) 529 animations.SpColorMorphTo(self.node, endColor=getColorUIHighlight(), duration=0.2) 530 animations.MorphVector2(self.node, 'scale', startVal=(0.5, 0.5), duration=0.5, sleep=True) 531 532 def PulseNode(): 533 offset = random.normalvariate(2.0, 1.0) 534 animations.MorphVector2(self.node, 'scale', startVal=(1.0, 1.0), endVal=(0.8, 0.8), duration=0.15, timeOffset=offset) 535 blue.synchro.SleepWallclock((offset + 0.15) * 1000) 536 animations.MorphVector2(self.node, 'scale', startVal=(0.8, 0.8), endVal=(1.0, 1.0), duration=0.4) 537 blue.synchro.SleepWallclock(500) 538 if not self.destroyed: 539 uthread.new(PulseNode) 540 541 uthread.new(PulseNode) 542 543 def ClaimLoot(self): 544 if self._claimed: 545 return 546 self._claimed = True 547 self.item = self.onClaimed() 548 self.SetState(uiconst.UI_PICKCHILDREN) 549 uthread.new(self.AnimRevealItem) 550 551 def AddIcon(self): 552 size = self.item.get_icon_size() 553 icon = self.item.get_icon() 554 if icon: 555 self.icon = Sprite(name='LootItem_Sprite', parent=self, align=uiconst.CENTER, state=uiconst.UI_NORMAL, width=size, height=size, texturePath=self.item.get_icon(), idx=0) 556 else: 557 self.icon = Icon(name='LootItem_Icon', parent=self, align=uiconst.CENTER, state=uiconst.UI_NORMAL, width=size, height=size, typeID=self.item.typeID, isCopy=self.item.is_copy(), idx=0) 558 self.icon.LoadTooltipPanel = self.LoadItemTooltipPanel 559 560 def AnimRevealItem(self): 561 self.frame.SetVideoPath(res('nodeHarvest_R4.webm')) 562 animations.FadeOut(self.nodeSpinner, duration=0.2) 563 animations.MorphVector2(self.node, 'scale', startVal=(1.0, 1.0), endVal=(2.0, 2.0), duration=0.15, sleep=True) 564 animations.MorphVector2(self.node, 'scale', startVal=(2.0, 2.0), endVal=(0.5, 0.5), duration=0.1) 565 animations.FadeOut(self.node, duration=0.15) 566 blue.synchro.SleepWallclock(25) 567 backdrop = Sprite(parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=48, height=48, texturePath=res('Hacking_NodeExploredBackground.png'), opacity=0.0) 568 animations.FadeIn(backdrop, duration=0.25, timeOffset=0.1) 569 self.AddIcon() 570 if self.icon: 571 animations.FadeTo(self.icon, duration=0.15) 572 animations.MorphVector2(self.icon, 'scale', startVal=(4.0, 4.0), endVal=(0.9, 0.9), duration=0.15, sleep=True) 573 animations.MorphVector2(self.icon, 'scale', startVal=(0.9, 0.9), endVal=(1.0, 1.0), duration=0.15) 574 animations.SpGlowFadeOut(self.icon, duration=0.3) 575 animations.MorphScalar(self.icon, 'glowExpand', startVal=0.5, endVal=10.0, duration=0.3) 576 animations.SpColorMorphTo(self.frame, endColor=getColorUIHighlight(2.0), duration=0.15) 577 578 def OnClick(self): 579 self.ClaimLoot() 580 581 def OnMouseEnter(self): 582 animations.SpColorMorphTo(self.frame, endColor=getColorUIHighlight(4.0), duration=0.15) 583 animations.FadeTo(self.back, startVal=self.back.opacity, endVal=0.4, duration=0.3) 584 585 def OnMouseExit(self): 586 animations.SpColorMorphTo(self.frame, endColor=getColorUIHighlight(2.0), duration=0.3) 587 animations.FadeTo(self.back, startVal=self.back.opacity, endVal=0.1, duration=0.3) 588 589 def LoadItemTooltipPanel(self, panel, owner): 590 panel.LoadStandardSpacing() 591 panel.AddLabelMedium(text=self.item.get_name()) 592 593 594 class Obstacle(Container): 595 default_state = uiconst.UI_DISABLED 596 default_clipChildren = False 597 default_width = 1 598 default_height = 1 599 _obstacleTexturePaths = ['res:/UI/Texture/classes/hacking/defSoftAntiVirus.png', 600 'res:/UI/Texture/classes/hacking/defSoftFirewall.png', 601 'res:/UI/Texture/classes/hacking/defSoftHoneyPotHealing.png', 602 'res:/UI/Texture/classes/hacking/defSoftHoneyPotStrength.png', 603 'res:/UI/Texture/classes/hacking/defSoftIds.png'] 604 _noiseTexturePaths = [res('Hacking_VirusNoise01.png'), 605 res('Hacking_VirusNoise02.png'), 606 res('Hacking_VirusNoise03.png'), 607 res('Hacking_VirusNoise04.png')] 608 609 def ApplyAttributes(self, attributes): 610 super(Obstacle, self).ApplyAttributes(attributes) 611 self.Layout() 612 613 def Layout(self): 614 self.node = Sprite(parent=self, align=uiconst.CENTER, width=64, height=64, texturePath='res:/UI/Texture/classes/hacking/tileUnflipped.png', color=(0.3, 0.3, 0.3)) 615 self.virus = Sprite(parent=self, align=uiconst.CENTER, width=64, height=64, texturePath=random.choice(self._obstacleTexturePaths), color=getColorUIHighlight(), opacity=0.0) 616 self.frame = Sprite(parent=self, align=uiconst.CENTER, width=64, height=64, texturePath='res:/UI/Texture/classes/hacking/tileIconFrame.png', color=getColorUIHighlight(), opacity=0.0) 617 self.back = Sprite(parent=self, align=uiconst.CENTER, width=48, height=48, texturePath=res('hacking_NodeExploredBackground.png'), opacity=0.0) 618 self.noise = Sprite(parent=self, align=uiconst.CENTER, width=150, height=100, color=getColorUIHighlight(), opacity=0.25, textureSecondaryPath='res:/UI/Texture/classes/hacking/healRing1.png', spriteEffect=trinity.TR2_SFX_MASK, blendMode=trinity.TR2_SBM_ADD) 619 620 def AnimReveal(self): 621 animations.FadeOut(self.node, duration=0.2) 622 animations.FadeIn(self.frame, endVal=0.5, duration=0.2) 623 animations.FadeIn(self.back, duration=0.3) 624 animations.SpGlowFadeOut(self.frame, duration=0.3, timeOffset=0.2) 625 animations.MorphScalar(self.frame, 'glowExpand', startVal=0.5, endVal=10.0, duration=0.3, timeOffset=0.2) 626 animations.BlinkIn(self.virus, sleep=True) 627 animations.SpColorMorphTo(self.virus, endColor=(0.2, 0.2, 0.2, 1.0)) 628 animations.SpColorMorphTo(self.frame, endColor=(0.3, 0.3, 0.3, 0.3)) 629 uthread.new(self.AnimPulseNoise) 630 631 def AnimPulseNoise(self): 632 offset = 2.0 + random.random() * 12.0 633 self.noise.SetTexturePath(random.choice(self._noiseTexturePaths)) 634 animations.MorphVector2(self.noise, 'scaleSecondary', startVal=(5.0, 5.0), endVal=(0.25, 0.25), duration=4.0, timeOffset=offset, sleep=True) 635 if not self.destroyed: 636 uthread.new(self.AnimPulseNoise) 637 638 639 class HintTooltip(TooltipPersistentPanel): 640 default_pointerDirection = uiconst.POINT_LEFT_2 641 642 def ApplyAttributes(self, attributes): 643 super(HintTooltip, self).ApplyAttributes(attributes) 644 self.owner = attributes.get('owner') 645 self.pickState = uiconst.TR2_SPS_ON 646 uicore.uilib.RegisterForTriuiEvents(uiconst.UI_MOUSEMOVEDRAG, self.OnGlobalMouseMoveDrag) 647 648 def LoadTooltip(self, panel, owner): 649 self.AddLabelMedium(text=localization.GetByLabel('UI/Crate/HackingHint'), padding=(24, 8, 24, 8)) 650 651 def ShowPanel(self, owner): 652 animations.FadeTo(self, duration=1.5) 653 654 def OnClick(self, *args): 655 FadeOutPanelAndClose(self) 656 657 def OnGlobalMouseMoveDrag(self, *args): 658 if not self.destroyed: 659 RefreshPanelPosition(self) 660 return True 661 return False