targetMgr.py (55808B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\parklife\targetMgr.py 2 import sys 3 import blue 4 import localization 5 import telemetry 6 import uthread 7 from carbon.common.script.sys.service import Service 8 from carbonui import uiconst 9 from carbonui.primitives.container import Container 10 from carbonui.primitives.line import Line 11 from carbonui.uicore import uicore 12 from carbonui.util.various_unsorted import SortListOfTuples 13 from eve.client.script.parklife import states as state 14 from eve.client.script.parklife.targetUtils import get_closest_entity_target 15 from eve.client.script.ui.control.eveIcon import Icon 16 from eve.client.script.ui.inflight.activeitem import ActiveItem 17 from eve.client.script.ui.inflight.bracketsAndTargets.targetInBar import TargetInBar 18 from eve.client.script.ui.inflight.bracketsAndTargets.targetInBarFighter import TargetInBarFighter 19 from eve.client.script.ui.inflight.selectedItemWnd import SelectedItemWnd 20 from eve.client.script.ui.shared.pointerTool import pointerToolConst as pConst 21 from eve.client.script.ui.util.uix import GetBallparkRecord 22 from eve.common.script.sys import eveSessions, idCheckers 23 from eve.client.script.ui.view import overlaySettings 24 from eve.client.script.ui.view.viewStateConst import ViewOverlay 25 from eveexceptions import UserError 26 from menu import MenuLabel 27 import eve.common.lib.appConst as const 28 from player_messaging.client.ui_message import prompt_player_fsd_dialog 29 MAX_TARGET_WIDTH = 110 30 AVG_TARGET_HEIGHT = 200 31 MIN_TARGET_HEIHT = 170 32 TARGET_PADDING = 10 33 34 class TargetMgr(Service): 35 __guid__ = 'svc.target' 36 __exportedcalls__ = {'LockTarget': [], 37 'UnlockTarget': [], 38 'ClearTargets': [], 39 'GetActiveTargetID': [], 40 'GetTargets': [], 41 'GetTargeting': [], 42 'StartLockTarget': [], 43 'FailLockTarget': [], 44 'CancelAddTarget': []} 45 __notifyevents__ = ['OnTarget', 46 'OnTargets', 47 'OnTargetClear', 48 'ProcessSessionChange', 49 'OnSpecialFX', 50 'DoBallsAdded', 51 'DoBallRemove', 52 'DoBallClear', 53 'OnStateChange', 54 'DoBallsRemove', 55 'OnFleetStateChange'] 56 __dependencies__ = ['michelle', 57 'godma', 58 'settings', 59 'stateSvc'] 60 __update_on_reload__ = 0 61 62 def Run(self, memStream = None): 63 super(TargetMgr, self).Run(memStream) 64 self.viewMode = 'normal' 65 self.preViewMode = None 66 self.Reset() 67 if session.shipid and not session.stationid: 68 self.godma.GetStateManager().RefreshTargets() 69 self.ownerToShipIDCache = {} 70 self.deadShipsBeingRemoved = set() 71 self.disableSpinnyReticule = False 72 self.overrideBarHeight = None 73 74 def Stop(self, stream): 75 super(TargetMgr, self).Stop(stream) 76 self.viewMode = 'normal' 77 self.CheckViewMode() 78 self.Reset() 79 80 def PlaceOrigin(self): 81 if self.origin is not None: 82 return 83 self.CreateOrigin() 84 self.PositionOriginWithAnchors() 85 self.UpdateOriginDirection() 86 87 def CreateOrigin(self, *args): 88 if not len(self.targetsByID): 89 self.origin = None 90 return 91 par = uicore.layer.target 92 origin = Container(name='targetOrigin', parent=par, align=uiconst.RELATIVE, width=16, height=16, state=uiconst.UI_NORMAL, uniqueUiName=pConst.UNIQUE_NAME_TARGET_ANCHOR) 93 origin.OnMouseDown = (self.OnOriginMD, origin) 94 origin.OnMouseUp = (self.OnOriginMU, origin) 95 origin.GetMenu = self.GetOriginMenu 96 origin.hint = localization.GetByLabel('UI/Inflight/TargetListAnchor/TargetListAnchorHint') 97 origin.leftline = Line(parent=origin, align=uiconst.RELATIVE, width=4, height=1, left=-4, top=7, color=(1.0, 1.0, 1.0, 1.0)) 98 origin.topline = Line(parent=origin, align=uiconst.RELATIVE, width=1, height=4, left=7, top=-4, color=(1.0, 1.0, 1.0, 1.0)) 99 origin.rightline = Line(parent=origin, align=uiconst.RELATIVE, width=4, height=1, left=15, top=7, color=(1.0, 1.0, 1.0, 1.0)) 100 origin.bottomline = Line(parent=origin, align=uiconst.RELATIVE, width=1, height=4, left=7, top=15, color=(1.0, 1.0, 1.0, 1.0)) 101 origin.opacity = 0.75 102 Icon(icon='ui_38_16_72', parent=origin, state=uiconst.UI_DISABLED) 103 self.origin = origin 104 if getattr(self, 'targetPar', None) is None or self.targetPar.destroyed: 105 targetPar = Container(parent=uicore.layer.target, align=uiconst.TOALL) 106 self.targetPar = targetPar 107 self.targetPar.rows = [] 108 109 def PositionOriginWithAnchors(self): 110 if not self.origin or self.origin.destroyed: 111 self.CreateOrigin() 112 if not self.origin: 113 return 114 origin = self.origin 115 (cX, cY), (toLeft, toTop) = self.GetOriginPosition(getDirection=1) 116 pl, pt, pw, ph = origin.parent.GetAbsolute() 117 originAlign = self.GetOriginAlign(toLeft, toTop) 118 origin.SetAlign(originAlign) 119 if toLeft: 120 origin.left = pw - cX - 8 121 else: 122 origin.left = cX - 8 123 if toTop: 124 origin.top = ph - cY - 8 125 else: 126 origin.top = cY - 8 127 128 def GetOriginMenu(self): 129 if settings.user.ui.Get('targetOriginLocked', 0): 130 m = [(MenuLabel('UI/Inflight/TargetListAnchor/UnlockAnchor'), self.UnlockOrigin)] 131 else: 132 m = [(MenuLabel('UI/Inflight/TargetListAnchor/LockAnchor'), self.LockOrigin)] 133 if settings.user.ui.Get('targetPositionLocked', 0): 134 m += [(MenuLabel('UI/Inflight/TargetListAnchor/UnlockTargets'), self.ToggleLockTargetPosition)] 135 else: 136 m += [(MenuLabel('UI/Inflight/TargetListAnchor/LockTargets'), self.ToggleLockTargetPosition)] 137 if settings.user.ui.Get('alignHorizontally', 1): 138 m += [(MenuLabel('UI/Inflight/TargetListAnchor/ArrangeTargetsVertically'), self.ToggleAlignment)] 139 else: 140 m += [(MenuLabel('UI/Inflight/TargetListAnchor/ArrangeTargetsHorizontally'), self.ToggleAlignment)] 141 if overlaySettings.IsFullscreenOverlayModeEnabled(ViewOverlay.Target): 142 m += [(MenuLabel('/Carbon/UI/Controls/Window/DisableOverlayMode'), lambda : overlaySettings.DisableFullscreenOverlayMode(ViewOverlay.Target))] 143 else: 144 m += [(MenuLabel('/Carbon/UI/Controls/Window/EnableOverlayMode'), lambda : overlaySettings.EnableFullscreenOverlayMode(ViewOverlay.Target))] 145 m += [(MenuLabel('UI/Commands/CmdUnlockTargetItems'), sm.GetService('cmd').CmdUnlockTargetItems)] 146 return m 147 148 def UnlockOrigin(self, *args): 149 settings.user.ui.Set('targetOriginLocked', 0) 150 151 def LockOrigin(self, *args): 152 settings.user.ui.Set('targetOriginLocked', 1) 153 154 def ToggleLockTargetPosition(self, *args): 155 current = settings.user.ui.Get('targetPositionLocked', 0) 156 settings.user.ui.Set('targetPositionLocked', not current) 157 158 def ToggleAlignment(self, *args): 159 current = settings.user.ui.Get('alignHorizontally', 1) 160 settings.user.ui.Set('alignHorizontally', not current) 161 self.ArrangeTargets() 162 163 def GetTargetLayerAbsolutes(self): 164 d = uicore.desktop 165 wnd = uicore.layer.target 166 if wnd and not wnd.state == uiconst.UI_HIDDEN: 167 pl, pt, pw, ph = wnd.GetAbsolute() 168 else: 169 pl, pt, pw, ph = d.GetAbsolute() 170 return (wnd, 171 pl, 172 pt, 173 pw, 174 ph) 175 176 def GetOriginPosition(self, inPixels = 1, getDirection = 0): 177 d = uicore.desktop 178 wnd, pl, pt, pw, ph = self.GetTargetLayerAbsolutes() 179 myPrefs = settings.user.ui.Get('targetOrigin', None) 180 if myPrefs is None: 181 selecteditem = SelectedItemWnd.GetIfOpen() 182 if selecteditem and selecteditem.display and not selecteditem.IsMinimized(): 183 stack = getattr(selecteditem.sr, 'stack', None) 184 if stack: 185 selecteditem = stack 186 topAlignedWindows = selecteditem.FindConnectingWindows('top') 187 left, top, width, height = selecteditem.GetGroupAbsolute(topAlignedWindows) 188 dw = d.width 189 dh = d.height 190 else: 191 left, top, width, height, dw, dh = SelectedItemWnd.GetRegisteredPositionAndSizeByClass() 192 left -= 15 193 portionalCY = top / float(dh) 194 if left + width < d.width / 2: 195 portionalCX = (left + width - pl) / float(pw) 196 elif left >= d.width / 2: 197 portionalCX = (left - pl) / float(pw) 198 else: 199 portionalCX = (d.width - 300) / float(dw) 200 portionalCY = 16 / float(d.height) 201 else: 202 portionalCX, portionalCY = myPrefs 203 if inPixels: 204 ret = (int(portionalCX * pw), int(portionalCY * ph)) 205 else: 206 ret = (portionalCX, portionalCY) 207 if getDirection: 208 return (ret, (bool(portionalCX > 0.5), bool(portionalCY > 0.5))) 209 return ret 210 211 def OnOriginMU(self, origin, btn, *args): 212 if btn != 0 or settings.user.ui.Get('targetOriginLocked', 0): 213 return 214 if uicore.uilib.mouseOver == self.origin: 215 par, tl, tt, tw, th = self.GetTargetLayerAbsolutes() 216 origin.left = uicore.uilib.x - origin.grab[0] 217 origin.top = uicore.uilib.y - origin.grab[1] 218 origin.opacity = 0.75 219 d = uicore.desktop 220 l, t, w, h = origin.GetAbsolute() 221 cX = l - tl + w / 2 222 cY = t - tt + h / 2 223 pcX = cX / float(tw) 224 pcY = cY / float(th) 225 settings.user.ui.Set('targetOrigin', (pcX, pcY)) 226 self.ArrangeTargets() 227 sm.GetService('ui').ForceCursorUpdate() 228 origin.dragging = 0 229 uicore.uilib.UnclipCursor() 230 origin.hint = localization.GetByLabel('UI/Inflight/TargetListAnchor/TargetListAnchorHint') 231 232 def OnOriginMD(self, origin, btn, *args): 233 if btn != 0 or settings.user.ui.Get('targetOriginLocked', 0): 234 return 235 origin.opacity = 1.0 236 l, t, w, h = origin.GetAbsolute() 237 pl, pt, pw, ph = origin.parent.GetAbsolute() 238 origin.grab = [uicore.uilib.x - l, uicore.uilib.y - t] 239 origin.dragging = 1 240 origin.SetAlign(uiconst.ABSOLUTE) 241 origin.left = l 242 origin.top = t 243 uthread.new(self.BeginDrag, origin) 244 d = uicore.desktop 245 gx, gy = origin.grab 246 uicore.uilib.ClipCursor(gx, gy, d.width - (origin.width - gx), d.height - (origin.height - gy)) 247 248 def GetBaseLeftAndTop(self, *args): 249 (cX, cY), (toLeft, toTop) = self.GetOriginPosition(getDirection=1) 250 par, pl, pt, pw, ph = self.GetTargetLayerAbsolutes() 251 if toLeft: 252 baseleft = pw - cX 253 else: 254 baseleft = cX 255 if toTop: 256 basetop = ph - cY 257 else: 258 basetop = cY 259 return (baseleft, basetop) 260 261 def UpdateOriginDirection(self): 262 if not self.origin: 263 return 264 origin = self.origin 265 d = uicore.desktop 266 l, t, w, h = origin.GetAbsolute() 267 cX = l + w / 2 268 cY = t + h / 2 269 if cX > d.width / 2: 270 origin.leftline.state = uiconst.UI_NORMAL 271 origin.rightline.state = uiconst.UI_HIDDEN 272 else: 273 origin.rightline.state = uiconst.UI_NORMAL 274 origin.leftline.state = uiconst.UI_HIDDEN 275 if cY > d.height / 2: 276 origin.topline.state = uiconst.UI_NORMAL 277 origin.bottomline.state = uiconst.UI_HIDDEN 278 else: 279 origin.bottomline.state = uiconst.UI_NORMAL 280 origin.topline.state = uiconst.UI_HIDDEN 281 282 def BeginDrag(self, origin): 283 while self.origin and not origin.destroyed and getattr(origin, 'dragging', 0): 284 uicore.uilib.SetCursor(uiconst.UICURSOR_NONE) 285 origin.left = uicore.uilib.x - origin.grab[0] 286 origin.top = uicore.uilib.y - origin.grab[1] 287 self.UpdateOriginDirection() 288 if uicore.uilib.mouseOver == self.origin: 289 self.origin.hint = localization.GetByLabel('UI/Inflight/TargetListAnchor/AnchorIsMoving') 290 else: 291 self.origin.hint = '' 292 blue.pyos.synchro.SleepWallclock(1) 293 294 def Reset(self): 295 self.dogmaLM = None 296 self.allTargets = [] 297 self.rowDict = {} 298 self.ClearingTargets() 299 self.pendingTargets = [] 300 self.pendingTargeters = [] 301 self.targeting = {} 302 self.autoTargeting = [] 303 self.weaponsOnMe = {} 304 self.needtarget = [] 305 self.teams = [[], []] 306 self.origin = None 307 self.ownerToShipIDCache = {} 308 self.ClearTargetedBy() 309 uicore.layer.target.Flush() 310 311 def CheckViewMode(self): 312 toggleWnds = {'main': [ child for child in uicore.layer.main.children ], 313 'inflight': [ child for child in uicore.layer.inflight.children if child.name is not 'l_target' ]} 314 if self.viewMode == 'normal': 315 if self.origin: 316 self.origin.state = uiconst.UI_NORMAL 317 if self.preViewMode: 318 for wnd in toggleWnds: 319 layer = uicore.layer.Get(wnd) 320 for wndState, name in self.preViewMode: 321 wnd = layer.FindChild(name) 322 if wnd: 323 wnd.state = wndState 324 325 self.preViewMode = None 326 else: 327 if self.origin: 328 self.origin.state = uiconst.UI_HIDDEN 329 self.preViewMode = [] 330 for layer, children in toggleWnds.iteritems(): 331 for wnd in children: 332 if wnd and wnd.name not in 'l_bracket': 333 self.preViewMode.append((wnd.state, wnd.name)) 334 wnd.state = uiconst.UI_HIDDEN 335 336 def IsObserving(self): 337 return bool(self.viewMode == 'observe') 338 339 def ToggleTeam(self, itemID): 340 current = self.GetTeam(itemID) 341 if itemID in self.teams[current]: 342 self.teams[current].remove(itemID) 343 new = not current 344 if itemID not in self.teams[new]: 345 self.teams[new].append(itemID) 346 settings.user.ui.Set('targetTeamsII', self.teams[:]) 347 self.ArrangeTargets() 348 349 def RemoveFromTeam(self, itemID, reset = 0): 350 obs = self.IsObserving() 351 if obs: 352 if reset: 353 settings.user.ui.Set('targetTeamsII', [[], []]) 354 current = self.GetTeam(itemID) 355 if itemID in self.teams[current]: 356 self.teams[current].remove(itemID) 357 358 def MoveUp(self, itemID): 359 current = self.GetTeam(itemID) 360 teamOrder = self.teams[current] 361 idx = 0 362 if itemID in teamOrder: 363 idx = teamOrder.index(itemID) - 1 364 self.SetTeamOrder(itemID, idx) 365 self.ArrangeTargets() 366 367 def MoveDown(self, itemID): 368 current = self.GetTeam(itemID) 369 teamOrder = self.teams[current] 370 idx = 0 371 if itemID in teamOrder: 372 idx = teamOrder.index(itemID) + 1 373 self.SetTeamOrder(itemID, idx) 374 self.ArrangeTargets() 375 376 def GetTeam(self, itemID): 377 return itemID not in self.teams[0] 378 379 def GetTeamOrder(self, itemID): 380 current = self.GetTeam(itemID) 381 teamOrder = self.teams[current] 382 if itemID in teamOrder: 383 return teamOrder.index(itemID) 384 return -1 385 386 def SetTeamOrder(self, itemID, idx): 387 idx = max(0, idx) 388 current = self.GetTeam(itemID) 389 if itemID in self.teams[current]: 390 self.teams[current].remove(itemID) 391 self.teams[current].insert(idx, itemID) 392 393 def ToggleViewMode(self): 394 self.viewMode = ['normal', 'observe'][self.viewMode == 'normal'] 395 self.Reset() 396 if session.shipid and not session.stationid: 397 self.godma.GetStateManager().RefreshTargets() 398 self.CheckViewMode() 399 if self.viewMode == 'observe': 400 sm.GetService('infoPanel').ShowHideSidePanel(hide=True) 401 else: 402 sm.GetService('infoPanel').ShowHideSidePanel(hide=False) 403 404 def Show(self): 405 wnd = uicore.layer.target 406 if wnd: 407 for each in wnd.children: 408 each.state = uiconst.UI_NORMAL 409 410 def GetDogmaLM(self): 411 if self.dogmaLM is None: 412 self.dogmaLM = self.godma.GetDogmaLM() 413 return self.dogmaLM 414 415 def OnSpecialFX(self, shipID, moduleID, moduleTypeID, targetID, otherTypeID, guid, isOffensive, start, active, duration = -1, repeat = None, startTime = None, timeFromStart = 0, graphicInfo = None): 416 if isOffensive and targetID == session.shipid: 417 self.weaponsOnMe[shipID] = self.weaponsOnMe.get(shipID, 0) + (-1, +1)[start] 418 419 def OnStateChange(self, itemID, flag, true, *args): 420 if flag == state.selected and true and self.needtarget and len(self.needtarget) > 0: 421 if not self.IsTarget(itemID): 422 self.HideTargetingCursor() 423 target = self.needtarget[0] 424 if hasattr(target, 'GetDefaultEffect'): 425 effect = self.needtarget[0].GetDefaultEffect() 426 if effect is not None and effect.effectName == 'targetPassively': 427 uthread.pool('TargetManager::OnStateChange-->ActivateTargetPassively', self.LockTargetPassively, itemID, self.needtarget[0]) 428 else: 429 uthread.pool('TargetManager::OnStateChange-->LockTarget', self.TryLockTarget, itemID) 430 elif target is None: 431 self.LogError("target doesn't have a GetDefaultEffect because it None") 432 elif hasattr(target, '__class__'): 433 self.LogError(target.__class__.__name__, "doesn't have GetDefaultEffect attr") 434 else: 435 self.LogError(target, "doesn't have GetDefaultEffect attr") 436 self.needtarget = [] 437 438 def ProcessSessionChange(self, isRemote, session, change): 439 if not isRemote: 440 return 441 spaceShipChange = 'ship' in change and 'solarsystemid' not in change 442 if not sm.GetService('connection').IsConnected() or session.stationid is not None or session.charid is None: 443 self.CleanUp() 444 elif spaceShipChange and change['shipid'][0] is not None: 445 self.OnTargetClear() 446 self.pendingTargeters = [] 447 if 'solarsystemid' in change: 448 self.deadShipsBeingRemoved = set() 449 if 'fleetid' in change and change['fleetid'][1] is None: 450 self.UpdateFleetTags() 451 changingShipsInSpace = spaceShipChange and session.solarsystemid and session.shipid 452 loggingDirectlyIntoSpace = change.get('solarsystemid', (1, 1))[0] is None and not session.stationid 453 undocking = eveSessions.IsUndockingSessionChange(session, change) 454 if changingShipsInSpace or loggingDirectlyIntoSpace or undocking: 455 for otherID in self.targetedBy: 456 self.stateSvc.SetState(otherID, state.threatTargetsMe, 0) 457 458 if session.shipid: 459 uthread.new(self.godma.GetStateManager().RefreshTargets) 460 self.dogmaLM = None 461 462 def CleanUp(self): 463 self.viewMode = 'normal' 464 self.CheckViewMode() 465 self.ClearingTargets() 466 self.dogmaLM = None 467 self.ClearTargetedBy() 468 469 def ClearingTargets(self, *args): 470 if getattr(self, 'targetsByID', None) is not None: 471 for target in self.targetsByID.values(): 472 target.Close() 473 474 self.targetsByID = {} 475 self.groupIdByTarget = {} 476 self.deadShipsBeingRemoved = set() 477 478 def DoBallsAdded(self, *args, **kw): 479 import stackless 480 import blue 481 t = stackless.getcurrent() 482 timer = t.PushTimer(blue.pyos.taskletTimer.GetCurrent() + '::targetMgr') 483 try: 484 return self.DoBallsAdded_(*args, **kw) 485 finally: 486 t.PopTimer(timer) 487 488 def DoBallsAdded_(self, lst): 489 for ball, slimItem in lst: 490 if ball.id in self.pendingTargets: 491 self.OnTargetAdded(ball.id) 492 if ball.id in self.pendingTargeters: 493 self.OnTargetByOther(ball.id) 494 495 @telemetry.ZONE_METHOD 496 def DoBallsRemove(self, pythonBalls, isRelease): 497 if isRelease: 498 if len(self.pendingTargets) or len(self.autoTargeting) or len(self.targeting): 499 sm.GetService('audio').StopSoundLoop('TargetLocking', 'msg_TargetLocked_play') 500 for targetID, target in self.targetsByID.iteritems(): 501 target.Close() 502 503 if self.origin is not None and not self.origin.destroyed: 504 self.origin.Close() 505 self.origin = None 506 self.targetsByID = {} 507 self.groupIdByTarget = {} 508 self.pendingTargets = [] 509 self.rowDict = {} 510 self.deadShipsBeingRemoved = set() 511 return 512 for ball, slimItem, terminal in pythonBalls: 513 self.DoBallRemove(ball, slimItem, terminal) 514 515 def DoBallRemove(self, ball, slimItem, terminal): 516 if ball is None: 517 return 518 tid = ball.id 519 if tid in self.pendingTargets or tid in self.autoTargeting or tid in self.targeting: 520 sm.GetService('audio').StopSoundLoop('TargetLocking', 'msg_TargetLocked_play') 521 if tid not in self.deadShipsBeingRemoved: 522 self.ClearTarget(tid) 523 524 def DoBallClear(self, solitem): 525 self.CleanUp() 526 527 def OnTargets(self, targets): 528 for each in targets: 529 self.OnTarget(*each[1:]) 530 531 def OnTarget(self, what, tid = None, reason = None): 532 if what == 'add': 533 self.OnTargetAdded(tid) 534 elif what == 'clear': 535 self.OnTargetClear() 536 elif what == 'lost': 537 uthread.new(self.OnTargetLost, tid, reason) 538 elif what == 'otheradd': 539 self.OnTargetByOther(tid) 540 elif what == 'otherlost': 541 self.OnTargetByOtherLost(tid, reason) 542 sm.ChainEvent('ProcessTargetChanged', what, tid, reason) 543 544 def OnTargetAdded(self, tid): 545 if self.origin is None: 546 self.PlaceOrigin() 547 if tid in self.targeting: 548 del self.targeting[tid] 549 if tid in self.autoTargeting: 550 self.autoTargeting.remove(tid) 551 sm.GetService('audio').StopSoundLoop('TargetLocking', 'msg_TargetLocked_play') 552 slimItem = None 553 bp = sm.GetService('michelle').GetBallpark() 554 if bp is not None: 555 slimItem = bp.GetInvItem(tid) 556 if bp is None or slimItem is None: 557 if tid not in self.pendingTargets: 558 self.pendingTargets.append(tid) 559 return 560 self.stateSvc.SetState(tid, state.targeting, 0) 561 self.stateSvc.SetState(tid, state.targeted, 1) 562 if tid in self.pendingTargets: 563 self.pendingTargets.remove(tid) 564 sm.ScatterEvent('OnClientEvent_LockItem', slimItem) 565 if tid in self.targetsByID: 566 self.ClearTarget(tid) 567 is_observing = self.IsObserving() 568 if is_observing and not (tid in self.teams[0] or tid in self.teams[1]): 569 self.teams[1].append(tid) 570 if settings.user.ui.Get('alignHorizontally', 1): 571 padBottom = 0 572 else: 573 padBottom = TARGET_PADDING 574 targetClass = self.GetTargetClassForSlimItem(slimItem) 575 target = targetClass(name='target', parent=uicore.layer.target, align=uiconst.TOPRIGHT, width=[110, 160][is_observing], height=[150, 80][is_observing], state=uiconst.UI_PICKCHILDREN, padBottom=padBottom) 576 target.Startup(slimItem) 577 targetID = slimItem.itemID 578 self.targetsByID[targetID] = target 579 self.groupIdByTarget[targetID] = slimItem.groupID 580 bracket = sm.GetService('bracket').GetBracket(tid) 581 if bracket and bracket.targeted_indicator: 582 bracket.targeted_indicator.state = [uiconst.UI_DISABLED, uiconst.UI_HIDDEN][is_observing] 583 self.ArrangeTargets() 584 if not self.GetActiveTargetID(): 585 self.stateSvc.SetState(tid, state.activeTarget, 1) 586 if self.stateSvc.GetExclState(state.selected) is None: 587 self.stateSvc.SetState(tid, state.selected, 1) 588 589 def GetTargetClassForSlimItem(self, slimItem): 590 if slimItem.categoryID == const.categoryFighter: 591 return TargetInBarFighter 592 else: 593 return TargetInBar 594 595 def OnFleetStateChange(self, fleetState): 596 if not fleetState: 597 return 598 for itemID, tag in fleetState.targetTags.iteritems(): 599 target = self.GetTarget(itemID) 600 if target: 601 target.SetFleetTag(tag) 602 603 def UpdateFleetTags(self): 604 fleetSvc = sm.GetService('fleet') 605 for eachID, eachTarget in self.GetTargets().iteritems(): 606 tag = fleetSvc.GetTargetTag(eachID) 607 eachTarget.SetFleetTag(tag) 608 609 def OrderTarget(self, who): 610 if who not in self.needtarget[:]: 611 self.needtarget.append(who) 612 self.ShowTargetingCursor() 613 614 def IsSomeModuleWaitingForTargetClick(self): 615 return bool(self.needtarget) 616 617 def CancelTargetOrder(self, who = None): 618 if not who and len(self.needtarget): 619 for each in self.needtarget: 620 if each and not each.destroyed: 621 each.waitingForActiveTarget = 0 622 623 self.needtarget = [] 624 elif who in self.needtarget: 625 self.needtarget.remove(who) 626 who.waitingForActiveTarget = 0 627 if not len(self.needtarget): 628 self.HideTargetingCursor() 629 630 def ShowTargetingCursor(self): 631 uicore.layer.inflight.sr.tcursor.state = uiconst.UI_DISABLED 632 633 def HideTargetingCursor(self): 634 uicore.layer.inflight.sr.tcursor.state = uiconst.UI_HIDDEN 635 636 def GetOriginAlign(self, toLeft, toTop): 637 if toLeft: 638 if toTop: 639 align = uiconst.BOTTOMRIGHT 640 else: 641 align = uiconst.TOPRIGHT 642 elif toTop: 643 align = uiconst.BOTTOMLEFT 644 else: 645 align = uiconst.TOPLEFT 646 return align 647 648 def PrepareRowsOrColumns(self, originAlign, baseleft, basetop, *args): 649 targetPar = self.targetPar 650 alignmentDict = {(0, uiconst.TOPLEFT): (uiconst.TOLEFT, uiconst.TOTOP, (baseleft, 651 basetop, 652 0, 653 0)), 654 (0, uiconst.TOPRIGHT): (uiconst.TORIGHT, uiconst.TOTOP, (0, 655 basetop, 656 baseleft, 657 0)), 658 (0, uiconst.BOTTOMLEFT): (uiconst.TOLEFT, uiconst.TOBOTTOM, (baseleft, 659 0, 660 0, 661 basetop)), 662 (0, uiconst.BOTTOMRIGHT): (uiconst.TORIGHT, uiconst.TOBOTTOM, (0, 663 0, 664 baseleft, 665 basetop)), 666 (1, uiconst.TOPLEFT): (uiconst.TOTOP, uiconst.TOLEFT, (baseleft, 667 basetop, 668 0, 669 0)), 670 (1, uiconst.TOPRIGHT): (uiconst.TOTOP, uiconst.TORIGHT, (0, 671 basetop, 672 baseleft, 673 0)), 674 (1, uiconst.BOTTOMLEFT): (uiconst.TOBOTTOM, uiconst.TOLEFT, (baseleft, 675 0, 676 0, 677 basetop)), 678 (1, uiconst.BOTTOMRIGHT): (uiconst.TOBOTTOM, uiconst.TORIGHT, (0, 679 0, 680 baseleft, 681 basetop))} 682 horizontally = settings.user.ui.Get('alignHorizontally', 1) 683 rowAlignment, targetAlignment, targetParPadding = alignmentDict[horizontally, originAlign] 684 widthAvailable = uicore.desktop.width - baseleft 685 heightAvailable = uicore.desktop.height - basetop 686 if horizontally: 687 availableSpace = heightAvailable 688 maxHeight = AVG_TARGET_HEIGHT 689 maxWidth = 0 690 maxRowsPossible = availableSpace / maxHeight 691 else: 692 availableSpace = widthAvailable 693 maxHeight = 0 694 maxWidth = MAX_TARGET_WIDTH 695 maxRowsPossible = availableSpace / maxWidth 696 counter = 0 697 for eachRow in targetPar.children: 698 if not isinstance(eachRow, Container): 699 continue 700 if counter >= maxRowsPossible: 701 eachRow.display = False 702 counter += 1 703 continue 704 eachRow.display = True 705 if eachRow.align != rowAlignment: 706 eachRow.SetAlign(rowAlignment) 707 eachRow.height = maxHeight 708 eachRow.width = maxWidth 709 for eachTarget in eachRow.children: 710 if not isinstance(eachTarget, TargetInBar): 711 continue 712 eachTarget.SetAlign(targetAlignment) 713 if horizontally: 714 eachTarget.padBottom = 0 715 else: 716 eachTarget.padBottom = max(TARGET_PADDING, eachTarget.padBottom) 717 718 counter += 1 719 720 newRowList = [] 721 for i in xrange(maxRowsPossible): 722 aRow = getattr(targetPar, 'aRow_%s' % i, None) 723 if not aRow or aRow.destroyed: 724 aRow = Container(parent=targetPar, align=rowAlignment, height=maxHeight, width=maxWidth, name='aRowx_%s' % i, state=uiconst.UI_PICKCHILDREN) 725 aRow.numRow = i 726 setattr(targetPar, 'aRow_%s' % i, aRow) 727 newRowList.append(aRow) 728 729 targetPar.rows = newRowList 730 targetPar.padding = targetParPadding 731 return targetAlignment 732 733 def ArrangeTargets(self): 734 self.PositionOriginWithAnchors() 735 self.UpdateOriginDirection() 736 if self.origin: 737 self.origin.state = uiconst.UI_NORMAL 738 targetPar = getattr(self, 'targetPar', None) 739 if targetPar is None or getattr(self, 'origin', None) is None: 740 return 741 (cX, cY), (toLeft, toTop) = self.GetOriginPosition(getDirection=1) 742 originAlign = self.GetOriginAlign(toLeft, toTop) 743 baseleft, basetop = self.GetBaseLeftAndTop() 744 targetAlignment = self.PrepareRowsOrColumns(originAlign, baseleft, basetop) 745 targetsThatDontFit = [] 746 targetsAdded = [] 747 rows = targetPar.rows 748 for key, targetIDs in self.rowDict.iteritems(): 749 if len(rows) >= key + 1: 750 cont = rows[key] 751 else: 752 targetsThatDontFit += targetIDs 753 self.rowDict[key] = [] 754 continue 755 newTargetList = [] 756 counter = 0 757 for eachTargetID in targetIDs: 758 eachTarget = self.GetTarget(eachTargetID) 759 if getattr(eachTarget, 'isDragging', False): 760 continue 761 if eachTarget is None or eachTarget.destroyed: 762 continue 763 if not self.DoesTargetFit(cont, baseleft, basetop, counter + 1, excludedTargetID=eachTargetID): 764 targetsThatDontFit.append(eachTargetID) 765 counter += 1 766 continue 767 eachTarget.SetAlign(targetAlignment) 768 eachTarget.SetParent(cont) 769 targetsAdded.append(eachTarget.id) 770 newTargetList.append(eachTargetID) 771 counter += 1 772 773 self.rowDict[key] = newTargetList 774 775 horizontally = settings.user.ui.Get('alignHorizontally', 1) 776 wnd, pl, pt, pw, ph = self.GetTargetLayerAbsolutes() 777 for targetID, target in self.targetsByID.iteritems(): 778 if not isinstance(target, TargetInBar): 779 continue 780 if targetID in targetsAdded: 781 continue 782 if getattr(target, 'isDragging', False): 783 continue 784 myCont, numTargets = self.FindRow(rows, baseleft, basetop) 785 target.state = uiconst.UI_PICKCHILDREN 786 target.SetAlign(targetAlignment) 787 if myCont: 788 target.SetParent(myCont) 789 targetList = self.rowDict.get(myCont.numRow, []) 790 targetList.append(targetID) 791 self.rowDict[myCont.numRow] = targetList 792 if targetID in targetsThatDontFit: 793 targetsThatDontFit.remove(targetID) 794 795 if len(targetsThatDontFit) > 0: 796 self.LogError('did not add the following targets: ', targetsThatDontFit) 797 uthread.new(self.AdjustRowSize) 798 sm.ScatterEvent('OnTargetsArranged') 799 800 def FindRow(self, possibleContainers, baseLeft, baseTop, *args): 801 for cont in possibleContainers: 802 if self.DoesTargetFit(cont, baseLeft, baseTop): 803 numTargets = len([ child for child in cont.children if isinstance(child, TargetInBar) ]) 804 return (cont, numTargets) 805 806 return (None, 0) 807 808 def AdjustRowSize(self): 809 if self.IsObserving(): 810 return 811 targetPar = getattr(self, 'targetPar', None) 812 if targetPar is None: 813 return 814 blue.pyos.synchro.Yield() 815 horizontally = settings.user.ui.Get('alignHorizontally', 1) 816 if horizontally: 817 for eachRow in targetPar.rows: 818 if not eachRow.display: 819 continue 820 if self.overrideBarHeight is None: 821 maxHeight = self.GetRowMaxHeight(eachRow, MIN_TARGET_HEIHT) 822 uicore.animations.MorphScalar(eachRow, 'height', eachRow.height, maxHeight + TARGET_PADDING, duration=0.3) 823 else: 824 eachRow.height = self.overrideBarHeight 825 826 else: 827 maxLineHeights = self.GetLinesMaxHeights() 828 for lineIdx, values in maxLineHeights.iteritems(): 829 maxH = max([ h for h, targetID in values ]) 830 maxH = maxH 831 for h, targetID in values: 832 target = self.GetTarget(targetID) 833 if target: 834 padBottom = maxH - target.height 835 uicore.animations.MorphScalar(target, 'padBottom', target.padBottom, padBottom, duration=0.5) 836 837 def GetRowMaxHeight(self, targetRow, minSize, *args): 838 horizontally = settings.user.ui.Get('alignHorizontally', 1) 839 if horizontally: 840 maxHeight = max([minSize] + [ target.height for target in targetRow.children if isinstance(target, TargetInBar) ]) 841 return maxHeight 842 843 def GetLinesMaxHeights(self, *args): 844 heightByLineIdx = {} 845 for rowKey, targetIDs in self.rowDict.iteritems(): 846 if not targetIDs: 847 continue 848 for lineIdx, targetID in enumerate(targetIDs): 849 target = self.GetTarget(targetID) 850 if targetID: 851 heightList = heightByLineIdx.get(lineIdx, []) 852 heightList.append((target.height + TARGET_PADDING, targetID)) 853 heightByLineIdx[lineIdx] = heightList 854 855 return heightByLineIdx 856 857 def DoesTargetFit(self, cont, baseLeft, baseTop, idx = None, excludedTargetID = None, *args): 858 horizontally = settings.user.ui.Get('alignHorizontally', 1) 859 if horizontally: 860 parSize = uicore.desktop.width - baseLeft 861 commonTargetSize = MAX_TARGET_WIDTH 862 else: 863 parSize = uicore.desktop.height - baseTop 864 commonTargetSize = AVG_TARGET_HEIGHT 865 numTargets = 0 866 for child in cont.children[:idx]: 867 if not isinstance(child, TargetInBar): 868 continue 869 if child.id == excludedTargetID: 870 continue 871 numTargets += 1 872 873 totalSizeOfTargets = numTargets * commonTargetSize 874 return totalSizeOfTargets + commonTargetSize < parSize 875 876 def OnMoveTarget(self, target, *args): 877 if settings.user.ui.Get('targetPositionLocked', 0): 878 return 879 targetPar = getattr(self, 'targetPar', None) 880 if targetPar is None or targetPar.destroyed: 881 return targetPar 882 wnd, pl, pt, pw, ph = self.GetTargetLayerAbsolutes() 883 tl, tt, tw, th = targetPar.GetAbsolute() 884 clipper = (tl - 10, 885 tt - 5, 886 tl + tw + 20, 887 tt + th + 10) 888 uthread.new(self.DoRepositionDrag, target, clipper) 889 890 def DoRepositionDrag(self, myTarget, cursorClipper): 891 if uicore.uilib.leftbtn and uicore.uilib.mouseOver == myTarget.barAndImageCont: 892 uicore.uilib.ClipCursor(*cursorClipper) 893 else: 894 return 895 horizontalAlign = settings.user.ui.Get('alignHorizontally', True) 896 repositionLine = Line(align=uiconst.TORIGHT_NOPUSH, weight=2, color=(1, 1, 1, 0.5)) 897 oldParentRowOrColumn = getattr(myTarget.parent, 'numRow', None) 898 if oldParentRowOrColumn is None: 899 for rowKey, row in self.rowDict.iteritems(): 900 if myTarget.id in row: 901 oldParentRowOrColumn = rowKey 902 break 903 904 myTarget.opacity = 0.3 905 myTarget.isDragging = True 906 targetSvc = sm.GetService('target') 907 targetPar = getattr(self, 'targetPar', None) 908 if not targetPar: 909 return 910 myRow = None 911 posIndex = 0 912 while uicore.uilib.leftbtn: 913 (originX, originY), (toLeft, toTop) = targetSvc.GetOriginPosition(getDirection=1) 914 lessThanAll = True 915 for row in targetPar.children: 916 if not isinstance(row, Container): 917 continue 918 tl, tt, tw, th = row.GetAbsolute() 919 if tl - 2 <= uicore.uilib.x <= tl + tw + 2 and tt - 2 <= uicore.uilib.y <= tt + th + 2: 920 myRow = row 921 break 922 923 if not myRow: 924 blue.pyos.synchro.Yield() 925 continue 926 counter = 0 927 mouseX = uicore.uilib.x 928 mouseY = uicore.uilib.y 929 for target in myRow.children: 930 if not isinstance(target, TargetInBar): 931 continue 932 counter += 1 933 tl, tt, tw, th = target.GetAbsolute() 934 isOverTarget = tl <= mouseX < tl + tw and tt <= mouseY < tt + th 935 if isOverTarget: 936 if horizontalAlign: 937 if toLeft: 938 repositionLine.SetAlign(uiconst.TORIGHT_NOPUSH) 939 posIndex = counter 940 else: 941 posIndex = counter - 1 942 repositionLine.SetAlign(uiconst.TOLEFT_NOPUSH) 943 elif toTop: 944 posIndex = counter 945 repositionLine.SetAlign(uiconst.TOBOTTOM_NOPUSH) 946 else: 947 posIndex = counter - 1 948 repositionLine.SetAlign(uiconst.TOTOP_NOPUSH) 949 repositionLine.SetParent(myRow) 950 repositionLine.SetOrder(posIndex) 951 lessThanAll = False 952 break 953 954 if lessThanAll: 955 posIndex = -1 956 if horizontalAlign: 957 if toLeft: 958 if originX < mouseX: 959 posIndex = 0 960 repositionLine.SetAlign(uiconst.TORIGHT_NOPUSH) 961 else: 962 if originX > mouseX: 963 posIndex = 0 964 repositionLine.SetAlign(uiconst.TOLEFT_NOPUSH) 965 elif toTop: 966 if originY < mouseY: 967 posIndex = 0 968 repositionLine.SetAlign(uiconst.TOBOTTOM_NOPUSH) 969 else: 970 if originY > mouseY: 971 posIndex = 0 972 repositionLine.SetAlign(uiconst.TOTOP_NOPUSH) 973 repositionLine.SetParent(myRow) 974 repositionLine.SetOrder(posIndex) 975 self.ColorRepositionLine(myRow, myTarget.id, repositionLine) 976 blue.pyos.synchro.Yield() 977 978 uicore.uilib.UnclipCursor() 979 if myRow: 980 doAddTarget = True 981 if oldParentRowOrColumn is not None: 982 old = self.rowDict.get(oldParentRowOrColumn, []) 983 if myTarget.id in old: 984 targetsCurrentPos = (posIndex, posIndex - 1) 985 if oldParentRowOrColumn == myRow.numRow: 986 oldIndex = old.index(myTarget.id) 987 if oldIndex in targetsCurrentPos: 988 doAddTarget = False 989 elif oldIndex < posIndex: 990 posIndex -= 1 991 if doAddTarget: 992 old.remove(myTarget.id) 993 self.rowDict[oldParentRowOrColumn] = old 994 if doAddTarget: 995 posIndex = max(-1, posIndex) 996 newRow = self.rowDict.get(myRow.numRow, []) 997 if posIndex < 0: 998 newRow.append(myTarget.id) 999 else: 1000 newRow.insert(posIndex, myTarget.id) 1001 self.rowDict[myRow.numRow] = newRow 1002 myTarget.isDragging = False 1003 repositionLine.Close() 1004 myTarget.opacity = 1.0 1005 targetSvc.ArrangeTargets() 1006 1007 def ColorRepositionLine(self, myRow, excludedTargetID, repositionLine, *args): 1008 baseLeft, baseTop = self.GetBaseLeftAndTop() 1009 if self.DoesTargetFit(myRow, baseLeft, baseTop, excludedTargetID=excludedTargetID): 1010 repositionLine.SetRGBA(1, 1, 1, 0.5) 1011 else: 1012 repositionLine.SetRGBA(1, 0.5, 0, 0.5) 1013 1014 def SelectNextTarget(self): 1015 activeID = self.GetActiveTargetID() 1016 if activeID is None: 1017 return 1018 nextTarget = self.FindNextTarget(activeID, direction=1) 1019 if nextTarget: 1020 self._SetSelected(nextTarget) 1021 1022 def SelectPrevTarget(self): 1023 activeID = self.GetActiveTargetID() 1024 if activeID is None: 1025 return 1026 prevTarget = self.FindNextTarget(activeID, direction=-1) 1027 if prevTarget: 1028 self._SetSelected(prevTarget) 1029 1030 def FindNextTarget(self, activeID, direction = 1): 1031 allTargetIDsInOrder = self.GetSortedTargetList() 1032 if not allTargetIDsInOrder: 1033 return None 1034 elif activeID not in allTargetIDsInOrder: 1035 return allTargetIDsInOrder[0] 1036 activeIndex = allTargetIDsInOrder.index(activeID) 1037 if direction == 1: 1038 if activeIndex == len(allTargetIDsInOrder) - 1: 1039 return allTargetIDsInOrder[0] 1040 return allTargetIDsInOrder[activeIndex + 1] 1041 else: 1042 return allTargetIDsInOrder[activeIndex - 1] 1043 1044 def GetSortedTargetList(self, *args): 1045 sortedLists = [] 1046 for rowKey, targetIDs in self.rowDict.iteritems(): 1047 validTargetIDs = filter(lambda x: x not in self.deadShipsBeingRemoved, targetIDs) 1048 sortedLists.append((rowKey, validTargetIDs)) 1049 1050 sortedLists = SortListOfTuples(sortedLists) 1051 allTargetIDsInOrder = [] 1052 for eachList in sortedLists: 1053 allTargetIDsInOrder += eachList 1054 1055 return allTargetIDsInOrder 1056 1057 def _SetSelected(self, targetID): 1058 self.stateSvc.SetState(targetID, state.selected, 1) 1059 self.stateSvc.SetState(targetID, state.activeTarget, 1) 1060 1061 def OnTargetLost(self, tid, reason): 1062 (self.stateSvc.SetState(tid, state.targeted, 0), self.stateSvc.GetExclState(state.activeTarget)) 1063 if self.stateSvc.GetExclState(state.activeTarget) == tid: 1064 self.stateSvc.SetState(tid, state.activeTarget, 0) 1065 if tid in self.pendingTargets: 1066 self.pendingTargets.remove(tid) 1067 sm.GetService('audio').StopSoundLoop('TargetLocking', 'msg_TargetLocked_play') 1068 self.LogInfo('OnTargetLost ', tid) 1069 if reason == 'Exploding': 1070 self.ClearDeadTarget(targetID=tid, reason=reason) 1071 else: 1072 self.ClearTarget(tid, reason=reason) 1073 1074 def ClearDeadTarget(self, targetID, reason = None, *args): 1075 if targetID in self.targetsByID and targetID not in self.deadShipsBeingRemoved: 1076 try: 1077 self.deadShipsBeingRemoved.add(targetID) 1078 target_in_bar = self.targetsByID[targetID] 1079 self.SetFirstTargetActiveIfNoActive() 1080 target_in_bar.anim_disappear() 1081 except: 1082 self.LogException() 1083 finally: 1084 self.ClearTarget(targetID, reason=reason) 1085 1086 def OnTargetByOther(self, otherID): 1087 self.stateSvc.SetState(otherID, state.threatTargetsMe, 1) 1088 if otherID in self.targetedBy: 1089 self.LogError('already targeted by', otherID) 1090 else: 1091 self.AddTargetedBy(otherID) 1092 bp = sm.GetService('michelle').GetBallpark() 1093 if bp is not None: 1094 slimItem = bp.GetInvItem(otherID) 1095 if slimItem is not None: 1096 if slimItem.ownerID: 1097 self.ownerToShipIDCache[slimItem.ownerID] = otherID 1098 if bp is None or slimItem is None: 1099 if otherID not in self.pendingTargeters: 1100 self.pendingTargeters.append(otherID) 1101 return 1102 if otherID in self.pendingTargeters: 1103 self.pendingTargeters.remove(otherID) 1104 tgts = self.GetTargets().keys() + self.targeting.keys() 1105 if otherID != session.shipid and otherID not in tgts and otherID not in self.autoTargeting and min(settings.user.ui.Get('autoTargetBack', 0), sm.GetService('godma').GetItem(session.charid).maxLockedTargets, sm.GetService('godma').GetItem(session.shipid).maxLockedTargets) > len(tgts): 1106 if len(self.autoTargeting) < settings.user.ui.Get('autoTargetBack', 0): 1107 self.autoTargeting.append(otherID) 1108 uthread.pool('TargetManages::OnTargetByOther-->LockTarget', self.LockTarget, otherID, autotargeting=1) 1109 1110 def GetTarget(self, targetID): 1111 return self.targetsByID.get(targetID, None) 1112 1113 def OnTargetByOtherLost(self, otherID, reason): 1114 self.stateSvc.SetState(otherID, state.threatTargetsMe, 0) 1115 if otherID in self.pendingTargeters: 1116 self.pendingTargeters.remove(otherID) 1117 try: 1118 self.RemoveTargetedBy(otherID) 1119 except ValueError: 1120 self.LogInfo('was not targeted by', otherID) 1121 sys.exc_clear() 1122 1123 bp = sm.GetService('michelle').GetBallpark() 1124 if bp is not None: 1125 slimItem = bp.GetInvItem(otherID) 1126 if slimItem is not None: 1127 if slimItem.ownerID and slimItem.ownerID in self.ownerToShipIDCache: 1128 del self.ownerToShipIDCache[slimItem.ownerID] 1129 1130 def OnTargetClear(self, targetsToSkip = None): 1131 for tid in self.targetsByID.keys(): 1132 if targetsToSkip and tid in targetsToSkip: 1133 continue 1134 self.stateSvc.SetState(tid, state.activeTarget, 0) 1135 self.stateSvc.SetState(tid, state.targeting, 0) 1136 self.stateSvc.SetState(tid, state.targeted, 0) 1137 self.CancelTargetOrder() 1138 self.ClearTarget(tid) 1139 1140 def GetTargetedBy(self): 1141 return self.targetedBy 1142 1143 def IsTargeted(self): 1144 return len(self.targetedBy) > 0 1145 1146 def GetTargeting(self): 1147 return self.targeting.keys() 1148 1149 def ClearTarget(self, tid, reason = None): 1150 removedTarget = False 1151 if tid in self.targetsByID: 1152 t = self.targetsByID[tid] 1153 del self.targetsByID[tid] 1154 groupID = self.groupIdByTarget[tid] 1155 del self.groupIdByTarget[tid] 1156 self.deadShipsBeingRemoved.discard(tid) 1157 t.Close() 1158 self.ArrangeTargets() 1159 removedTarget = True 1160 sm.ScatterEvent('OnClientEvent_UnlockItem', tid) 1161 if tid in self.pendingTargets: 1162 self.pendingTargets.remove(tid) 1163 if removedTarget and not self.targetsByID: 1164 if self.origin is not None and not self.origin.destroyed: 1165 self.origin.Close() 1166 self.origin = None 1167 self.stateSvc.SetState(tid, state.activeTarget, 0) 1168 for rowKey, row in self.rowDict.iteritems(): 1169 if tid in row: 1170 row.remove(tid) 1171 self.rowDict[rowKey] = row 1172 break 1173 1174 if self.targetsByID: 1175 self.SetFirstTargetActiveIfNoActive() 1176 1177 def SetFirstTargetActiveIfNoActive(self): 1178 active = self.stateSvc.GetExclState(state.activeTarget) 1179 if active is None and self.targetsByID: 1180 allTargetIDsInOrder = self.GetSortedTargetList() 1181 if allTargetIDsInOrder: 1182 targetToSelect = allTargetIDsInOrder[0] 1183 self.stateSvc.SetState(targetToSelect, state.activeTarget, 1) 1184 1185 def GetTargetingStartTime(self, targetID): 1186 return self.targeting.get(targetID, None) 1187 1188 def BeingTargeted(self, targetID): 1189 return targetID in self.targeting 1190 1191 def StartLockTarget(self, tid, autotargeting = 0): 1192 if tid in self.GetTargets(): 1193 self.ClearTarget(tid) 1194 self.stateSvc.SetState(tid, state.targeting, 0) 1195 sm.GetService('audio').StopSoundLoop('TargetLocking') 1196 if tid in self.targeting: 1197 return 1198 self.LogInfo('targetMgr: Locking Target for ', tid) 1199 sm.GetService('audio').StartSoundLoop('TargetLocking') 1200 sm.ScatterEvent('OnTargetLockStarted', GetBallparkRecord(tid)) 1201 self.stateSvc.SetState(tid, state.targeting, 1) 1202 self.targeting[tid] = blue.os.GetSimTime() 1203 1204 def FailLockTarget(self, tid): 1205 if tid in self.targeting: 1206 del self.targeting[tid] 1207 if tid in self.autoTargeting: 1208 self.autoTargeting.remove(tid) 1209 self.stateSvc.SetState(tid, state.targeted, 0) 1210 self.stateSvc.SetState(tid, state.targeting, 0) 1211 sm.GetService('audio').StopSoundLoop('TargetLocking') 1212 sm.ScatterEvent('OnFailLockTarget', tid) 1213 1214 def CancelAddTarget(self, tid): 1215 self.stateSvc.SetState(tid, state.targeted, 0) 1216 self.stateSvc.SetState(tid, state.targeting, 0) 1217 sm.GetService('audio').StopSoundLoop('TargetLocking') 1218 sm.ScatterEvent('OnFailLockTarget', tid) 1219 self.GetDogmaLM().CancelAddTarget(tid) 1220 1221 def TryLockTarget(self, itemID): 1222 if itemID in self.GetTargeting() or itemID in self.targetsByID: 1223 return 1224 slimItem = GetBallparkRecord(itemID) 1225 if not slimItem: 1226 return 1227 if slimItem.groupID in const.nonTargetableGroups: 1228 return 1229 if itemID == session.shipid and session.shipid == session.structureid: 1230 return 1231 self.LockTarget(itemID) 1232 1233 def GetDistanceToTarget(self, itemID): 1234 if session.shipid is None or session.solarsystemid is None: 1235 raise RuntimeError('Failed to get distance to target. Must be in ship in space (shipID: %s, solarSystemID: %s).' % (session.shipid, session.solarsystemid)) 1236 if itemID is None or itemID == session.shipid or idCheckers.IsUniverseCelestial(itemID): 1237 raise ValueError('Failed to get distance to target. Target item is not valid (itemID: %s).' % itemID) 1238 bp = sm.GetService('michelle').GetBallpark() 1239 if bp is None: 1240 return RuntimeError('Failed to get distance to target. Ballpark is not available.') 1241 otherBall = bp and bp.GetBall(itemID) or None 1242 if otherBall is None: 1243 return RuntimeError('Failed to get distance to target. Target ball is not available (itemID: %s).' % itemID) 1244 distanceToTarget = max(0, otherBall.surfaceDist) 1245 return distanceToTarget 1246 1247 def GetMaxTargetRange(self): 1248 shipItem = sm.GetService('godma').GetStateManager().GetItem(session.shipid) 1249 if shipItem is None: 1250 return 1251 return shipItem.maxTargetRange 1252 1253 def IsInTargetingRange(self, itemID): 1254 try: 1255 distanceToTarget = self.GetDistanceToTarget(itemID) 1256 except (RuntimeError, ValueError): 1257 return False 1258 1259 maxTargetRange = self.GetMaxTargetRange() 1260 if maxTargetRange is None: 1261 return False 1262 return distanceToTarget < maxTargetRange 1263 1264 def LockTarget(self, tid, autotargeting = 0): 1265 try: 1266 self._LockTarget(tid, autotargeting) 1267 except Exception: 1268 self.FailLockTarget(tid) 1269 sys.exc_clear() 1270 1271 def _LockTarget(self, tid, autotargeting = 0): 1272 self.StartLockTarget(tid, autotargeting) 1273 try: 1274 flag, targetList = self.GetDogmaLM().AddTarget(tid) 1275 if not flag: 1276 self.OnTargetAdded(tid) 1277 except UserError as e: 1278 self.FailLockTarget(tid) 1279 if autotargeting: 1280 sys.exc_clear() 1281 return 1282 if e.msg in ('DeniedShipChanged', 'TargetingAttemptCancelled'): 1283 sys.exc_clear() 1284 return 1285 prompt_player_fsd_dialog(e.msg, e.dict) 1286 raise 1287 1288 self.LogInfo('targetMgr: Locking Target for ', tid, ' done') 1289 1290 def UnlockTarget(self, tid): 1291 if tid in self.targetsByID: 1292 self.GetDogmaLM().RemoveTarget(tid) 1293 self.RemoveFromTeam(tid) 1294 1295 def UnlockTargets(self): 1296 targetsToUnlock = self.targetsByID.keys() 1297 if targetsToUnlock: 1298 self.GetDogmaLM().RemoveTargets(targetsToUnlock) 1299 for tID in targetsToUnlock: 1300 self.RemoveFromTeam(tID) 1301 1302 def ToggleLockTarget(self, targetID): 1303 if self.IsTarget(targetID): 1304 self.UnlockTarget(targetID) 1305 else: 1306 self.TryLockTarget(targetID) 1307 1308 def LockTargetPassively(self, tid, smb): 1309 self.StartLockTarget(tid, 0) 1310 try: 1311 smb.OnStateChange(tid, state.activeTarget, True) 1312 except UserError as e: 1313 self.FailLockTarget(tid) 1314 if e.msg == 'DeniedShipChanged': 1315 sys.exc_clear() 1316 return 1317 raise 1318 1319 self.LogInfo('targetMgr: PassiveLocking Target for ', tid, ' done') 1320 1321 def ClearTargets(self): 1322 self.GetDogmaLM().ClearTargets() 1323 1324 def GetActiveTargetID(self): 1325 selected = self.stateSvc.GetExclState(state.activeTarget) 1326 if selected and selected in self.targetsByID: 1327 return selected 1328 1329 def GetTargets(self): 1330 return self.targetsByID 1331 1332 def IsTarget(self, targetID): 1333 return targetID in self.targetsByID 1334 1335 def GetNumAdditionalTargetsAllowed(self): 1336 maxTargets = sm.GetService('godma').GetItem(session.shipid).maxLockedTargets 1337 currTargets = len(self.GetTargets()) 1338 return maxTargets - currTargets 1339 1340 def FindClosestEntity(self, targetPriority = None): 1341 return get_closest_entity_target(targetPriority) 1342 1343 def AddTargetedBy(self, enemyID): 1344 self.targetedBy.append(enemyID) 1345 sm.ScatterEvent('OnClientEvent_TargetedByChanged', enemyID) 1346 1347 def RemoveTargetedBy(self, enemyID): 1348 self.targetedBy.remove(enemyID) 1349 sm.ScatterEvent('OnClientEvent_TargetedByChanged', enemyID) 1350 1351 def ClearTargetedBy(self): 1352 self.targetedBy = [] 1353 sm.ScatterEvent('OnClientEvent_TargetedByChanged', None)