shipAlert.py (12792B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\inflight\shipAlert.py 2 import math 3 import blue 4 from carbonui.fontconst import EVE_SMALL_FONTSIZE 5 from carbonui.primitives.container import Container 6 from carbonui.primitives.sprite import Sprite 7 from carbonui.util.color import Color 8 from eve.client.script.ui.control import eveLabel 9 from eve.client.script.util.settings import IsShipHudTopAligned 10 from eve.common.lib import appConst as const 11 from eveaudio.shiphealthnotification import SoundNotification 12 import uthread 13 import carbonui.const as uiconst 14 import localization 15 from carbonui.uicore import uicore 16 SHIELD_INDEX = 0 17 ARMOR_INDEX = 1 18 HULL_INDEX = 2 19 CAPACITOR_INDEX = 3 20 CARGOHOLD_INDEX = 4 21 NAMES_TO_LEVEL = {'shield': SHIELD_INDEX, 22 'armour': ARMOR_INDEX, 23 'hull': HULL_INDEX, 24 'capacitor': CAPACITOR_INDEX, 25 'cargoHold': CARGOHOLD_INDEX} 26 27 class ShipAlertContainer(Container): 28 __notifyevents__ = ['OnSessionChanged', 'OnDamageStateChange', 'OnCapacitorChange'] 29 messages = ['UI/Inflight/ShieldLevelAlert', 'UI/Inflight/ArmorLevelAlert', 'UI/Inflight/HullLevelAlert'] 30 rtpcNames = ['shield_level', 31 'armor_level', 32 'hull_level', 33 'capacitor_level', 34 'cargo_hold_level'] 35 hudGlowColor = (1.0, 0.4, 0.4, 0.2) 36 37 def ApplyAttributes(self, attributes): 38 Container.ApplyAttributes(self, attributes) 39 self.alertText = None 40 self.fullScreen = Container(name='shipAlerts', parent=uicore.layer.inflight, align=uiconst.TOALL, state=uiconst.UI_DISABLED) 41 self.labelCont = Container(name='fakeTextCont', parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=400) 42 self.warningLabelCont = Container(name='warningLabelCont', parent=self.labelCont, align=uiconst.TOBOTTOM, height=40, top=100) 43 self.warningLabel = eveLabel.EveCaptionLarge(name='warningLabel', parent=self.warningLabelCont, align=uiconst.CENTER, bold=True, color=(1, 1, 1, 1.0), idx=0) 44 self.warningLabel.uppercase = True 45 self.warningLabel.opacity = 0.0 46 self.exceptionLabel = eveLabel.Label(name='fakeException', parent=self.labelCont, align=uiconst.TOBOTTOM, fontsize=EVE_SMALL_FONTSIZE, color=(1, 0, 0, 0.4)) 47 self.damageElements = self.AddSideElements() 48 self.oldDamageState = [1, 49 1, 50 1, 51 1, 52 1] 53 self.alertStartTimes = [None, 54 None, 55 None, 56 None, 57 None] 58 self.isActuallyDamaged = [False, 59 False, 60 False, 61 False, 62 False] 63 self.lastRTPCLevels = [None, 64 None, 65 None, 66 None, 67 None] 68 self.animMethods = [self.DoShieldAnimation, self.DoArmorAnimation, self.DoHullAnimation] 69 self.animDuration = 2.0 70 self.UpdatePosition() 71 sm.RegisterNotify(self) 72 self.enteringCapsule = False 73 74 def AddSideElements(self): 75 name = 'red bars' 76 texture = 'res:/UI/Texture/classes/ShipAlert/warped2.png' 77 cont = Container(name=name, parent=self.fullScreen, align=uiconst.TOALL) 78 width = 1024 79 height = 256 80 Sprite(parent=cont, texturePath=texture, align=uiconst.CENTERTOP, height=height, width=width, color=(1, 0, 0, 1), rotation=math.pi, useSizeFromTexture=True) 81 Sprite(parent=cont, texturePath=texture, align=uiconst.CENTERBOTTOM, height=height, width=width, color=(1, 0, 0, 1), rotation=0, useSizeFromTexture=True) 82 cont.opacity = 0 83 return cont 84 85 def _OnClose(self, *args): 86 Container._OnClose(self, *args) 87 self.fullScreen.Close() 88 89 def SetNotificationEnabled(self, levelName, enabled): 90 level = NAMES_TO_LEVEL[levelName] 91 if enabled: 92 isActive = self.IsLevelActive(level, self.oldDamageState[level]) 93 if isActive: 94 self.LevelTakenDamage(level, True) 95 else: 96 self.alertStartTimes[level] = None 97 98 def AlertThresholdChanged(self, levelName): 99 level = NAMES_TO_LEVEL[levelName] 100 isActive = self.IsLevelActive(level, self.oldDamageState[level]) 101 if isActive: 102 self.LevelTakenDamage(level, True) 103 else: 104 self.alertStartTimes[level] = None 105 106 def UpdatePosition(self): 107 if self.parent is None: 108 return 109 self.height = uicore.desktop.height - self.parent.height 110 self.width = self.parent.width 111 self.top = self.parent.height 112 self.labelCont.height = self.height 113 self.alignedTop = IsShipHudTopAligned() 114 if not self.alignedTop: 115 self.align = uiconst.CENTERBOTTOM 116 self.warningLabelCont.align = uiconst.TOBOTTOM 117 self.exceptionLabel.align = uiconst.TOBOTTOM 118 else: 119 self.align = uiconst.CENTERTOP 120 self.warningLabelCont.align = uiconst.TOTOP 121 self.exceptionLabel.align = uiconst.TOTOP 122 123 def OnSessionChanged(self, isRemote, sess, change): 124 if 'shipid' not in change: 125 return 126 if sess.sessionChangeReason in ('eject', 'storeVessel'): 127 return 128 self.alertStartTimes[2] = None 129 ship = sm.GetService('godma').GetItem(change['shipid'][1]) 130 if ship is not None and ship.groupID == const.groupCapsule and not session.structureid: 131 self.DoEnteringCapsuleAnimation() 132 133 def OnCapacitorChange(self, load, maxCap, level): 134 isActive, changeDirection = self.SetDamageAmountAndCheckIfActive(3, level) 135 if isActive and changeDirection < 0: 136 self.LevelTakenDamage(3) 137 138 def OnDamageStateChange(self, shipID, damageState): 139 if shipID != session.shipid: 140 return 141 self.NewDamageState(damageState) 142 143 def NewDamageState(self, damageState): 144 activateHigher = False 145 for level in [HULL_INDEX, ARMOR_INDEX, SHIELD_INDEX]: 146 damageAmount = damageState[level] 147 isActive, changeDirection = self.SetDamageAmountAndCheckIfActive(level, damageAmount) 148 if changeDirection < 0: 149 activateHigher = True 150 if isActive and (changeDirection < 0 or activateHigher): 151 self.LevelTakenDamage(level, changeDirection < 0) 152 elif changeDirection > 0: 153 if level == HULL_INDEX: 154 self.alertStartTimes[HULL_INDEX] = None 155 self.exceptionLabel.text = '' 156 157 def IsLevelActive(self, level, damageAmount): 158 info = SoundNotification(level) 159 enabled = settings.user.notifications.Get(info.activeFlagSettingsName, 1) 160 alertLevel = settings.user.notifications.Get(info.healthThresholdSettingsName, info.defaultThreshold) 161 if enabled and damageAmount < alertLevel: 162 return True 163 return False 164 165 def SetDamageAmountAndCheckIfActive(self, level, damageAmount): 166 isActive = self.IsLevelActive(level, damageAmount) 167 changeDirection = 0 168 if self.oldDamageState is not None and damageAmount != self.oldDamageState[level]: 169 if damageAmount < self.oldDamageState[level]: 170 changeDirection = -1 171 elif damageAmount > self.oldDamageState[level]: 172 changeDirection = 1 173 rtpcLevel = min(int((1.0 - damageAmount) * 100), 99) 174 if self.lastRTPCLevels[level] is None or self.lastRTPCLevels[level] != rtpcLevel: 175 sm.GetService('audio').SetGlobalRTPC(self.rtpcNames[level], rtpcLevel) 176 self.lastRTPCLevels[level] = rtpcLevel 177 self.oldDamageState[level] = damageAmount 178 return (isActive, changeDirection) 179 180 def LevelTakenDamage(self, level, isDamaged = True): 181 self.isActuallyDamaged[level] = isDamaged 182 self.alertStartTimes[level] = blue.os.GetSimTime() 183 if level != CAPACITOR_INDEX: 184 if getattr(self, 'alertAnimation_Thread', None) is None: 185 self.alertAnimation_Thread = uthread.new(self.DoAlertAnimation_Thread) 186 elif getattr(self, 'capacitorAnimation_Thread', None) is None: 187 self.capacitorAnimation_Thread = uthread.new(self.DoCapacitorAnimation_Thread) 188 189 def SetWarningText(self, text): 190 if not self.enteringCapsule: 191 self.warningLabel.text = text 192 193 def GetAlertLevelAndStartTime(self): 194 alertLevel = self.GetActiveAlertLevel() 195 if alertLevel is None: 196 return (None, None) 197 alertStartTime = self.alertStartTimes[alertLevel] 198 return (alertLevel, alertStartTime) 199 200 def DoAlertAnimation_Thread(self): 201 alertLevel, alertStartTime = self.GetAlertLevelAndStartTime() 202 if alertLevel is None or alertStartTime is None: 203 return 204 alertActive = True 205 while alertActive and not self.destroyed: 206 self.SetWarningText(localization.GetByLabel(self.messages[alertLevel])) 207 if not self.enteringCapsule: 208 animationMethod = self.animMethods[alertLevel] 209 animationMethod() 210 else: 211 blue.synchro.SleepSim(self.animDuration * 1000) 212 alertLevel, alertStartTime = self.GetAlertLevelAndStartTime() 213 if alertLevel is None or alertStartTime is None: 214 alertActive = False 215 else: 216 alertActive = alertStartTime < 0 or blue.os.TimeDiffInMs(alertStartTime, blue.os.GetSimTime()) < self.animDuration * 1000 217 218 self.alertAnimation_Thread = None 219 220 def GetActiveAlertLevel(self): 221 highestAlertLevel = None 222 for level, startTime in enumerate(self.alertStartTimes[:3]): 223 if startTime is None: 224 continue 225 if not self.IsLevelActive(level, self.oldDamageState[level]): 226 continue 227 valid = startTime < 0 or blue.os.TimeDiffInMs(startTime, blue.os.GetSimTime()) < self.animDuration * 1000 228 if valid: 229 highestAlertLevel = level 230 231 return highestAlertLevel 232 233 def DoCapacitorAnimation_Thread(self): 234 alertActive = True 235 while alertActive: 236 self.DoCapacitorAnimation(self.animDuration) 237 blue.synchro.SleepSim(self.animDuration * 1000) 238 capacitorAlertStartTime = self.alertStartTimes[CAPACITOR_INDEX] 239 if capacitorAlertStartTime is None: 240 alertActive = False 241 else: 242 alertActive = blue.os.TimeDiffInMs(capacitorAlertStartTime, blue.os.GetSimTime()) < self.animDuration * 1000 243 244 self.capacitorAnimation_Thread = None 245 246 def DoCapacitorAnimation(self, totalDuration): 247 loops = 1.0 248 duration = totalDuration / loops 249 sm.GetService('audio').SendUIEvent('ui_warning_capacitor') 250 uicore.animations.MorphScalar(uicore.layer.shipui.capacitorContainer, 'opacity', 1.0, 0.5, duration=duration, loops=loops, curveType=uiconst.ANIM_WAVE) 251 252 def DoShieldAnimation(self, duration = 2.0, fromHigher = False): 253 uicore.animations.MorphScalar(self.damageElements, 'opacity', 0, 0.7, duration=duration, curveType=uiconst.ANIM_WAVE) 254 uicore.animations.SpGlowFadeIn(uicore.layer.shipui.hpGauges.shieldGauge, duration=duration, glowColor=self.hudGlowColor, glowExpand=3.0, curveType=uiconst.ANIM_WAVE) 255 if not fromHigher: 256 sm.GetService('audio').SendUIEvent('ui_warning_shield') 257 blue.synchro.SleepSim(duration * 1000) 258 259 def DoArmorAnimation(self, duration = 1.0, fromHigher = False): 260 uicore.animations.MorphScalar(self.damageElements, 'opacity', 0, 0.7, duration=duration, curveType=uiconst.ANIM_WAVE) 261 uicore.animations.SpGlowFadeIn(uicore.layer.shipui.hpGauges.armorGauge, duration=duration, glowColor=self.hudGlowColor, glowExpand=3.0, curveType=uiconst.ANIM_WAVE) 262 self.DoShieldAnimation(duration, True) 263 if not fromHigher: 264 sm.GetService('audio').SendUIEvent('ui_warning_armor') 265 blue.synchro.SleepSim(duration * 1000) 266 267 def DoHullAnimation(self, duration = 0.6): 268 uicore.animations.MorphScalar(self.damageElements, 'opacity', 0, 1, duration=duration, curveType=uiconst.ANIM_WAVE) 269 uicore.animations.SpGlowFadeIn(uicore.layer.shipui.hpGauges.structureGauge, duration=duration, glowColor=self.hudGlowColor, glowExpand=3.0, curveType=uiconst.ANIM_WAVE) 270 self.DoArmorAnimation(duration, True) 271 sm.GetService('audio').SendUIEvent('ui_warning_hull') 272 blue.synchro.SleepSim(duration * 1000) 273 274 def DoEnteringCapsuleAnimation(self): 275 loops = 1.0 276 duration = 2.0 / loops 277 self.SetWarningText(localization.GetByLabel('UI/Inflight/CapsuleEjected')) 278 self.enteringCapsule = True 279 self.warningLabel.color = Color.RED 280 uicore.animations.MorphScalar(self.warningLabel, 'opacity', 1, 0, duration=duration, loops=loops)