playerOwned.py (22391B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\parklife\playerOwned.py 2 import sys 3 import blue 4 import carbonui.const as uiconst 5 import dogma.data 6 import eve.common.script.mgt.posConst as pos 7 import evetypes 8 import localization 9 import log 10 import telemetry 11 import uthread 12 from carbon.common.script.sys.service import Service 13 from eve.client.script.ui.util import uix 14 from eve.client.script.ui.util import utilWindows 15 from eve.common.lib import appConst as const 16 from eve.common.script.net import eveMoniker 17 from eveexceptions import UserError 18 from player_messaging.client.ui_message import prompt_player_fsd_dialog 19 ONLINE_STATES = (pos.STRUCTURE_ONLINING, 20 pos.STRUCTURE_REINFORCED, 21 pos.STRUCTURE_ONLINE, 22 pos.STRUCTURE_OPERATING, 23 pos.STRUCTURE_VULNERABLE, 24 pos.STRUCTURE_SHIELD_REINFORCE, 25 pos.STRUCTURE_ARMOR_REINFORCE, 26 pos.STRUCTURE_INVULNERABLE) 27 UNANCHORABLE_STATES = (pos.STRUCTURE_ONLINING, 28 pos.STRUCTURE_REINFORCED, 29 pos.STRUCTURE_ONLINE, 30 pos.STRUCTURE_OPERATING, 31 pos.STRUCTURE_UNANCHORED, 32 pos.STRUCTURE_VULNERABLE, 33 pos.STRUCTURE_SHIELD_REINFORCE, 34 pos.STRUCTURE_ARMOR_REINFORCE, 35 pos.STRUCTURE_INVULNERABLE) 36 37 class PlayerOwned(Service): 38 __guid__ = 'svc.pwn' 39 __exportedcalls__ = {'CanAnchorStructure': [], 40 'CanUnanchorStructure': [], 41 'CanOnlineStructure': [], 42 'CanOfflineStructure': [], 43 'CanAssumeControlStructure': [], 44 'GetStructureState': [], 45 'CompareShipStructureHarmonic': [], 46 'CheckAnchoringPosition': [], 47 'Anchor': [], 48 'EnterTowerPassword': [], 49 'EnterShipPassword': [], 50 'AssumeStructureControl': [], 51 'RelinquishStructureControl': [], 52 'UnlockStructureTarget': [], 53 'GetCurrentTarget': [], 54 'ClrCurrentTarget': [], 55 'GetCurrentControl': []} 56 __notifyevents__ = ['OnSlimItemChange', 57 'OnTargetOBO', 58 'DoSessionChanging', 59 'DoBallsAdded', 60 'DoBallRemove', 61 'DoBallsRemove'] 62 __dependencies__ = ['godma', 'michelle'] 63 64 def Run(self, memStream = None): 65 Service.Run(self, memStream) 66 sm.FavourMe(self.DoBallsAdded) 67 self.currenttargets = {} 68 self.currentcontrol = {} 69 self.currentlyAssuming = {} 70 71 def Stop(self, stream): 72 Service.Stop(self) 73 74 def OnSlimItemChange(self, oldItem, newItem): 75 if newItem.categoryID != const.categoryStarbase: 76 return 77 if newItem.posState == oldItem.posState and newItem.posTimestamp == oldItem.posTimestamp and newItem.controllerID == oldItem.controllerID and newItem.incapacitated == oldItem.incapacitated: 78 return 79 if oldItem.controllerID is not None and newItem.controllerID == None: 80 uthread.new(self.RelinquishStructureControl, oldItem, silent=True, force=True) 81 stateName, stateTimestamp, stateDelay = self.GetStructureState(newItem) 82 if stateName == 'onlining': 83 uthread.pool('pwn::StalledOnlineEvent', self.StalledOnlineEvent, newItem.itemID, newItem.posState, stateTimestamp, stateDelay) 84 85 def StalledOnlineEvent(self, itemID, posState, stateTimestamp, stateDelay): 86 item = self.michelle.GetItem(itemID) 87 if item is None or item.posState != posState or item.posTimestamp != stateTimestamp: 88 return 89 x1, x2, stateDelay = self.GetStructureState(item) 90 blue.pyos.synchro.SleepWallclock(stateDelay) 91 item = self.michelle.GetItem(itemID) 92 if item is None: 93 return 94 if item.posState != posState or item.posTimestamp != stateTimestamp: 95 if item.posState != pos.STRUCTURE_ONLINE: 96 return 97 sm.ScatterEvent('OnStructureFullyOnline', itemID) 98 if item.controlTowerID is not None: 99 sm.ScatterEvent('OnSpecialFX', item.controlTowerID, itemID, item.typeID, None, None, 'effects.StructureOnlined', 0, 1, 0) 100 101 def CompareShipStructureHarmonic(self, shipID, itemID): 102 item = self.michelle.GetItem(itemID) 103 if not item: 104 return False 105 if item.groupID == const.groupControlTower: 106 controlTowerID = itemID 107 towerItem = item 108 else: 109 controlTowerID = item.controlTowerID 110 if controlTowerID is None: 111 return False 112 towerItem = self.michelle.GetItem(controlTowerID) 113 if towerItem is None: 114 return False 115 forceFieldID = towerItem.forceFieldID 116 if forceFieldID is None: 117 return False 118 fieldBall = self.michelle.GetBall(forceFieldID) 119 shipBall = self.michelle.GetBall(shipID) 120 if not shipBall or not fieldBall: 121 return False 122 if fieldBall.harmonic != -1 and fieldBall.harmonic == shipBall.harmonic: 123 return True 124 return False 125 126 def GetStructureState(self, slimItem): 127 stateName = 'Unknown_State_%s' % slimItem.posState 128 stateTimestamp = None 129 stateDelay = None 130 godmaSM = self.godma.GetStateManager() 131 if slimItem.posState == pos.STRUCTURE_ANCHORED: 132 stateName = const.pwnStructureStateAnchored 133 if slimItem.posTimestamp is not None: 134 delayMs = godmaSM.GetType(slimItem.typeID).anchoringDelay 135 if blue.os.GetWallclockTime() - slimItem.posTimestamp < delayMs * 10000: 136 stateName = const.pwnStructureStateAnchoring 137 stateTimestamp = slimItem.posTimestamp 138 stateDelay = delayMs 139 elif slimItem.posState == pos.STRUCTURE_ONLINING: 140 stateName = const.pwnStructureStateOnline 141 if slimItem.posState == pos.STRUCTURE_ONLINING and slimItem.posTimestamp is not None: 142 delayMs = godmaSM.GetType(slimItem.typeID).onliningDelay 143 if blue.os.GetWallclockTime() - slimItem.posTimestamp < delayMs * 10000: 144 stateName = const.pwnStructureStateOnlining 145 stateTimestamp = slimItem.posTimestamp 146 stateDelay = delayMs 147 elif slimItem.posState == pos.STRUCTURE_UNANCHORED: 148 stateName = const.pwnStructureStateUnanchored 149 if slimItem.posTimestamp is not None: 150 delayMs = godmaSM.GetType(slimItem.typeID).unanchoringDelay 151 if blue.os.GetWallclockTime() - slimItem.posTimestamp < delayMs * 10000: 152 stateName = const.pwnStructureStateUnanchoring 153 stateTimestamp = slimItem.posTimestamp 154 stateDelay = delayMs 155 elif slimItem.posState == pos.STRUCTURE_VULNERABLE: 156 stateName = const.pwnStructureStateVulnerable 157 elif slimItem.posState == pos.STRUCTURE_INVULNERABLE: 158 stateName = const.pwnStructureStateInvulnerable 159 elif slimItem.posState == pos.STRUCTURE_REINFORCED: 160 delayMs = (blue.os.GetWallclockTime() - slimItem.posTimestamp) / 10000 161 if delayMs < 0: 162 stateName = const.pwnStructureStateReinforced 163 stateDelay = -delayMs 164 stateTimestamp = blue.os.GetWallclockTime() + delayMs 165 elif slimItem.posState in (pos.STRUCTURE_SHIELD_REINFORCE, pos.STRUCTURE_ARMOR_REINFORCE): 166 stateName = const.pwnStructureStateReinforced 167 stateTimestamp = slimItem.posTimestamp + slimItem.posDelayTime 168 stateDelay = slimItem.posDelayTime 169 elif slimItem.posState == pos.STRUCTURE_OPERATING: 170 stateName = const.pwnStructureStateOnline 171 delayMs = (blue.os.GetWallclockTime() - slimItem.posTimestamp) / 10000 172 if delayMs < 0: 173 stateName = const.pwnStructureStateOperating 174 stateDelay = -delayMs 175 stateTimestamp = blue.os.GetWallclockTime() + delayMs 176 elif slimItem.posState == pos.STRUCTURE_ONLINE: 177 stateName = const.pwnStructureStateOnline 178 if slimItem.incapacitated: 179 stateName = const.pwnStructureStateIncapacitated 180 return (stateName, stateTimestamp, stateDelay) 181 182 def EnterTowerPassword(self, towerID): 183 password = utilWindows.NamePopup(caption=localization.GetByLabel('UI/Inflight/POS/TowerShieldHarmonic'), label=localization.GetByLabel('UI/Inflight/POS/EnterTheSharedSecret'), setvalue='', maxLength=50, passwordChar='*') 184 if password is None: 185 return 186 posMgr = eveMoniker.GetPOSMgr() 187 posMgr.SetTowerPassword(towerID, password) 188 189 def EnterShipPassword(self): 190 format = [{'type': 'text', 191 'refreshheight': 1, 192 'text': localization.GetByLabel('UI/Inflight/POS/EnterHarmonicPassword'), 193 'frame': 0}, {'type': 'edit', 194 'setvalue': '', 195 'label': '_hide', 196 'key': 'name', 197 'maxLength': 50, 198 'passwordChar': '*', 199 'setfocus': 1, 200 'frame': 0}] 201 retval = uix.HybridWnd(format, caption=localization.GetByLabel('UI/Inflight/POS/ShipShieldHarmonic'), windowID='enterShipPassword', modal=1, buttons=uiconst.OKCANCEL, icon=uiconst.OKCANCEL, minW=360, minH=120, unresizeAble=True) 202 if retval is not None: 203 if session.stationid: 204 prompt_player_fsd_dialog('CannotSetShieldHarmonicPassword') 205 else: 206 ship = eveMoniker.GetShipAccess() 207 ship.SetShipPassword(retval['name']) 208 209 def Anchor(self, itemID, position): 210 item = sm.GetService('michelle').GetItem(itemID) 211 if item is None: 212 return 213 for row in dogma.data.get_type_effects(item.typeID): 214 if row.effectID == const.effectAnchorDropForStructures: 215 posMgr = eveMoniker.GetPOSMgr() 216 posMgr.AnchorStructure(itemID, position) 217 break 218 219 def CheckAnchoringPosition(self, itemID, position): 220 item = self.michelle.GetItem(itemID) 221 if item is None: 222 return 223 if item.categoryID != const.categoryStarbase: 224 raise UserError('CantConfigureThat') 225 bp = self.michelle.GetBallpark() 226 shipBall = bp.GetBall(session.shipid) 227 itemBall = bp.GetBall(itemID) 228 if item.groupID == const.groupControlTower: 229 actualDistance = bp.GetCenterDist(session.shipid, itemID) - shipBall.radius - itemBall.radius 230 if actualDistance > 30000: 231 raise UserError('CantConfigureDistant2', {'actual': actualDistance, 232 'needed': 30000}) 233 self.CheckForStructures(itemID) 234 else: 235 towerID = self.LocateControlTower(itemID, 'CantAnchorRequireTower') 236 self.CheckTowerAvailablility(towerID, itemID) 237 238 def CheckForStructures(self, towerID): 239 bp = self.michelle.GetBallpark() 240 if bp is None: 241 return 242 towerItem = self.michelle.GetItem(towerID) 243 if towerItem is None: 244 return 245 typeID = towerItem.typeID 246 maxRange = self.godma.GetType(typeID).maxStructureDistance 247 self.LogInfo('CheckForStructures', towerID, maxRange) 248 for ballID in bp.balls.itervalues(): 249 if ballID < 0: 250 continue 251 self.LogInfo('CheckForStructures.iteration', ballID) 252 ballItem = self.michelle.GetItem(ballID) 253 if ballItem is None: 254 continue 255 if ballItem.categoryID == const.categoryStarbase: 256 ball = bp.GetBall(ballID) 257 if not ball.isFree: 258 raise UserError('CantAnchorTowerInvalidStructures', {'typeID': ballItem.typeID}) 259 self.LogInfo('Anchor ignore', evetypes.GetName(ballItem.typeID)) 260 261 def LocateControlTower(self, locusID, raiseError = None): 262 bp = self.michelle.GetBallpark() 263 if bp is None: 264 return 265 for ballID in bp.GetBallIdsAndDistInRange(locusID, 300000): 266 if ballID < 0: 267 continue 268 item = self.michelle.GetItem(ballID) 269 if item is None or item.groupID != const.groupControlTower: 270 continue 271 maxDistance = self.godma.GetType(item.typeID).maxStructureDistance 272 if bp.DistanceBetween(ballID, locusID) <= maxDistance: 273 return ballID 274 275 if raiseError is not None: 276 item = self.michelle.GetItem(locusID) 277 raise UserError(raiseError, {'itemTypeID': item.typeID}) 278 279 def CheckTowerAvailablility(self, towerID, structureID): 280 if towerID is None: 281 return 282 if towerID != structureID: 283 if not self.IsStructureFullyOnline(towerID): 284 raise UserError('CantTowerNotOnline') 285 286 def IsStructureFullyAnchored(self, itemID): 287 slimItem = self.GetSlimItem(itemID) 288 if slimItem is None: 289 return 0 290 if slimItem.posState != pos.STRUCTURE_ANCHORED: 291 return 0 292 if slimItem.posTimestamp is not None: 293 godmaSM = self.godma.GetStateManager() 294 delayMs = godmaSM.GetType(slimItem.typeID).anchoringDelay 295 if blue.os.GetWallclockTime() - slimItem.posTimestamp < delayMs * 10000: 296 return 0 297 return 1 298 299 def IsStructureFullyOnline(self, itemID): 300 slimItem = self.GetSlimItem(itemID) 301 if slimItem is None: 302 return 0 303 if not hasattr(slimItem, 'posState'): 304 return 0 305 if slimItem.posState not in ONLINE_STATES: 306 return 0 307 if slimItem.posState == pos.STRUCTURE_ONLINING and slimItem.posTimestamp is not None: 308 godmaSM = self.godma.GetStateManager() 309 delayMs = godmaSM.GetType(slimItem.typeID).onliningDelay 310 if blue.os.GetWallclockTime() - slimItem.posTimestamp < delayMs * 10000: 311 return 0 312 return 1 313 314 def IsStructureFullyUnanchored(self, itemID): 315 slimItem = self.GetSlimItem(itemID) 316 if slimItem is None: 317 return 0 318 if slimItem.posState != pos.STRUCTURE_UNANCHORED: 319 return 0 320 if slimItem.posTimestamp is not None: 321 godmaSM = self.godma.GetStateManager() 322 delayMs = godmaSM.GetType(slimItem.typeID).unanchoringDelay 323 if blue.os.GetWallclockTime() - slimItem.posTimestamp < delayMs * 10000: 324 return 0 325 return 1 326 327 def CanAnchorStructure(self, itemID): 328 return self.IsStructureFullyUnanchored(itemID) 329 330 def CanOnlineStructure(self, itemID, fullyAnchored = None): 331 return self.IsStructureFullyAnchored(itemID) 332 333 def CanOfflineStructure(self, itemID, fullyOnline = None): 334 return self.IsStructureFullyOnline(itemID) 335 336 def CanUnanchorStructure(self, itemID): 337 slimItem = self.GetSlimItem(itemID) 338 if slimItem is None: 339 return 0 340 godmaSM = self.godma.GetStateManager() 341 if slimItem.posState == pos.STRUCTURE_ANCHORED: 342 if slimItem.posTimestamp is not None: 343 delayMs = godmaSM.GetType(slimItem.typeID).anchoringDelay 344 if blue.os.GetWallclockTime() - slimItem.posTimestamp < delayMs * 10000: 345 return 0 346 elif slimItem.posState in UNANCHORABLE_STATES: 347 return 0 348 return godmaSM.TypeHasEffect(slimItem.typeID, const.effectAnchorLiftForStructures) 349 350 def StructureIsOrphan(self, itemID): 351 item = self.michelle.GetItem(itemID) 352 if item is None: 353 return False 354 if item.categoryID == const.categorySovereigntyStructure: 355 return False 356 if item.groupID == const.groupControlTower: 357 return False 358 controlTowerID = item.controlTowerID 359 if controlTowerID is None: 360 return True 361 towerItem = self.michelle.GetItem(controlTowerID) 362 if towerItem is None: 363 return True 364 return False 365 366 def DoBallsAdded(self, *args, **kw): 367 import stackless 368 import blue 369 t = stackless.getcurrent() 370 timer = t.PushTimer(blue.pyos.taskletTimer.GetCurrent() + '::playerOwned') 371 try: 372 return self.DoBallsAdded_(*args, **kw) 373 finally: 374 t.PopTimer(timer) 375 376 def DoBallsAdded_(self, ballsToAdd): 377 for ball, slimItem in ballsToAdd: 378 try: 379 if slimItem is None: 380 continue 381 if slimItem.categoryID != const.categoryStarbase: 382 continue 383 controllerID = slimItem.controllerID 384 if controllerID is not None and controllerID == session.shipid: 385 uthread.new(self.RelinquishStructureControl, slimItem) 386 except: 387 self.LogError('DoBallsAdded - failed to say i have control', (ball, slimItem)) 388 log.LogTraceback() 389 sys.exc_clear() 390 391 @telemetry.ZONE_METHOD 392 def DoBallsRemove(self, pythonBalls, isRelease): 393 for ball, slimItem, terminal in pythonBalls: 394 self.DoBallRemove(ball, slimItem, terminal) 395 396 def DoBallRemove(self, ball, slimItem, terminal): 397 if slimItem is None: 398 return 399 if slimItem.categoryID != const.categoryStarbase: 400 return 401 if slimItem.controllerID == session.charid: 402 uthread.new(self.RelinquishStructureControl, slimItem, silent=True, force=True) 403 404 def DoSessionChanging(self, isRemote, session, change): 405 if 'stationid' in change: 406 self.currenttargets = {} 407 self.currentcontrol = {} 408 409 def CanAssumeControlStructure(self, structureID): 410 item = sm.GetService('michelle').GetItem(structureID) 411 if item is None: 412 return 0 413 for typeAttribute in dogma.data.get_type_attributes(item.typeID): 414 if typeAttribute.attributeID == const.attributePosPlayerControlStructure: 415 return 1 416 417 return 0 418 419 def AssumeStructureControl(self, slimItem, silent = False, force = False): 420 item = sm.GetService('michelle').GetItem(slimItem.itemID) or slimItem 421 if item and getattr(item, 'itemID', None) and (item.itemID in self.currentlyAssuming or item.itemID in self.currentcontrol): 422 raise UserError('StructureControlled', {'item': (const.UE_TYPEID, item.typeID)}) 423 if slimItem.posState < pos.STRUCTURE_ONLINING: 424 raise UserError('StructureNotControllableUntilOnline', {'item': (const.UE_TYPEID, item.typeID)}) 425 self.currentlyAssuming[item.itemID] = True 426 if item and not item.controllerID or force: 427 for typeAttribute in dogma.data.get_type_attributes(item.typeID): 428 if typeAttribute.attributeID == const.attributePosPlayerControlStructure: 429 self.currentcontrol[item.itemID] = True 430 if not silent: 431 try: 432 posMgr = eveMoniker.GetPOSMgr() 433 posMgr.AssumeStructureControl(item.itemID) 434 except UserError as e: 435 del self.currentcontrol[item.itemID] 436 self.currentlyAssuming.pop(item.itemID, None) 437 prompt_player_fsd_dialog(e.msg, e.dict) 438 sys.exc_clear() 439 440 sm.ScatterEvent('OnAssumeStructureControl', item.itemID) 441 break 442 443 self.currentlyAssuming.pop(item.itemID, None) 444 445 def RelinquishStructureControl(self, slimItem, silent = False, force = False): 446 item = sm.GetService('michelle').GetItem(slimItem.itemID) or slimItem 447 if item and item.controllerID or force: 448 for typeAttribute in dogma.data.get_type_attributes(item.typeID): 449 if typeAttribute.attributeID == const.attributePosPlayerControlStructure: 450 if item.itemID in self.currentcontrol: 451 del self.currentcontrol[item.itemID] 452 if item.itemID in self.currenttargets: 453 del self.currenttargets[item.itemID] 454 if not silent: 455 try: 456 posMgr = eveMoniker.GetPOSMgr() 457 posMgr.RelinquishStructureControl(item.itemID) 458 except UserError as e: 459 prompt_player_fsd_dialog(e.msg, e.dict) 460 sys.exc_clear() 461 462 sm.ScatterEvent('OnRelinquishStructureControl', item.itemID) 463 break 464 465 def UnlockStructureTarget(self, structureID): 466 if structureID in self.currenttargets: 467 sm.GetService('pwntarget').UnLockTargetOBO(structureID, self.currenttargets[structureID]) 468 del self.currenttargets[structureID] 469 470 def GetControllerIDName(self, itemID): 471 slimItem = self.GetSlimItem(itemID) 472 if slimItem is None: 473 return (0, '') 474 controller = getattr(slimItem, 'controllerID', 0) 475 if controller: 476 ct = cfg.eveowners.Get(controller).name 477 else: 478 ct = localization.GetByLabel('UI/Generic/NotAvailableShort') 479 if itemID in self.currenttargets: 480 del self.currenttargets[itemID] 481 return (controller, ct) 482 483 def GetDogmaLM(self): 484 return self.godma.GetStateManager().GetDogmaLM() 485 486 def OnTargetOBO(self, what, sid = None, tid = None, reason = None): 487 if what == 'add': 488 self.currenttargets[sid] = tid 489 elif what == 'lost': 490 if sid in self.currenttargets: 491 del self.currenttargets[sid] 492 493 def ClrCurrentTarget(self, structureID = None): 494 if structureID and structureID in self.currenttargets: 495 del self.currenttargets[structureID] 496 del self.currentcontrol[structureID] 497 elif structureID is None: 498 self.currenttargets = {} 499 self.currentcontrol = {} 500 501 def GetCurrentTarget(self, structureID = None): 502 if structureID is None: 503 return self.currenttargets 504 return self.currenttargets.get(structureID, None) 505 506 def GetCurrentControl(self, structureID = None): 507 if structureID is None: 508 return self.currentcontrol 509 return self.currentcontrol.get(structureID, None) 510 511 def GetSlimItem(self, itemID): 512 bp = sm.GetService('michelle').GetBallpark() 513 if bp is None: 514 return 515 slimItem = bp.GetInvItem(itemID) 516 return slimItem