tournamentRefereeTools.py (74973B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\devtools\script\tournamentRefereeTools.py 2 from collections import namedtuple 3 import blue 4 import carbonui.const as uiconst 5 import evetypes 6 import localization 7 import telemetry 8 import tournamentmanagement.const as tourneyConst 9 import uthread 10 import utillib 11 from carbon.common.script.sys.service import Service 12 from carbon.common.script.util import timerstuff 13 from carbon.common.script.util.timerstuff import AutoTimer 14 from carbonui.control.button import Button 15 from carbonui.control.combo import Combo 16 from carbonui.control.scrollentries import SE_BaseClassCore 17 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText 18 from carbonui.primitives.container import Container 19 from carbonui.primitives.containerAutoSize import ContainerAutoSize 20 from carbonui.primitives.fill import Fill 21 from carbonui.primitives.flowcontainer import FlowContainer 22 from carbonui.primitives.layoutGrid import LayoutGrid 23 from carbonui.uicore import uicore 24 from carbonui.util.various_unsorted import MapIcon, SortListOfTuples, Transplant 25 from eve.client.script.ui.control.entries.generic import Generic 26 from eve.client.script.ui.control.entries.util import GetFromClass 27 from eve.client.script.ui.control.eveIcon import Icon 28 from carbonui.control.window import Window 29 from eve.client.script.ui.control.eveLabel import EveLabelMedium 30 from eve.client.script.ui.util import uix 31 from eve.client.script.ui.control import eveIcon, eveLabel, eveScroll 32 from eve.common.lib import appConst as const 33 from eve.common.script.net import eveMoniker 34 from eveexceptions import UserError 35 from eveservices.menu import GetMenuService 36 from player_messaging.client.ui_message import prompt_player_fsd_dialog 37 EntryRow = namedtuple('EntryRow', 'character groupName typeName maxDistance distance') 38 EntryRow.__guid__ = 'at.EntryRow' 39 WINDOW_WIDTH = 525 40 MINCOLWIDTH = 16 41 PREGAME_RANGE_LINES = 34 42 43 class ColumnLine(SE_BaseClassCore): 44 __guid__ = 'listentry.ColumnLine' 45 46 def __init__(self, **kwargs): 47 self.overlay = None 48 super(ColumnLine, self).__init__(**kwargs) 49 50 @telemetry.ZONE_METHOD 51 def Startup(self, args): 52 self._clicks = 0 53 self.clickTimer = None 54 self.columns = [] 55 self.cursor = uiconst.UICURSOR_DEFAULT 56 57 @telemetry.ZONE_METHOD 58 def Load(self, node): 59 self.LoadLite(node) 60 node.needReload = 0 61 if node.Get('selectable', 1) and node.Get('selected', 0): 62 self.Select() 63 else: 64 self.Deselect() 65 if self.overlay is not None: 66 if self.overlay.parent == self: 67 self.overlay.SetParent(None) 68 self.overlay = None 69 if node.Get('overlay', None) is not None: 70 node.overlay.SetParent(self, idx=0) 71 self.overlay = node.overlay 72 self.UpdateOverlay() 73 self.UpdateTriangles() 74 75 def _OnSizeChange_NoBlock(self, *args): 76 self.UpdateOverlay() 77 78 def UpdateOverlay(self): 79 if self.overlay is not None: 80 customTabstops = GetCustomTabstops(self.sr.node.columnID) 81 if customTabstops: 82 totalColWidth = sum(customTabstops) 83 else: 84 totalColWidth = sum([ each.width for each in self.columns ]) 85 self.overlay.left = max(totalColWidth, self.width - self.overlay.width) 86 87 def LoadLite(self, node): 88 i = 0 89 for each in node.texts: 90 self.LoadColumn(i, each) 91 i += 1 92 93 for each in self.columns[i:]: 94 each.Close() 95 96 self.columns = self.columns[:i] 97 self.UpdateColumnOrder(0) 98 99 @telemetry.ZONE_METHOD 100 def UpdateColumnOrder(self, updateEntries = 1, onlyVisible = False): 101 displayOrder = settings.user.ui.Get('columnDisplayOrder_%s' % self.sr.node.columnID, None) or [ i for i in xrange(len(self.columns)) ] 102 customTabstops = GetCustomTabstops(self.sr.node.columnID) 103 if displayOrder is not None and len(displayOrder) == len(self.columns): 104 left = 0 105 for columnIdx in displayOrder: 106 colWidth = customTabstops[columnIdx] 107 col = self.columns[columnIdx] 108 col.left = left 109 col.width = colWidth 110 if not self.sr.node.Get('editable', 0): 111 col.width -= 2 112 left += colWidth 113 114 self.sr.node.customTabstops = customTabstops 115 if updateEntries: 116 associates = self.FindAssociatingEntries() 117 for node in associates: 118 if node.panel and (not onlyVisible or onlyVisible and node.panel.state != uiconst.UI_HIDDEN): 119 node.panel.UpdateColumnOrder(0) 120 node.panel.UpdateOverlay() 121 122 def OnMouseEnter(self, *args): 123 SE_BaseClassCore.OnMouseEnter(self, *args) 124 if self.sr.node: 125 if self.sr.node.Get('OnMouseEnter', None): 126 self.sr.node.OnMouseEnter(self) 127 128 def OnMouseExit(self, *args): 129 SE_BaseClassCore.OnMouseExit(self, *args) 130 if self.sr.node: 131 if self.sr.node.Get('OnMouseExit', None): 132 self.sr.node.OnMouseExit(self) 133 134 def OnClick(self, *args): 135 if self.sr.node: 136 if self.sr.node.Get('selectable', 1): 137 self.sr.node.scroll.SelectNode(self.sr.node) 138 prompt_player_fsd_dialog('ListEntryClick') 139 if self.sr.node.Get('OnClick', None): 140 self.sr.node.OnClick(self) 141 142 def GetMenu(self): 143 if self.sr.node and self.sr.node.Get('scroll', None) and getattr(self.sr.node.scroll, 'GetSelectedNodes', None): 144 self.sr.node.scroll.GetSelectedNodes(self.sr.node) 145 if self.sr.node and self.sr.node.Get('GetMenu', None): 146 return self.sr.node.GetMenu(self) 147 if getattr(self, 'itemID', None) or getattr(self, 'typeID', None): 148 return GetMenuService().GetMenuFromItemIDTypeID(getattr(self, 'itemID', None), getattr(self, 'typeID', None)) 149 return [] 150 151 def LoadColumn(self, idx, textOrObject): 152 node = self.sr.node 153 if len(self.columns) > idx: 154 col = self.columns[idx] 155 col.height = self.height 156 else: 157 col = Container(name='column_%s' % idx, parent=self, align=uiconst.TOPLEFT, height=self.height, clipChildren=1, state=uiconst.UI_PICKCHILDREN, idx=0) 158 col.textCtrl = eveLabel.Label(text='', parent=col, fontsize=self.sr.node.Get('fontsize', 12), letterspace=self.sr.node.Get('letterspace', 0), uppercase=self.sr.node.Get('uppercase', 0), state=uiconst.UI_DISABLED, align=uiconst.CENTERLEFT, maxLines=1) 159 col.textCtrl.left = self.sr.node.Get('padLeft', 6) 160 col.editHandle = None 161 col.triangle = None 162 col.columnIdx = idx 163 col.OnDblClick = (self.OnHeaderDblClick, col) 164 col.OnClick = (self.OnHeaderClick, col) 165 col.GetMenu = lambda *args: self.OnHeaderGetMenu(col) 166 col.cursor = uiconst.UICURSOR_DEFAULT 167 self.columns.append(col) 168 for each in col.children[:]: 169 if each not in (col.textCtrl, 170 col.editHandle, 171 col.triangle, 172 textOrObject): 173 each.Close() 174 175 if isinstance(textOrObject, basestring): 176 col.textCtrl.state = uiconst.UI_DISABLED 177 col.textCtrl.text = textOrObject 178 else: 179 col.textCtrl.state = uiconst.UI_HIDDEN 180 if textOrObject not in col.children: 181 Transplant(textOrObject, col, 0) 182 if self.sr.node.Get('editable', 0): 183 col.state = uiconst.UI_NORMAL 184 if col.editHandle: 185 col.editHandle.state = uiconst.UI_NORMAL 186 else: 187 par = Container(name='scaleHandle_%s' % idx, parent=col, align=uiconst.TOPRIGHT, height=self.height - 2, width=5, idx=0, state=uiconst.UI_NORMAL) 188 par.OnMouseDown = (self.StartScaleCol, par) 189 par.OnMouseUp = (self.EndScaleCol, par) 190 par.OnMouseMove = (self.ScalingCol, par) 191 par.cursor = uiconst.UICORSOR_HORIZONTAL_RESIZE 192 par.columnIdx = idx 193 col.editHandle = par 194 else: 195 col.state = uiconst.UI_PICKCHILDREN 196 if col.editHandle: 197 col.editHandle.state = uiconst.UI_HIDDEN 198 199 def FindAssociatingEntries(self): 200 ret = [] 201 for node in self.sr.node.scroll.GetNodes()[self.sr.node.idx + 1:]: 202 if node.Get('columnID', None) == self.sr.node.columnID: 203 ret.append(node) 204 205 return ret 206 207 def GetHeight(self, *args): 208 node, _ = args 209 node.height = uix.GetTextHeight(''.join([ text for text in node.texts if isinstance(text, basestring) ]), maxLines=1) + 1 210 return node.height 211 212 def StartScaleCol(self, sender, *args): 213 if uicore.uilib.rightbtn: 214 return 215 l, t, w, h = sender.parent.GetAbsolute() 216 sl, st, sw, sh = sender.GetAbsolute() 217 associates = self.FindAssociatingEntries() 218 self._startScalePosition = uicore.uilib.x 219 self._startScalePositionDiff = sl - uicore.uilib.x 220 self._scaleColumnIdx = sender.columnIdx 221 self._scaleColumnInitialWidth = sender.parent.width 222 self._minLeft = l + MINCOLWIDTH 223 self.scaleEntries = associates 224 self.ScalingCol(sender) 225 226 def ScalingCol(self, sender, *args): 227 if getattr(self, '_startScalePosition', None): 228 diff = uicore.uilib.x - self._startScalePosition 229 sender.parent.width = max(MINCOLWIDTH, self._scaleColumnInitialWidth + diff) 230 self.sr.node.customTabstops[self._scaleColumnIdx] = sender.parent.width 231 self.UpdateColumnOrder(onlyVisible=True) 232 233 def EndScaleCol(self, sender, *args): 234 prefsID = self.sr.node.Get('columnID', None) 235 if prefsID: 236 current = settings.user.ui.Get('listentryColumns_%s' % prefsID, self.sr.node.customTabstops) 237 current[self._scaleColumnIdx] = sender.parent.width 238 settings.user.ui.Set('listentryColumns_%s' % prefsID, current) 239 self.sr.node.customTabstops[self._scaleColumnIdx] = sender.parent.width 240 self.scaleEntries = None 241 self._startScalePosition = 0 242 243 def ChangeSort(self, sender, *args): 244 columnID = self.sr.node.Get('columnID', None) 245 if columnID: 246 current = settings.user.ui.Get('columnSorts_%s' % columnID, {}) 247 if sender.columnIdx in current: 248 direction = not current[sender.columnIdx] 249 else: 250 direction = False 251 current[sender.columnIdx] = direction 252 settings.user.ui.Set('columnSorts_%s' % columnID, current) 253 current = settings.user.ui.Get('activeSortColumns', {}) 254 current[columnID] = sender.columnIdx 255 settings.user.ui.Set('activeSortColumns', current) 256 self.UpdateTriangles() 257 self.UpdateColumnOrder() 258 associates = self.FindAssociatingEntries() 259 self.UpdateColumnSort(associates, columnID) 260 callback = self.sr.node.Get('OnSortChange', None) 261 if callback: 262 callback() 263 264 def UpdateColumnSort(self, entries, columnID): 265 if not entries: 266 return 267 startIdx = entries[0].idx 268 endIdx = entries[-1].idx 269 entries = SortColumnEntries(entries, columnID) 270 self.sr.node.scroll.sr.nodes = self.sr.node.scroll.sr.nodes[:startIdx] + entries + self.sr.node.scroll.sr.nodes[endIdx + 1:] 271 idx = 0 272 for entry in self.sr.node.scroll.GetNodes()[startIdx:]: 273 if entry.Get('needReload', 0) and entry.panel: 274 entry.panel.LoadLite(entry) 275 idx += 1 276 277 self.sr.node.scroll.UpdatePosition() 278 279 def GetSortDirections(self): 280 prefsID = self.sr.node.Get('columnID', None) 281 if prefsID: 282 return settings.user.ui.Get('columnSorts_%s' % prefsID, {}) 283 return {} 284 285 def OnHeaderDblClick(self, sender, *args): 286 self._clicks += 1 287 self.ExecClick(sender) 288 289 def OnHeaderClick(self, sender, *args): 290 self._clicks += 1 291 self.clickTimer = AutoTimer(250, self.ExecClick, sender) 292 293 def OnHeaderGetMenu(self, sender, *args): 294 m = [(localization.GetByLabel('UI/Control/Entries/ColumnMoveForward'), self.ChangeColumnOrder, (sender, -1)), (localization.GetByLabel('UI/Control/Entries/ColumnMoveBackward'), self.ChangeColumnOrder, (sender, 1))] 295 return m 296 297 def ChangeColumnOrder(self, column, direction): 298 currentDisplayOrder = settings.user.ui.Get('columnDisplayOrder_%s' % self.sr.node.columnID, None) or [ i for i in xrange(len(self.sr.node.texts)) ] 299 newDisplayOrder = currentDisplayOrder[:] 300 currentlyInDisplayOrder = currentDisplayOrder.index(column.columnIdx) 301 newDisplayOrder.pop(currentlyInDisplayOrder) 302 newDisplayOrder.insert(max(0, direction + currentlyInDisplayOrder), column.columnIdx) 303 settings.user.ui.Set('columnDisplayOrder_%s' % self.sr.node.columnID, newDisplayOrder) 304 self.UpdateColumnOrder() 305 306 def ExecClick(self, sender, *args): 307 if self._clicks > 1: 308 self.ResetColumn(sender) 309 elif self._clicks == 1: 310 self.ChangeSort(sender) 311 if not self.destroyed: 312 self._clicks = 0 313 self.clickTimer = None 314 315 def ResetColumn(self, sender, *args): 316 shift = uicore.uilib.Key(uiconst.VK_SHIFT) 317 if shift: 318 idxs = [] 319 for i in xrange(len(self.sr.node.texts)): 320 idxs.append(i) 321 322 else: 323 idxs = [sender.columnIdx] 324 associates = self.FindAssociatingEntries() 325 for columnIdx in idxs: 326 textsInColumn = [] 327 columnWidths = [] 328 for node in [self.sr.node] + associates: 329 text = node.texts[columnIdx] 330 textsInColumn.append(text) 331 padLeft = node.Get('padLeft', 6) 332 padRight = node.Get('padRight', 6) 333 fontsize = node.Get('fontsize', 12) 334 hspace = node.Get('letterspace', 0) 335 uppercase = node.Get('uppercase', 0) 336 extraSpace = 0 337 if node is self.sr.node and self.sr.node.Get('editable', 0): 338 extraSpace = 10 339 if isinstance(text, basestring): 340 textWidth = uix.GetTextWidth(text, fontsize, hspace, uppercase) 341 if text: 342 columnWidths.append(padLeft + textWidth + padRight + 3 + extraSpace) 343 else: 344 columnWidths.append(3 + extraSpace) 345 else: 346 textWidth = text.width 347 columnWidths.append(text.width) 348 349 self.sr.node.customTabstops[columnIdx] = newWidth = max(columnWidths) 350 self.UpdateColumnOrder() 351 352 def UpdateTriangles(self): 353 activeColumn = settings.user.ui.Get('activeSortColumns', {}).get(self.sr.node.columnID, 0) 354 sortDirections = self.GetSortDirections() 355 for column in self.columns: 356 direction = sortDirections.get(column.columnIdx, True) 357 if column.columnIdx == activeColumn and self.sr.node.Get('editable', 0): 358 if not column.triangle: 359 column.triangle = Icon(align=uiconst.CENTERRIGHT, pos=(3, 0, 16, 16), parent=column, idx=0, name='directionIcon', icon='ui_1_16_16') 360 column.triangle.state = uiconst.UI_DISABLED 361 if direction == 1: 362 MapIcon(column.triangle, 'ui_1_16_16') 363 else: 364 MapIcon(column.triangle, 'ui_1_16_15') 365 elif column.triangle: 366 column.triangle.state = uiconst.UI_HIDDEN 367 368 @classmethod 369 def GetCopyData(cls, node): 370 displayOrder = settings.user.ui.Get('columnDisplayOrder_%s' % node.columnID, None) or [ i for i in xrange(len(node.texts)) ] 371 retString = [] 372 for i in displayOrder: 373 if i <= len(node.texts) - 1: 374 retString.append(node.texts[i]) 375 376 return '<t>'.join(retString) 377 378 379 def GetCustomTabstops(columnID): 380 return settings.user.ui.Get('listentryColumns_%s' % columnID, None) 381 382 383 def SortColumnEntries(nodes, columnID): 384 if not nodes: 385 return nodes 386 displayOrder = settings.user.ui.Get('columnDisplayOrder_%s' % columnID, None) or [ i for i in xrange(len(nodes[0].sortData)) ] 387 c = 0 388 sortData = [] 389 for node in nodes: 390 if not c: 391 c = len(node.sortData) 392 elif c != len(node.sortData): 393 raise RuntimeError('Mismatch in column sizes') 394 sortData.append((ReorderSortData(node.sortData[:], columnID, displayOrder), node)) 395 396 sortDirections = settings.user.ui.Get('columnSorts_%s' % columnID, [0, {}]) 397 sortData = SortListOfTuples(sortData) 398 activeColumn = settings.user.ui.Get('activeSortColumns', {}).get(columnID, 0) 399 if activeColumn in sortDirections and sortDirections[activeColumn] is False: 400 sortData.reverse() 401 return sortData 402 403 404 def ReorderSortData(sortData, columnID, displayOrder): 405 if not sortData: 406 return sortData 407 if len(displayOrder) != len(sortData): 408 return sortData 409 ret = [] 410 activeColumn = settings.user.ui.Get('activeSortColumns', {}).get(columnID, 0) 411 if activeColumn in displayOrder: 412 di = displayOrder.index(activeColumn) 413 else: 414 di = 0 415 for columnIdx in displayOrder[di:]: 416 ret.append(sortData[columnIdx]) 417 418 return ret 419 420 421 def InitCustomTabstops(columnID, entries): 422 idxs = [] 423 for i in xrange(len(entries[0].texts)): 424 idxs.append(i) 425 426 if not len(idxs): 427 return 428 current = GetCustomTabstops(columnID) 429 if current is not None: 430 if len(current) == len(idxs): 431 return 432 retval = [] 433 for columnIdx in idxs: 434 textsInColumn = [] 435 columnWidths = [] 436 for node in entries: 437 text = node.texts[columnIdx] 438 textsInColumn.append(text) 439 padLeft = node.Get('padLeft', 6) 440 padRight = node.Get('padRight', 6) 441 fontsize = node.Get('fontsize', 12) 442 hspace = node.Get('letterspace', 0) 443 uppercase = node.Get('uppercase', 0) 444 if isinstance(text, basestring): 445 textWidth = uix.GetTextWidth(text, fontsize, hspace, uppercase) 446 else: 447 textWidth = text.width 448 extraSpace = 0 449 if node.Get('editable', 0): 450 extraSpace = 10 451 columnWidths.append(padLeft + textWidth + padRight + 3 + extraSpace) 452 453 retval.append(max(columnWidths)) 454 455 settings.user.ui.Set('listentryColumns_%s' % columnID, retval) 456 457 458 class AtCompetitorEntry(ColumnLine): 459 __guid__ = 'listentry.AtCompetitorEntry' 460 461 def Startup(self, args): 462 super(AtCompetitorEntry, self).Startup(args) 463 self.warn = Fill(name='warn', parent=self, padTop=1, color=(1.0, 0.0, 0.0, 0.125), state=uiconst.UI_HIDDEN) 464 465 466 class TournamentRefereeTool(Window): 467 __guid__ = 'form.TournamentRefereeTool' 468 __notifyevents__ = ['OnCompetitorTrackingUpdate', 'OnCompetitorTrackingStart', 'OnRemovalAsRef'] 469 default_arenaRadius = 125 470 default_windowID = 'TournamentRefereeTool' 471 472 def ApplyAttributes(self, attributes): 473 Window.ApplyAttributes(self, attributes) 474 self.SetCaption('Tournament Referee Tool') 475 self.SetMinSize((WINDOW_WIDTH, 550)) 476 self.centerItemID = None 477 self.arenaRadius = 125000 478 self.isToggling = False 479 self.playersCanLock = True 480 self.playersCanWarp = True 481 self.playersCanLaunchDrones = False 482 self.matchDetails = [None, 483 None, 484 None, 485 None] 486 self.ConstructLayout() 487 sm.RegisterForNotifyEvent(self, 'ProcessTournamentMatchUpdate') 488 self.solarsystemID = None 489 self.pregameRangeTimer = None 490 self.countdownTimer = None 491 492 def ConstructLayout(self): 493 localTournamentService = sm.GetService('allianceTournamentSvc') 494 tourneyMgr = sm.RemoteSvc('tourneyMgr') 495 tournaments, tourneySystems, activeSystems = tourneyMgr.GetTourneySetup() 496 locations = [] 497 for systemID, (_combatBeacons, _warpBubbles) in tourneySystems.iteritems(): 498 locations.append(systemID) 499 500 uthread.new(cfg.evelocations.Prime, locations) 501 self.beaconOptions = {'red': [('1A', 0), 502 ('1B', 1), 503 ('1C', 2), 504 ('1D', 3)], 505 'blue': [('2A', 0), 506 ('2B', 1), 507 ('2C', 2), 508 ('2D', 3)]} 509 self.resetButton = Button(label='Reset Match', parent=self.content, align=uiconst.TOBOTTOM, func=self.ResetMatch, state=uiconst.UI_HIDDEN, padding=(0, 4, 0, 0)) 510 tourneyOptions = [] 511 for tourneyID, name in tournaments.iteritems(): 512 if len(tourneyMgr.GetPotentialMatches(tourneyID)) > 0: 513 tourneyOptions.append((name, tourneyID)) 514 515 systemOptions = [] 516 defaultSelectSolarSystem = '__random__' 517 for systemID in tourneySystems: 518 systemName = cfg.evelocations.Get(systemID).locationName 519 if systemID in activeSystems: 520 systemName = '!' + systemName + ' - IN USE!' 521 systemOptions.append((systemName, systemID)) 522 if systemID == session.solarsystemid: 523 defaultSelectSolarSystem = systemID 524 525 self.allianceSelections = ContainerAutoSize(name='aliSelect', parent=self.content, align=uiconst.TOTOP) 526 self.pointOptions = [] 527 self.banOptions = [] 528 self.timeSelected = 600 529 self.overtimeSelected = 300 530 531 def TourneySelChanged(_combo, _tName, tourneyID): 532 if tourneyID is None: 533 self.matchSelect.options = [] 534 else: 535 possibleMatches = tourneyMgr.GetPotentialMatches(tourneyID) 536 menuOptions = [] 537 allDetails = tourneyMgr.GetAllCurrentSeriesMatchDetails(tourneyID) 538 for seriesID, details in possibleMatches.iteritems(): 539 seriesText = '[S%d M%d/%d] %s vs %s' % (seriesID + 1, 540 allDetails[seriesID][0] + 1, 541 allDetails[seriesID][1], 542 details['redTeam'], 543 details['blueTeam']) 544 if details['system'] > 0: 545 seriesText += ' - {}'.format(cfg.evelocations.Get(details['system']).locationName) 546 menuOptions.append((seriesText, (seriesID, details['redTeam'], details['blueTeam']))) 547 548 self.matchSelect.LoadOptions(menuOptions) 549 tournamentDetails = tourneyMgr.QueryTournamentDetails(tourneyID) 550 ships = tournamentDetails['allowedShipList'] 551 self.banOptions = sorted(ships) 552 maxPoints = tournamentDetails['maximumPointsMatch'] 553 self.pointOptions = [(str(maxPoints), maxPoints)] 554 self.pointsSelect.LoadOptions(self.pointOptions) 555 self.timeSelected = tournamentDetails['matchLength'] 556 self.overtimeSelected = tournamentDetails['overtimeLength'] 557 self.timeSelect.SelectItemByValue(self.timeSelected) 558 self.overtimeSelect.SelectItemByValue(self.overtimeSelected) 559 self.externalRulesetID = tournamentDetails['externalRulesetID'] 560 561 self.tourneySelect = Combo(label='Select Tournament:', parent=self.allianceSelections, align=uiconst.TOTOP, padding=(0, 16, 0, 24), name='tourneySel', options=[('Select Tourney', None)] + tourneyOptions, callback=TourneySelChanged) 562 self.matchSelect = Combo(label='Select Match:', parent=self.allianceSelections, align=uiconst.TOTOP, padding=(0, 0, 0, 24), name='matchSel', options=[('Pick Tourney First', None)]) 563 self.solSystemSelect = Combo(label='Select Solar System', parent=self.allianceSelections, align=uiconst.TOTOP, options=systemOptions, pos=(0, 0, 0, 0), padding=(0, 0, 0, 24), select=defaultSelectSolarSystem) 564 self.pointsSelect = Combo(label='Points Allowed', parent=self.allianceSelections, align=uiconst.TOTOP, name='pointSel', options=self.pointOptions, padding=(0, 0, 0, 24)) 565 self.timeSelect = Combo(label='Match Length', parent=self.allianceSelections, align=uiconst.TOTOP, name='timeSel', options=(('10:00', 600), 566 ('9:00', 540), 567 ('8:00', 480), 568 ('7:00', 420), 569 ('6:00', 360), 570 ('5:00', 300), 571 ('2:00', 120)), select=self.timeSelected, padding=(0, 0, 0, 24)) 572 self.overtimeSelect = Combo(label='Overtime Length', parent=self.allianceSelections, align=uiconst.TOTOP, name='timeSel', options=(('5:00', 300), 573 ('4:00', 240), 574 ('3:00', 180), 575 ('2:00', 120), 576 ('1:00', 60), 577 ('None', 0)), select=self.overtimeSelected, padding=(0, 0, 0, 8)) 578 self.startButton = Button(label='Start Match', parent=self.allianceSelections, align=uiconst.TOTOP, pos=(0, 0, 0, 0), padding=(0, 0, 0, 8), func=self.StartMatch) 579 self.teleportButtonSystem = Button(label='Teleport Self to System', parent=self.allianceSelections, align=uiconst.TOTOP, pos=(0, 0, 0, 0), padding=(0, 0, 0, 8), func=self.TeleportRef) 580 self.teleportButtonHome = Button(label='Teleport Self Home', parent=self.allianceSelections, align=uiconst.TOTOP, pos=(0, 0, 0, 0), padding=(0, 0, 0, 8), func=self.TeleportRefHome) 581 self.shipPilotCheck = Container(name='shipPilotCheck', parent=self.content, state=uiconst.UI_HIDDEN, align=uiconst.TOALL) 582 Button(label="LET'S DO THIS", parent=self.shipPilotCheck, align=uiconst.TORIGHT, func=self.CompleteShipPilotCheck) 583 boxes = Container(name='boxContainer', parent=self.shipPilotCheck, align=uiconst.TOALL) 584 redTeamBox = Container(name='redTeamBox', parent=boxes, align=uiconst.TOTOP_PROP, height=0.5) 585 blueTeamBox = Container(name='blueTeamBox', parent=boxes, align=uiconst.TOTOP_PROP, height=0.5) 586 blueButtons = FlowContainer(name='shipPilotCheckButtons', parent=blueTeamBox, align=uiconst.TOBOTTOM, padding=(0, 16, 4, 4)) 587 redButtons = FlowContainer(name='shipPilotCheckButtons', parent=redTeamBox, align=uiconst.TOBOTTOM, padding=(0, 16, 4, 4)) 588 Button(label='Refresh Info', parent=blueButtons, align=uiconst.TOLEFT, func=self.RefreshShipPilotCheck, args=(1,)) 589 self.blueLockBtn = Button(label='Lock Member List', parent=blueButtons, align=uiconst.TOLEFT, func=self.LockMemberList, args=(1,)) 590 self.blueUnlockBtn = Button(label='Unlock Member List', parent=blueButtons, align=uiconst.TOLEFT, func=self.UnlockMemberList, args=(1,), state=uiconst.UI_HIDDEN) 591 self.blueTeleportBtn = Button(label='Teleport Players', parent=blueButtons, align=uiconst.TOLEFT, func=self.TeleportPlayers, args=(1,), state=uiconst.UI_HIDDEN) 592 self.blueTeleportBeacon = Combo(label='Beacon select', parent=blueButtons, align=uiconst.TOLEFT, state=uiconst.UI_HIDDEN, options=[]) 593 self.blueOverFleetBtn = Button(label='Override Fleet Boss charID', parent=blueButtons, align=uiconst.TOLEFT, func=self.OverrideFleetBossID, args=(1,)) 594 self.blueAddPlayerBtn = Button(label='Add Player', parent=blueButtons, align=uiconst.TOLEFT, func=self.AddPlayer, args=(1,), state=uiconst.UI_HIDDEN) 595 self.blueReturnBtn = Button(label='Return Players', parent=blueButtons, align=uiconst.TOLEFT, func=self.ReturnTeamPlayers, args=(1,), state=uiconst.UI_HIDDEN) 596 Button(label='Refresh Info', parent=redButtons, align=uiconst.TOLEFT, func=self.RefreshShipPilotCheck, args=(0,)) 597 self.redLockBtn = Button(label='Lock Member List', parent=redButtons, align=uiconst.TOLEFT, func=self.LockMemberList, args=(0,)) 598 self.redUnlockBtn = Button(label='Unlock Member List', parent=redButtons, align=uiconst.TOLEFT, func=self.UnlockMemberList, args=(0,), state=uiconst.UI_HIDDEN) 599 self.redTeleportBtn = Button(label='Teleport Players', parent=redButtons, align=uiconst.TOLEFT, func=self.TeleportPlayers, args=(0,), state=uiconst.UI_HIDDEN) 600 self.redTeleportBeacon = Combo(label='Beacon select', parent=redButtons, align=uiconst.TOLEFT, state=uiconst.UI_HIDDEN, options=[]) 601 self.redOverFleetBtn = Button(label='Override Fleet Boss charID', parent=redButtons, align=uiconst.TOLEFT, func=self.OverrideFleetBossID, args=(0,)) 602 self.redAddPlayerBtn = Button(label='Add Player', parent=redButtons, align=uiconst.TOLEFT, func=self.AddPlayer, args=(0,), state=uiconst.UI_HIDDEN) 603 self.redReturnBtn = Button(label='Return Players', parent=redButtons, align=uiconst.TOLEFT, func=self.ReturnTeamPlayers, args=(0,), state=uiconst.UI_HIDDEN) 604 self.shipcheckBlueTeamLabel = eveLabel.Label(text='Blue Team', parent=blueTeamBox, color=(0.5, 0.5, 1, 1), align=uiconst.TOTOP) 605 self.shipcheckRedTeamLabel = eveLabel.Label(text='Red Team', parent=redTeamBox, color=(1, 0.3, 0.3, 1), align=uiconst.TOTOP) 606 self.shipcheckRedScroll = eveScroll.Scroll(parent=redTeamBox, id='atRedTeamScroll') 607 self.shipcheckBlueScroll = eveScroll.Scroll(parent=blueTeamBox, id='atBlueTeamScroll') 608 self.pregameList = Container(name='pregameList', parent=self.content, state=uiconst.UI_HIDDEN, align=uiconst.TOALL) 609 pregameRangeContainer = Container(name='rangeCont', parent=self.pregameList, align=uiconst.TORIGHT, width=110) 610 for idx in xrange(PREGAME_RANGE_LINES): 611 label = eveLabel.Label(text='', parent=pregameRangeContainer, align=uiconst.TOTOP, padTop=5, padLeft=4, maxLines=1) 612 setattr(self, 'pregameDistance%d' % (idx,), label) 613 614 lockCont = Container(name='locks', parent=self.pregameList, align=uiconst.TOBOTTOM, height=50) 615 self.pregameLockStatus = eveLabel.EveLabelLarge(text="Player locking: <color='green'>Allowed</color>", parent=lockCont, align=uiconst.TOLEFT_PROP, width=0.5, padTop=10) 616 tempContainer = Container(parent=lockCont, align=uiconst.TORIGHT_PROP, width=0.5) 617 Button(label='Toggle Locking', parent=tempContainer, func=self.ToggleLocks, align=uiconst.TORIGHT, padTop=5, padBottom=5) 618 warpCont = Container(name='warps', parent=self.pregameList, align=uiconst.TOBOTTOM, height=50) 619 self.pregameWarpStatus = eveLabel.EveLabelLarge(text="Player warping: <color='red'>Disallowed</color>", parent=warpCont, align=uiconst.TOLEFT_PROP, width=0.5, padTop=10) 620 tempContainer = Container(parent=warpCont, align=uiconst.TORIGHT_PROP, width=0.5) 621 Button(label='Toggle Warping', parent=tempContainer, func=self.ToggleWarping, align=uiconst.TORIGHT, padTop=5, padBottom=5) 622 moveCont = Container(name='move', parent=self.pregameList, align=uiconst.TOBOTTOM, height=50) 623 self.pregameMoveStatus = eveLabel.EveLabelLarge(text="Player movement: <color='red'>Disallowed</color>", parent=moveCont, align=uiconst.TOLEFT_PROP, width=0.5, padTop=10) 624 tempContainer = Container(parent=moveCont, align=uiconst.TORIGHT_PROP, width=0.5) 625 Button(label='Toggle Movement', parent=tempContainer, func=self.ToggleMovement, align=uiconst.TORIGHT, padTop=5, padBottom=5) 626 droneCont = Container(name='drones', parent=self.pregameList, align=uiconst.TOBOTTOM, height=50) 627 self.pregameDroneStatus = eveLabel.EveLabelLarge(text="Player drones: <color='red'>Disallowed</color>", parent=droneCont, align=uiconst.TOLEFT_PROP, width=0.5, padTop=10) 628 tempContainer = Container(parent=droneCont, align=uiconst.TORIGHT_PROP, width=0.5) 629 Button(label='Toggle Drones', parent=tempContainer, func=self.ToggleDrones, align=uiconst.TORIGHT, padTop=5, padBottom=5) 630 stepOne = Container(name='stepOne', parent=self.pregameList, align=uiconst.TOTOP, height=50) 631 self.pregameStepOneText = eveLabel.EveLabelLarge(text="Step 1 - Let them warp, don't let them lock", parent=stepOne, align=uiconst.TOLEFT_PROP, width=0.5, padTop=10) 632 tempContainer = Container(parent=stepOne, align=uiconst.TORIGHT_PROP, width=0.5) 633 Button(label='Do Step 1', parent=tempContainer, func=self.PreGameStepOne, align=uiconst.TORIGHT, padTop=5, padBottom=5) 634 stepThree = Container(name='stepThree', parent=self.pregameList, align=uiconst.TOTOP, height=50) 635 self.pregameStepThreeText = eveLabel.EveLabelLarge(text='Step 2 - Lock warping again', parent=stepThree, align=uiconst.TOLEFT_PROP, width=0.5, padTop=10) 636 tempContainer = Container(parent=stepThree, align=uiconst.TORIGHT_PROP, width=0.5) 637 Button(label='Do Step 2', parent=tempContainer, func=self.PreGameStepThree, align=uiconst.TORIGHT, padTop=5, padBottom=5) 638 stepFour = Container(name='stepFour', parent=self.pregameList, align=uiconst.TOTOP, height=50) 639 self.pregameStepFourText = eveLabel.EveLabelLarge(text='Step 3 - Start Countdown', parent=stepFour, align=uiconst.TOLEFT_PROP, width=0.5, padTop=10) 640 tempContainer = Container(parent=stepFour, align=uiconst.TORIGHT_PROP, width=0.5) 641 Button(label='Do Step 3', parent=tempContainer, func=self.PreGameStepFour, align=uiconst.TORIGHT, padTop=5, padBottom=5) 642 self.countdownCont = Container(name='Countdown', parent=self.pregameList, align=uiconst.TOALL, state=uiconst.UI_HIDDEN) 643 self.countdownText = eveLabel.Label(parent=self.countdownCont, align=uiconst.CENTERTOP, fontsize=48, color=(1, 0, 0, 1)) 644 self.countdownAbort = Button(label='Abort!', parent=self.countdownCont, align=uiconst.TOALL, func=self.AbortCountdown, padTop=65, padBottom=28) 645 self.countdownAbort.width = self.countdownAbort.height = 0 646 self.countdownAbort.sr.label.fontsize = 32 647 self.ConstructRangeCheckLayout(localTournamentService) 648 self.postgameList = Container(name='postgameList', parent=self.content, state=uiconst.UI_HIDDEN, align=uiconst.TOALL) 649 stepOne = Container(name='stepOne', parent=self.postgameList, align=uiconst.TOTOP, height=50) 650 self.postgameStepOneText = eveLabel.EveLabelLarge(text='Step 1 - Send everyone back home', parent=stepOne, align=uiconst.TOLEFT_PROP, width=0.75, padTop=10) 651 tempContainer = Container(parent=stepOne, align=uiconst.TORIGHT_PROP, width=0.2) 652 stepOneBtn = Button(label='Do Step 1', parent=tempContainer, func=self.PostGameStepOne, align=uiconst.TOLEFT, padTop=5, padBottom=5, state=uiconst.UI_HIDDEN) 653 stepTwo = Container(name='stepTwo', parent=self.postgameList, align=uiconst.TOTOP, height=50) 654 self.postgameStepTwoText = eveLabel.EveLabelLarge(text='Step 2 - Clean up the grid', parent=stepTwo, align=uiconst.TOLEFT_PROP, width=0.75, padTop=10) 655 tempContainer = Container(parent=stepTwo, align=uiconst.TORIGHT_PROP, width=0.2) 656 stepTwoBtn = Button(label='Do Step 2', parent=tempContainer, func=self.PostGameStepTwo, align=uiconst.TOLEFT, padTop=5, padBottom=5, state=uiconst.UI_HIDDEN) 657 stepThree = Container(name='stepThree', parent=self.postgameList, align=uiconst.TOBOTTOM, height=50) 658 self.postgameStepThreeText = eveLabel.EveLabelLarge(text='Step 3 (optional) - Teleport home', parent=stepThree, align=uiconst.TOLEFT_PROP, width=0.75, padTop=10) 659 tempContainer = Container(parent=stepThree, align=uiconst.TORIGHT_PROP, width=0.2) 660 stepThreeBtn = Button(label='Do Step 3', parent=tempContainer, func=self.PostGameStepThree, align=uiconst.TOLEFT, padTop=5, padBottom=5, state=uiconst.UI_HIDDEN) 661 self.postGameButtons = [stepOneBtn, stepTwoBtn, stepThreeBtn] 662 self.OnCompetitorTrackingStart(localTournamentService.competitorsByShipID) 663 664 def ConstructRangeCheckLayout(self, localTournamentService): 665 self.rangeCheck = Container(name='range check', state=uiconst.UI_HIDDEN, parent=self.content, align=uiconst.TOALL) 666 self.layout_grid = LayoutGrid(parent=self.rangeCheck, align=uiconst.TOTOP, columns=3, cellSpacing=(8, 8)) 667 EveLabelMedium(text='Center Item ID', parent=self.layout_grid, align=uiconst.CENTERLEFT) 668 self.centerItemIDEdit = SingleLineEditText(name='centerItemIDEdit', setvalue=str(session.shipid), width=120) 669 self.layout_grid.AddCell(self.centerItemIDEdit, colSpan=2) 670 EveLabelMedium(text='Arena Radius km', parent=self.layout_grid, align=uiconst.CENTERLEFT) 671 self.arenaRadiusEdit = SingleLineEditText(name='arenaRadiusEdit', setvalue=self.default_arenaRadius, parent=self.layout_grid, ints=(1, 250)) 672 Button(label='Match Completed', parent=self.layout_grid, func=self.MatchCompleted) 673 startButtonText = 'Stop Tracking' if localTournamentService.isCompetitorsTrackingActive else 'Start' 674 self.startButton = Button(label=startButtonText) 675 self.startButton.OnClick = self.OnToggleStart 676 self.layout_grid.AddCell(self.startButton, colSpan=3) 677 self.scroll = eveScroll.Scroll(name='competitorsList', parent=self.rangeCheck, align=uiconst.TOALL, padTop=8) 678 679 def WaitForSessionChanges(self, buttons): 680 blue.synchro.SleepWallclock(11000) 681 for button in buttons: 682 button.state = uiconst.UI_NORMAL 683 684 def StartMatch(self, *args): 685 if session.solarsystemid != self.solSystemSelect.GetValue(): 686 raise UserError('You must be in the selected system to start a match') 687 self.banningScreen = Container(name='banningScreen', parent=self.content, state=uiconst.UI_HIDDEN, align=uiconst.TOALL, width=5) 688 self.redTeamBanningHeader = eveLabel.EveLabelLarge(text='RedTeam', parent=self.banningScreen, align=uiconst.TOTOP, color=(1, 0.3, 0.3, 1)) 689 self.redBanBox = ContainerAutoSize(name='redBanBox', parent=self.banningScreen, align=uiconst.TOTOP, top=4, _only_use_callback_when_size_changes=True, callback=self.StartMatchWindowSize) 690 self.redBans = {} 691 self.redBanChoice = Combo(label='Red Team Ban:', parent=self.banningScreen, options=self.banOptions, top=20, align=uiconst.TOTOP) 692 Button(label="Perform Red's Ban", parent=self.banningScreen, func=self.SendBan, args=(0, self.redBanChoice), align=uiconst.TOTOP) 693 self.blueTeamBanningHeader = eveLabel.EveLabelLarge(text='BlueTeam', parent=self.banningScreen, align=uiconst.TOTOP, top=30, color=(0.5, 0.5, 1, 1)) 694 self.blueBanBox = ContainerAutoSize(name='blueBanBox', parent=self.banningScreen, align=uiconst.TOTOP, top=4, _only_use_callback_when_size_changes=True, callback=self.StartMatchWindowSize) 695 self.blueBans = {} 696 self.blueBanChoice = Combo(label='Blue Team Ban:', parent=self.banningScreen, options=self.banOptions, top=20, align=uiconst.TOTOP) 697 Button(label="Perform Blue's Ban", parent=self.banningScreen, func=self.SendBan, args=(1, self.blueBanChoice), align=uiconst.TOTOP) 698 autoBanBox = Container(name='autoBanBox', parent=self.banningScreen, align=uiconst.TOTOP, height=200, top=10) 699 autoBanOverrides = Container(name='autoBanOverrides', parent=autoBanBox, align=uiconst.TOLEFT, width=200) 700 autoBanOutput = Container(name='autoBanOutput', parent=autoBanBox) 701 autoBanRedCapt = ContainerAutoSize(name='redCapt', parent=autoBanOverrides, align=uiconst.TOTOP, top=4) 702 eveLabel.Label(text='Red Captain:', parent=autoBanRedCapt, top=4) 703 self.autoBanRedCharName = eveLabel.Label(text='?', parent=autoBanRedCapt, top=4, left=100) 704 self.autoBanRedCharID = SingleLineEditText(name='redCaptID', setvalue='', OnFocusLost=self.LookupBanChars, align=uiconst.TOTOP, parent=autoBanOverrides, top=4) 705 autoBanBlueCapt = ContainerAutoSize(name='blueCapt', parent=autoBanOverrides, align=uiconst.TOTOP, top=4) 706 eveLabel.Label(text='Blue Captain:', parent=autoBanBlueCapt, top=4) 707 self.autoBanBlueCharName = eveLabel.Label(text='?', parent=autoBanBlueCapt, top=4, left=100) 708 self.autoBanBlueCharID = SingleLineEditText(name='blueCaptID', setvalue='', OnFocusLost=self.LookupBanChars, align=uiconst.TOTOP, parent=autoBanOverrides, top=4) 709 autoBanNumberBox = Container(name='autoBanNumberBox', parent=autoBanOverrides, align=uiconst.TOTOP, top=4, height=SingleLineEditText.default_height) 710 eveLabel.Label(text='Number of AutoBans: ', parent=Container(parent=autoBanNumberBox), align=uiconst.CENTERLEFT) 711 self.autoBanQty = SingleLineEditText(parent=autoBanNumberBox, name='autoBanQty', setvalue='3', align=uiconst.TORIGHT, width=50) 712 Button(label='Initiate Autobans', parent=autoBanOverrides, func=self.Autobans, align=uiconst.TOTOP, top=4) 713 eveLabel.Label(text='Auto Ban Output:', parent=autoBanOutput, align=uiconst.TOTOP, top=4, padLeft=125) 714 self.autoBanText = eveLabel.Label(text='', parent=autoBanOutput, align=uiconst.TOTOP, height=100, top=4, padLeft=125) 715 Button(label='Finalize Bans', parent=self.banningScreen, func=self.FinalizeBans, top=5, align=uiconst.TOTOP) 716 selectedMatch = self.matchSelect.GetValue() 717 self.redTeam = selectedMatch[1] 718 self.blueTeam = selectedMatch[2] 719 self.matchMoniker = eveMoniker.Moniker('tourneyMgr', self.solSystemSelect.GetValue()) 720 self.matchDetails = [-1, 721 None, 722 None, 723 None] 724 matchID, beaconIDs, captainIDs = self.matchMoniker.CreateMatch(self.tourneySelect.GetValue(), selectedMatch[0], self.pointsSelect.GetValue(), self.timeSelect.GetValue(), self.overtimeSelect.GetValue(), self.externalRulesetID) 725 self.SetCaption('Tournament Match: ' + self.matchSelect.GetKey()) 726 self.matchDetails[0] = matchID 727 self.matchDetails[3] = beaconIDs 728 self.autoBanRedCharID.SetValue(str(captainIDs[0])) 729 self.redTeamBanningHeader.text = 'Red Team - %s' % (self.redTeam,) 730 self.autoBanBlueCharID.SetValue(str(captainIDs[1])) 731 self.blueTeamBanningHeader.text = 'Blue Team - %s' % (self.blueTeam,) 732 self.LookupBanChars() 733 self.StartMatchWindowSize() 734 735 def StartMatchWindowSize(self): 736 width, height = self.GetWindowSizeForContentSize(height=self.blueBanBox.height + self.redBanBox.height, width=self.blueBanBox.width + self.redBanBox.width) 737 self.SetMinSize(size=(WINDOW_WIDTH, 500 + height), refresh=True) 738 739 def ProcessTournamentMatchUpdate(self, matchState): 740 myMatchID = self.matchDetails[0] 741 if matchState['matchID'] != myMatchID: 742 if myMatchID != -1: 743 return 744 uiScreenPerState = {tourneyConst.tournamentStateBanning: [self.banningScreen], 745 tourneyConst.tournamentStatePregame: [self.shipPilotCheck], 746 tourneyConst.tournamentStateWarpin: [self.pregameList], 747 tourneyConst.tournamentStateCountdown: [self.pregameList, self.countdownCont, self.countdownAbort], 748 tourneyConst.tournamentStateStarting: [self.pregameList, self.countdownCont], 749 tourneyConst.tournamentStateInProgress: [self.rangeCheck], 750 tourneyConst.tournamentStateComplete: [self.postgameList], 751 tourneyConst.tournamentStateClosed: [self.allianceSelections]} 752 allScreens = (self.allianceSelections, 753 self.banningScreen, 754 self.shipPilotCheck, 755 self.pregameList, 756 self.rangeCheck, 757 self.postgameList, 758 self.countdownCont, 759 self.countdownAbort) 760 for screen in allScreens: 761 if screen in uiScreenPerState[matchState['state']]: 762 screen.state = uiconst.UI_NORMAL 763 else: 764 screen.state = uiconst.UI_HIDDEN 765 766 if matchState['state'] == tourneyConst.tournamentStateWarpin: 767 if self.pregameRangeTimer is None: 768 self.pregameRangeTimer = timerstuff.AutoTimer(1000, self.UpdatePregameRanges) 769 else: 770 self.pregameRangeTimer = None 771 if 'matchStartTime' in matchState: 772 self.matchStartTime = matchState['matchStartTime'] 773 if matchState['state'] in (tourneyConst.tournamentStateCountdown, tourneyConst.tournamentStateStarting): 774 if self.countdownTimer is None: 775 self.UpdateTimer() 776 self.countdownTimer = timerstuff.AutoTimer(100, self.UpdateTimer) 777 else: 778 self.countdownTimer = None 779 if matchState['state'] == tourneyConst.tournamentStateInProgress: 780 if self.centerItemID is None: 781 self.startButton.SetLabel('Stop Tracking') 782 closestBeacon = None 783 ballpark = sm.GetService('michelle').GetBallpark() 784 for beaconID in self.matchDetails[3]: 785 try: 786 distance = ballpark.GetBall(beaconID).surfaceDist 787 if not closestBeacon or distance < closestBeacon[1]: 788 closestBeacon = (beaconID, distance) 789 except AttributeError: 790 pass 791 792 self.centerItemIDEdit.SetValue(str(closestBeacon[0])) 793 self.centerItemID = closestBeacon[0] 794 self.arenaRadius = 125000 795 self.arenaRadiusEdit.SetValue('125') 796 localTournamentService = sm.GetService('allianceTournamentSvc') 797 localTournamentService.StartTracking(self.centerItemID, self.arenaRadius) 798 elif self.centerItemID is not None: 799 localTournamentService = sm.GetService('allianceTournamentSvc') 800 localTournamentService.StopTracking() 801 self.centerItemID = None 802 uthread.new(self.WaitForSessionChanges, self.postGameButtons) 803 if 'solarsystemID' in matchState: 804 if self.solarsystemID != matchState['solarsystemID']: 805 self.solarsystemID = matchState['solarsystemID'] 806 self.redTeleportBeacon.LoadOptions(self.beaconOptions['red']) 807 self.blueTeleportBeacon.LoadOptions(self.beaconOptions['blue']) 808 809 def CreateBanElement(typeID, parent, teamIdx): 810 811 def RemoveBan(*args): 812 self.matchMoniker.UnBanShipType(self.matchDetails[0], typeID, teamIdx) 813 814 banContainer = Container(name='banEle', parent=parent, align=uiconst.TOTOP, height=16) 815 Button(label='X', parent=banContainer, func=RemoveBan, align=uiconst.TOLEFT) 816 eveLabel.Label(text=evetypes.GetName(typeID), parent=banContainer, align=uiconst.TOLEFT) 817 return banContainer 818 819 if 'redTeamBans' in matchState: 820 redBans = matchState['redTeamBans'] 821 keysToRemove = set(self.redBans.keys()) 822 for typeID in redBans: 823 if typeID in keysToRemove: 824 keysToRemove.remove(typeID) 825 if typeID not in self.redBans: 826 self.redBans[typeID] = CreateBanElement(typeID, self.redBanBox, 0) 827 828 for typeID in keysToRemove: 829 self.redBans[typeID].Close() 830 del self.redBans[typeID] 831 832 if 'blueTeamBans' in matchState: 833 blueBans = matchState['blueTeamBans'] 834 keysToRemove = set(self.blueBans.keys()) 835 for typeID in blueBans: 836 if typeID in keysToRemove: 837 keysToRemove.remove(typeID) 838 if typeID not in self.blueBans: 839 self.blueBans[typeID] = CreateBanElement(typeID, self.blueBanBox, 1) 840 841 for typeID in keysToRemove: 842 self.blueBans[typeID].Close() 843 del self.blueBans[typeID] 844 845 if 'autoBanText' in matchState: 846 autoBanText = matchState['autoBanText'] 847 self.autoBanText.text = autoBanText 848 updatePilotDisplay = False 849 if 'redTeamDetails' in matchState: 850 self.matchDetails[1] = matchState['redTeamDetails'] 851 updatePilotDisplay = True 852 if 'blueTeamDetails' in matchState: 853 self.matchDetails[2] = matchState['blueTeamDetails'] 854 updatePilotDisplay = True 855 if updatePilotDisplay: 856 self.UpdateShipPilotDisplay() 857 if 'redTeamLocked' in matchState: 858 if matchState['redTeamLocked']: 859 self.redLockBtn.state = uiconst.UI_HIDDEN 860 self.redUnlockBtn.state = uiconst.UI_NORMAL 861 self.redOverFleetBtn.state = uiconst.UI_HIDDEN 862 self.redAddPlayerBtn.state = uiconst.UI_NORMAL 863 self.redTeleportBtn.state = uiconst.UI_NORMAL 864 self.redTeleportBeacon.state = uiconst.UI_NORMAL 865 else: 866 self.redLockBtn.state = uiconst.UI_NORMAL 867 self.redUnlockBtn.state = uiconst.UI_HIDDEN 868 self.redOverFleetBtn.state = uiconst.UI_NORMAL 869 self.redAddPlayerBtn.state = uiconst.UI_HIDDEN 870 self.redTeleportBtn.state = uiconst.UI_HIDDEN 871 self.redTeleportBeacon.state = uiconst.UI_HIDDEN 872 if 'blueTeamLocked' in matchState: 873 if matchState['blueTeamLocked']: 874 self.blueLockBtn.state = uiconst.UI_HIDDEN 875 self.blueUnlockBtn.state = uiconst.UI_NORMAL 876 self.blueOverFleetBtn.state = uiconst.UI_HIDDEN 877 self.blueAddPlayerBtn.state = uiconst.UI_NORMAL 878 self.blueTeleportBtn.state = uiconst.UI_NORMAL 879 self.blueTeleportBeacon.state = uiconst.UI_NORMAL 880 else: 881 self.blueLockBtn.state = uiconst.UI_NORMAL 882 self.blueUnlockBtn.state = uiconst.UI_HIDDEN 883 self.blueOverFleetBtn.state = uiconst.UI_NORMAL 884 self.blueAddPlayerBtn.state = uiconst.UI_HIDDEN 885 self.blueTeleportBtn.state = uiconst.UI_HIDDEN 886 self.blueTeleportBeacon.state = uiconst.UI_HIDDEN 887 if 'warpRestrict' in matchState: 888 self.playersCanWarp = not matchState['warpRestrict'] 889 if self.playersCanWarp: 890 self.pregameWarpStatus.text = "Player warping: <color='green'>Allowed</color>" 891 else: 892 self.pregameWarpStatus.text = "Player warping: <color='red'>Disallowed</color>" 893 if 'moveRestrict' in matchState: 894 self.playersCanMove = not matchState['moveRestrict'] 895 if self.playersCanMove: 896 self.pregameMoveStatus.text = "Player movement: <color='green'>Allowed</color>" 897 else: 898 self.pregameMoveStatus.text = "Player movement: <color='red'>Disallowed</color>" 899 if 'lockRestrict' in matchState: 900 self.playersCanLock = not matchState['lockRestrict'] 901 if self.playersCanLock: 902 self.pregameLockStatus.text = "Player locking: <color='green'>Allowed</color>" 903 else: 904 self.pregameLockStatus.text = "Player locking: <color='red'>Disallowed</color>" 905 if 'droneRestrict' in matchState: 906 self.playersCanLaunchDrones = not matchState['droneRestrict'] 907 if self.playersCanLaunchDrones: 908 self.pregameDroneStatus.text = "Player drones: <color='green'>Allowed</color>" 909 else: 910 self.pregameDroneStatus.text = "Player drones: <color='red'>Disallowed</color>" 911 if matchState['state'] in (tourneyConst.tournamentStatePregame, tourneyConst.tournamentStateWarpin): 912 self.resetButton.state = uiconst.UI_NORMAL 913 else: 914 self.resetButton.state = uiconst.UI_HIDDEN 915 916 def LookupBanChars(self, *args): 917 try: 918 self.autoBanRedCharName.text = cfg.eveowners.Get(int(self.autoBanRedCharID.GetValue())).ownerName 919 except Exception: 920 self.autoBanRedCharName.text = '?' 921 922 try: 923 self.autoBanBlueCharName.text = cfg.eveowners.Get(int(self.autoBanBlueCharID.GetValue())).ownerName 924 except Exception: 925 self.autoBanRedCharName.text = '?' 926 927 def Autobans(self, *args): 928 tourneyID = self.tourneySelect.GetValue() 929 self.matchMoniker.StartAutobanning(self.matchDetails[0], tourneyID, redCharID=int(self.autoBanRedCharID.GetValue()), blueCharID=int(self.autoBanBlueCharID.GetValue()), totalNumBans=int(self.autoBanQty.GetValue())) 930 931 def FinalizeBans(self, *args): 932 self.matchMoniker.FinalizeBans(self.matchDetails[0]) 933 self.MakeUnKillable() 934 935 def SendBan(self, teamIdx, comboBox, *args): 936 curBans = self.matchMoniker.BanShipType(self.matchDetails[0], comboBox.GetValue(), teamIdx) 937 938 def ToggleLocks(self, *args): 939 self.matchMoniker.OverrideLockRestrict(self.matchDetails[0], self.playersCanLock) 940 941 def ToggleWarping(self, *args): 942 self.matchMoniker.OverrideWarpRestrict(self.matchDetails[0], self.playersCanWarp) 943 944 def ToggleMovement(self, *args): 945 self.matchMoniker.OverrideMoveRestrict(self.matchDetails[0], self.playersCanMove) 946 947 def ToggleDrones(self, *args): 948 self.matchMoniker.OverrideDroneRestrict(self.matchDetails[0], self.playersCanLaunchDrones) 949 950 def CompleteShipPilotCheck(self, *args): 951 if self.matchMoniker.IsOtherMatchInProgress(): 952 raise UserError('TournamentOtherMatchInSystemInProgress') 953 problems = [] 954 tharWereErrors = False 955 if self.redLockBtn.state != uiconst.UI_HIDDEN: 956 problems.append('Red team membership not locked') 957 if self.blueLockBtn.state != uiconst.UI_HIDDEN: 958 problems.append('Blue team membership not locked') 959 for teamIdx in (1, 2): 960 for charID, shipType, shipID, locationID, pointVal, errors in self.matchDetails[teamIdx]: 961 if errors: 962 tharWereErrors = True 963 if locationID != self.solarsystemID: 964 problems.append("%s doesn't look like they're here" % (cfg.eveowners[charID].ownerName,)) 965 966 if tharWereErrors: 967 problems.append('Errors remain') 968 if problems: 969 ret = prompt_player_fsd_dialog('CustomQuestion', {'header': "This doesn't seem right", 970 'question': 'The following problems remain:<br><br>' + '<br>'.join(problems) + '<br><br>Ignore and get this party started?'}, uiconst.YESNO) 971 if ret != uiconst.ID_YES: 972 return 973 self.pregameStepOneText.text = "Step 1 - Let them warp, don't let them lock" 974 self.pregameStepThreeText.text = 'Step 2 - Lock warping again' 975 self.pregameStepFourText.text = 'Step 3 - Start Countdown' 976 self.matchMoniker.CompletePregameChecks(self.matchDetails[0]) 977 978 def UpdatePregameRanges(self): 979 bp = sm.GetService('michelle').GetBallpark() 980 metersInKM = 1000.0 981 maximumDistance = 55 982 lines = ["<color='red'>" + self.redTeam] 983 for charID, shipType, shipID, locationID, pointVal, errors in self.matchDetails[1]: 984 try: 985 dist = bp.GetBall(shipID).surfaceDist 986 if dist / metersInKM > maximumDistance: 987 color = 'yellow' 988 else: 989 color = 'red' 990 lines.append("<color='%s'> %.1fkm %s" % (color, dist / metersInKM, cfg.eveowners.Get(charID).ownerName)) 991 except Exception: 992 lines.append("<color='red'> -- %s" % (cfg.eveowners.Get(charID).ownerName,)) 993 994 lines.append("<color='blue'>" + self.blueTeam) 995 for charID, shipType, shipID, locationID, pointVal, errors in self.matchDetails[2]: 996 try: 997 dist = bp.GetBall(shipID).surfaceDist 998 if dist / metersInKM > maximumDistance: 999 color = 'yellow' 1000 else: 1001 color = 'blue' 1002 lines.append("<color='%s'> %.1fkm %s" % (color, dist / metersInKM, cfg.eveowners.Get(charID).ownerName)) 1003 except: 1004 lines.append("<color='blue'> -- %s" % (cfg.eveowners.Get(charID).ownerName,)) 1005 1006 if len(lines) > PREGAME_RANGE_LINES: 1007 hidden = len(lines) - PREGAME_RANGE_LINES + 1 1008 lines = lines[:PREGAME_RANGE_LINES - 1] 1009 lines.append("<color='yellow'>+%d more" % (hidden,)) 1010 lines += [''] * (PREGAME_RANGE_LINES - len(lines)) 1011 for idx, line in enumerate(lines): 1012 getattr(self, 'pregameDistance%d' % (idx,)).text = line 1013 1014 def PreGameStepOne(self, *args): 1015 self.matchMoniker.OverrideLockRestrict(self.matchDetails[0], True) 1016 self.matchMoniker.OverrideWarpRestrict(self.matchDetails[0], False) 1017 self.pregameStepOneText.text = "<color='green'>%s</color>" % (self.pregameStepOneText.text,) 1018 1019 def PreGameStepThree(self, *args): 1020 self.matchMoniker.OverrideWarpRestrict(self.matchDetails[0], True) 1021 self.pregameStepThreeText.text = "<color='green'>%s</color>" % (self.pregameStepThreeText.text,) 1022 1023 def PreGameStepFour(self, *args): 1024 self.matchMoniker.StartCountdown(self.matchDetails[0]) 1025 self.pregameStepFourText.text = "<color='green'>%s</color>" % (self.pregameStepFourText.text,) 1026 1027 def UpdateTimer(self): 1028 timeDiffMS = max(0, -blue.os.TimeDiffInMs(self.matchStartTime, blue.os.GetWallclockTime())) 1029 self.countdownText.text = '%.1f' % (float(timeDiffMS) / 1000.0,) 1030 1031 def AbortCountdown(self, *args): 1032 stopped = self.matchMoniker.AbortCountdown(self.matchDetails[0]) 1033 if stopped: 1034 self.pregameStepFourText.text = 'Step 4 - Start Countdown' 1035 1036 def MatchCompleted(self, *args): 1037 ret = prompt_player_fsd_dialog('CustomQuestion', {'header': 'Is it really over?', 1038 'question': 'Are you certain you want to prematurely end the match?'}, uiconst.YESNO) 1039 if ret != uiconst.ID_YES: 1040 return 1041 self.matchMoniker.MatchCompleted(self.matchDetails[0]) 1042 self.postgameStepOneText.text = 'Step 1 - Send everyone back home' 1043 self.postgameStepTwoText.text = 'Step 2 - Clean up the grid' 1044 self.postgameStepThreeText.text = 'Step 3 (optional) - Teleport home' 1045 1046 def PostGameStepOne(self, *args): 1047 self.matchMoniker.ReturnAllPlayers(self.matchDetails[0]) 1048 self.postgameStepOneText.text = "<color='green'>%s</color>" % (self.postgameStepOneText.text,) 1049 self.MakeKillable() 1050 1051 def PostGameStepTwo(self, *args): 1052 self.matchMoniker.CleanupGrid(self.matchDetails[0]) 1053 self.postgameStepTwoText.text = "<color='green'>%s</color>" % (self.postgameStepTwoText.text,) 1054 1055 def PostGameStepThree(self, *args): 1056 self.matchMoniker.TeleportRefHome(self.matchDetails[0]) 1057 self.postgameStepThreeText.text = "<color='green'>%s</color>" % (self.postgameStepThreeText.text,) 1058 1059 def OverrideFleetBossID(self, teamIdx, *args): 1060 format = [{'type': 'edit', 1061 'key': 'fleetbossid', 1062 'setfocus': True, 1063 'label': u'New Fleet Boss Char ID'}] 1064 retVal = uix.HybridWnd(format, caption=u'Specify new fleet boss charID', windowID='overrideFleetBoss', minW=410, minH=100) 1065 if retVal: 1066 newFleetBossID = int(retVal['fleetbossid']) 1067 if newFleetBossID: 1068 self.matchMoniker.OverrideFleetBossID(self.matchDetails[0], teamIdx, newFleetBossID) 1069 1070 def OverrideError(self, teamIdx, charID, errorString): 1071 ret = prompt_player_fsd_dialog('CustomQuestion', {'header': 'YOU SURE DUDE?!?', 1072 'question': 'Override<br>%s<br>for pilot %s?' % (errorString, cfg.eveowners.Get(charID).ownerName)}, uiconst.YESNO) 1073 if ret != uiconst.ID_YES: 1074 return 1075 self.matchMoniker.OverrideError(self.matchDetails[0], charID, errorString) 1076 1077 def OverrideAllErrors(self, teamIdx, charID, errorStrings): 1078 errorList = '' 1079 for errorString in errorStrings: 1080 errorList += '<br>' + errorString 1081 1082 ret = prompt_player_fsd_dialog('CustomQuestion', {'header': 'YOU ABSOLUTELY SURE DUDE?!?', 1083 'question': 'Override ALL ERRORS for pilot %s?<br><br>Errors are: %s' % (cfg.eveowners.Get(charID).ownerName, errorList)}, uiconst.YESNO) 1084 if ret != uiconst.ID_YES: 1085 return 1086 for errorString in errorStrings: 1087 self.matchMoniker.OverrideError(self.matchDetails[0], charID, errorString) 1088 1089 def RemovePlayer(self, teamIdx, charID): 1090 ret = prompt_player_fsd_dialog('CustomQuestion', {'header': "JUST CHECKIN'", 1091 'question': 'Remove %s from their team?' % cfg.eveowners.Get(charID).ownerName}, uiconst.YESNO) 1092 if ret != uiconst.ID_YES: 1093 return 1094 self.matchMoniker.RemovePlayer(self.matchDetails[0], teamIdx, charID) 1095 1096 def GetPrematchPilotMenu(self, node): 1097 basePilotMenu = GetMenuService().GetMenuFromItemIDTypeID(node.sr.node.id[1], const.typeCharacter) 1098 errorMenu = [] 1099 for error in node.sr.node.errors: 1100 errorMenu.append(('Override: %s' % (error,), self.OverrideError, (node.sr.node.id[0], node.sr.node.id[1], error))) 1101 1102 if errorMenu: 1103 errorMenu.append(None) 1104 errorMenu.append(('Remove Player', self.RemovePlayer, (node.sr.node.id[0], node.sr.node.id[1]))) 1105 errorMenu.append(None) 1106 errorMenu.append(('Override all errors (!!!)', self.OverrideAllErrors, (node.sr.node.id[0], node.sr.node.id[1], node.sr.node.errors))) 1107 return errorMenu + basePilotMenu 1108 1109 def UpdateShipPilotDisplay(self): 1110 redTeam = [] 1111 pointTotal = 0 1112 for charID, shipType, shipID, locationID, pointVal, errors in self.matchDetails[1]: 1113 data = utillib.KeyVal(id=(0, charID), errors=errors, label='%s<t>%s<t>%s<t>%s<t><color=red>%s</color>' % (cfg.eveowners.Get(charID).ownerName, 1114 evetypes.GetName(shipType), 1115 cfg.evelocations.Get(locationID).locationName, 1116 pointVal, 1117 ' - '.join(errors)), GetMenu=self.GetPrematchPilotMenu, hint='\n'.join(errors) if errors else 'No errors') 1118 listEntry = GetFromClass(Generic, data) 1119 redTeam.append(listEntry) 1120 pointTotal += pointVal 1121 1122 self.shipcheckRedScroll.Load(contentList=redTeam, headers=['Name', 1123 'Ship Type', 1124 'Location', 1125 'Point Value', 1126 'Errors'], noContentHint='No pilots found') 1127 self.shipcheckRedTeamLabel.text = 'Red Team - %s - %d points' % (self.redTeam, pointTotal) 1128 blueTeam = [] 1129 pointTotal = 0 1130 for charID, shipType, shipID, locationID, pointVal, errors in self.matchDetails[2]: 1131 data = utillib.KeyVal(id=(1, charID), errors=errors, label='%s<t>%s<t>%s<t>%s<t><color=red>%s</color>' % (cfg.eveowners.Get(charID).ownerName, 1132 evetypes.GetName(shipType), 1133 cfg.evelocations.Get(locationID).locationName, 1134 pointVal, 1135 ' - '.join(errors)), GetMenu=self.GetPrematchPilotMenu, hint='\n'.join(errors) if errors else 'No errors') 1136 listEntry = GetFromClass(Generic, data) 1137 blueTeam.append(listEntry) 1138 pointTotal += pointVal 1139 1140 self.shipcheckBlueScroll.Load(contentList=blueTeam, headers=['Name', 1141 'Ship Type', 1142 'Location', 1143 'Point Value', 1144 'Errors'], noContentHint='No pilots found') 1145 self.shipcheckBlueTeamLabel.text = 'Blue Team - %s - %d points' % (self.blueTeam, pointTotal) 1146 1147 def RefreshShipPilotCheck(self, whichTeam, *args): 1148 self.matchMoniker.UpdateFleetDetails(self.matchDetails[0], whichTeam) 1149 1150 def LockMemberList(self, whichTeam, *args): 1151 memberList = [ x[0] for x in self.matchDetails[whichTeam + 1] ] 1152 self.matchMoniker.LockMemberList(self.matchDetails[0], whichTeam, memberList) 1153 1154 def UnlockMemberList(self, whichTeam, *args): 1155 self.matchMoniker.UnlockMemberList(self.matchDetails[0], whichTeam) 1156 1157 def AddPlayer(self, whichTeam): 1158 format = [{'type': 'edit', 1159 'key': 'charid', 1160 'setfocus': True, 1161 'label': u'Char ID to add'}] 1162 retVal = uix.HybridWnd(format, caption=u'Gimme a dude', windowID='addPlayerToTournament', minW=250, minH=100) 1163 if retVal: 1164 newCharID = int(retVal['charid']) 1165 if newCharID: 1166 self.matchMoniker.AddPlayer(self.matchDetails[0], whichTeam, newCharID) 1167 1168 def TeleportPlayers(self, whichTeam, *args): 1169 if whichTeam == 0: 1170 beaconIdx = self.redTeleportBeacon.GetValue() 1171 self.redReturnBtn.state = uiconst.UI_NORMAL 1172 else: 1173 beaconIdx = self.blueTeleportBeacon.GetValue() 1174 self.blueReturnBtn.state = uiconst.UI_NORMAL 1175 self.matchMoniker.TeleportPlayers(self.matchDetails[0], whichTeam, beaconIdx) 1176 1177 def ReturnTeamPlayers(self, whichTeam, *args): 1178 self.matchMoniker.ReturnTeamPlayers(self.matchDetails[0], whichTeam) 1179 1180 def TeleportRef(self, *args): 1181 teleportMoniker = eveMoniker.Moniker('tourneyMgr', self.solSystemSelect.GetValue()) 1182 teleportMoniker.TeleportToArena() 1183 1184 def TeleportRefHome(self, *args): 1185 teleportMoniker = eveMoniker.Moniker('tourneyMgr', self.solSystemSelect.GetValue()) 1186 teleportMoniker.TeleportToStation() 1187 1188 def ResetMatch(self, *args): 1189 ret = prompt_player_fsd_dialog('CustomQuestion', {'header': 'Mildly Annoying', 1190 'question': 'Reseting is a moderate inconveniance, you sure you want that?'}, uiconst.YESNO) 1191 if ret != uiconst.ID_YES: 1192 return 1193 self.matchMoniker.ResetMatch(self.matchDetails[0]) 1194 self.MakeKillable() 1195 1196 def Close(self, *args, **kwds): 1197 matchID = self.matchDetails[0] 1198 if matchID > 0: 1199 self.matchMoniker.RemoveSelfFromReferees(matchID) 1200 Window.Close(self, *args, **kwds) 1201 1202 def OnRemovalAsRef(self, matchID, *args): 1203 if matchID == self.matchDetails[0]: 1204 Window.Close(self) 1205 1206 def OnToggleStart(self, *args): 1207 if self.isToggling: 1208 return 1209 try: 1210 self.isToggling = True 1211 self.centerItemID = int(self.centerItemIDEdit.GetValue()) 1212 self.arenaRadius = int(self.arenaRadiusEdit.GetValue()) * 1000 1213 localTournamentService = sm.GetService('allianceTournamentSvc') 1214 if localTournamentService.isCompetitorsTrackingActive: 1215 localTournamentService.StopTracking() 1216 self.startButton.SetLabel('Start') 1217 else: 1218 localTournamentService.StartTracking(self.centerItemID, self.arenaRadius) 1219 self.startButton.SetLabel('Stop') 1220 finally: 1221 self.isToggling = False 1222 1223 def UpdateColumnSort(self, scroll, entries, columnID): 1224 if not entries: 1225 return 1226 startIdx = entries[0].idx 1227 endIdx = entries[-1].idx 1228 entries = SortColumnEntries(entries, columnID) 1229 scroll.sr.nodes = scroll.sr.nodes[:startIdx] + entries + scroll.sr.nodes[endIdx + 1:] 1230 idx = 0 1231 for entry in scroll.GetNodes()[startIdx:]: 1232 if entry.panel: 1233 entry.panel.SetOrder(-1) 1234 entry.idx = startIdx + idx 1235 if entry.Get('needReload', 0) and entry.panel: 1236 entry.panel.LoadLite(entry) 1237 idx += 1 1238 1239 def OnCompetitorTrackingUpdate(self, competitorsByShipID): 1240 scrolllist = [] 1241 for node in self.scroll.GetNodes(): 1242 data = competitorsByShipID.get(node.shipID, None) 1243 if data: 1244 distance = '%0.1f km' % (data.distance * 0.001) 1245 maxDistance = '%0.1f km' % (data.maxDistance * 0.001) 1246 if distance != node.texts.distance: 1247 node.needReload = True 1248 node.texts = node.texts._replace(distance=distance, maxDistance=maxDistance) 1249 node.sortData = node.sortData._replace(distance=data.distance, maxDistance=data.maxDistance) 1250 if data.maxDistance > self.arenaRadius: 1251 node.panel.warn.state = uiconst.UI_DISABLED 1252 if data.shipLost: 1253 node.overlay.state = uiconst.UI_HIDDEN 1254 else: 1255 node.overlay.state = uiconst.UI_PICKCHILDREN 1256 scrolllist.append(node) 1257 1258 self.UpdateColumnSort(self.scroll, scrolllist, 'AtCompetitorsScroll') 1259 1260 def OnCompetitorTrackingStart(self, competitorsByShipID): 1261 scrolllist = [] 1262 for shipData in competitorsByShipID.values(): 1263 data = utillib.KeyVal() 1264 data.shipID = shipData.shipID 1265 data.texts = EntryRow(character=shipData.ownerName, groupName=shipData.groupName, typeName=shipData.typeName, maxDistance='%.1f km' % (shipData.maxDistance * 0.001), distance='%.1f km' % (shipData.distance * 0.001)) 1266 data.sortData = EntryRow(character=shipData.ownerName, groupName=shipData.groupName, typeName=shipData.typeName, maxDistance=shipData.maxDistance, distance=shipData.distance) 1267 data.columnID = 'AtCompetitorsScroll' 1268 data.isSelected = False 1269 data.GetMenu = lambda x: GetMenuService().GetMenuFromItemIDTypeID(shipData.shipID, shipData.typeID) 1270 iconPar = Container(name='iconParent', parent=None, align=uiconst.TOPLEFT, width=16, height=16, state=uiconst.UI_HIDDEN) 1271 icon = eveIcon.Icon(parent=iconPar, icon='ui_38_16_182', pos=(0, 0, 16, 16), align=uiconst.RELATIVE) 1272 icon.hint = 'Destroy Ship' 1273 icon.shipID = shipData.shipID 1274 icon.OnClick = (self.DestroyShip, icon) 1275 data.overlay = iconPar 1276 entry = GetFromClass(AtCompetitorEntry, data) 1277 scrolllist.append(entry) 1278 1279 scrolllist = SortColumnEntries(scrolllist, 'AtCompetitorsScroll') 1280 data = utillib.KeyVal() 1281 data.texts = ('Character', 'Group', 'Type', 'Max Distance', 'Distance') 1282 data.columnID = 'AtCompetitorsScroll' 1283 data.editable = True 1284 data.showBottomLine = True 1285 data.selectable = False 1286 data.hilightable = False 1287 scrolllist.insert(0, GetFromClass(AtCompetitorEntry, data)) 1288 if scrolllist: 1289 InitCustomTabstops('AtCompetitorsScroll', scrolllist) 1290 self.scroll.LoadContent(contentList=scrolllist) 1291 1292 def DestroyShip(self, button): 1293 localTournamentService = sm.GetService('allianceTournamentSvc') 1294 shipData = localTournamentService.competitorsByShipID[button.shipID] 1295 header = 'Destroy Ship' 1296 warning = 'Are you sure you want to destroy this ship?<br /><br />Character: <b>%s</b><br />Type: <b>%s</b>' % (shipData.ownerName, shipData.typeName) 1297 if prompt_player_fsd_dialog('CustomWarning', {'header': header, 1298 'warning': warning}, uiconst.YESNO) == uiconst.ID_YES: 1299 sm.GetService('slash').SlashCmd('/heal %d 0' % button.shipID) 1300 channelID = (('solarsystemid2', session.solarsystemid2),) 1301 message = u'<url=showinfo:%d>%s</url> piloted by <url=showinfo:1377//%s>%s</url> has been disqualified for boundary violations.' % (shipData.typeID, 1302 shipData.typeName, 1303 shipData.charID, 1304 shipData.ownerName) 1305 c = sm.StartService('LSC').GetChannelWindow(channelID[0]) 1306 c.Speak(message, session.charid, localEcho=True) 1307 sm.StartService('LSC').SendMessage(channelID, message) 1308 1309 1310 class RefWindowSpawningWindow(Window): 1311 __guid__ = 'form.RefWindowSpawningWindow' 1312 default_windowID = 'tournament' 1313 default_fixedWidth = 280 1314 default_fixedHeight = 110 1315 1316 def ApplyAttributes(self, attributes): 1317 Window.ApplyAttributes(self, attributes) 1318 self.SetScope(uiconst.SCOPE_ALL) 1319 self.SetCaption('Match Starter') 1320 self.SetMinSize([self.width, self.height]) 1321 self.MakeUnResizeable() 1322 self.ConstructLayout() 1323 self.nextWndIDNum = 0 1324 1325 def ConstructLayout(self): 1326 Button(label='Create New Match', parent=self.content, padding=(5, 5, 5, 5), func=self.NewMatch, align=uiconst.TOTOP) 1327 1328 def NewMatch(self, *args): 1329 TournamentRefereeTool.Open(windowID='TournamentRefereeTool%d' % (self.nextWndIDNum,)) 1330 self.nextWndIDNum += 1 1331 1332 1333 class AllianceTournamentSvc(Service): 1334 __guid__ = 'svc.allianceTournamentSvc' 1335 __dependencies__ = ['michelle'] 1336 1337 def Run(self, *args): 1338 self.isCompetitorsTrackingActive = False 1339 self.competitorsByShipID = {} 1340 1341 def Show(self): 1342 RefWindowSpawningWindow.Open() 1343 1344 def StartTracking(self, centerItemID, arenaRadius): 1345 self.LogInfo('Start tracking arena center item', centerItemID, 'using a radius of', arenaRadius, 'meters') 1346 self.centerItemID = centerItemID 1347 self.arenaRadius = arenaRadius 1348 uthread.new(self._MonitorCompetitorsTask).context = 'at::competitortracking' 1349 1350 def StopTracking(self): 1351 self.LogInfo('Stop tracking competitors') 1352 self.isCompetitorsTrackingActive = False 1353 self.competitorsByShipID = {} 1354 sm.ScatterEvent('OnCompetitorTrackingStart', {}) 1355 1356 def _RegisterCompetitors(self): 1357 self.competitorsByShipID = {} 1358 ballpark = self.michelle.GetBallpark() 1359 for ball, slim in ballpark.GetBallsAndItems(): 1360 if ball.id != session.shipid and slim.categoryID == const.categoryShip and slim.groupID != const.groupCapsule and slim.charID: 1361 distance = ballpark.DistanceBetween(self.centerItemID, ball.id) 1362 if distance is None or distance >= self.arenaRadius: 1363 continue 1364 data = utillib.KeyVal(charID=slim.ownerID, shipID=ball.id, typeID=slim.typeID, groupID=slim.groupID, ownerName=cfg.eveowners.Get(slim.ownerID).ownerName, typeName=evetypes.GetName(slim.typeID), groupName=evetypes.GetGroupNameByGroup(slim.groupID), distance=distance, maxDistance=distance, shipLost=False) 1365 self.competitorsByShipID[ball.id] = data 1366 1367 sm.ScatterEvent('OnCompetitorTrackingStart', self.competitorsByShipID) 1368 1369 def _MonitorCompetitorsTask(self): 1370 if self.isCompetitorsTrackingActive: 1371 return 1372 try: 1373 self._RegisterCompetitors() 1374 self.isCompetitorsTrackingActive = True 1375 self.LogInfo('Starting monitoring task') 1376 while self.isCompetitorsTrackingActive: 1377 blue.pyos.synchro.SleepWallclock(500) 1378 ballpark = sm.GetService('michelle').GetBallpark() 1379 ball = ballpark.GetBall(self.centerItemID) 1380 if not ball: 1381 self.LogInfo('We lost the center ball. Must abort tracking') 1382 self.StopTracking() 1383 for shipID, data in self.competitorsByShipID.iteritems(): 1384 ball = ballpark.GetBall(shipID) 1385 if ball: 1386 data.distance = ballpark.DistanceBetween(self.centerItemID, shipID) 1387 data.maxDistance = max(data.maxDistance, data.distance) 1388 else: 1389 data.shipLost = True 1390 1391 sm.ScatterEvent('OnCompetitorTrackingUpdate', self.competitorsByShipID) 1392 1393 finally: 1394 self.isCompetitorsTrackingActive = False 1395 self.LogInfo('Stopping monitoring task')