structure.py (29374B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\structures\structure.py 2 import datetime 3 from random import randint 4 import signals 5 import structures 6 from structures import reinforce 7 import logging 8 logger = logging.getLogger(__name__) 9 10 class Structure(object): 11 12 def __init__(self): 13 self.state = structures.STATE_UNKNOWN 14 self.damage = (None, None, None) 15 self.vulnerable = None 16 self.firstAggressed = None 17 self.lastAggressed = None 18 self.notificationSent = False 19 self.repairing = None 20 self.unanchoring = None 21 self.reinforceTiming = reinforce.ReinforceTiming() 22 self.upkeepState = None 23 self.abandonAt = None 24 self.countdownTimer = CountdownTimer(self) 25 self.deployStartTime = None 26 self.deployEndTime = None 27 self.structureSize = structures.STRUCTURE_SIZE_UNDEFINED 28 self.deedState = None 29 self.hangarView = None 30 self.OnStateChanged = signals.Signal(signalName='OnStateChanged') 31 self.OnDamageChanged = signals.Signal(signalName='OnDamageChanged') 32 self.OnVulnerabilityChanged = signals.Signal(signalName='OnVulnerabilityChanged') 33 self.OnRepairingChanged = signals.Signal(signalName='OnRepairingChanged') 34 self.OnDeployTimeChanged = signals.Signal(signalName='OnDeployTimeChanged') 35 self.OnAggressionChanged = signals.Signal(signalName='OnAggressionChanged') 36 self.OnUnanchoringChanged = signals.Signal(signalName='OnUnanchoringChanged') 37 self.OnFirstAggressed = signals.Signal(signalName='OnFirstAggressed') 38 self.OnRepairCompleted = signals.Signal(signalName='OnRepairCompleted') 39 self.OnReinforceTimeChanged = signals.Signal(signalName='OnReinforceTimeChanged') 40 41 def IsFlexStructure(self): 42 return self.structureSize == structures.STRUCTURE_SIZE_FLEX 43 44 def IsMediumStructure(self): 45 return self.structureSize == structures.STRUCTURE_SIZE_MEDIUM 46 47 def Update(self): 48 self.UpdateVulnerability() 49 self.UpdateState() 50 self.UpdateTimers() 51 self.UpdateRepair() 52 self.UpdateUnanchoring() 53 self.UpdateReinforceTimer() 54 self.UpdateUpkeep() 55 self.UpdateDeed() 56 57 def SaveState(self, state): 58 pass 59 60 def SaveDamage(self, damage): 61 pass 62 63 def SaveVulnerable(self, vulnerable): 64 pass 65 66 def SaveReinforceTimes(self): 67 pass 68 69 def SaveTimer(self, start, end, paused): 70 pass 71 72 def SaveRepairing(self, repairing): 73 pass 74 75 def SaveUnanchoring(self, unanchoring): 76 pass 77 78 def _SaveDeployTimer(self, start, end): 79 pass 80 81 def SaveAbandoned(self): 82 pass 83 84 def SaveUpkeepState(self): 85 pass 86 87 def GetRepairTime(self): 88 return structures.STATE_REPAIR_TIME.get(self.state, structures.DEFAULT_REPAIR_TIMER) 89 90 def GetReinforceDurationArmor(self): 91 return structures.REINFORCE_DURATION_ARMOR_DEFAULT 92 93 def GetReinforceDurationHull(self): 94 return structures.REINFORCE_DURATION_HULL_DEFAULT 95 96 def ApplyJitterToReinforceExitTime(self, exitTime): 97 if self.IsFlexStructure(): 98 jitterRange = structures.REINFORCE_EXIT_JITTER_FLEX_SECONDS 99 elif self.IsMediumStructure(): 100 jitterRange = structures.REINFORCE_EXIT_JITTER_MEDIUM_SECONDS 101 elif self.IsInsurgencyFOB(): 102 jitterRange = structures.REINFORCE_EXIT_JITTER_INSURGENCY_FOB_SECONDS 103 else: 104 jitterRange = structures.REINFORCE_EXIT_JITTER_DEFAULT_SECONDS 105 return exitTime + reinforce.GenerateJitterTimeDelta(jitterRange) 106 107 def GenerateArmorReinforceExitDateTime(self, startDateTime): 108 duration = self.GetReinforceDurationArmor() 109 exitTime = startDateTime + datetime.timedelta(seconds=duration) 110 exitTime = self.reinforceTiming.GetEarliestTimeAfterDatetime(exitTime) 111 exitTime = self.ApplyJitterToReinforceExitTime(exitTime) 112 return exitTime 113 114 def GenerateHullReinforceExitDateTime(self, startDateTime): 115 if self.IsFlexStructure(): 116 duration = structures.FLEX_REINFORCE_DURATION_HULL 117 else: 118 duration = self.GetReinforceDurationHull() 119 exitTime = startDateTime + datetime.timedelta(seconds=duration) 120 exitTime = self.reinforceTiming.GetEarliestTimeAfterDatetime(exitTime) 121 exitTime = self.ApplyJitterToReinforceExitTime(exitTime) 122 return exitTime 123 124 def GetAnchoringTime(self): 125 return structures.ANCHORING_TIME 126 127 def GetFlexDeployingTime(self): 128 return structures.FLEX_DEPLOYING_TIME 129 130 def GetUnanchoringTime(self): 131 return structures.UNANCHORING_TIME 132 133 def HandleStateChanged(self): 134 self.countdownTimer.ClearTimer() 135 self.SetDeployingTimer(None, None) 136 self.SetRepairing(None) 137 self.UpdateVulnerability() 138 self.UpdateTimers() 139 self.SetAggression(None) 140 self.UpdateShieldArmorHull() 141 self.UpdateRepair() 142 self.UpdateUnanchoring() 143 self.UpdateReinforceTimer() 144 145 def HandleDamageChanged(self): 146 self.UpdateAggression() 147 self.Update() 148 149 def UpdateShieldArmorHull(self, *args): 150 if self.state in structures.STATE_SHIELD_ARMOR_HULL: 151 self.SetDamage(*structures.STATE_SHIELD_ARMOR_HULL[self.state]) 152 153 def UpdateVulnerability(self, *args): 154 if self.state in structures.STATE_VULNERABILITY: 155 self.SetVulnerable(structures.STATE_VULNERABILITY[self.state]) 156 157 def UpdateState(self, *args): 158 if self.state == structures.STATE_SHIELD_VULNERABLE: 159 if self.IsArmorDamaged() and self.CanHaveArmorPhases(): 160 self.PlaySpecialFX('effects.StructureRepairStateFailed') 161 if self._CanHaveArmorReinforce(): 162 self.SetState(structures.STATE_ARMOR_REINFORCE) 163 else: 164 self.SetState(structures.STATE_ARMOR_VULNERABLE) 165 elif self.IsHullDamaged(): 166 self.PlaySpecialFX('effects.StructureRepairStateFailed') 167 if self._CanHaveHullReinforce(): 168 self.SetState(structures.STATE_HULL_REINFORCE) 169 else: 170 self.SetState(structures.STATE_HULL_VULNERABLE) 171 elif self.state == structures.STATE_ARMOR_REINFORCE: 172 if self.countdownTimer.IsExpired(): 173 self.SetState(structures.STATE_ARMOR_VULNERABLE) 174 elif self.state == structures.STATE_ARMOR_VULNERABLE: 175 if not self.IsDamaged(): 176 self.SetState(structures.STATE_SHIELD_VULNERABLE) 177 elif self.IsHullDamaged(): 178 self.PlaySpecialFX('effects.StructureRepairStateFailed') 179 if self._CanHaveHullReinforce(): 180 self.SetState(structures.STATE_HULL_REINFORCE) 181 else: 182 self.SetState(structures.STATE_HULL_VULNERABLE) 183 elif self.state == structures.STATE_HULL_REINFORCE: 184 if self.countdownTimer.IsExpired(): 185 self.SetState(structures.STATE_HULL_VULNERABLE) 186 elif self.state == structures.STATE_HULL_VULNERABLE: 187 if self.IsShieldOrArmorFullyHealed(): 188 self.SetState(structures.STATE_SHIELD_VULNERABLE) 189 elif self.state == structures.STATE_ANCHOR_VULNERABLE: 190 if not self.IsDamaged(): 191 self.SetState(structures.STATE_ANCHORING) 192 elif self.state == structures.STATE_ANCHORING: 193 if self.countdownTimer.IsExpired(): 194 self.SetState(structures.STATE_ONLINING_VULNERABLE) 195 elif self.state == structures.STATE_FITTING_INVULNERABLE: 196 if self.countdownTimer.IsExpired(): 197 self.PlaySpecialFX('effects.StructureRepairStateComplete') 198 self.SetState(structures.STATE_SHIELD_VULNERABLE) 199 elif self.state == structures.STATE_ONLINING_VULNERABLE: 200 if not self.IsDamaged() and self.HasDeedInSlot(): 201 self.SetState(structures.STATE_SHIELD_VULNERABLE) 202 elif self.state == structures.STATE_DEPLOY_VULNERABLE: 203 if self.IsDeployTimeCompleted() and not self.IsHullDamaged(): 204 self.SetState(structures.STATE_SHIELD_VULNERABLE) 205 elif self.state == structures.STATE_ONLINE_DEPRECATED: 206 self.SetState(structures.STATE_SHIELD_VULNERABLE) 207 208 def _CanHaveArmorReinforce(self): 209 if self.IsUpkeepState_Abandoned(): 210 return False 211 if self.IsFlexStructure(): 212 return False 213 if not self.IsMediumStructure() and self.IsUpkeepState_Low(): 214 return False 215 return True 216 217 def _CanHaveHullReinforce(self): 218 if self.IsUpkeepState_Abandoned(): 219 return False 220 if self.IsFlexStructure() and self.IsUpkeepState_Low(): 221 return False 222 if self.IsMediumStructure(): 223 return False 224 if self.IsInsurgencyFOB(): 225 return False 226 return True 227 228 def CanHaveArmorPhases(self): 229 return True 230 231 def IsDeployTimeCompleted(self): 232 return self.deployEndTime and self.deployEndTime < self.GetTimeNow() 233 234 def UpdateAggression(self, *args): 235 if self.IsAggressed(): 236 aggressed = self.GetFirstAggressed() 237 if not aggressed: 238 self.SetAggression(self.GetTimeNow(), self.GetTimeNow()) 239 else: 240 self.SetAggression(aggressed, self.GetTimeNow()) 241 else: 242 self.SetAggression(None) 243 244 def UpdateRepair(self, *args): 245 if self.ShouldRepair(): 246 if self.GetRepairing() is None: 247 self.countdownTimer.SetTimer(self.GetTimeNow() + datetime.timedelta(seconds=self.GetRepairTime()), self.GetTimeNow()) 248 self.SetRepairing(True) 249 elif self.ShouldRepairPause(): 250 self.countdownTimer.Pause() 251 self.SetRepairing(False) 252 else: 253 self.countdownTimer.Unpause() 254 self.SetRepairing(True) 255 if self.IsRepairing() and self.countdownTimer.IsExpired(): 256 self.PlaySpecialFX('effects.StructureRepairStateComplete') 257 self.countdownTimer.ClearTimer() 258 if self.state == structures.STATE_DEPLOY_VULNERABLE: 259 self.RepairHullOnly() 260 else: 261 self.FullyRepairSelf() 262 self.OnRepairCompleted() 263 else: 264 self.SetRepairing(None) 265 266 def UpdateTimers(self, *args): 267 if self.ShouldRepair(): 268 return 269 if self.state == structures.STATE_SHIELD_VULNERABLE: 270 self.countdownTimer.ClearTimer() 271 elif self.state == structures.STATE_ARMOR_REINFORCE: 272 if not self.countdownTimer.IsRunning(): 273 start = self.GetTimeNow() 274 self.countdownTimer.SetTimer(self.GenerateArmorReinforceExitDateTime(start)) 275 elif self.state == structures.STATE_ARMOR_VULNERABLE: 276 self.countdownTimer.ClearTimer() 277 elif self.state == structures.STATE_HULL_REINFORCE: 278 if not self.countdownTimer.IsRunning(): 279 start = self.GetTimeNow() 280 self.countdownTimer.SetTimer(self.GenerateHullReinforceExitDateTime(start)) 281 elif self.state == structures.STATE_HULL_VULNERABLE: 282 self.countdownTimer.ClearTimer() 283 elif self.state == structures.STATE_ANCHOR_VULNERABLE: 284 self.countdownTimer.ClearTimer() 285 elif self.state == structures.STATE_ANCHORING: 286 if not self.countdownTimer.IsRunning(): 287 self.countdownTimer.SetTimer(self.GetTimeNow() + datetime.timedelta(seconds=self.GetAnchoringTime())) 288 elif self.state == structures.STATE_FITTING_INVULNERABLE: 289 if not self.countdownTimer.IsRunning(): 290 self.countdownTimer.SetTimer(self.GetTimeNow() + datetime.timedelta(seconds=structures.FITTING_INVULNERABLE_TIME)) 291 elif self.state == structures.STATE_ONLINING_VULNERABLE: 292 self.countdownTimer.ClearTimer() 293 elif self.state == structures.STATE_DEPLOY_VULNERABLE: 294 if self.deployStartTime is None or self.deployEndTime is None: 295 self.SetDeployingTimer(self.GetTimeNow(), self.GetTimeNow() + datetime.timedelta(seconds=self.GetFlexDeployingTime())) 296 elif self.state == structures.STATE_ONLINE_DEPRECATED: 297 self.countdownTimer.ClearTimer() 298 elif self.state == structures.STATE_FOB_INVULNERABLE: 299 self.countdownTimer.ClearTimer() 300 301 def SetDeployingTimer(self, startTime, endTime): 302 if startTime == self.deployStartTime and endTime == self.deployEndTime: 303 return 304 self.deployStartTime = startTime 305 self.deployEndTime = endTime 306 self._SaveDeployTimer(self.deployStartTime, self.deployEndTime) 307 self.OnDeployTimeChanged() 308 309 def UpdateUnanchoring(self): 310 if structures.STATE_CANCELS_UNANCHOR.get(self.state) is True: 311 if self.GetUnanchoring() is not None and hasattr(self, 'LogUnanchoringForceCancelled'): 312 self.LogUnanchoringForceCancelled(self.state) 313 self.SetUnanchoring(None) 314 if self.HasUnanchoringExpired(): 315 self.SetState(structures.STATE_UNANCHORED) 316 317 def UpdateReinforceTimer(self): 318 if self.CanApplyNextReinforceTime(): 319 currentTime = self.GetTimeNow() 320 if self.reinforceTiming.IsNextChangeReady(currentTime): 321 self.reinforceTiming.ApplyNextTiming() 322 self.SaveReinforceTimes() 323 self.OnReinforceTimeChanged(None, None) 324 325 def GetState(self): 326 return self.state 327 328 def SetState(self, state): 329 if state not in structures.STATES: 330 raise structures.InvalidStructureState(state) 331 current = self.GetState() 332 if state != current: 333 self.state = state 334 self.SaveState(state) 335 self.HandleStateChanged() 336 self.OnStateChanged(self, current, state) 337 338 def IsOnline(self): 339 return self.GetState() not in structures.OFFLINE_STATES 340 341 def IsOffline(self): 342 return self.GetState() in structures.OFFLINE_STATES 343 344 def IsDisabled(self): 345 return self.GetState() in structures.DISABLED_STATES 346 347 def GetUnanchoring(self): 348 return self.unanchoring 349 350 def SetUnanchoring(self, unanchoring): 351 if unanchoring is not None and not isinstance(unanchoring, datetime.datetime): 352 raise TypeError('Unanchoring time must be a datetime object or None') 353 if unanchoring != self.GetUnanchoring(): 354 self.unanchoring = unanchoring 355 self.SaveUnanchoring(unanchoring) 356 self.OnUnanchoringChanged(self, unanchoring) 357 358 def SetUnanchoringRemaining(self, seconds): 359 self.SetUnanchoring(self.GetTimeNow() + datetime.timedelta(seconds=int(seconds))) 360 361 def GetUnanchoringRemaining(self): 362 unanchoring = self.GetUnanchoring() 363 if unanchoring is not None: 364 return int((unanchoring - self.GetTimeNow()).total_seconds()) 365 366 def StartUnanchoring(self): 367 if self.GetUnanchoring() is None: 368 self.SetUnanchoring(self.GetTimeNow() + datetime.timedelta(seconds=self.GetUnanchoringTime())) 369 370 def StopUnanchoring(self): 371 if self.GetUnanchoring(): 372 self.SetUnanchoring(None) 373 374 def IsUnanchoring(self): 375 return self.unanchoring is not None 376 377 def GetUnanchorTime(self): 378 return self.unanchoring 379 380 def HasUnanchoringExpired(self): 381 unanchoring = self.GetUnanchoring() 382 return unanchoring is not None and unanchoring <= self.GetTimeNow() 383 384 def IsShieldDamaged(self): 385 ALMOST_MAX_SHIELD_LEVEL = 0.995 386 return self.GetShield() < ALMOST_MAX_SHIELD_LEVEL 387 388 def IsArmorDamaged(self): 389 return self.GetArmor() < 1 390 391 def IsHullDamaged(self): 392 return self.GetHull() < 1 393 394 def IsDamaged(self): 395 if self.GetDamage() == (None, None, None): 396 return False 397 return self.IsShieldDamaged() or self.IsArmorDamaged() or self.IsHullDamaged() 398 399 def IsShieldOrArmorFullyHealed(self): 400 if self.GetDamage() == (None, None, None): 401 return True 402 if not self.IsShieldDamaged(): 403 return True 404 if not self.IsArmorDamaged(): 405 return True 406 return False 407 408 def IsInFittingState(self): 409 return self.GetState() == structures.STATE_FITTING_INVULNERABLE 410 411 def SetDamage(self, shield, armor, hull): 412 damage = (max(min(float(shield), 1.0), 0.0), max(min(float(armor), 1.0), 0.0), max(min(float(hull), 1.0), 0.0)) 413 if damage != self.GetDamage(): 414 self.damage = damage 415 self.SaveDamage(damage) 416 self.HandleDamageChanged() 417 self.OnDamageChanged(self, damage) 418 419 def GetDamage(self): 420 return self.damage 421 422 def CanHaveAutoRepair(self): 423 return True 424 425 def ShouldRepair(self): 426 if self.state in structures.STATES_THAT_REQUIRE_AUTO_REPAIR_TO_REPAIR and not self.CanHaveAutoRepair(): 427 return False 428 elif not self.IsVulnerable(): 429 return False 430 elif self.state == structures.STATE_DEPLOY_VULNERABLE: 431 return self.IsHullDamaged() 432 elif self.state == structures.STATE_ONLINING_VULNERABLE: 433 return self.IsDamaged() and self.HasDeedInSlot() 434 else: 435 return self.IsDamaged() 436 437 def ShouldRepairPause(self): 438 return self.GetLastAggressed() 439 440 def IsRepairing(self): 441 return bool(self.repairing) 442 443 def GetRepairing(self): 444 return self.repairing 445 446 def SetRepairing(self, repairing): 447 if repairing is not None and not isinstance(repairing, bool): 448 raise TypeError('Repairing must be a bool or None') 449 if repairing != self.repairing: 450 self.repairing = repairing 451 self.SaveRepairing(repairing) 452 self.OnRepairingChanged(self, repairing) 453 454 def IsAggressed(self): 455 if self.state == structures.STATE_SHIELD_VULNERABLE: 456 return self.IsShieldDamaged() 457 if self.state == structures.STATE_ARMOR_VULNERABLE: 458 return self.IsArmorDamaged() 459 if self.state == structures.STATE_HULL_VULNERABLE: 460 return self.IsHullDamaged() 461 if self.state == structures.STATE_ANCHOR_VULNERABLE: 462 return self.IsHullDamaged() 463 if self.state == structures.STATE_DEPLOY_VULNERABLE: 464 return self.IsHullDamaged() 465 466 def IsDamageBelowNotificationThreshold(self): 467 if self.state == structures.STATE_SHIELD_VULNERABLE: 468 return self.GetShield() < 0.95 469 return True 470 471 def GetFirstAggressed(self): 472 return self.firstAggressed 473 474 def GetLastAggressed(self): 475 return self.lastAggressed 476 477 def SetAggression(self, aggressed, latest = None): 478 if aggressed is not None and not isinstance(aggressed, datetime.datetime): 479 raise TypeError('Aggression time must be a datetime object or None') 480 if latest is not None and not isinstance(aggressed, datetime.datetime): 481 raise TypeError('Latest aggression time must be a datetime object or None') 482 firstAggressed = self.GetFirstAggressed() 483 if aggressed != firstAggressed or latest != self.GetLastAggressed(): 484 self.firstAggressed = aggressed 485 self.lastAggressed = latest 486 self.OnAggressionChanged(self, self.firstAggressed, self.lastAggressed) 487 if self.firstAggressed is None: 488 self.notificationSent = False 489 if self.firstAggressed and not self.notificationSent: 490 if self.IsDamageBelowNotificationThreshold(): 491 self.notificationSent = True 492 self.OnFirstAggressed(self, self.firstAggressed) 493 494 def GetShield(self): 495 return self.GetDamage()[0] 496 497 def GetArmor(self): 498 return self.GetDamage()[1] 499 500 def GetHull(self): 501 return self.GetDamage()[2] 502 503 def GetVulnerable(self): 504 return self.vulnerable 505 506 def IsVulnerable(self): 507 return bool(self.GetVulnerable()) 508 509 def SetVulnerable(self, vulnerable): 510 vulnerable = bool(int(vulnerable)) 511 existing = self.GetVulnerable() 512 if vulnerable != existing: 513 self.vulnerable = vulnerable 514 self.SaveVulnerable(vulnerable) 515 self.OnVulnerabilityChanged(self, existing, vulnerable) 516 517 def SetReinforceTimes(self, weekday, hour, userID, characterID): 518 self.reinforceTiming.SetReinforceTimes(weekday, hour) 519 self.SaveReinforceTimes() 520 self.OnReinforceTimeChanged(userID, characterID) 521 522 def SetNextReinforceTimes(self, weekday, hour, delaySeconds, userID, characterID): 523 applyAtTime = self.GetTimeNow() + datetime.timedelta(seconds=int(delaySeconds)) 524 self.reinforceTiming.SetNextReinforceTimes(weekday, hour, applyAtTime) 525 self.SaveReinforceTimes() 526 self.OnReinforceTimeChanged(userID, characterID) 527 528 def GetTimeNow(self): 529 now = datetime.datetime.utcnow() 530 return now.replace(microsecond=0) 531 532 def IsStateHullVulnerable(self): 533 return self.state in (structures.STATE_HULL_VULNERABLE, structures.STATE_ANCHOR_VULNERABLE, structures.STATE_ONLINING_VULNERABLE) 534 535 def IsStateArmorVulnerable(self): 536 return self.state == structures.STATE_ARMOR_VULNERABLE 537 538 def IsStateShieldVulnerable(self): 539 return self.state == structures.STATE_SHIELD_VULNERABLE 540 541 def FullyRepairSelf(self): 542 self.SetDamage(1.0, 1.0, 1.0) 543 544 def RepairHullOnly(self): 545 self.SetDamage(0.0, 0.0, 1.0) 546 547 def HasOnlineServiceModule(self): 548 raise NotImplementedError() 549 550 def SetAbandonAt(self, abandonAt): 551 if abandonAt is not None: 552 if not isinstance(abandonAt, datetime.datetime): 553 raise TypeError('abandonAt must be a datetime object or None') 554 if self.upkeepState != structures.UPKEEP_STATE_LOW_POWER: 555 raise RuntimeError('Structure must be in Low Power to set abandon timer - current upkeep state = %s' % self.upkeepState) 556 if not self.StructureAllowsAbandonment(): 557 raise RuntimeError('This structure does not allow abandonment') 558 self.abandonAt = abandonAt 559 self.SaveAbandoned() 560 561 def UpdateUpkeep(self): 562 if self.upkeepState == structures.UPKEEP_STATE_FULL_POWER: 563 if not self.HasOnlineServiceModule(): 564 self.SetUpkeepState(structures.UPKEEP_STATE_LOW_POWER) 565 elif self.abandonAt is not None: 566 self.SetAbandonAt(None) 567 elif self.upkeepState == structures.UPKEEP_STATE_LOW_POWER: 568 if self.HasOnlineServiceModule(): 569 self.SetUpkeepState(structures.UPKEEP_STATE_FULL_POWER) 570 elif self.abandonAt is None: 571 if self.StructureAllowsAbandonment(): 572 abandonDurationSec = randint(structures.ABANDONING_TIME_MIN, structures.ABANDONING_TIME_MAX) 573 self.SetAbandonAt(self.GetTimeNow() + datetime.timedelta(seconds=abandonDurationSec)) 574 elif self.abandonAt < self.GetTimeNow(): 575 self.SetUpkeepState(structures.UPKEEP_STATE_ABANDONED) 576 else: 577 self.ConsiderSendingImpendingAbandonWarnings() 578 elif self.upkeepState == structures.UPKEEP_STATE_ABANDONED: 579 if self.HasOnlineServiceModule(): 580 self.SetUpkeepState(structures.UPKEEP_STATE_FULL_POWER) 581 else: 582 logger.warn('UpdateUpkeep called for for unrecognised upkeep state - falling back to Full Power [%s]', self) 583 self.SetUpkeepState(structures.UPKEEP_STATE_FULL_POWER) 584 585 def SetUpkeepState(self, newUpkeepState): 586 if newUpkeepState not in structures.ALL_UPKEEP_STATES: 587 raise ValueError('newUpkeepState must be one of ALL_UPKEEP_STATES') 588 if self.upkeepState != newUpkeepState: 589 oldUpkeepState = self.upkeepState 590 self.upkeepState = newUpkeepState 591 self.SaveUpkeepState() 592 self.OnUpkeepStateChanged(oldUpkeepState, newUpkeepState) 593 self.UpdateUpkeep() 594 595 def OnUpkeepStateChanged(self, oldUpkeepState, newUpkeepState): 596 pass 597 598 def IsUpkeepState_Full(self): 599 return self.upkeepState == structures.UPKEEP_STATE_FULL_POWER 600 601 def IsUpkeepState_Low(self): 602 return self.upkeepState == structures.UPKEEP_STATE_LOW_POWER 603 604 def IsUpkeepState_Abandoned(self): 605 return self.upkeepState == structures.UPKEEP_STATE_ABANDONED 606 607 def CanApplyNextReinforceTime(self): 608 return self.state == structures.STATE_SHIELD_VULNERABLE and not self.IsDamaged() 609 610 def CanActivateEquipment(self): 611 return self.state in structures.CAN_ACTIVATE_EQUIPMENT_IN_STATE 612 613 def PlaySpecialFX(self, guid): 614 pass 615 616 def ConsiderSendingImpendingAbandonWarnings(self): 617 raise NotImplementedError() 618 619 def StructureAllowsAbandonment(self): 620 return True 621 622 def UpdateDeed(self): 623 newDeedState = self.CalculateDeedState() 624 if newDeedState == self.deedState: 625 return 626 self.deedState = newDeedState 627 self.Update() 628 self.OnDeedStateChanged() 629 630 def HasDeedInSlot(self): 631 return self.deedState 632 633 def CalculateDeedState(self): 634 raise NotImplementedError() 635 636 def OnDeedStateChanged(self): 637 pass 638 639 def IsInsurgencyFOB(self): 640 return False 641 642 643 class CountdownTimer(object): 644 645 def __init__(self, structure): 646 self._structure = structure 647 self.endDateTime = None 648 self.startDateTime = None 649 self.pausedDateTime = None 650 self.OnTimerChanged = signals.Signal(signalName='OnTimerChanged') 651 652 def LoadFromRow(self, structureRow): 653 from carbon.common.script.util.format import BlueToDate 654 self.startDateTime = BlueToDate(structureRow.timerStart) 655 self.endDateTime = BlueToDate(structureRow.timerEnd) 656 657 def IsRunning(self): 658 return self.startDateTime and self.endDateTime 659 660 def GetTimerRemaining(self): 661 if self.endDateTime is not None: 662 return int((self.endDateTime - self._structure.GetTimeNow()).total_seconds()) 663 664 def IsExpired(self): 665 return self.endDateTime is None or self.endDateTime <= self._structure.GetTimeNow() 666 667 def ClearTimer(self): 668 if self.endDateTime is not None or self.startDateTime is not None or self.pausedDateTime is not None: 669 self.startDateTime = None 670 self.endDateTime = None 671 self.pausedDateTime = None 672 self._structure.SaveTimer(self.startDateTime, self.endDateTime, self.pausedDateTime) 673 self.OnTimerChanged(self, self.startDateTime, self.endDateTime, self.pausedDateTime) 674 675 def SetTimer(self, endDateTime, startDateTime = None, pausedDateTime = None): 676 if endDateTime is not None and not isinstance(endDateTime, datetime.datetime): 677 raise TypeError('Timer must be a datetime object or None') 678 if isinstance(pausedDateTime, bool): 679 pausedDateTime = self._structure.GetTimeNow() if pausedDateTime else None 680 elif pausedDateTime is not None and not isinstance(pausedDateTime, datetime.datetime): 681 raise TypeError('Paused must be a datetime object, a bool or None') 682 if endDateTime != self.endDateTime or startDateTime != self.startDateTime or pausedDateTime != self.pausedDateTime: 683 self.startDateTime = startDateTime or self._structure.GetTimeNow() 684 self.endDateTime = endDateTime 685 self.pausedDateTime = pausedDateTime 686 self._structure.SaveTimer(self.startDateTime, self.endDateTime, self.pausedDateTime) 687 self.OnTimerChanged(self, self.startDateTime, self.endDateTime, self.pausedDateTime) 688 689 def IsPaused(self): 690 return self.pausedDateTime is not None 691 692 def Pause(self): 693 if not self.IsRunning(): 694 return 695 if not self.pausedDateTime: 696 self.SetTimer(self.endDateTime, self.startDateTime, self._structure.GetTimeNow()) 697 698 def Unpause(self): 699 if not self.IsRunning(): 700 logger.warn('CountdownTimer.Unpause() called for structure timer that is not running. %s', self._structure) 701 return 702 if self.pausedDateTime: 703 elapsed = self._structure.GetTimeNow() - self.pausedDateTime 704 start = elapsed + self.startDateTime 705 end = elapsed + self.endDateTime 706 self.SetTimer(end, start) 707 708 def GetTimesBlue(self): 709 if self.startDateTime and self.endDateTime: 710 from carbon.common.script.util.format import DateToBlue 711 return (DateToBlue(self.startDateTime), DateToBlue(self.endDateTime), DateToBlue(self.pausedDateTime)) 712 713 def GetEndTimeBlue(self): 714 from carbon.common.script.util.format import DateToBlue 715 return DateToBlue(self.endDateTime) 716 717 718 def LookupState(state): 719 if state: 720 state = str(state).lower() 721 for value, name in structures.STATES.iteritems(): 722 if str(value) == state: 723 return value 724 if name.startswith(state): 725 return value