agentDialogueWindow.py (19751B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\station\agents\agentDialogueWindow.py 2 import logging 3 import blue 4 import telemetry 5 import carbonui.const as uiconst 6 import localization 7 from carbon.common.script.util.format import FmtTimeInterval 8 from carbonui.control.window import Window 9 from carbonui.primitives.container import Container 10 from eve.client.script.ui.control import eveEdit 11 from carbonui.button.group import ButtonGroup 12 from eve.client.script.ui.control.eveLoadingWheel import LoadingWheel 13 from eve.client.script.ui.eveColor import SUCCESS_GREEN_HEX 14 from eve.client.script.ui.station.agents import agentDialogueUtil 15 from eve.client.script.ui.station.agents.agentConst import LABEL_BY_BUTTON_TYPE 16 from eve.client.script.ui.station.agents.agentDialogueUtil import GetAgentNameAndLevel 17 from eve.common.lib import appConst 18 from gametime import MIN 19 from random import choice 20 from jobboard.client import get_agent_mission_job 21 from jobboard.client.ui.track_button import TrackJobButton 22 from localization import GetByLabel 23 SINGLE_PANE_VIEW = 'SinglePaneView' 24 DOUBLE_PANE_VIEW = 'DoublePaneView' 25 MIN_HEIGHT = 545 26 MIN_WIDTH = 835 27 logger = logging.getLogger(__name__) 28 29 class AgentDialogueWindow(Window): 30 __guid__ = 'form.AgentDialogueWindow' 31 __notifyevents__ = ['OnSessionChanged', 'OnAgentMissionChange'] 32 default_width = 900 33 default_height = 650 34 default_minSize = (MIN_WIDTH, MIN_HEIGHT) 35 default_windowID = 'AgentDialogueWindow' 36 default_iconNum = 'res:/ui/Texture/WindowIcons/agent.png' 37 38 def ApplyAttributes(self, attributes): 39 Window.ApplyAttributes(self, attributes) 40 self.isLoading = False 41 self.objectiveHtml = None 42 self.briefingHtml = None 43 self.viewMode = None 44 self.leftPane = None 45 self.rightPane = None 46 self.agentID = None 47 self.agentDivisionID = None 48 self.SetAgentID(attributes.agentID) 49 self.buttonGroup = ButtonGroup(parent=self.content, align=uiconst.TOBOTTOM) 50 self.mainCont = Container(name='mainCont', parent=self.content, padBottom=16) 51 self.loadingWheel = LoadingWheel(parent=self, align=uiconst.CENTER, state=uiconst.UI_HIDDEN, idx=0) 52 53 def ConstructBrowsers(self): 54 self.briefingBrowser = eveEdit.Edit(name='briefing_browser', parent=self.leftPane, readonly=1) 55 self.briefingBrowser.sr.window = self 56 self.objectiveBrowser = eveEdit.Edit(name='objective_browser', parent=self.rightPane, readonly=1) 57 self.objectiveBrowser.sr.window = self 58 59 def SetAgentID(self, agentID): 60 if agentID is not None: 61 agentInfo = sm.GetService('agents').GetAgentByID(agentID) 62 agentNameAndLevel = GetAgentNameAndLevel(agentID, agentInfo.level) 63 self.SetCaption(localization.GetByLabel('UI/Agents/Dialogue/AgentConversationWith', agentNameAndLevel=agentNameAndLevel)) 64 self.agentDivisionID = agentInfo.divisionID 65 self.agentID = agentID 66 67 def GetAgentID(self): 68 return self.agentID 69 70 def GetAgentMoniker(self): 71 return sm.GetService('agents').GetAgentMoniker(self.GetAgentID()) 72 73 def OnSessionChanged(self, isRemote, sess, change): 74 if not self.destroyed: 75 self.briefingBrowser.SessionChanged() 76 self.objectiveBrowser.SessionChanged() 77 if 'stationid' in change: 78 self.InteractWithAgent() 79 80 def OnAgentMissionChange(self, action, agentID): 81 if not self.destroyed: 82 if action == appConst.agentMissionModified and self.agentID == agentID: 83 self.InteractWithAgent() 84 85 def DisableButtons(self): 86 for button in self.buttonGroup.buttons: 87 button.Disable() 88 89 def SetBriefingHTML(self, html): 90 self.briefingHtml = html 91 92 def SetObjectiveHTML(self, html): 93 self.objectiveHtml = html 94 95 def LoadBriefingBrowserHTML(self, html, hideBackground = 0, newThread = 1): 96 if self.destroyed: 97 return 98 if not self.viewMode: 99 self.SetSinglePaneView() 100 if not self.briefingBrowser: 101 return 102 self.ShowLoad() 103 self.briefingHtml = html 104 self.briefingBrowser.sr.hideBackground = hideBackground 105 while self.briefingBrowser.IsLoading(): 106 blue.pyos.synchro.Yield() 107 108 self.briefingBrowser.LoadHTML(html, newThread=newThread) 109 110 def LoadObjectiveBrowserHTML(self, html, hideBackground = 0, newThread = 1): 111 if self.destroyed: 112 return 113 if not self.viewMode: 114 self.SetDoublePaneView() 115 if not self.objectiveBrowser: 116 return 117 self.ShowLoad() 118 self.objectiveHtml = html 119 self.objectiveBrowser.sr.hideBackground = hideBackground 120 while self.objectiveBrowser.IsLoading(): 121 blue.pyos.synchro.Yield() 122 123 self.objectiveBrowser.LoadHTML(html, newThread=newThread) 124 125 @telemetry.ZONE_METHOD 126 def SetSinglePaneView(self, briefingHtml = None): 127 if self.viewMode != SINGLE_PANE_VIEW: 128 self._ReconstructSinglePane() 129 if briefingHtml: 130 self.SetBriefingHTML(briefingHtml) 131 self.LoadBriefingBrowserHTML(self.briefingHtml) 132 133 def _ReconstructSinglePane(self): 134 self.viewMode = SINGLE_PANE_VIEW 135 self.LockWidth(MIN_WIDTH / 2) 136 self.mainCont.Flush() 137 self.leftPane = Container(name='leftPane', parent=self.mainCont, align=uiconst.TOALL) 138 self.ConstructBrowsers() 139 140 @telemetry.ZONE_METHOD 141 def SetDoublePaneView(self, briefingHtml = None, objectiveHtml = None): 142 if self.viewMode != DOUBLE_PANE_VIEW: 143 self._ReconstructDoublePane() 144 if briefingHtml: 145 self.SetBriefingHTML(briefingHtml) 146 self.LoadBriefingBrowserHTML(briefingHtml) 147 if objectiveHtml: 148 self.SetObjectiveHTML(objectiveHtml) 149 self.LoadObjectiveBrowserHTML(objectiveHtml) 150 151 def _ReconstructDoublePane(self): 152 self.viewMode = DOUBLE_PANE_VIEW 153 self.SetFixedWidth(None) 154 self.SetMinSize((MIN_WIDTH, MIN_HEIGHT)) 155 self.mainCont.Flush() 156 self.leftPane = Container(name='leftPane', parent=self.mainCont, align=uiconst.TOLEFT_PROP, width=0.5, padRight=8) 157 self.rightPane = Container(name='rightPane', parent=self.mainCont, align=uiconst.TOALL, padLeft=8) 158 self.ConstructBrowsers() 159 160 def RefreshBrowsers(self): 161 self.briefingBrowser.UpdatePosition(fromWhere='AgentDialogueWindow.RefreshBrowsers') 162 self.objectiveBrowser.UpdatePosition(fromWhere='AgentDialogueWindow.RefreshBrowsers') 163 164 @telemetry.ZONE_METHOD 165 def InteractWithAgent(self, actionID = None): 166 if self.isLoading: 167 return 168 self.isLoading = True 169 try: 170 self._StartLoading(actionID) 171 agentSaysText, actions, lastActionInfo = self._GetConversation(actionID) 172 if self.destroyed or agentSaysText is None: 173 return 174 self.ReconstructLayout(actions, agentSaysText, lastActionInfo) 175 finally: 176 self._StopLoading() 177 178 def _StartLoading(self, actionID): 179 if actionID: 180 self.DisableButtons() 181 self.loadingWheel.Show() 182 183 def _StopLoading(self): 184 self.isLoading = False 185 self.loadingWheel.Hide() 186 187 def ReconstructLayout(self, actions, agentSaysText, lastActionInfo): 188 actions = actions or [] 189 briefingHTML = self.GetBriefingHTML(actions, agentSaysText, lastActionInfo) 190 objectiveHtml = self.GetObjectiveHTML(lastActionInfo) 191 if objectiveHtml or lastActionInfo.get('missionCompleted'): 192 self.SetDoublePaneView(briefingHtml=briefingHTML, objectiveHtml=objectiveHtml) 193 else: 194 self.SetSinglePaneView(briefingHtml=briefingHTML) 195 self.ReconstructButtons(actions, lastActionInfo) 196 197 def GetObjectiveHTML(self, lastActionInfo): 198 objectiveData = self.GetAgentMoniker().GetMissionObjectiveInfo() 199 if objectiveData and not (lastActionInfo['missionCompleted'] or lastActionInfo['missionDeclined'] or lastActionInfo['missionQuit'] or lastActionInfo['missionCantReplay']): 200 return self._GetObjectiveHTML(objectiveData) 201 else: 202 return None 203 204 def _GetObjectiveHTML(self, objectiveData): 205 return '\n <html>\n <head>\n <link rel="stylesheet" type="text/css" href="res:/ui/css/missionobjectives.css">\n </head>\n <body>\n %s\n </body>\n </html>\n ' % agentDialogueUtil.GetMissionObjectiveHTML(self.GetAgentID(), objectiveData) 206 207 def GetBriefingHTML(self, actions, agentSaysText, lastActionInfo): 208 agentHeader = self.GetAgentHeader(lastActionInfo) 209 briefingData = sm.GetService('agents').GetMissionBriefingInfo(self.GetAgentID()) 210 missionTitle = self._GetMissionTitleHTML(briefingData) if briefingData else '' 211 replayTimer = '' 212 timeLeft = lastActionInfo.get('missionCantReplay', None) 213 if timeLeft: 214 agentSaysText = self._GetNoMissionMessage(timeLeft) 215 replayTimer = localization.GetByLabel('UI/Agents/DefaultMessages/MissionCantReplay', timeLeft=FmtTimeInterval(timeLeft, breakAt='min' if timeLeft > MIN else 'sec'), timerColor=SUCCESS_GREEN_HEX) 216 replayTimer = '<br>' + replayTimer 217 replayTimer = replayTimer.replace('<color=', '<font color=') 218 replayTimer = replayTimer.replace('</color>', '</font>') 219 extraMissionInfoHTML = None 220 else: 221 specialInteractionActions = [ (actionID, actionData) for actionID, actionData in actions if type(actionData) == dict ] 222 extraMissionInfoHTML = self.GetExtraMissionInfoHTML(specialInteractionActions, briefingData) 223 adminHTML = self.GetAdminHTML(actions) 224 return self._GetBriefingHTML(agentHeader, missionTitle, agentSaysText, replayTimer, extraMissionInfoHTML, adminHTML) 225 226 def _GetNoMissionMessage(self, timeLeft): 227 if self.agentDivisionID and self.agentDivisionID == appConst.corpDivisionHeraldry: 228 if timeLeft: 229 label = 'UI/Agents/DefaultMessages/NoMissionHeraldryTimer' 230 else: 231 label = 'UI/Agents/DefaultMessages/NoMissionHeraldry' 232 else: 233 label = choice(['UI/Agents/DefaultMessages/NoMission1', 'UI/Agents/DefaultMessages/NoMission2']) 234 return localization.GetByLabel(label) 235 236 def _GetBriefingHTML(self, agentHeader, missionTitle, agentSaysText, replayTimer, extraMissionInfoHTML, adminHTML): 237 body = '' 238 for item in [agentHeader, 239 missionTitle, 240 agentSaysText, 241 replayTimer, 242 extraMissionInfoHTML, 243 adminHTML]: 244 if item: 245 if body: 246 body += '<br>' 247 body += unicode(item) 248 249 return '\n <html>\n <head>\n <link rel="stylesheet" type="text/css" href="res:/ui/css/agentconvo.css">\n </head>\n <body background-color=#00000000 link=#ffa800>\n %s\n </body>\n </html>\n ' % body 250 251 def GetAgentHeader(self, lastActionInfo): 252 lp = lastActionInfo.get('loyaltyPoints', 0) 253 agentLocationWrap = self.GetAgentMoniker().GetAgentLocationWrap() 254 agent = sm.GetService('agents').GetAgentByID(self.GetAgentID()) 255 agentHeader = agentDialogueUtil.GetAgentLocationHeader(agent, agentLocationWrap, lp) 256 return agentHeader 257 258 def GetExtraMissionInfoHTML(self, specialInteractionActions, briefingInformation): 259 extraMissionInfo = '' 260 if specialInteractionActions: 261 extraMissionInfo += self.GetSpecialInteractionHTML(specialInteractionActions) 262 elif briefingInformation: 263 extraMissionInfo += self.GetMissionTimeHTML(briefingInformation) 264 extraMissionInfo += '<br><center>%s</center>' % briefingInformation[appConst.agentMissionBriefingImage] 265 return extraMissionInfo 266 267 def GetMissionTimeHTML(self, briefingInformation): 268 missionTimeText = self.GetMissionTimeText(briefingInformation) 269 if missionTimeText: 270 return '<br>%s' % missionTimeText 271 else: 272 return '' 273 274 def GetSpecialInteractionHTML(self, specialInteractionActions): 275 specialInteractionHTML = '' 276 for actionID, briefingData in specialInteractionActions: 277 sm.GetService('agents').PrimeMessageArguments(self.GetAgentID(), briefingData[appConst.agentMissionBriefingMissionID], briefingData[appConst.agentMissionBriefingKeywords]) 278 message = (briefingData[appConst.agentMissionBriefingTitleID], briefingData[appConst.agentMissionBriefingMissionID]) 279 missionTitle = self.GetMessageText(message) 280 specialInteractionHTML += '\n <span id=subheader><a href="localsvc:method=AgentDoAction&agentID=%d&actionID=%d">%s</a> >></span><br>\n ' % (self.GetAgentID(), actionID, missionTitle) 281 if briefingData[appConst.agentMissionBriefingBriefingID] is not None: 282 if isinstance(briefingData[appConst.agentMissionBriefingBriefingID], basestring) or briefingData[appConst.agentMissionBriefingBriefingID] > 0: 283 message = (briefingData[appConst.agentMissionBriefingBriefingID], briefingData[appConst.agentMissionBriefingMissionID]) 284 briefingText = self.GetMessageText(message) 285 else: 286 briefingText = localization.GetByLabel('UI/Agents/Dialogue/StandardMission/CorruptBriefing') 287 specialInteractionHTML += '\n <div id=basetext>%s</div>\n <br>\n ' % briefingText 288 289 return specialInteractionHTML 290 291 def _GetMissionTitleHTML(self, briefingData): 292 message = (briefingData[appConst.agentMissionBriefingTitleID], briefingData[appConst.agentMissionBriefingMissionID]) 293 missionTitle = self.GetMessageText(message) 294 return '<br><span id=subheader>%s</span><br>' % missionTitle 295 296 def GetMessageText(self, message): 297 return sm.GetService('agents').ProcessMessage(message, self.GetAgentID()) 298 299 def GetMissionTimeText(self, briefingInformation): 300 if briefingInformation[appConst.agentMissionBriefingDeclineTime] is not None: 301 if briefingInformation[appConst.agentMissionBriefingDeclineTime] == -1: 302 return localization.GetByLabel('UI/Agents/StandardMission/DeclineMessageGeneric') 303 else: 304 timeRemaining = briefingInformation[appConst.agentMissionBriefingDeclineTime] 305 timeBreakAt = 'min' if timeRemaining > appConst.MIN else 'sec' 306 return localization.GetByLabel('UI/Agents/StandardMission/DeclineMessageTimeLeft', timeRemaining=FmtTimeInterval(timeRemaining, breakAt=timeBreakAt)) 307 elif briefingInformation[appConst.agentMissionBriefingExpirationTime] is not None: 308 return localization.GetByLabel('UI/Agents/Dialogue/ThisMissionExpiresAt', expireTime=briefingInformation[appConst.agentMissionBriefingExpirationTime]) 309 310 def ReconstructButtons(self, actions, lastActionInfo): 311 self.buttonGroup.FlushButtons() 312 cantReplay = lastActionInfo.get('missionCantReplay', None) 313 if not cantReplay: 314 for actionID, actionData in actions: 315 if type(actionData) is int: 316 label, func, kwargs = self._GetActionButtonData(actionData, actionID) 317 self.buttonGroup.AddButton(label, func, **kwargs) 318 319 appendCloseButton = not self.buttonGroup.buttons or any((self._IsCloseButtonAction(actionData) for actionID, actionData in actions)) 320 if appendCloseButton and len(self.buttonGroup.buttons) < 3: 321 self.buttonGroup.AddButton(localization.GetByLabel('UI/Common/Buttons/Close'), self.CloseByUser, uiName='CloseAgentConversation_Button') 322 job = get_agent_mission_job(self.agentID, wait=False) 323 if job: 324 TrackJobButton(parent=self.buttonGroup, job=job) 325 self.buttonGroup.state = uiconst.UI_PICKCHILDREN 326 327 def GetAdminHTML(self, actions): 328 adminHTML = '' 329 adminOptions = self._GetAdminOptions(actions) 330 if adminOptions: 331 if len(adminOptions) == 1: 332 adminHTML = '<br>' 333 adminHTML += adminOptions[0] 334 else: 335 adminHTML = '<ol>' 336 adminHTML += ''.join([ '<br><li>%s</li>' % x for x in adminOptions ]) 337 adminHTML += '</ol>' 338 return adminHTML 339 340 def _GetAdminOptions(self, actions): 341 adminOptions = [] 342 for actionID, actionData in actions: 343 if type(actionData) in (str, unicode): 344 adminOptions.append('<a href="localsvc:method=AgentDoAction&agentID=%d&actionID=%d">%s</a>' % (self.GetAgentID(), actionID, actionData)) 345 346 return adminOptions 347 348 def _GetActionButtonData(self, actionData, actionID): 349 labelPath = LABEL_BY_BUTTON_TYPE.get(actionData, None) 350 if labelPath: 351 label = localization.GetByLabel(labelPath) 352 else: 353 logger.error('Unknown button ID for agent action, id =', actionData) 354 label = 'Unknown ID ' + str(actionData) 355 btnData = (label, sm.GetService('agents').DoAction, {'args': (self.GetAgentID(), actionID), 356 'uiName': u'{}_Button'.format(labelPath.split('/')[-1])}) 357 return btnData 358 359 def _IsCloseButtonAction(self, actionData): 360 return actionData in (appConst.agentDialogueButtonRequestMission, 361 appConst.agentDialogueButtonContinue, 362 appConst.agentDialogueButtonQuit, 363 appConst.agentDialogueButtonCancelResearch) 364 365 def _GetConversation(self, actionID): 366 (agentSaysMsg, availableActions), lastActionInfo = self.ExecuteAgentAction(actionID) 367 if actionID is None and len(availableActions): 368 firstAction = availableActions[0] 369 firstActionID, firstActionMsg = firstAction 370 if firstActionMsg in (appConst.agentDialogueButtonRequestMission, appConst.agentDialogueButtonViewMission) and (len(availableActions) == 1 or not self._IsLocatorAgent(availableActions) and not self._IsResearchAgent()): 371 (agentSaysMsg, availableActions), lastActionInfo = self.ExecuteAgentAction(firstActionID) 372 agentSaysText = self.GetMessageText(agentSaysMsg) 373 return (agentSaysText, availableActions, lastActionInfo) 374 375 def _IsResearchAgent(self): 376 isResearchAgent = False 377 if sm.GetService('agents').GetAgentByID(self.GetAgentID()).agentTypeID == appConst.agentTypeResearchAgent: 378 isResearchAgent = True 379 return isResearchAgent 380 381 def _IsLocatorAgent(self, availableActions): 382 agentHasLocatorService = False 383 for id, dlg in availableActions: 384 if dlg == appConst.agentDialogueButtonLocateCharacter: 385 agentHasLocatorService = True 386 387 return agentHasLocatorService 388 389 def ExecuteAgentAction(self, actionID): 390 return self.GetAgentMoniker().DoAction(actionID) 391 392 def ShowMissionObjectives(self, contentID): 393 objectiveData = self.GetAgentMoniker().GetMissionObjectiveInfo(session.charid, contentID) 394 if not self.destroyed: 395 if objectiveData: 396 objectiveHtml = self._GetObjectiveHTML(objectiveData) 397 self.SetDoublePaneView(objectiveHtml=objectiveHtml) 398 else: 399 self.SetSinglePaneView()