targetInBar.py (44132B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\inflight\bracketsAndTargets\targetInBar.py 2 import _weakref 3 import math 4 import appConst 5 import eveicon 6 import mining 7 import random 8 import blue 9 import evetypes 10 import localization 11 import telemetry 12 import trinity 13 import uthread 14 import uthread2 15 import utillib 16 from carbon.common.script.util import commonutils, timerstuff 17 from carbon.common.script.util.format import FmtDist 18 from carbonui import uiconst, Align, PickState 19 from carbonui.primitives.container import Container 20 from carbonui.primitives.containerAutoSize import ContainerAutoSize 21 from carbonui.primitives.frame import Frame 22 from carbonui.primitives.sprite import Sprite 23 from carbonui.primitives.transform import Transform 24 from carbonui.uianimations import animations 25 from carbonui.uiconst import BlendMode, OutputMode 26 from carbonui.uicore import uicore 27 from chroma import Color 28 from eve.client.script.parklife import states as state 29 from eve.client.script.ui import eveColor 30 from eve.client.script.ui.control import eveIcon, eveLabel 31 from eve.client.script.ui.inflight.bracketsAndTargets.bracketVarious import GetIconColor 32 from eve.client.script.ui.inflight.bracketsAndTargets.activeTargetIndicator import ActiveTargetIndicator 33 from eve.client.script.ui.inflight.bracketsAndTargets.weaponIcons import FighterAbilityWeapon, Weapon 34 from eve.client.script.ui.inflight.squadrons.shipFighterState import GetShipFighterState 35 from eve.client.script.ui.shared.stateFlag import AddAndSetFlagIcon 36 from eve.client.script.ui.util import uix 37 from eveservices.menu import GetMenuService 38 from gametime import GetDurationInClient 39 from mining.client import mining_signals 40 from mining.client.asteroid_scanning_service import AsteroidScanningService 41 from mining.client.ui.asteroid_quantity_gauge_circular import AsteroidQuantityGaugeCircular 42 from spacecomponents.client.messages import MSG_ON_TARGET_BRACKET_ADDED, MSG_ON_TARGET_BRACKET_REMOVED 43 from spacecomponents.common.helper import HasMineableComponent 44 accuracyThreshold = 0.8 45 SHIELD = 0 46 ARMOR = 1 47 HULL = 2 48 HOVERTIME = 250 49 50 class TargetInBar(ContainerAutoSize): 51 __guid__ = 'uicls.TargetInBar' 52 __notifyevents__ = ['ProcessShipEffect', 53 'OnStateChange', 54 'OnJamStart', 55 'OnJamEnd', 56 'OnSlimItemChange', 57 'OnDroneStateChange2', 58 'OnDroneControlLost', 59 'OnStateSetupChange', 60 'OnSetPlayerStanding', 61 'OnItemNameChange', 62 'OnUIRefresh', 63 'OnFleetJoin_Local', 64 'OnFleetLeave_Local', 65 'OnSuspectsAndCriminalsUpdate', 66 'OnDisapprovalUpdate', 67 'OnCrimewatchEngagementUpdated'] 68 69 def ApplyAttributes(self, attributes): 70 super(TargetInBar, self).ApplyAttributes(attributes) 71 self.lastDistance = None 72 self.sr.updateTimer = None 73 self.drones = {} 74 self.activeModules = set([]) 75 self.lastDataUsedForLabel = None 76 self.lastTextUsedForLabel = None 77 self.lastTextUsedDistance = None 78 self.lastTextUsedForShipType = None 79 self.itemID = None 80 self.slimItem = None 81 self.weaponsOnTarget = {} 82 self.jammingModules = {} 83 self.innerHealthBorder = pow(28, 2) 84 self.outerHealthBorder = pow(42, 2) 85 self._hoverThread = None 86 self.fleetTag = None 87 self.healthBar = None 88 self.asteroid_gauge = None 89 self.connect_signals() 90 91 def Close(self): 92 super(TargetInBar, self).Close() 93 self.disconnect_signals() 94 95 def connect_signals(self): 96 mining_signals.on_mining_scan_completed.connect(self.on_mining_scan_completed) 97 mining_signals.on_mining_overlay_disabled.connect(self.on_mining_overlay_disabled) 98 mining_signals.on_mining_scan_data_cleared.connect(self.on_mining_scan_data_cleared) 99 100 def disconnect_signals(self): 101 mining_signals.on_mining_scan_completed.disconnect(self.on_mining_scan_completed) 102 mining_signals.on_mining_overlay_disabled.disconnect(self.on_mining_overlay_disabled) 103 mining_signals.on_mining_scan_data_cleared.disconnect(self.on_mining_scan_data_cleared) 104 105 def on_mining_scan_data_cleared(self): 106 self.check_show_asteroid_gauge() 107 108 def on_mining_overlay_disabled(self): 109 self.check_show_asteroid_gauge() 110 111 def on_mining_scan_completed(self): 112 self.check_show_asteroid_gauge() 113 114 def OnUIRefresh(self): 115 self.Flush() 116 bp = sm.GetService('michelle').GetBallpark() 117 if bp is not None: 118 slimItem = bp.GetInvItem(self.id) 119 self.Startup(slimItem) 120 121 def GetTargetDragData(self, *args): 122 if settings.user.ui.Get('targetPositionLocked', 0): 123 return [] 124 return [self] 125 126 def Startup(self, slimItem): 127 sm.RegisterNotify(self) 128 GetShipFighterState().ConnectFighterTargetUpdatedHandler(self._OnFighterTargetUpdate) 129 self.ball = _weakref.ref(sm.GetService('michelle').GetBall(slimItem.itemID)) 130 self.slimItem = _weakref.ref(slimItem) 131 self.id = slimItem.itemID 132 self.itemID = slimItem.itemID 133 self.typeID = slimItem.typeID 134 self.AddUIObjects(slimItem, self.itemID) 135 barAndImageCont = self.barAndImageCont 136 barAndImageCont.isDragObject = True 137 barAndImageCont.GetDragData = self.GetTargetDragData 138 barAndImageCont.OnMouseDown = self.OnTargetMouseDown 139 barAndImageCont.OnClick = self.OnTargetClick 140 barAndImageCont.GetMenu = self.GetTargetMenu 141 barAndImageCont.OnMouseEnter = self.OnTargetMouseEnter 142 barAndImageCont.OnMouseExit = self.OnTargetMouseExit 143 self.active_target_transform = Transform(parent=self.icon_container, scalingCenter=(0.5, 0.5), align=Align.CENTER, width=self.icon_container.width, height=self.icon_container.height) 144 self.active_target_indicator = ActiveTargetIndicator(parent=self.active_target_transform, itemID=self.itemID) 145 self.slimForFlag = slimItem 146 self.SetStandingIcon() 147 if slimItem.categoryID == appConst.categoryEntity: 148 self.SetBracketIcon() 149 self.SetFleetTag(sm.GetService('fleet').GetTargetTag(self.itemID)) 150 self.sr.hilite = Sprite(name='hiliteSprite', parent=self.icon_container, left=-3, top=-3, width=100, height=100, texturePath='res:/UI/Texture/classes/Target/targetUnderlay.png', color=(1.0, 1.0, 1.0, 0.05)) 151 self.active_target_indicator.RotateArrows() 152 labelClass = eveLabel.EveLabelSmall 153 labelContainer = ContainerAutoSize(parent=self, name='labelContainer', align=uiconst.TOTOP) 154 self.labelContainer = labelContainer 155 self.sr.label = labelClass(text=' ', parent=labelContainer, align=uiconst.TOTOP, state=uiconst.UI_DISABLED, maxLines=1) 156 self.sr.label2 = labelClass(text=' ', parent=labelContainer, align=uiconst.TOTOP, state=uiconst.UI_DISABLED, maxLines=1) 157 self.sr.shipLabel = labelClass(text=' ', parent=labelContainer, align=uiconst.TOTOP, state=uiconst.UI_DISABLED, maxLines=1) 158 self.sr.distanceLabel = labelClass(text=' ', parent=labelContainer, align=uiconst.TOTOP, state=uiconst.UI_DISABLED, maxLines=1) 159 self.SetTargetLabel() 160 self.sr.assignedPar = Container(name='assignedPar', align=uiconst.TOTOP, parent=self, height=32) 161 self.sr.assigned = Container(name='assigned', align=uiconst.CENTERTOP, parent=self.sr.assignedPar, height=32) 162 self.sr.updateTimer = timerstuff.AutoTimer(random.randint(750, 1000), self.UpdateData) 163 self.UpdateData() 164 selected = sm.GetService('stateSvc').GetExclState(state.selected) 165 self.Select(selected == slimItem.itemID) 166 hilited = sm.GetService('stateSvc').GetExclState(state.mouseOver) 167 self.Hilite(hilited == slimItem.itemID) 168 activeTargetID = sm.GetService('target').GetActiveTargetID() 169 self.ActiveTarget(activeTargetID == slimItem.itemID) 170 drones = sm.GetService('michelle').GetDrones() 171 for key in drones: 172 droneState = drones[key] 173 if droneState.targetID == self.id: 174 self.drones[droneState.droneID] = droneState.typeID 175 176 self.UpdateDrones() 177 for moduleInfo in sm.GetService('godma').GetStateManager().GetActiveModulesOnTargetID(slimItem.itemID): 178 if moduleInfo: 179 moduleID = moduleInfo.itemID 180 if moduleID and moduleID not in self.activeModules: 181 self.AddWeapon(moduleInfo) 182 183 self._AddActiveFighterAbilities() 184 185 def has_damage_bar(self): 186 if not self.slimItem: 187 return False 188 slimItem = self.slimItem() 189 return slimItem.categoryID not in (appConst.categoryAsteroid, appConst.categoryFighter) and slimItem.groupID not in (appConst.groupHarvestableCloud, appConst.groupOrbitalTarget) and not HasMineableComponent(self.typeID) 190 191 def AddUIDeathObjects(self, discSize): 192 self.remove_animation_icon = Sprite(name='remove_animation_icon', parent=self.icon_container, align=uiconst.CENTER, display=False, width=64, height=64, blendMode=BlendMode.ADD, outputMode=OutputMode.COLOR_AND_GLOW, glowBrightness=0.0) 193 self.discSprite = Sprite(name='discSprite', parent=self.icon_container, pickState=PickState.OFF, align=uiconst.CENTER, texturePath='res:/UI/Texture/Icons/target_killed.png', width=discSize, height=discSize) 194 self.discSprite.display = False 195 self.lineSprite = Sprite(name='lineSprite', parent=self.barAndImageCont, align=uiconst.CENTER, texturePath='res:/UI/Texture/Icons/target_killed_line.png', width=100, height=100) 196 self.lineSprite.display = False 197 198 def AddUIObjects(self, slimItem, itemID = None, **kwargs): 199 barAndImageCont = Container(parent=self, name='barAndImageCont', align=uiconst.TOTOP, height=100, state=uiconst.UI_NORMAL) 200 self.barAndImageCont = barAndImageCont 201 self.iconSize = iconSize = 94 202 self.icon_container = Transform(parent=barAndImageCont, name='iconPar', width=iconSize, height=iconSize, align=uiconst.CENTERTOP, state=uiconst.UI_DISABLED, scalingCenter=(0.5, 0.5)) 203 self.AddUIDeathObjects(94) 204 maskSize = 50 205 iconPadding = (iconSize - maskSize) / 2 206 self.icon = eveIcon.Icon(parent=self.icon_container, left=iconPadding, top=iconPadding, width=maskSize, height=maskSize, typeID=slimItem.typeID, textureSecondaryPath='res:/UI/Texture/classes/Target/shipMask.png', color=(1.0, 1.0, 1.0, 1.0), blendMode=BlendMode.BLEND, spriteEffect=trinity.TR2_SFX_MODULATE, state=uiconst.UI_DISABLED, ignoreSize=True) 207 if slimItem.groupID == appConst.groupOrbitalTarget: 208 sm.GetService('photo').GetPortrait(slimItem.ownerID, 64, self.icon) 209 if self.has_damage_bar(): 210 self.healthBar = TargetHealthBars(parent=self.icon_container, itemID=itemID) 211 else: 212 self.check_show_asteroid_gauge() 213 self.circle = Sprite(name='circle', align=uiconst.CENTER, parent=self.icon_container, width=iconSize + 2, height=iconSize + 2, texturePath='res:/UI/Texture/classes/Target/outerCircle.png', color=(1.0, 1.0, 1.0, 0.5), state=uiconst.UI_DISABLED) 214 215 def check_show_asteroid_gauge(self): 216 if self.has_asteroid_gauge(): 217 if not self.asteroid_gauge: 218 self.construct_asteroid_quantity_gauge() 219 elif self.asteroid_gauge: 220 self.asteroid_gauge.Close() 221 self.asteroid_gauge = None 222 223 def construct_asteroid_quantity_gauge(self): 224 self.asteroid_gauge = AsteroidQuantityGaugeCircular(parent=self.icon_container, asteroid_id=self.itemID, align=Align.CENTER, pickState=PickState.OFF) 225 226 def has_asteroid_gauge(self): 227 if not self.slimItem: 228 return False 229 slimItem = self.slimItem() 230 if not slimItem: 231 return False 232 return mining.is_harvestable(slimItem.typeID) and AsteroidScanningService.get_instance().is_quantity_known(slimItem.itemID) 233 234 def OnItemNameChange(self, *args): 235 uthread.new(self.SetTargetLabel) 236 237 def SetTargetLabel(self): 238 self.label = uix.GetSlimItemName(self.slimForFlag) 239 if self.slimForFlag.corpID: 240 self.label = localization.GetByLabel('UI/Inflight/Target/TargetLabelWithTicker', target=uix.GetSlimItemName(self.slimForFlag), ticker=cfg.corptickernames.Get(self.slimForFlag.corpID).tickerName) 241 if self.slimForFlag.corpID and self.slimForFlag.typeID and self.slimForFlag.categoryID == appConst.categoryShip: 242 self.shipLabel = evetypes.GetName(self.slimForFlag.typeID) 243 else: 244 self.shipLabel = '' 245 self.UpdateData() 246 247 def OnSetPlayerStanding(self, *args): 248 self.SetStandingIcon() 249 250 def OnStateSetupChange(self, *args): 251 self.SetStandingIcon() 252 253 def SetStandingIcon(self): 254 stateMgr = sm.GetService('stateSvc') 255 flag = stateMgr.CheckStates(self.slimForFlag, 'flag') 256 self.standingIcon = AddAndSetFlagIcon(parentCont=self.icon_container, flag=flag, align=uiconst.CENTERBOTTOM, top=8, left=0, showHint=False) 257 258 def SetBracketIcon(self): 259 slimItem = self.slimItem() 260 if not slimItem: 261 return 262 bracketData = sm.GetService('bracket').GetBracketDataByTypeID(slimItem.typeID) 263 if not bracketData: 264 return 265 texturePath = bracketData.texturePath 266 if not texturePath: 267 return 268 iconColor = GetIconColor(slimItem) 269 if not getattr(self, 'bracketIcon', None) or self.bracketIcon.destroyed: 270 self.bracketIcon = Sprite(parent=self.icon_container, align=uiconst.CENTERBOTTOM, pos=(0, 5, 16, 16)) 271 self.bracketIcon.SetRGBA(*iconColor) 272 self.bracketIcon.SetTexturePath(texturePath) 273 274 def OnSuspectsAndCriminalsUpdate(self, criminalizedCharIDs, decriminalizedCharIDs): 275 return self._UpdateOnSuspectCriminalAndDisapprovalChanges(criminalizedCharIDs, decriminalizedCharIDs) 276 277 def OnDisapprovalUpdate(self, newCharIDs, removedCharIDs): 278 return self._UpdateOnSuspectCriminalAndDisapprovalChanges(newCharIDs, removedCharIDs) 279 280 def _UpdateOnSuspectCriminalAndDisapprovalChanges(self, newCharIDs, removedCharIDs): 281 if self.slimForFlag.charID in newCharIDs or self.slimForFlag.charID in removedCharIDs: 282 self.SetStandingIcon() 283 284 def OnCrimewatchEngagementUpdated(self, otherCharId, timeout): 285 if self.slimForFlag.charID == otherCharId: 286 self.SetStandingIcon() 287 288 def OnFleetJoin_Local(self, member, *args): 289 if session.charid == member.charID or self.slimForFlag.charID == member.charID: 290 self.SetStandingIcon() 291 292 def OnFleetLeave_Local(self, member, *args): 293 if session.charid == member.charID or self.slimForFlag.charID == member.charID: 294 self.SetStandingIcon() 295 296 def SetFleetTag(self, fleetTag): 297 if not session.fleetid or fleetTag in (None, ''): 298 if self.fleetTag: 299 self.fleetTag.Close() 300 self.fleetTag = None 301 return 302 if self.fleetTag is None or self.fleetTag.destroyed: 303 self.fleetTag = eveLabel.EveLabelMediumBold(parent=self.icon_container, align=uiconst.CENTERBOTTOM, left=15, top=8, idx=0) 304 self.fleetTag.text = fleetTag 305 306 def OnSlimItemChange(self, oldSlim, newSlim): 307 uthread.new(self._OnSlimItemChange, oldSlim, newSlim) 308 309 def _OnSlimItemChange(self, oldSlim, newSlim): 310 if self.itemID != oldSlim.itemID or self.destroyed: 311 return 312 self.itemID = newSlim.itemID 313 self.slimItem = _weakref.ref(newSlim) 314 if oldSlim.corpID != newSlim.corpID or oldSlim.charID != newSlim.charID: 315 self.label = uix.GetSlimItemName(newSlim) 316 self.UpdateData() 317 318 def OnStateChange(self, itemID, flag, true, *args): 319 if not self.destroyed: 320 uthread.new(self._OnStateChange, itemID, flag, true) 321 322 def _OnStateChange(self, itemID, flag, true): 323 if self.destroyed or self.itemID != itemID: 324 return 325 if flag == state.mouseOver: 326 self.Hilite(true) 327 elif flag == state.selected: 328 self.Select(true) 329 elif flag == state.activeTarget: 330 self.ActiveTarget(true) 331 332 def Hilite(self, state): 333 if self.sr.hilite: 334 self.sr.hilite.state = [uiconst.UI_HIDDEN, uiconst.UI_DISABLED][state] 335 336 def Select(self, state): 337 pass 338 339 def OnJamStart(self, sourceBallID, moduleID, targetBallID, jammingType, startTime, duration): 340 if targetBallID != self.id: 341 return 342 durationInClient = GetDurationInClient(startTime, duration) 343 if durationInClient < 0.0: 344 return 345 moduleInfo = self.GetModuleInfo(moduleID) 346 if moduleInfo and moduleID not in self.activeModules: 347 self.AddWeapon(moduleInfo) 348 self.jammingModules[moduleID] = (sourceBallID, 349 moduleID, 350 targetBallID, 351 startTime, 352 duration) 353 self.StartTimer(moduleID, durationInClient) 354 355 def OnJamEnd(self, sourceBallID, moduleID, targetBallID, jammingType): 356 if not self or self.destroyed: 357 return 358 if moduleID in self.jammingModules: 359 moduleIconCont = self.GetWeapon(moduleID) 360 if moduleIconCont: 361 if moduleIconCont.icon: 362 moduleIconCont.StopAnimations() 363 moduleIconCont.opacity = 1.0 364 moduleIconCont.icon.SetRGBA(1, 1, 1, 1.0) 365 moduleIconCont.icon.baseAlpha = 0.3 366 self.RemoveTimer(moduleID) 367 del self.jammingModules[moduleID] 368 369 def StartTimer(self, moduleID, duration, *args): 370 moduleIconCont = self.GetWeapon(moduleID) 371 if moduleIconCont and moduleIconCont.icon and moduleIconCont.timer: 372 moduleIconCont.icon.SetRGBA(1, 1, 1, 1.0) 373 moduleIconCont.icon.baseAlpha = 1.0 374 moduleIconCont.timer.StartTimer(duration) 375 376 def RemoveTimer(self, moduleID, *args): 377 moduleIconCont = self.GetWeapon(moduleID) 378 if moduleIconCont and moduleIconCont.icon and moduleIconCont.timer: 379 moduleIconCont.icon.SetRGBA(1, 1, 1, moduleIconCont.icon.baseAlpha) 380 381 def _HoverThread(self): 382 while True: 383 blue.synchro.SleepWallclock(HOVERTIME) 384 self.OnTargetMouseHover() 385 386 def KillHoverThread(self, *args): 387 if self._hoverThread: 388 self._hoverThread.kill() 389 self._hoverThread = None 390 391 def OnTargetMouseHover(self, *args): 392 if not self.icon_container or self.icon_container.destroyed or not self.healthBar: 393 self.KillHoverThread() 394 return 395 if self.healthBar.destroyed: 396 self.KillHoverThread() 397 return 398 l, t, w, h = self.icon_container.GetAbsolute() 399 cX = w / 2 + l 400 cY = h / 2 + t 401 x = uicore.uilib.x - cX 402 y = uicore.uilib.y - cY 403 if y > 55: 404 self.barAndImageCont.SetHint('') 405 return 406 length2 = pow(x, 2) + pow(y, 2) 407 if length2 < self.innerHealthBorder or length2 > self.outerHealthBorder: 408 self.barAndImageCont.SetHint('') 409 return 410 rad = math.atan2(y, x) 411 degrees = 180 * rad / math.pi 412 if degrees < 0: 413 degrees = 360 + degrees 414 if degrees > 45 and degrees < 135: 415 return 416 self.SetHintText() 417 418 def SetHintText(self): 419 hintList = [] 420 percLeft = self.healthBar.GetDamageHint(SHIELD) 421 if percLeft is not None: 422 percLeft = math.floor(100 * percLeft) 423 hintList.append(localization.GetByLabel('UI/Inflight/Target/GaugeShieldRemaining', percentage=percLeft)) 424 percLeft = self.healthBar.GetDamageHint(ARMOR) 425 if percLeft is not None: 426 percLeft = math.floor(100 * percLeft) 427 hintList.append(localization.GetByLabel('UI/Inflight/Target/GaugeArmorRemaining', percentage=percLeft)) 428 percLeft = self.healthBar.GetDamageHint(HULL) 429 if percLeft is not None: 430 percLeft = math.floor(100 * percLeft) 431 hintList.append(localization.GetByLabel('UI/Inflight/Target/GaugeStructureRemaining', percentage=percLeft)) 432 hint = '<br>'.join(hintList) 433 self.barAndImageCont.SetHint(hint) 434 435 def GetShipID(self): 436 return self.itemID 437 438 def GetIcon(self, icon, typeID, size): 439 if not self.destroyed: 440 icon.LoadIconByTypeID(typeID) 441 icon.SetSize(size, size) 442 443 def _OnClose(self, *args): 444 sm.UnregisterNotify(self) 445 self.sr.updateTimer = None 446 GetShipFighterState().DisconnectFighterTargetUpdatedHandler(self._OnFighterTargetUpdate) 447 448 def _AddActiveFighterAbilities(self): 449 abilitiesOnTarget = GetShipFighterState().abilityTargetTracker.GetFighterAbilitiesForTarget(self.itemID) 450 for fighterID, abilitySlotID in abilitiesOnTarget: 451 self._AddFighterAbility(fighterID, abilitySlotID) 452 453 self.ArrangeWeapons() 454 self.SetSizeAutomatically() 455 uthread.new(sm.GetService('target').AdjustRowSize) 456 457 def _OnFighterTargetUpdate(self, fighterID, abilitySlotID, targetID): 458 if targetID != self.itemID: 459 return 460 abilitiesOnTarget = GetShipFighterState().abilityTargetTracker.GetFighterAbilitiesForTarget(self.itemID) 461 if (fighterID, abilitySlotID) in abilitiesOnTarget: 462 if (fighterID, abilitySlotID) not in self.activeModules: 463 self._AddFighterAbility(fighterID, abilitySlotID) 464 else: 465 self._RemoveFighterAbility(fighterID, abilitySlotID) 466 self.ArrangeWeapons() 467 self.SetSizeAutomatically() 468 uthread.new(sm.GetService('target').AdjustRowSize) 469 470 def _AddFighterAbility(self, fighterID, abilitySlotID): 471 cont = FighterAbilityWeapon(parent=self.sr.assigned, fighterID=fighterID, abilitySlotID=abilitySlotID) 472 self.activeModules.add((fighterID, abilitySlotID)) 473 474 def _RemoveFighterAbility(self, fighterID, abilitySlotID): 475 iconCont = self.GetWeapon((fighterID, abilitySlotID)) 476 if iconCont: 477 iconCont.Close() 478 self.activeModules.discard((fighterID, abilitySlotID)) 479 480 def ProcessShipEffect(self, godmaStm, effectState): 481 slimItem = self.slimItem() 482 if slimItem and effectState.environment[3] == slimItem.itemID: 483 if effectState.start: 484 if self.GetWeapon(effectState.itemID): 485 return 486 moduleInfo = self.GetModuleInfo(effectState.itemID) 487 if moduleInfo: 488 self.AddWeapon(moduleInfo) 489 else: 490 self.RemoveWeapon(effectState.itemID) 491 492 def AddWeapon(self, moduleInfo): 493 if self is None or self.destroyed: 494 return 495 cont = Weapon(parent=self.sr.assigned, moduleInfo=moduleInfo, getJammingInfoFunc=self.GetJammingModuleInfo) 496 self.activeModules.add(moduleInfo.itemID) 497 self.ArrangeWeapons() 498 self.SetSizeAutomatically() 499 uthread.new(sm.GetService('target').AdjustRowSize) 500 501 def GetJammingModuleInfo(self, moduleID): 502 if moduleID in self.jammingModules: 503 sourceBallID, moduleID, targetBallID, startTime, duration = self.jammingModules[moduleID] 504 return utillib.KeyVal(startTime=startTime, duration=duration) 505 506 def IsEffectActivatible(self, effect): 507 return effect.isDefault and effect.effectName != 'online' and effect.effectCategory in (appConst.dgmEffActivation, appConst.dgmEffTarget) 508 509 def RemoveWeapon(self, moduleID): 510 iconCont = self.GetWeapon(moduleID) 511 if iconCont: 512 iconCont.Close() 513 self.activeModules.discard(moduleID) 514 self.ArrangeWeapons() 515 self.SetSizeAutomatically() 516 uthread.new(sm.GetService('target').AdjustRowSize) 517 518 def ArrangeWeapons(self): 519 if self and not self.destroyed and self.sr.assigned: 520 numWeapons = len(self.sr.assigned.children) 521 if numWeapons > 2: 522 size = 24 523 else: 524 size = 32 525 left = 0 526 top = 0 527 row = 0 528 column = -1 529 maxColumns = 4 530 for cont in self.sr.assigned.children: 531 if isinstance(cont, Frame): 532 continue 533 column += 1 534 if column >= maxColumns: 535 column = 0 536 row += 1 537 cont.width = cont.height = size 538 cont.left = column * size 539 cont.top = row * size 540 cont.state = uiconst.UI_PICKCHILDREN 541 542 if row > 0: 543 self.sr.assigned.width = maxColumns * size 544 else: 545 self.sr.assigned.width = size * (column + 1) 546 self.sr.assigned.height = max(32, size * (row + 1)) 547 self.sr.assignedPar.height = self.sr.assigned.height 548 549 def GetWeapon(self, moduleID): 550 if self is None or self.destroyed: 551 return 552 if self.sr.assigned: 553 for cont in self.sr.assigned.children: 554 if isinstance(cont, Frame): 555 continue 556 if cont.sr.moduleID == moduleID: 557 return cont 558 559 def GetModuleInfo(self, moduleID): 560 ship = sm.GetService('godma').GetItem(session.shipid) 561 if ship is None: 562 return 563 for module in ship.modules: 564 if module.itemID == moduleID: 565 return module 566 567 def ResetModuleIcon(self, moduleID, *args): 568 if moduleID in self.activeModules: 569 weapon = self.GetWeapon(moduleID) 570 icon = weapon.icon 571 icon.SetAlpha(icon.baseAlpha) 572 573 def OnTargetClick(self, *args): 574 sm.GetService('stateSvc').SetState(self.itemID, state.selected, 1) 575 sm.GetService('stateSvc').SetState(self.itemID, state.activeTarget, 1) 576 GetMenuService().TacticalItemClicked(self.itemID) 577 578 def GetTargetMenu(self): 579 m = [] 580 m += GetMenuService().CelestialMenu(self.itemID) 581 return m 582 583 def OnTargetMouseDown(self, *args): 584 if getattr(self, 'slimItem', None): 585 if GetMenuService().TryExpandActionMenu(self.itemID, self.barAndImageCont): 586 return 587 588 def OnBeginMoveTarget(self, *args): 589 sm.GetService('target').OnMoveTarget(self) 590 591 def OnTargetMouseEnter(self, *args): 592 sm.GetService('stateSvc').SetState(self.id, state.mouseOver, 1) 593 if self._hoverThread is None: 594 self._hoverThread = uthread.new(self._HoverThread) 595 596 def OnTargetMouseExit(self, *args): 597 sm.GetService('stateSvc').SetState(self.itemID, state.mouseOver, 0) 598 self.KillHoverThread() 599 600 @telemetry.ZONE_METHOD 601 def UpdateData(self): 602 ball = self.ball() 603 if not ball: 604 return 605 dist = ball.surfaceDist 606 distanceInMeters = int(dist) 607 if self.label != self.lastTextUsedForLabel: 608 self.SetNameLabels(fullLabel=self.label) 609 self.lastTextUsedForLabel = self.label 610 if distanceInMeters != self.lastTextUsedDistance: 611 self.sr.distanceLabel.text = '<center>' + FmtDist(dist) 612 self.FadeText(self.sr.label2) 613 self.lastTextUsedDistance = distanceInMeters 614 if self.shipLabel != self.lastTextUsedForShipType: 615 if self.shipLabel: 616 self.sr.shipLabel.display = True 617 self.sr.shipLabel.text = '<center>' + self.shipLabel 618 self.FadeText(self.sr.shipLabel) 619 self.lastTextUsedForShipType = self.shipLabel 620 else: 621 self.sr.shipLabel.text = '' 622 self.sr.shipLabel.display = False 623 624 def SetNameLabels(self, fullLabel, *args): 625 hintMarkupStart = '' 626 hintMarkupEnd = '' 627 localizedHintPos = fullLabel.find('<localized hint') 628 if localizedHintPos >= 0: 629 strippedLabel = commonutils.StripTags(fullLabel, stripOnly=['localized']) 630 hintEndIndex = fullLabel.find('">') 631 if hintEndIndex > 0: 632 hintMarkupStart = fullLabel[localizedHintPos:hintEndIndex + 2] 633 hintMarkupEnd = '</localized>' 634 else: 635 strippedLabel = fullLabel 636 self.sr.label.text = strippedLabel 637 indexAtMaxLenght = self.sr.label.GetIndexUnderPos(self.width) 638 if indexAtMaxLenght[0] < len(strippedLabel): 639 lastBreak = strippedLabel.rfind(' ', 0, indexAtMaxLenght[0]) 640 if lastBreak != -1: 641 self.sr.label.text = strippedLabel[:lastBreak] 642 self.sr.label2.text = '<center>' + hintMarkupStart + strippedLabel[lastBreak:].strip() + hintMarkupEnd 643 self.FadeText(self.sr.label2) 644 self.sr.label2.display = True 645 else: 646 self.sr.label2.text = '' 647 self.sr.label2.display = False 648 self.sr.label.text = '<center>' + hintMarkupStart + self.sr.label.text + hintMarkupEnd 649 self.lastTextUsedForLabel = self.label 650 651 def FadeText(self, textLabel, *args): 652 maxFadeWidth = 10 653 fadeEnd = self.width - maxFadeWidth 654 textLabel.SetRightAlphaFade(fadeEnd=fadeEnd, maxFadeWidth=maxFadeWidth) 655 656 def ActiveTarget(self, true): 657 if self.destroyed: 658 return 659 targetSvc = sm.GetService('target') 660 if true: 661 if not targetSvc.disableSpinnyReticule: 662 self.active_target_indicator.state = uiconst.UI_DISABLED 663 self.icon_container.opacity = 1.0 664 self.circle.opacity = 0.5 665 else: 666 self.icon_container.width = self.icon_container.height = self.iconSize 667 self.active_target_indicator.state = uiconst.UI_HIDDEN 668 self.icon_container.opacity = 0.8 669 self.circle.opacity = 0.25 670 671 def OnDroneStateChange2(self, itemID, oldActivityState, activityState): 672 michelle = sm.GetService('michelle') 673 droneState = michelle.GetDroneState(itemID) 674 if activityState in (appConst.entityCombat, 675 appConst.entityEngage, 676 appConst.entityMining, 677 appConst.entitySalvaging): 678 if droneState and droneState.targetID == self.id: 679 self.drones[itemID] = droneState.typeID 680 elif itemID in self.drones: 681 del self.drones[itemID] 682 elif itemID in self.drones: 683 del self.drones[itemID] 684 self.UpdateDrones() 685 686 def OnDroneControlLost(self, droneID): 687 if droneID in self.drones: 688 del self.drones[droneID] 689 self.UpdateDrones() 690 691 def UpdateDrones(self): 692 if not self.drones: 693 self.RemoveWeapon('drones') 694 return 695 droneIconCont = self.GetWeapon('drones') 696 if not droneIconCont: 697 cont = Container(parent=self.sr.assigned, align=uiconst.RELATIVE, width=32, height=32, state=uiconst.UI_HIDDEN) 698 icon = Sprite(parent=cont, align=uiconst.TOALL, width=0, height=0, state=uiconst.UI_NORMAL, texturePath='res:/UI/Texture/Icons/56_64_5.png') 699 cont.sr.moduleID = 'drones' 700 cont.icon = icon 701 icon.sr.moduleID = 'drones' 702 self.ArrangeWeapons() 703 self.UpdateDroneHint() 704 705 def UpdateDroneHint(self): 706 dronesByTypeID = {} 707 droneIcon = self.GetWeapon('drones') 708 if droneIcon is None: 709 return 710 for droneID, droneTypeID in self.drones.iteritems(): 711 if droneTypeID not in dronesByTypeID: 712 dronesByTypeID[droneTypeID] = 0 713 dronesByTypeID[droneTypeID] += 1 714 715 hintLines = [] 716 for droneTypeID, number in dronesByTypeID.iteritems(): 717 hintLines.append(localization.GetByLabel('UI/Inflight/Target/DroneHintLine', drone=droneTypeID, count=number)) 718 719 droneIcon.icon.hint = localization.GetByLabel('UI/Inflight/Target/DroneHintLabel', droneHintLines='<br>'.join(hintLines)) 720 721 def anim_disappear(self): 722 if self.has_asteroid_gauge(): 723 self.anim_asteroid_depleted() 724 else: 725 self.anim_death() 726 727 def anim_death(self): 728 self.state = uiconst.UI_DISABLED 729 if self.healthBar: 730 self.healthBar.SetDamage([0.0, 731 0.0, 732 0.0, 733 0.0, 734 0.0]) 735 uthread2.sleep_sim(random.random() * 0.2) 736 sm.GetService('audio').SendUIEvent('target_destroy_play') 737 self.discSprite.display = True 738 discCurve = ((0.0, (1.0, 0.0, 0.0, 0.0)), (0.1, (1.0, 0.0, 0.0, 0.2)), (2.0, (1.0, 0.0, 0.0, 0.2))) 739 animations.SpColorMorphTo(self.discSprite, curveType=discCurve, duration=0.1) 740 self.remove_animation_icon.texturePath = 'res:/UI/Texture/Icons/target_killed_skull.png' 741 self.remove_animation_icon.SetSize(64, 64) 742 self.remove_animation_icon.display = True 743 animations.BlinkIn(self, duration=0.2, loops=6, sleep=True) 744 animations.Tr2DScaleTo(self.icon_container, startScale=(1.0, 1.0), endScale=(1.0, 0.0), sleep=True, duration=0.04, curveType=uiconst.ANIM_LINEAR) 745 self.icon_container.display = False 746 747 def anim_asteroid_depleted(self): 748 self.state = uiconst.UI_DISABLED 749 self.discSprite.display = True 750 color = Color(a=0.4, *eveColor.SUCCESS_GREEN[:3]) 751 self.discSprite.color = Color(a=0.0, *eveColor.SUCCESS_GREEN[:3]) 752 animations.SpColorMorphTo(self.discSprite, endColor=color, duration=0.6) 753 animations.BlinkOut(self.icon, loops=2) 754 self.remove_animation_icon.texturePath = 'res:/UI/Texture/classes/Seasons/Agency/ContentCard/checkmark_claimReward.png' 755 self.remove_animation_icon.SetSize(36, 36) 756 self.remove_animation_icon.display = True 757 animations.FadeTo(self.remove_animation_icon, 0.0, 1.0, duration=0.6, timeOffset=0.1) 758 animations.SpMaskIn(self.remove_animation_icon, duration=0.3, timeOffset=0.1) 759 animations.MorphScalar(self.remove_animation_icon, 'glowBrightness', 0.0, 0.6, duration=1.0, timeOffset=0.1, curveType=uiconst.ANIM_OVERSHOT5) 760 animations.Tr2DScaleOut(self.active_target_transform, duration=0.3, timeOffset=0.1) 761 uthread2.sleep(1.6) 762 animations.FadeOut(self, duration=0.15, sleep=True) 763 self.icon_container.display = False 764 765 766 class TargetHealthBars(Container): 767 __notifyevents__ = ['OnDamageMessage', 'OnDamageMessages'] 768 default_name = 'targetHealthBars' 769 default_width = 94 770 default_height = 94 771 default_align = uiconst.CENTER 772 allHealthTexture = 'res:/UI/Texture/classes/Target/targetBackground.png' 773 allHealthMinusShieldTexture = 'res:/UI/Texture/classes/Target/targetBackgroundNoShield.png' 774 shieldTextureLeft = 'res:/UI/Texture/classes/Target/shieldLeft.png' 775 shieldTextureRight = 'res:/UI/Texture/classes/Target/shieldRight.png' 776 armorTextureLeft = 'res:/UI/Texture/classes/Target/armorLeft.png' 777 armorTextureRight = 'res:/UI/Texture/classes/Target/armorRight.png' 778 hullTextureLeft = 'res:/UI/Texture/classes/Target/hullLeft.png' 779 hullTextureRight = 'res:/UI/Texture/classes/Target/hullRight.png' 780 781 def ApplyAttributes(self, attributes): 782 self.damageValuseForTooltip = {} 783 Container.ApplyAttributes(self, attributes) 784 self.itemID = attributes.itemID 785 self.sr.damageTimer = timerstuff.AutoTimer(random.randint(750, 1000), self.UpdateDamage) 786 self.width = attributes.get('size', self.default_width) 787 self.height = attributes.get('size', self.default_height) 788 self.shieldBar = self.AddHealthBar(name='shieldBar', texturePathLeft=self.shieldTextureLeft, texturePathRight=self.shieldTextureRight) 789 self.armorBar = self.AddHealthBar(name='armorBar', texturePathLeft=self.armorTextureLeft, texturePathRight=self.armorTextureRight) 790 self.hullBar = self.AddHealthBar(name='hullBar', texturePathLeft=self.hullTextureLeft, texturePathRight=self.hullTextureRight) 791 self.healthBarBackground = Sprite(name='healthBarBackground', parent=self, width=self.width, height=self.height, texturePath=self.allHealthTexture, align=uiconst.CENTER, state=uiconst.UI_DISABLED) 792 self.UpdateDamage() 793 sm.RegisterNotify(self) 794 bp = sm.GetService('michelle').GetBallpark() 795 bp.componentRegistry.SendMessageToItem(self.itemID, MSG_ON_TARGET_BRACKET_ADDED, self) 796 797 def SetGaugeTextureForBar(self, name, texturePath): 798 if texturePath is None: 799 texturePath = 'res:/UI/Texture/classes/Target/gaugeColor.png' 800 bar = getattr(self, name) 801 bar.leftBar.SetSecondaryTexturePath(texturePath) 802 bar.rightBar.SetSecondaryTexturePath(texturePath) 803 804 def AddHealthBar(self, name, texturePathLeft, texturePathRight, *args): 805 cont = Container(name=name, parent=self, width=self.width, height=self.height, align=uiconst.CENTER) 806 leftBar = Sprite(name='%s_Left' % name, parent=cont, width=self.width, height=self.height, texturePath=texturePathLeft, textureSecondaryPath='res:/UI/Texture/classes/Target/gaugeColor.png', idx=0, blendMode=1, spriteEffect=trinity.TR2_SFX_MODULATE, state=uiconst.UI_DISABLED) 807 leftBar.baseRotation = 0 808 leftBar.rotationSecondary = leftBar.baseRotation 809 rightBar = Sprite(name='%s_Right' % name, parent=cont, width=self.width, height=self.height, texturePath=texturePathRight, textureSecondaryPath='res:/UI/Texture/classes/Target/gaugeColor.png', idx=0, blendMode=1, spriteEffect=trinity.TR2_SFX_MODULATE, state=uiconst.UI_DISABLED) 810 rightBar.baseRotation = -3 / 4.0 * math.pi 811 rightBar.rotationSecondary = rightBar.baseRotation 812 cont.leftBar = leftBar 813 cont.rightBar = rightBar 814 return cont 815 816 def UpdateDamage(self): 817 bp = sm.GetService('michelle').GetBallpark() 818 if bp is None: 819 self.sr.damageTimer = None 820 return 821 dmg = bp.GetDamageState(self.itemID) 822 if dmg is not None: 823 self.PrepareHint(dmg) 824 self.SetDamage(dmg) 825 826 def PrepareHint(self, state): 827 for i, layer in enumerate([SHIELD, ARMOR, HULL]): 828 if state[i] is None: 829 self.damageValuseForTooltip[layer] = None 830 else: 831 self.damageValuseForTooltip[layer] = max(0, state[i]) 832 833 def SetDamage(self, state, *args): 834 visible = 0 835 healthBars = [self.shieldBar, self.armorBar, self.hullBar] 836 fullAnimationTime = 0.4 837 for i, healthBar in enumerate(healthBars): 838 if state[i] is None: 839 healthBar.display = False 840 else: 841 healthState = state[i] 842 healthState = max(0, healthState) 843 lastState = getattr(healthBar, 'lastState', None) 844 healthBar.lastState = healthState 845 leftBar = healthBar.leftBar 846 rightBar = healthBar.rightBar 847 if lastState: 848 totalChange = healthState - lastState 849 animationTime = max(0.1, fullAnimationTime * abs(totalChange)) 850 else: 851 animationTime = None 852 if healthState <= 0.5: 853 portionOfBar = (0.5 - healthState) / 0.5 854 rotation = leftBar.baseRotation + portionOfBar * 0.75 * math.pi 855 if lastState and lastState > 0.5: 856 below50Damage = lastState - 0.5 857 below50Percentage = float(below50Damage) / abs(totalChange) 858 if animationTime is None: 859 rightBar.rotationSecondary = 0.0 860 leftBar.rotationSecondary = rotation 861 else: 862 curvePoints = ([0, rightBar.rotationSecondary or 0.0], [below50Percentage or 0.0, 0.0]) 863 uicore.animations.MorphScalar(rightBar, 'rotationSecondary', duration=animationTime, curveType=curvePoints) 864 curvePoints = ([0, leftBar.rotationSecondary or 0.0], [below50Percentage or 0.0, leftBar.rotationSecondary or 0.0], [1.0, rotation]) 865 uicore.animations.MorphScalar(leftBar, 'rotationSecondary', duration=animationTime, curveType=curvePoints) 866 else: 867 rightBar.rotationSecondary = 0 868 if animationTime is None: 869 leftBar.rotationSecondary = rotation 870 else: 871 uicore.animations.MorphScalar(leftBar, 'rotationSecondary', startVal=leftBar.rotationSecondary or 0.0, endVal=rotation, duration=animationTime, curveType=uiconst.ANIM_LINEAR) 872 else: 873 portionOfBar = (1 - healthState) / 0.5 874 rotation = rightBar.baseRotation + portionOfBar * 0.75 * math.pi 875 if lastState and lastState <= 0.5: 876 above50Damage = 0.5 - lastState 877 above50Percentage = float(above50Damage) / abs(totalChange) 878 if animationTime is None: 879 leftBar.rotationSecondary = leftBar.baseRotation - 0.02 880 rightBar.rotationSecondary = rotation 881 else: 882 curvePoints = ([0, leftBar.rotationSecondary], [above50Percentage, leftBar.baseRotation - 0.02]) 883 uicore.animations.MorphScalar(leftBar, 'rotationSecondary', duration=animationTime, curveType=curvePoints) 884 curvePoints = ([0, rightBar.rotationSecondary], [above50Percentage, rightBar.rotationSecondary], [1.0, rotation]) 885 uicore.animations.MorphScalar(rightBar, 'rotationSecondary', duration=animationTime, curveType=curvePoints) 886 else: 887 if animationTime is None: 888 rightBar.rotationSecondary = rotation 889 else: 890 uicore.animations.MorphScalar(rightBar, 'rotationSecondary', startVal=rightBar.rotationSecondary, endVal=rotation, duration=animationTime, curveType=uiconst.ANIM_LINEAR) 891 leftBar.rotationSecondary = leftBar.baseRotation - 0.02 892 healthBar.display = True 893 visible += 1 894 895 if visible == 0: 896 self.healthBarBackground.display = False 897 else: 898 if visible == 2: 899 self.healthBarBackground.SetTexturePath(self.allHealthMinusShieldTexture) 900 else: 901 self.healthBarBackground.SetTexturePath(self.allHealthTexture) 902 self.healthBarBackground.display = True 903 904 def _OnClose(self, *args): 905 self.sr.damageTimer = None 906 bp = sm.GetService('michelle').GetBallpark() 907 bp.componentRegistry.SendMessageToItem(self.itemID, MSG_ON_TARGET_BRACKET_REMOVED) 908 909 def GetDamageHint(self, whichHealthBar, *args): 910 return self.damageValuseForTooltip.get(whichHealthBar, 1.0) 911 912 def OnDamageMessages(self, dmgmsgs): 913 for msg in dmgmsgs: 914 didBlink = self.OnDamageMessage(*msg[1:]) 915 if didBlink: 916 break 917 918 def OnDamageMessage(self, damageMessagesArgs): 919 attackType = damageMessagesArgs.get('attackType', 'me') 920 if attackType != 'me': 921 return False 922 damage = damageMessagesArgs.get('damage', 0) 923 if damage == 0: 924 return False 925 target = damageMessagesArgs.get('target', None) 926 if target is None: 927 return False 928 if isinstance(target, long): 929 if target == self.itemID: 930 self.DoBlink() 931 return True 932 if isinstance(target, basestring): 933 targetID = damageMessagesArgs.get('target_ID', None) 934 if targetID == self.itemID: 935 self.DoBlink() 936 return True 937 return False 938 939 def DoBlink(self, *args): 940 uicore.animations.FadeTo(self, startVal=1.3, endVal=1.0, duration=0.75, loops=1, curveType=uiconst.ANIM_OVERSHOT)