characterCreationContainer_new.py (67012B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\login\characterCreationContainer_new.py 2 import logging 3 import math 4 import random 5 import time 6 import types 7 import blue 8 import telemetry 9 import carbonui.const as uiconst 10 import charactercreator.client.animparams as animparams 11 import charactercreator.client.characterCreationMetrics as ccm 12 import charactercreator.client.scalingUtils as ccScalingUtils 13 import charactercreator.const as ccConst 14 import eve.common.lib.appConst as const 15 import evegraphics.settings as gfxsettings 16 import everesourceprefetch 17 import gatekeeper 18 import geo2 19 import localization 20 import paperdoll 21 import trinity 22 import uthread 23 from carbon.client.script.environment.AudioUtil import PlaySound 24 from carbonui.control.button import Button 25 from carbonui.control.buttonIcon import ButtonIcon 26 from carbonui.primitives.container import Container 27 from carbonui.primitives.fill import Fill 28 from carbonui.uianimations import animations 29 from carbonui.uicore import uicore 30 from carbonui.util.bunch import Bunch 31 from charactercreator.client.characterCreationSteps_new import ModeStorage, GetStepOrder, GetStepsUpToAndIncluding 32 from charactercreator.client.logging.stepLogger import StepLogger 33 from charactercreator.const import FINALIZE_BUTTON_ANALYTIC_ID, NEXT_BUTTON_ANALYTIC_ID, BACK_BUTTON_ANALYTIC_ID 34 from characterdata.races import CHARACTER_CREATION_RACE_IDS 35 from eve.client.script.ui.camera.charCreationCamera import CONTROL_NONE 36 from eve.client.script.ui.login.charcreation_new import charCreationSignals, soundConst 37 from eve.client.script.ui.login.charcreation_new.charCreationButtons import EXIT_BUTTON_SIZE 38 from eve.client.script.ui.login.charcreation_new.dollManager import GetCharacterCreationDollManager 39 from eve.client.script.ui.login.charcreation_new.loadingWheel import CharacterCreationLoadingWheel 40 from eve.client.script.ui.login.charcreation_new.portraitManager import GetCharacterCreationPortraitManager 41 from eve.client.script.ui.login.charcreation_new.sceneManager import GetCharacterCreationSceneManager 42 from eve.client.script.ui.login.charcreation_new.steps.characterCustomization import CharacterCustomization 43 from eve.client.script.ui.login.charcreation_new.steps.characterNaming import CharacterNaming 44 from eve.client.script.ui.login.charcreation_new.steps.characterPortrait import CharacterPortrait 45 from eve.client.script.ui.login.charcreation_new.steps.dollSelection.characterDollSelection import CharacterDollSelection 46 from eve.client.script.ui.login.charcreation_new.steps.empireSelectionStep import EmpireSelectionStep 47 from eve.client.script.ui.shared.colorThemes import DEFAULT_COLORTHEMEID, COLOR_THEME_ID_BY_RACE 48 from eve.client.script.ui.util.disconnectNotice import DisconnectNotice 49 from eve.common.lib import appConst 50 from eveexceptions import UserError 51 from eveprefs import prefs, boot 52 from locks import TempLock 53 from player_messaging.client.ui_message import prompt_player_fsd_dialog 54 from storylines.client.airnpe import is_air_npe_enabled 55 NETWORKMODE_BASIC = 1 56 NETWORKMODE_PORTRAIT = 2 57 LEFT_SIDE_WITH = 180 58 LEFT_SIDE_HEIGHT = 400 59 RIGHT_SIDE_WIDTH = 350 60 RIGHT_SIDE_HEIGHT = 150 61 BOTTOM_LEFT_SIDE_WIDTH = 220 62 BOTTOM_LEFT_SIDE_HEIGHT = ccConst.BUTTON_AREA_HEIGHT 63 BUTTON_WIDTH = 145 64 BUTTON_HEIGHT = 36 65 BUTTON_HEIGHT_PRIMARY = 50 66 BUTTON_WIDTH_PRIMARY = 200 67 BUTTON_FONT_SIZE = 18 68 BACKGROUND_TRANSITION_SECONDS = 2.5 69 RESOURCE_WHEEL_SEPARATION = 8 70 DOLLSTATES_TO_RETURN_TO_CC = [paperdoll.State.no_existing_customization, paperdoll.State.force_recustomize] 71 RACE_TO_RESOURCE_NAME = {const.raceCaldari: 'caldari', 72 const.raceAmarr: 'amarr', 73 const.raceMinmatar: 'minmatar', 74 const.raceGallente: 'gallente'} 75 TOP_NAVIGATION_LINE_HEIGHT = 1 76 BOTTOM_NAVIGATION_LINE_HEIGHT = 1 77 TOP_NAVIGATION_LINE_OPACITY = 0.25 78 BOTTOM_NAVIGATION_LINE_OPACITY = 0.25 79 EXIT_BUTTON_MARGIN = 10 80 BG_OPACITY = 1.0 81 BG_WIDTH = 2117 82 BG_HEIGHT = 1200 83 VIGNETTE_RGB_DATA = ((0.0, (0.0, 0.0, 0.0)), (0.5, (0.0, 0.0, 0.0)), (1.0, (0.0, 0.0, 0.0))) 84 VIGNETTE_ALPHA_DATA = ((0.0, 0.0), (0.8, 0.5), (1.0, 1.0)) 85 VIGNETTE_OPACITY = 0.7 86 logger = logging.getLogger(__name__) 87 88 class CharacterData(object): 89 90 def __init__(self, charID): 91 self.charID = charID 92 self.bloodlineID = None 93 self.genderID = None 94 self.dna = None 95 96 97 class CharacterCreationContainer_new(Container): 98 __notifyevents__ = ['OnSetDevice', 99 'OnGraphicSettingsChanged', 100 'OnHideUI', 101 'OnShowUI', 102 'OnDollUpdated', 103 'OnMapShortcut', 104 'OnUIRefresh', 105 'OnDisconnect'] 106 __update_on_reload__ = 1 107 108 def ApplyAttributes(self, attributes): 109 super(CharacterCreationContainer_new, self).ApplyAttributes(attributes) 110 sm.RegisterNotify(self) 111 self.sceneManager = GetCharacterCreationSceneManager() 112 self.portraitManager = GetCharacterCreationPortraitManager() 113 self.dollManager = GetCharacterCreationDollManager() 114 self.needSculptingTutorial = True 115 self.needNavigationTutorial = True 116 self.dollSelected = False 117 self.customizationStepSkipped = False 118 self.step = None 119 self.vignette = None 120 self.exitButton = None 121 self._characterData = {} 122 self._activeCharID = None 123 self._spareCharID = ccConst.SPARE_CHAR_ID 124 self._characterData[self._spareCharID] = CharacterData(self._spareCharID) 125 self._dollsDirty = False 126 charCreationSignals.onEmpireFactionSelected.connect(self.OnEmpireFactionSelected) 127 128 def SetNameCallback(self, name): 129 self.charName = name 130 131 @telemetry.ZONE_METHOD 132 def OnSetDevice(self, *args): 133 self.UpdateLayout() 134 self.portraitManager.UpdateBackdrop() 135 136 def OnDisconnect(self, reason = 0, msg = ''): 137 disconnectNotice = DisconnectNotice(logProvider=self) 138 disconnectNotice.OnDisconnect(reason, msg) 139 140 @telemetry.ZONE_METHOD 141 def UpdateLayout(self): 142 try: 143 self.LockEverything() 144 with TempLock('CharacterCreationLayerUpdate'): 145 for each in self.mainCont.children: 146 if hasattr(each, 'UpdateLayout'): 147 each.UpdateLayout() 148 149 desktopWidth = uicore.desktop.width 150 self.topNavigationContainer.width = desktopWidth 151 self.topNavigationContainer.height = ccScalingUtils.GetTopNavHeight() 152 finally: 153 self.UnlockEverything() 154 155 @telemetry.ZONE_METHOD 156 def OnOpenView(self, **kwargs): 157 self.startTime = blue.os.GetWallclockTime() 158 self.sceneManager.Initialize() 159 self.portraitManager.Initialize() 160 uicore.cmd.commandMap.UnloadAllAccelerators() 161 uicore.cmd.commandMap.LoadAcceleratorsByCategory('general') 162 uicore.cmd.commandMap.LoadAcceleratorsByCategory('charactercreator') 163 self.freezingAnimation = False 164 from eve.client.script.ui.shared.preview import PreviewCharacterWnd, PreviewWnd 165 previewCharWnd = PreviewCharacterWnd.GetIfOpen() 166 if previewCharWnd: 167 self.previewCharWindowWasOpenOn = (previewCharWnd.charID, previewCharWnd.dna) 168 previewCharWnd.CloseByUser() 169 else: 170 self.previewCharWindowWasOpenOn = None 171 previewWnd = PreviewWnd.GetIfOpen() 172 if previewWnd: 173 self.previewWindowWasOpenOn = previewWnd.typeID 174 previewWnd.CloseByUser() 175 else: 176 self.previewWindowWasOpenOn = None 177 self.characterSvc = sm.GetService('character') 178 self.sceneManagerSvc = sm.GetService('sceneManager') 179 self.fastCharacterCreation = gfxsettings.Get(gfxsettings.GFX_CHAR_FAST_CHARACTER_CREATION) 180 self.mode = ccConst.MODE_FULLINITIAL_CUSTOMIZATION 181 self.modeStorage = ModeStorage() 182 self.modeObject = self.modeStorage.GetModeFor(self.mode) 183 self.dollSelected = False 184 self.customizationStepSkipped = False 185 self.raceID = None 186 self.schoolID = None 187 self.charName = '' 188 sm.GetService('cc').ClearMyAvailabelTypeIDs() 189 self._stepID = None 190 self.floor = None 191 self.showingHelp = 0 192 self.topNavigationContainer = None 193 self.CreateUI() 194 self.technologyViewsTracker = None 195 self.audioService = sm.GetService('audio') 196 self.worldLevel = self.audioService.GetWorldVolume() 197 self.audioService.SetWorldVolume(0.0) 198 self.stepLogger = StepLogger(blue.os.GetWallclockTime) 199 self.finalStepLogger = None 200 self.metrics = None 201 self.approve_in_progress = False 202 self.save_in_progress = False 203 charCreationSignals.onDollSelectionRandomizeStarting.connect(self.OnDollRandomizeStarting) 204 charCreationSignals.onDollSelectionDollRandomized.connect(self.OnDollRandomized) 205 206 def Finalize(self): 207 self.Save() 208 209 def CreateLoadingWheel(self): 210 self.loadingWheel = CharacterCreationLoadingWheel(name='loadingWheel', parent=self, align=uiconst.CENTER, state=uiconst.UI_NORMAL) 211 self.loadingWheel.forcedOn = 0 212 213 def CreateUI(self): 214 self.uiContainer = Container(name='uiContainer', parent=self, align=uiconst.TOALL) 215 self.CreateLoadingWheel() 216 self.leftSide = Container(name='leftSide', parent=self.uiContainer, align=uiconst.TOPLEFT, pos=(0, 217 0, 218 LEFT_SIDE_WITH, 219 LEFT_SIDE_HEIGHT)) 220 self.rightSide = Container(name='rightSide', parent=self.uiContainer, align=uiconst.BOTTOMRIGHT, pos=(0, 221 BOTTOM_LEFT_SIDE_HEIGHT - BUTTON_HEIGHT, 222 RIGHT_SIDE_WIDTH, 223 RIGHT_SIDE_HEIGHT)) 224 self.bottomLeftSide = Container(name='bottomLeftSide', parent=self.uiContainer, align=uiconst.BOTTOMLEFT, pos=(0, 225 0, 226 BOTTOM_LEFT_SIDE_WIDTH, 227 BOTTOM_LEFT_SIDE_HEIGHT)) 228 self.buttonNavLeft = Container(name='buttonNavLeft', parent=self.bottomLeftSide, align=uiconst.TOTOP, height=BUTTON_HEIGHT, padLeft=10) 229 self.buttonNavRight = Container(name='buttonNavRight', parent=self.rightSide, align=uiconst.TOBOTTOM, height=BUTTON_HEIGHT_PRIMARY, padRight=20) 230 self.finalizeBtn = Button(name='finalizeButtonCC', parent=self.buttonNavRight, align=uiconst.TORIGHT, label=localization.GetByLabel('UI/CharacterCreation/EnterGame'), func=self.Finalize, left=10, args=(), state=uiconst.UI_HIDDEN) 231 self.saveBtn = Button(name='saveButtonCC', parent=self.buttonNavRight, align=uiconst.TORIGHT, label=localization.GetByLabel('UI/CharacterCreation/Finalize'), func=self.Save, left=10, args=(), state=uiconst.UI_HIDDEN, analyticID=FINALIZE_BUTTON_ANALYTIC_ID) 232 self.approveBtn = Button(name='nextButtonCC', parent=self.buttonNavRight, align=uiconst.TORIGHT, label=localization.GetByLabel('UI/Generic/Next'), func=self.Approve, left=10, args=()) 233 self.backBtn = Button(name='backButtonCC', parent=self.buttonNavLeft, align=uiconst.TOLEFT, label=localization.GetByLabel('UI/Commands/Back'), func=self.Back, args=(), left=10) 234 self.blackOut = Fill(name='blackOutFill', parent=self, color=(0.0, 0.0, 0.0, 0.0)) 235 self.mainCont = Container(name='mainCont', parent=self, align=uiconst.TOALL) 236 self.topNavigationContainer = Container(name='topNavigationContainer', parent=self.uiContainer, align=uiconst.TOTOP_NOPUSH, width=self.uiContainer.width, height=ccScalingUtils.GetTopNavHeight(), bgColor=(0.0, 0.0, 0.0, 1.0)) 237 self.topNavigationContainer.SetOrder(1) 238 self.UpdateLayout() 239 240 def OnAvailabilityCheck(self, name): 241 if self.finalStepLogger: 242 self.finalStepLogger.AddTriedName(name) 243 244 def OnUIRefresh(self): 245 while self.dollManager.GetDoll(self._activeCharID) is None and self.dollManager.GetDoll(self._activeCharID).IsBusyUpdating(): 246 blue.synchro.Yield() 247 248 self.Flush() 249 self.CreateUI() 250 self.SwitchStep(self.stepID) 251 252 def OnHelpMouseEnter(self, btn, *args): 253 PlaySound('ui_icc_button_mouse_over_play') 254 btn.sr.icon.SetAlpha(1.0) 255 256 def OnHelpMouseExit(self, btn, *args): 257 if not self.showingHelp: 258 btn.sr.icon.SetAlpha(0.5) 259 260 def SetHintText(self, modifier, hintText = ''): 261 if self.stepID in (ccConst.CUSTOMIZATIONSTEP, ccConst.PORTRAITSTEP): 262 self.step.SetHintText(modifier, hintText) 263 264 def SetMode(self, modeID): 265 self.mode = modeID 266 self.modeObject = self.modeStorage.GetModeFor(modeID) 267 268 def GetModeIDForDollState(self, dollState): 269 mode = ccConst.MODE_LIMITED_RECUSTOMIZATION 270 if dollState == paperdoll.State.full_recustomizing: 271 mode = ccConst.MODE_FULL_BLOODLINECHANGE 272 elif dollState in (paperdoll.State.resculpting, paperdoll.State.no_existing_customization, paperdoll.State.force_recustomize): 273 mode = ccConst.MODE_FULL_RECUSTOMIZATION 274 return mode 275 276 def GetActiveCharacterData(self): 277 return self._characterData[self._activeCharID] 278 279 def SetBloodline(self, charID, bloodlineID): 280 self._characterData[charID].bloodlineID = bloodlineID 281 282 def SetActiveBloodline(self, bloodlineID): 283 self._characterData[self._activeCharID].bloodlineID = bloodlineID 284 285 def SetActiveGender(self, genderID): 286 self._characterData[self._activeCharID].genderID = genderID 287 288 @telemetry.ZONE_METHOD 289 def SetCharDetails(self, charID = None, gender = None, raceID = None, bloodlineID = None, dollState = None): 290 self.portraitManager.ClearFacePortrait() 291 self.dollState = dollState 292 self.raceID = raceID 293 self._activeCharID = 0 294 self._characterData[0] = CharacterData(0) 295 if charID is not None: 296 if charID not in self._characterData: 297 self._characterData[charID] = CharacterData(charID) 298 self._characterData[charID].bloodlineID = bloodlineID 299 self._characterData[charID].genderID = int(gender) 300 self._activeCharID = charID 301 if dollState not in (paperdoll.State.force_recustomize, paperdoll.State.no_existing_customization): 302 self._characterData[self._activeCharID].dna = sm.GetService('paperdoll').GetMyPaperDollData(self._activeCharID) 303 mode = self.GetModeIDForDollState(dollState) 304 else: 305 mode = ccConst.MODE_FULLINITIAL_CUSTOMIZATION 306 self.SetMode(mode) 307 self.availableSteps = self.modeObject.GetSteps() 308 stepID = self.availableSteps[0] 309 self.stepsUsed = {stepID} 310 self.mainCont.Flush() 311 self.stepLogger.Start() 312 if dollState in (paperdoll.State.force_recustomize, paperdoll.State.no_existing_customization) or mode == ccConst.MODE_FULLINITIAL_CUSTOMIZATION: 313 self.metrics = ccm.CharacterCreationMetrics(mode, ccConst.LOGIN) 314 else: 315 self.metrics = ccm.CharacterCreationMetrics(mode, ccConst.HANGAR) 316 self.needSculptingTutorial = self.CanChangeBaseAppearance() 317 if self.raceID is None: 318 self._ChangeRace(self._GetRandomRaceID()) 319 if self.GetActiveCharacterData().bloodlineID is None or self.GetActiveCharacterData().genderID is None: 320 self.SetActiveBloodline(self.SelectRandomBloodline()) 321 self.SetActiveGender(self.SelectRandomGender()) 322 self.SwitchStep(stepID) 323 324 @telemetry.ZONE_METHOD 325 def GetInfo(self): 326 data = self.GetActiveCharacterData() 327 return Bunch(charID=self._activeCharID, raceID=self.raceID, bloodlineID=data.bloodlineID, genderID=data.genderID, dna=data.dna, schoolID=self.schoolID, stepID=self.stepID, charName=self.charName) 328 329 def CanChangeBaseAppearance(self, *args): 330 return self.modeObject.CanChangeBaseAppearance() 331 332 def GetMode(self, *args): 333 return self.mode 334 335 def CanChangeBloodline(self, *args): 336 return self.modeObject.CanChangeBloodLine() 337 338 def CanChangeGender(self, *args): 339 return self.modeObject.CanChangeGender() 340 341 def CanChangeName(self, *args): 342 return self.modeObject.CanChangeName() 343 344 def _AddExitButton(self, toStep): 345 if self.exitButton and not self.exitButton.destroyed: 346 self.exitButton.Close() 347 self.exitButton = ButtonIcon(name='exitButton', parent=self.topNavigationContainer, func=self.CancelCharacterCreation, texturePath='res:/UI/Texture/Icons/73_16_45.png', align=uiconst.TOPRIGHT, left=EXIT_BUTTON_MARGIN, top=EXIT_BUTTON_MARGIN, width=EXIT_BUTTON_SIZE, height=EXIT_BUTTON_SIZE, idx=0) 348 349 def ConstructNavigationIfNeeded(self, toStep): 350 self._AddExitButton(toStep) 351 self.topNavigationContainer.Hide() 352 sm.GetService('gameui').MoveResourceLoadingIndicator(newAlignment=uiconst.BOTTOMLEFT, newLeft=20, newTop=RESOURCE_WHEEL_SEPARATION + ccConst.BUTTON_AREA_HEIGHT) 353 354 @telemetry.ZONE_METHOD 355 def SwitchStep(self, toStep, *args): 356 if GetStepOrder(toStep) > GetStepOrder(self.stepID): 357 if not self.PassedStepCheck(toStep): 358 return 359 try: 360 self.LockEverything() 361 self.backBtn.state = uiconst.UI_NORMAL 362 charCreationSignals.onStepSwitched(self.stepID, toStep) 363 self.FadeToBlack(why=localization.GetByLabel('UI/Generic/Loading')) 364 with TempLock('CharacterCreationLayerUpdate'): 365 self.UnfreezeAnimationIfNeeded() 366 self.BlockOnUpdate() 367 self.ConstructNavigationIfNeeded(toStep) 368 if self.stepID == ccConst.CUSTOMIZATIONSTEP: 369 sm.StartService('audio').SendUIEvent(unicode('ui_icc_sculpting_mouse_over_loop_stop')) 370 self.step.StoreHistorySliderPosition() 371 elif self.stepID == ccConst.PORTRAITSTEP: 372 sm.StartService('audio').SendUIEvent(unicode('ui_icc_sculpting_mouse_over_loop_stop')) 373 self.sceneManager.StorePortraitCameraSettings() 374 self.step = None 375 raceTheme = COLOR_THEME_ID_BY_RACE.get(self.raceID, DEFAULT_COLORTHEMEID) 376 sm.GetService('uiColor').SetNoCharTheme(raceTheme) 377 self.BlockOnUpdate() 378 self._UpdateNavigationButtons(toStep) 379 self.mainCont.Flush() 380 self.Cleanup() 381 self.BlockOnUpdate() 382 self.metrics.new_page(toStep) 383 self.StartStep(toStep) 384 self.stepID = toStep 385 self.stepsUsed.add(toStep) 386 self.portraitManager.UpdateBackdrop() 387 finally: 388 self.UnlockEverything() 389 self.setupDone = 1 390 self.FadeFromBlack() 391 self.UnfreezeAnimationIfNeeded() 392 sm.ScatterEvent('OnCharacterCreationStep', self.stepID, toStep) 393 394 @property 395 def stepID(self): 396 return self._stepID 397 398 @stepID.setter 399 def stepID(self, newStepID): 400 self._stepID = newStepID 401 self.UpdateButtonAnalyticIDs(newStepID) 402 403 def UpdateButtonAnalyticIDs(self, newStepID): 404 self.backBtn.analyticID = BACK_BUTTON_ANALYTIC_ID % newStepID 405 self.approveBtn.analyticID = NEXT_BUTTON_ANALYTIC_ID % newStepID 406 407 def BlockOnUpdate(self): 408 info = self.GetInfo() 409 characters = self.characterSvc.characters 410 if info.charID in characters and self.characterSvc.GetSingleCharactersDoll(info.charID).busyUpdating: 411 start_time = time.clock() 412 while self.characterSvc.GetSingleCharactersDoll(info.charID).busyUpdating and time.clock() - start_time < 60: 413 blue.synchro.Yield() 414 415 if self.characterSvc.GetSingleCharactersDoll(info.charID).busyUpdating: 416 raise UserError('uiwarning01') 417 418 def _UpdateNavigationButtons(self, toStep): 419 self.approveBtn.Show() 420 self.backBtn.Show() 421 isGoingToFinalStep = toStep == self.availableSteps[-1] 422 if toStep == ccConst.EMPIRESTEP: 423 self.approveBtn.state = uiconst.UI_HIDDEN 424 self.finalizeBtn.state = uiconst.UI_HIDDEN 425 self.saveBtn.state = uiconst.UI_HIDDEN 426 elif isGoingToFinalStep: 427 self.approveBtn.state = uiconst.UI_HIDDEN 428 isNewChar = self._activeCharID in (ccConst.DEFAULT_CHAR_ID, ccConst.SPARE_CHAR_ID) 429 if isNewChar: 430 self.finalizeBtn.state = uiconst.UI_HIDDEN 431 self.saveBtn.state = uiconst.UI_HIDDEN 432 else: 433 self.finalizeBtn.state = uiconst.UI_HIDDEN 434 self.saveBtn.state = uiconst.UI_NORMAL 435 elif toStep == ccConst.DOLLSTEP: 436 self.finalizeBtn.state = uiconst.UI_HIDDEN 437 self.saveBtn.state = uiconst.UI_HIDDEN 438 self.approveBtn.state = uiconst.UI_HIDDEN 439 else: 440 self.approveBtn.state = uiconst.UI_NORMAL 441 self.finalizeBtn.state = uiconst.UI_HIDDEN 442 self.saveBtn.state = uiconst.UI_HIDDEN 443 444 def _HideBackButtonIfNoCharacters(self): 445 if not sm.GetService('cc').GetCharactersToSelect(): 446 self.backBtn.Hide() 447 448 def StartStep(self, toStep): 449 self.stepLogger.SetStep(toStep) 450 if toStep == ccConst.EMPIRESTEP: 451 self.StartEmpireSelectionStep() 452 elif toStep == ccConst.CUSTOMIZATIONSTEP: 453 self.StartCustomizationStep() 454 elif toStep == ccConst.PORTRAITSTEP: 455 self.StartPortraitStep() 456 elif toStep == ccConst.NAMINGSTEP: 457 self.StartNamingStep() 458 elif toStep == ccConst.DOLLSTEP: 459 self.StartDollSelectionStep() 460 else: 461 raise NotImplementedError() 462 463 def StartEmpireSelectionStep(self): 464 self.dollSelected = False 465 self.raceID = None 466 self.schoolID = None 467 self.step = EmpireSelectionStep(parent=self.mainCont) 468 charCreationSignals.onEmpireFactionButtonClicked.connect(self.OnEmpireFactionButtonClicked) 469 charCreationSignals.onEmpireSchoolButtonClicked.connect(self.SelectSchool) 470 charCreationSignals.onEmpireSchoolSelected.connect(self.OnEmpireSchoolSelected) 471 472 def OnEmpireFactionSelected(self, factionID): 473 if self.sceneManager.avatarScene is not None: 474 self._dollsDirty = True 475 476 def OnEmpireFactionButtonClicked(self, factionID): 477 raceID = appConst.raceByFaction[factionID] 478 if raceID != self.raceID: 479 self.SelectRace(raceID) 480 self.PlayFactionSelectionSound(factionID) 481 482 def PlayFactionSelectionSound(self, factionID): 483 soundPath = '' 484 if factionID == appConst.factionCaldariState: 485 soundPath = soundConst.CALDARI_SELECTION_LOOP 486 elif factionID == appConst.factionAmarrEmpire: 487 soundPath = soundConst.AMARR_SELECTION_LOOP 488 elif factionID == appConst.factionGallenteFederation: 489 soundPath = soundConst.GALLENTE_SELECTION_LOOP 490 elif factionID == appConst.factionMinmatarRepublic: 491 soundPath = soundConst.MINMATAR_SELECTION_LOOP 492 if not soundPath: 493 return 494 PlaySound(soundPath) 495 496 def StopFactionSelectionSound(self): 497 factionID = appConst.factionByRace.get(self.raceID, None) 498 soundPath = '' 499 if factionID == appConst.factionCaldariState: 500 soundPath = soundConst.CALDARI_SELECTION_LOOP_STOP 501 elif factionID == appConst.factionAmarrEmpire: 502 soundPath = soundConst.AMARR_SELECTION_LOOP_STOP 503 elif factionID == appConst.factionGallenteFederation: 504 soundPath = soundConst.GALLENTE_SELECTION_LOOP_STOP 505 elif factionID == appConst.factionMinmatarRepublic: 506 soundPath = soundConst.MINMATAR_SELECTION_LOOP_STOP 507 if not soundPath: 508 return 509 PlaySound(soundPath) 510 511 def OnEmpireSchoolSelected(self, schoolID): 512 if schoolID: 513 self.AnimShowApproveButton() 514 else: 515 self.approveBtn.Hide() 516 517 def OnDollSelectionDollClicked(self, charID): 518 if charID is not None: 519 self.SelectDoll(charID) 520 521 def AnimShowApproveButton(self): 522 self.approveBtn.state = uiconst.UI_NORMAL 523 animations.FadeTo(self.approveBtn, 0.0, 1.0, duration=0.3, timeOffset=1.0, callback=self.approveBtn.Enable) 524 525 def IsNamingStep(self, step): 526 return step == ccConst.NAMINGSTEP 527 528 @telemetry.ZONE_METHOD 529 def FadeToBlack(self, why = ''): 530 self.ShowLoading(why=why, forceOn=True) 531 animations.FadeIn(self.blackOut, duration=0.5, sleep=True) 532 533 @telemetry.ZONE_METHOD 534 def FadeFromBlack(self): 535 animations.FadeOut(self.blackOut, duration=0.5) 536 self.HideLoading(forceOff=1) 537 538 @telemetry.ZONE_METHOD 539 def PassedStepCheck(self, toStep, *args): 540 if toStep not in self.availableSteps: 541 raise UserError('CCStepUnavailable') 542 if toStep == ccConst.CUSTOMIZATIONSTEP and (self.raceID is None or self.GetActiveCharacterData().bloodlineID is None or self.GetActiveCharacterData().genderID is None): 543 raise UserError('CCMustSelectRaceAndBloodline') 544 isNamingStep = self.IsNamingStep(toStep) 545 if (toStep == ccConst.PORTRAITSTEP or isNamingStep) and not prefs.GetValue('ignoreCCValidation', False): 546 info = self.GetInfo() 547 self.dollManager.ToggleClothes(forcedValue=0) 548 self.characterSvc.ValidateDollCustomizationComplete(info.charID) 549 currentStepID = None 550 if self.step: 551 currentStepID = self.step.stepID 552 if self.step: 553 self.step.ValidateStepComplete() 554 return True 555 556 @telemetry.ZONE_METHOD 557 def Approve(self, skipCustomization = True, *args): 558 if not self.approve_in_progress: 559 self.PlayApprovalSound() 560 self.approve_in_progress = True 561 self.stepLogger.IncrementNextTryCount() 562 idx = self.availableSteps.index(self.stepID) 563 try: 564 if len(self.availableSteps) > idx + 1: 565 if self.stepID == ccConst.DOLLSTEP: 566 self.customizationStepSkipped = skipCustomization 567 if skipCustomization and len(self.availableSteps) > idx + 2: 568 nextStep = self.availableSteps[idx + 2] 569 else: 570 nextStep = self.availableSteps[idx + 1] 571 else: 572 nextStep = self.availableSteps[idx + 1] 573 self.SwitchStep(nextStep) 574 uicore.registry.SetFocus(self) 575 finally: 576 self.approve_in_progress = False 577 578 def PlayApprovalSound(self): 579 if self.stepID == ccConst.CUSTOMIZATIONSTEP: 580 PlaySound(soundConst.CUSTOMIZATION_CONFIRMATION) 581 else: 582 PlaySound(soundConst.NEXT_STEP) 583 584 @telemetry.ZONE_METHOD 585 def GoToCustomization(self, *args): 586 self.Approve(skipCustomization=False) 587 588 @telemetry.ZONE_METHOD 589 def RandomizeSelectedDoll(self, *args): 590 if self.dollSelected: 591 charCreationSignals.onDollSelectionRandomizeStarting(self._activeCharID) 592 self.RandomizeCharacter(self._activeCharID, True) 593 doll = self.characterSvc.GetSingleCharactersDoll(self._activeCharID) 594 while doll.busyUpdating: 595 blue.synchro.Yield() 596 597 charCreationSignals.onDollSelectionDollRandomized(self._activeCharID) 598 599 def OnDollRandomizeStarting(self, charID): 600 self.backBtn.state = uiconst.UI_DISABLED 601 602 def OnDollRandomized(self, charID): 603 self.backBtn.state = uiconst.UI_NORMAL 604 605 def RandomizeCharacter(self, charID = None, fullRandomize = False): 606 if charID is None: 607 charID = self._activeCharID 608 doll = self.characterSvc.GetSingleCharactersDoll(charID) 609 if doll.busyUpdating: 610 return 611 self.LockNavigation() 612 PlaySound(soundConst.RANDOMIZE) 613 if fullRandomize: 614 self.RerollCharacter(charID) 615 else: 616 self.dollManager.ToggleClothes(forcedValue=0) 617 if self._characterData[charID].genderID == ccConst.GENDERID_FEMALE: 618 itemList = ccConst.femaleRandomizeItems.keys() 619 else: 620 itemList = ccConst.maleRandomizeItems.keys() 621 canChangeBaseAppearance = self.CanChangeBaseAppearance() 622 blacklist = ccConst.randomizerCategoryBlacklist[:] 623 if not canChangeBaseAppearance: 624 blacklist += ccConst.recustomizationRandomizerBlacklist 625 if boot.region == 'optic' and self._characterData[charID].genderID == ccConst.GENDERID_FEMALE: 626 blacklist.append(ccConst.scarring) 627 categoryList = [] 628 for item in itemList: 629 if item not in blacklist: 630 categoryList.append(item) 631 632 self.characterSvc.RandomizeCharacterGroups(charID, self.raceID, categoryList, doUpdate=False, fullRandomization=True) 633 if canChangeBaseAppearance: 634 self.characterSvc.RandomizeCharacterSculpting(charID, self.raceID, doUpdate=False) 635 decalModifiers = doll.buildDataManager.GetModifiersByCategory(ccConst.tattoo) 636 for modifier in decalModifiers: 637 modifier.IsDirty = True 638 639 self.characterSvc.UpdateDoll(charID, 'RandomizeCharacter') 640 self.UnlockNavigation() 641 642 def CheckAndGetName(self): 643 isAvailable = self.step.CheckAvailability() 644 if isAvailable.charName is None: 645 prompt_player_fsd_dialog('CustomInfo', {'info': isAvailable.reason}) 646 return isAvailable.charName 647 648 @telemetry.ZONE_METHOD 649 def Save(self, *args): 650 if not self.save_in_progress: 651 self.save_in_progress = True 652 self.BlockOnUpdate() 653 if self.finalStepLogger: 654 self.finalStepLogger.Finalize() 655 self.stepLogger.IncrementNextTryCount() 656 try: 657 selectedPortraitInfo = self.portraitManager.GetActivePortraitInfo() 658 if selectedPortraitInfo and selectedPortraitInfo.backgroundID < const.NCC_MIN_NORMAL_BACKGROUND_ID: 659 prompt_player_fsd_dialog('CustomInfo', {'info': localization.GetByLabel('UI/CharacterCreation/CannotSaveWithThisBackground')}) 660 return 661 self.LockEverything() 662 if self.step: 663 self.step.ValidateStepComplete() 664 if self.stepID != self.availableSteps[-1]: 665 raise UserError('CCCannotSave') 666 if self._activeCharID is not None and self.modeObject.AskForPortraitConfirmation(): 667 self.UpdateExistingCharacter() 668 return 669 if self.GetActiveCharacterData().bloodlineID is None or self.GetActiveCharacterData().genderID is None: 670 raise UserError('CCCannotSave2') 671 else: 672 characterName = self.CheckAndGetName() 673 if characterName is None: 674 return 675 self.SaveAndEnterCurrentCharacter(characterName) 676 finally: 677 if self and not self.destroyed: 678 self.UnlockEverything() 679 self.save_in_progress = False 680 681 def SaveAndEnterCurrentCharacter(self, characterName): 682 PlaySound(soundConst.FINALIZE) 683 charID = self.SaveCurrentCharacter(characterName, self.portraitManager.activePortraitIndex) 684 self.metrics.complete_cc(charid=charID) 685 if charID: 686 self.characterSvc.CachePortraitInfo(charID, self.portraitManager.GetActivePortraitInfo()) 687 self.tryLoginElseCharacterSelection(charID) 688 689 def tryLoginElseCharacterSelection(self, charID): 690 try: 691 if gatekeeper.user.IsInCohort(gatekeeper.cohortToCharacterSelectionTest): 692 sm.GetService('cc').GetCharactersToSelect(force=True) 693 uthread.pool('GameUI::ActivateView::charsel', sm.GetService('viewState').ActivateView, 'charsel') 694 else: 695 skipTutorial = self.CheckSkipTutorial() if is_air_npe_enabled() else True 696 sm.GetService('cc').FinishCharacterCreation(charID, skipTutorial) 697 except: 698 cc = sm.GetService('cc') 699 cc.StopIntro() 700 cc.GetCharactersToSelect(force=True) 701 sm.GetService('loading').ProgressWnd(localization.GetByLabel('UI/CharacterCreation/CharacterSelection'), localization.GetByLabel('UI/CharacterCreation/FailedToEnterGame'), 2, 2) 702 uthread.pool('GameUI::ActivateView::charsel', sm.GetService('viewState').ActivateView, 'charsel') 703 raise 704 705 def CheckSkipTutorial(self): 706 if sm.RemoteSvc('charUnboundMgr').GetNumCharacters() > 1: 707 if prompt_player_fsd_dialog('AskStartWithTutorial', {}, uiconst.YESNO, default=uiconst.ID_NO) == uiconst.ID_NO: 708 return True 709 return False 710 711 def OnEsc(self): 712 self.Back() 713 714 def CancelCharacterCreation(self): 715 if self.modeObject.ExitToStation(): 716 msg = 'AskCancelCharCustomization' 717 else: 718 msg = 'AskCancelCharCreation' 719 self.audioService.SendUIEvent('ui_es_pop_up_play') 720 popUp = prompt_player_fsd_dialog(msg, {}, uiconst.YESNO) 721 self.audioService.SendUIEvent('ui_es_pop_up_stop') 722 if popUp != uiconst.ID_YES: 723 return 724 self.needNavigationTutorial = True 725 self.needSculptingTutorial = True 726 self.audioService.SendUIEvent('ui_es_stop') 727 self.metrics.cancel_cc() 728 if self.modeObject.ExitToStation(): 729 self.ExitToStation(updateDoll=False) 730 else: 731 sm.StartService('cc').GoBack() 732 self.StopFactionSelectionSound() 733 734 @telemetry.ZONE_METHOD 735 def Back(self, *args): 736 idx = self.availableSteps.index(self.stepID) 737 if idx == 0: 738 self.CancelCharacterCreation() 739 else: 740 if self.stepID == ccConst.NAMINGSTEP and self.customizationStepSkipped and idx > 1: 741 nextStep = self.availableSteps[idx - 2] 742 else: 743 nextStep = self.availableSteps[idx - 1] 744 PlaySound(soundConst.PREVIOUS_STEP) 745 self.SwitchStep(nextStep) 746 uicore.registry.SetFocus(self) 747 748 @telemetry.ZONE_METHOD 749 def LockEverything(self, *args): 750 if not getattr(self, 'setupDone', 0): 751 return 752 containers = [self, self.topNavigationContainer] 753 for container in containers: 754 container.pickState = uiconst.TR2_SPS_OFF 755 756 self.LockNavigation() 757 758 @telemetry.ZONE_METHOD 759 def LockNavigation(self, *args): 760 if not getattr(self, 'setupDone', 0): 761 return 762 self.buttonNavRight.state = uiconst.UI_DISABLED 763 self.buttonNavLeft.state = uiconst.UI_DISABLED 764 765 @telemetry.ZONE_METHOD 766 def UnlockEverything(self, *args): 767 containers = [self, self.topNavigationContainer] 768 for container in containers: 769 container.pickState = uiconst.TR2_SPS_CHILDREN 770 771 self.UnlockNavigation() 772 773 @telemetry.ZONE_METHOD 774 def UnlockNavigation(self, *args): 775 if not self.parent.isopen: 776 return 777 self.buttonNavRight.state = uiconst.UI_PICKCHILDREN 778 self.buttonNavLeft.state = uiconst.UI_PICKCHILDREN 779 780 @telemetry.ZONE_METHOD 781 def SelectRaceIfDifferent(self, raceID, check = 1): 782 if self.raceID != raceID: 783 self._ChangeRace(raceID) 784 self._UpdateResourcePriority(raceID) 785 786 @telemetry.ZONE_METHOD 787 def SelectRace(self, raceID): 788 self._ChangeRace(raceID) 789 self._UpdateResourcePriority(raceID) 790 charCreationSignals.onEmpireFactionSelected(appConst.factionByRace[raceID]) 791 792 def _ChangeRace(self, raceID): 793 self.ClearSteps(what='race') 794 self.dollManager.ResetClothesStorage() 795 self.raceID = raceID 796 if hasattr(self.step, 'OnRaceSelected'): 797 self.step.OnRaceSelected(raceID) 798 self.portraitManager.UpdateBackdrop() 799 800 def _GetRandomRaceID(self): 801 return random.choice(CHARACTER_CREATION_RACE_IDS) 802 803 def _UpdateResourcePriority(self, raceID): 804 raceAsString = RACE_TO_RESOURCE_NAME.get(raceID, None) 805 if raceAsString: 806 everesourceprefetch.ScheduleFront('interior_' + raceAsString) 807 everesourceprefetch.ScheduleFront('bloodline_select_' + raceAsString) 808 809 @telemetry.ZONE_METHOD 810 def SelectBloodline(self, bloodlineID): 811 if self.GetActiveCharacterData().bloodlineID != bloodlineID: 812 self.ClearSteps(what='bloodline') 813 if self.stepID == ccConst.CUSTOMIZATIONSTEP: 814 uthread.new(self._SwitchBloodlines, bloodlineID, fadeout=True) 815 self.dollManager.ResetClothesStorage() 816 817 def _SwitchBloodlines(self, bloodlineID, fadeout = False, resetToFace = False): 818 if fadeout: 819 self.FadeToBlack(why=localization.GetByLabel('UI/Common/Loading')) 820 self.characterSvc.StopEditing() 821 self.LockEverything() 822 genderID = self.GetActiveCharacterData().genderID 823 appearanceInfo = self.characterSvc.CopyCharacterAppearanceInfoForBloodline(self._activeCharID) 824 self.SetActiveBloodline(bloodlineID) 825 self.characterSvc.RemoveCharacter(self._activeCharID) 826 self.AddCharacter(self._activeCharID, bloodlineID, self.raceID, genderID, dna=appearanceInfo) 827 doll = self.characterSvc.GetSingleCharactersDoll(self._activeCharID) 828 while doll.busyUpdating: 829 blue.synchro.Yield() 830 831 self.sceneManager.camera.UpdateAvatar(self.characterSvc.GetSingleCharactersAvatar(self._activeCharID)) 832 self.step.ReloadTattooMenu() 833 self.step.GoToAssetMode(forcedMode=1) 834 if resetToFace: 835 if hasattr(self.step, 'LoadFaceMode'): 836 uthread.new(self.step.LoadFaceMode) 837 self.UnlockEverything() 838 if fadeout: 839 self.FadeFromBlack() 840 841 @telemetry.ZONE_METHOD 842 def SelectBloodlineAndGender(self, bloodlineID, genderID, check = 1): 843 isBloodlineChanged = self.GetActiveCharacterData().bloodlineID != bloodlineID 844 isGenderChanged = self.GetActiveCharacterData().genderID != genderID 845 self.WarnOfUnsavedChanges(check, isBloodlineChanged, isGenderChanged) 846 if isBloodlineChanged or isGenderChanged: 847 self.ClearSteps(what='bloodline') 848 self.SetActiveBloodline(bloodlineID) 849 self.SetActiveGender(genderID) 850 self.dollManager.ResetClothesStorage() 851 if getattr(self.step, 'sr') and getattr(self.step.sr, 'historySlider'): 852 self.step.sr.historySlider.LoadHistory(0) 853 854 def SelectRandomBloodline(self): 855 bloodlineIDs = [1, 856 2, 857 3, 858 4, 859 5, 860 6, 861 7, 862 8, 863 11, 864 12, 865 13, 866 14] 867 return random.choice(bloodlineIDs) 868 869 def SelectRandomGender(self): 870 genderIDs = [0, 1] 871 return random.choice(genderIDs) 872 873 def WarnOfUnsavedChanges(self, check, isBloodlineChanged, isGenderChanged): 874 isBloodlineUnsaved = isBloodlineChanged and self.GetActiveCharacterData().bloodlineID is not None 875 isGenderUnsaved = isGenderChanged and self.GetActiveCharacterData().genderID is not None 876 areThereUnsavedChanges = isBloodlineUnsaved or isGenderUnsaved 877 isCustomized = self.stepID == ccConst.CUSTOMIZATIONSTEP and ccConst.CUSTOMIZATIONSTEP in self.stepsUsed 878 shouldWarn = check and areThereUnsavedChanges and isCustomized 879 if shouldWarn: 880 dnaLog = self.dollManager.GetDollDNAHistory() 881 if dnaLog and len(dnaLog) > 1: 882 message = 'CharCreationLoseChangeBloodline' if isBloodlineUnsaved else 'CharCreationLoseChangeGender' 883 if prompt_player_fsd_dialog(message, {}, uiconst.YESNO) != uiconst.ID_YES: 884 return 885 886 @telemetry.ZONE_METHOD 887 def SelectSchool(self, schoolID): 888 if schoolID == self.schoolID: 889 return 890 if self.finalStepLogger: 891 self.finalStepLogger.SetSchool(schoolID) 892 self.schoolID = schoolID 893 uicore.layer.charactercreation.controller.metrics.pick_school(schoolID) 894 charCreationSignals.onEmpireSchoolSelected(schoolID) 895 896 @telemetry.ZONE_METHOD 897 def OnDollUpdated(self, charID, redundantUpdate, fromWhere, *args): 898 if fromWhere in ('AddCharacter', 'OnSetDevice', 'InitAvatarPositions_Naming'): 899 return 900 self.ClearSteps(what='dollUpdated') 901 902 @telemetry.ZONE_METHOD 903 def OnGraphicSettingsChanged(self, changes): 904 shouldGoBack = False 905 if gfxsettings.GFX_CHAR_FAST_CHARACTER_CREATION in changes: 906 header = localization.GetByLabel('UI/CharacterCreation/LoseChangesHeader') 907 text = localization.GetByLabel('UI/CharacterCreation/LoseChanges') 908 if prompt_player_fsd_dialog('CustomQuestion', {'header': header, 909 'question': text}, uiconst.YESNO) == uiconst.ID_YES: 910 self.sceneManager.avatarScene = None 911 shouldGoBack = True 912 else: 913 gfxsettings.Set(gfxsettings.GFX_CHAR_FAST_CHARACTER_CREATION, 0, pending=False) 914 if shouldGoBack: 915 if self._activeCharID is not None: 916 trinity.WaitForResourceLoads() 917 self.ExitToStation() 918 else: 919 sm.GetService('cc').GoBack() 920 if gfxsettings.UI_NCC_GREEN_SCREEN in changes: 921 self.portraitManager.UpdateBackdrop() 922 if self.floor: 923 self.floor.display = not gfxsettings.Get(gfxsettings.UI_NCC_GREEN_SCREEN) 924 925 def ReloadStep(self): 926 self.ShowLoading() 927 try: 928 self.SwitchStep(self.stepID) 929 finally: 930 self.HideLoading() 931 932 @telemetry.ZONE_METHOD 933 def TearDown(self): 934 self.Cleanup() 935 self.characterSvc.TearDown() 936 self.floor = None 937 self.sceneManager.TearDown() 938 self.portraitManager.TearDown() 939 self.dollManager.TearDown() 940 self.freezingAnimation = False 941 self.dollSelected = False 942 self.customizationStepSkipped = False 943 944 @telemetry.ZONE_METHOD 945 def StartDollSelectionStep(self, *args): 946 self.customizationStepSkipped = False 947 info = self.GetInfo() 948 self.sceneManagerSvc.Show2DBackdropScene() 949 self.SetupSceneAndCharacter(extraDoll=True) 950 avatar = self.characterSvc.GetSingleCharactersAvatar(info.charID) 951 if avatar is not None: 952 network = animparams.GetParamsPerAvatar(avatar, info.charID) 953 network.SetControlParameter('ControlParameters|NetworkMode', NETWORKMODE_BASIC) 954 self.sceneManager.SetupCamera(avatar, ccConst.CAMERA_MODE_BODY, callback=self.CameraMoveCB, frontClip=0.1, backClip=100.0, controlStyle=CONTROL_NONE) 955 self.sceneManager.SetTwoDollsLighting() 956 charCreationSignals.onDollSelectionDollClicked.connect(self.OnDollSelectionDollClicked) 957 characterIDs = sorted([self._activeCharID, self._spareCharID]) 958 self.step = CharacterDollSelection(parent=self.mainCont, characterIDs=characterIDs, selectedCharacterID=self._activeCharID) 959 self.step.InitAvatarPositions() 960 self.sceneManager.scene.SetupShadowMaps() 961 962 @telemetry.ZONE_METHOD 963 def StartCustomizationStep(self, *args): 964 info = self.GetInfo() 965 self.sceneManagerSvc.Show2DBackdropScene() 966 self.SetupSceneAndCharacter() 967 avatar = self.characterSvc.GetSingleCharactersAvatar(info.charID) 968 if avatar is not None: 969 network = animparams.GetParamsPerAvatar(avatar, info.charID) 970 network.SetControlParameter('ControlParameters|NetworkMode', NETWORKMODE_BASIC) 971 self.sceneManager.SetupCamera(avatar, ccConst.CAMERA_MODE_FACE, callback=self.CameraMoveCB, frontClip=0.1, backClip=100.0) 972 self.sceneManager.SetSingleDollLighting() 973 self.step = CharacterCustomization(parent=self.mainCont) 974 self.step.InitAvatarPositions() 975 if self.CanChangeBaseAppearance(): 976 self.StartEditMode(showPreview=True, callback=self.step.ChangeSculptingCursor) 977 self.sceneManager.camera.ToggleMode(ccConst.CAMERA_MODE_FACE, avatar=avatar, transformTime=500.0) 978 self.sceneManager.scene.SetupShadowMaps() 979 980 def CameraMoveCB(self, viewMatrix): 981 info = self.GetInfo() 982 if info.charID not in self.characterSvc.characters: 983 return 984 if not len(self.characterSvc.characters): 985 return 986 avatar = self.characterSvc.GetSingleCharactersAvatar(info.charID) 987 matrix = geo2.MatrixInverse(viewMatrix.transform) 988 view = matrix[3][:3] 989 if info.genderID: 990 height = 1.7 991 else: 992 height = 1.6 993 head = (0, height, 0) 994 rot = avatar.rotation 995 vec = (view[0] - head[0], view[1] - head[1], view[2] - head[2]) 996 vecLength = geo2.Vec3Distance((0, 0, 0), vec) 997 vec = geo2.QuaternionTransformVector(geo2.QuaternionInverse(rot), vec) 998 norm = 1.0 / math.sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]) 999 vec = (vec[0] * norm, vec[1] * norm, vec[2] * norm) 1000 leftright = math.atan2(vec[2], vec[0]) 1001 updown = math.asin(vec[1]) 1002 leftright = 1 - abs(leftright) / 3.1415927 * 2 1003 updown = 2 * updown / 3.1415927 1004 dist = (vecLength - 1.0) / 7.0 1005 network = animparams.GetParamsPerAvatar(avatar, info.charID) 1006 network.SetControlParameter('ControlParameters|HeadLookLeftRight', leftright) 1007 network.SetControlParameter('ControlParameters|HeadLookUpDown', updown) 1008 network.SetControlParameter('ControlParameters|CameraDistance', dist) 1009 1010 @telemetry.ZONE_METHOD 1011 def StartPortraitStep(self): 1012 info = self.GetInfo() 1013 if not self.portraitManager.alreadyLoadedOldPortraitData: 1014 if self.modeObject.GetOldPortraitData(): 1015 self.portraitManager.FetchOldPortraitData(info.charID) 1016 self.step = CharacterPortrait(parent=self.mainCont) 1017 self.SetupSceneAndCharacter() 1018 avatar = self.characterSvc.GetSingleCharactersAvatar(info.charID) 1019 if avatar is not None and avatar.animationUpdater is not None: 1020 network = animparams.GetParamsPerAvatar(avatar, info.charID) 1021 network.SetControlParameter('ControlParameters|NetworkMode', NETWORKMODE_PORTRAIT) 1022 self.sceneManager.SetupForPortraitStep(avatar) 1023 self.characterSvc.StartPosing(charID=info.charID, callback=self.step.ChangeSculptingCursor) 1024 1025 @telemetry.ZONE_METHOD 1026 def StartNamingStep(self, *args): 1027 info = self.GetInfo() 1028 avatar = self.characterSvc.GetSingleCharactersAvatar(info.charID) 1029 self.SetupSceneAndCharacter() 1030 self.sceneManager.SetUpNamingStepCamera(self.characterSvc.GetSingleCharactersAvatar(info.charID)) 1031 self.SetAvatarAnimationNetworkMode(NETWORKMODE_PORTRAIT) 1032 while not self.characterSvc.sculpting: 1033 blue.synchro.Yield() 1034 1035 self.sceneManager.SetupCamera(avatar, ccConst.CAMERA_MODE_PORTRAIT, callback=self.CameraMoveCB) 1036 self.sceneManager.camera.Update() 1037 self.sceneManager.SetSingleDollCloseupLighting(self.GetInfo().genderID) 1038 self.step = CharacterNaming(parent=self.mainCont) 1039 self.step.InitAvatarPositions() 1040 doll = self.characterSvc.GetSingleCharactersDoll(info.charID) 1041 while doll.busyUpdating: 1042 blue.synchro.Yield() 1043 1044 self.portraitManager.SetBackdrop(random.choice(ccConst.defaultBackgroundOptions)) 1045 self.CapturePortrait(0) 1046 self.sceneManager.SetUpNamingStepCamera(self.characterSvc.GetSingleCharactersAvatar(info.charID)) 1047 self.sceneManager.SetupCamera(avatar, ccConst.CAMERA_MODE_FACE) 1048 self.SetAvatarAnimationNetworkMode(NETWORKMODE_BASIC) 1049 charCreationSignals.onNameInputChanged.connect(self.OnNameInputChanged) 1050 1051 def OnNameInputChanged(self, isValidName): 1052 if isValidName: 1053 if not self.saveBtn.display: 1054 self.saveBtn.Show() 1055 animations.FadeTo(self.saveBtn, 0.0, 1.0, duration=0.3) 1056 else: 1057 self.saveBtn.Hide() 1058 1059 def SetAvatarAnimationNetworkMode(self, networkMode): 1060 info = self.GetInfo() 1061 avatar = self.characterSvc.GetSingleCharactersAvatar(info.charID) 1062 if avatar is not None: 1063 if info.charID in self.characterSvc.characters: 1064 network = animparams.GetParamsPerAvatar(avatar, info.charID) 1065 network.SetControlParameter('ControlParameters|NetworkMode', networkMode) 1066 while network.rebuilding: 1067 blue.synchro.Yield() 1068 1069 @telemetry.ZONE_METHOD 1070 def ClearSteps(self, what = None, force = 0, *args): 1071 if self.stepID is None: 1072 return 1073 stepAlreadyCleared = getattr(self.step, 'stepAlreadyCleared', 0) 1074 if not force and stepAlreadyCleared: 1075 return 1076 currentStepID = self.stepID 1077 currentStepOrder = GetStepOrder(currentStepID) 1078 if currentStepOrder <= GetStepOrder(ccConst.CUSTOMIZATIONSTEP): 1079 self.portraitManager.ClearFacePortrait() 1080 firstStep = self.availableSteps[0] 1081 self.stepsUsed = GetStepsUpToAndIncluding(currentStepID) or {firstStep} 1082 if self.step: 1083 self.step.stepAlreadyCleared = 1 1084 1085 @telemetry.ZONE_METHOD 1086 def Cleanup(self): 1087 self.characterSvc.StopEditing() 1088 info = self.GetInfo() 1089 charID = info.charID 1090 if charID in self.characterSvc.characters: 1091 self.characterSvc.StopPosing(charID) 1092 self.sceneManager.Cleanup() 1093 self.portraitManager.Cleanup() 1094 1095 def SelectDoll(self, charID): 1096 if charID != self._activeCharID: 1097 self._spareCharID = self._activeCharID 1098 self._activeCharID = charID 1099 self.dollManager.ClearDnaLog() 1100 charCreationSignals.onDollSelectionDollSelected(charID) 1101 self.dollSelected = True 1102 1103 @telemetry.ZONE_METHOD 1104 def SetupSceneAndCharacter(self, extraDoll = False): 1105 createExtraDoll = self.mode == ccConst.MODE_FULLINITIAL_CUSTOMIZATION 1106 if not createExtraDoll: 1107 extraDoll = False 1108 info = self.GetInfo() 1109 charA = min(self._activeCharID, self._spareCharID) 1110 charB = max(self._activeCharID, self._spareCharID) 1111 if self.sceneManager.SetAvatarScene(info): 1112 self.AddCharacter(self._activeCharID, info.bloodlineID, info.raceID, info.genderID, dna=info.dna) 1113 if createExtraDoll: 1114 spareBloodlineID = self.SelectRandomBloodline() 1115 spareGenderID = 1 - info.genderID 1116 self._characterData[self._spareCharID].bloodlineID = spareBloodlineID 1117 self._characterData[self._spareCharID].genderID = spareGenderID 1118 self.AddCharacter(self._spareCharID, spareBloodlineID, self.raceID, spareGenderID, dna=info.dna) 1119 elif self._dollsDirty: 1120 self.RerollCharacter(self._activeCharID, cameraUpdate=False) 1121 self.RerollCharacter(self._spareCharID, cameraUpdate=False) 1122 self._dollsDirty = False 1123 elif extraDoll: 1124 avatarA = self.characterSvc.GetSingleCharactersAvatar(charA) 1125 avatarA.display = True 1126 avatarB = self.characterSvc.GetSingleCharactersAvatar(charB) 1127 avatarB.display = True 1128 else: 1129 avatarA = self.characterSvc.GetSingleCharactersAvatar(self._activeCharID) 1130 avatarA.display = True 1131 if createExtraDoll: 1132 avatarB = self.characterSvc.GetSingleCharactersAvatar(self._spareCharID) 1133 avatarB.display = False 1134 self.BlockOnUpdate() 1135 1136 @telemetry.ZONE_METHOD 1137 def AddCharacter(self, charID, bloodlineID, raceID, genderID, scene = None, dna = None, validateColors = True, position = (0.0, 0.0, 0.0)): 1138 self.dollManager.AddCharacter(charID, bloodlineID, raceID, genderID, scene or self.sceneManager.scene, dna, validateColors, position=position) 1139 1140 @telemetry.ZONE_METHOD 1141 def RerollCharacter(self, charID, cameraUpdate = True): 1142 self.characterSvc.RemoveCharacter(charID) 1143 bloodlineID = self.SelectRandomBloodline() 1144 self.dollManager.AddCharacter(charID, bloodlineID, self.raceID, self._characterData[charID].genderID, self.sceneManager.scene, None, True) 1145 if self.step and hasattr(self.step, 'InitAvatarPositions'): 1146 self.step.InitAvatarPositions() 1147 doll = self.characterSvc.GetSingleCharactersDoll(charID) 1148 while doll.busyUpdating: 1149 blue.synchro.Yield() 1150 1151 if cameraUpdate: 1152 self.sceneManager.camera.UpdateAvatar(self.characterSvc.GetSingleCharactersAvatar(charID)) 1153 1154 @telemetry.ZONE_METHOD 1155 def GetAvailableStyles(self, modifier): 1156 info = self.GetInfo() 1157 gender = info.genderID 1158 bloodline = info.bloodlineID 1159 currentModifier = self.characterSvc.GetModifierByCategory(info.charID, modifier) 1160 itemTypes = self.characterSvc.GetAvailableTypesByCategory(modifier, gender, info.raceID) 1161 activeIndex = None 1162 if currentModifier: 1163 currentType = currentModifier.GetTypeData() 1164 for i, each in enumerate(itemTypes): 1165 if each[1][0] == currentType[0] and each[1][1] == currentType[1] and each[1][2] == currentType[2]: 1166 activeIndex = i 1167 1168 return (itemTypes, activeIndex) 1169 1170 def GetModifierIntensity(self, modifierPath): 1171 info = self.GetInfo() 1172 modifier = self.characterSvc.GetModifiersByCategory(info.charID, modifierPath) 1173 if modifier: 1174 return modifier[0].weight 1175 return 0.0 1176 1177 @telemetry.ZONE_METHOD 1178 def GetAvailableColors(self, modifier): 1179 info = self.GetInfo() 1180 colors, activeColorIndex = self.characterSvc.GetCharacterColorVariations(info.charID, modifier) 1181 colors = tuple(colors) 1182 retColors = [] 1183 for name, color in colors: 1184 if color and type(color[0]) == types.TupleType: 1185 r = g = b = 0 1186 for _r, _g, _b, _a in color: 1187 r += _r 1188 g += _g 1189 b += _b 1190 1191 r = r / float(len(color)) 1192 g = g / float(len(color)) 1193 b = b / float(len(color)) 1194 retColors.append((name, (r, 1195 g, 1196 b, 1197 1.0), color)) 1198 else: 1199 retColors.append((name, color, color)) 1200 1201 return (retColors, activeColorIndex) 1202 1203 @telemetry.ZONE_METHOD 1204 def SetRandomHairDarkness(self, doUpdate = True): 1205 self.SetHairDarkness(random.random(), doUpdate=doUpdate) 1206 1207 @telemetry.ZONE_METHOD 1208 def SetHairDarkness(self, darkness, doUpdate = True): 1209 info = self.GetInfo() 1210 self.characterSvc.SetHairDarkness(info.charID, darkness) 1211 if doUpdate: 1212 sm.GetService('character').UpdateDoll(info.charID, fromWhere='SetHairDarkness') 1213 1214 @telemetry.ZONE_METHOD 1215 def SaveCurrentCharacter(self, charactername, portraitID): 1216 total = 3 1217 sm.GetService('loading').ProgressWnd(localization.GetByLabel('UI/CharacterCreation/Registering'), localization.GetByLabel('UI/CharacterCreation/CompilePrefs'), 1, total) 1218 try: 1219 if self.portraitManager.portraitInfo[portraitID] is None: 1220 raise UserError('CharCreationNoPortrait') 1221 info = self.GetInfo() 1222 charInfo = self.characterSvc.GetCharacterAppearanceInfo(info.charID) 1223 data = self.GetActiveCharacterData() 1224 charID = sm.GetService('cc').CreateCharacterWithDoll(charactername, data.bloodlineID, data.genderID, appConst.ancestryUndefined, charInfo, self.portraitManager.portraitInfo[portraitID], info.schoolID, info.raceID) 1225 except UserError as what: 1226 if not what.msg.startswith('CharNameInvalid'): 1227 prompt_player_fsd_dialog(*what.args) 1228 return 1229 sm.GetService('loading').ProgressWnd(localization.GetByLabel('UI/CharacterCreation/Registering'), localization.GetByLabel('UI/CharacterCreation/FailedForSomeReason'), 3, total) 1230 except RuntimeError as e: 1231 logger.error('Failed to create character: %s' % e) 1232 sm.GetService('loading').ProgressWnd(localization.GetByLabel('UI/CharacterCreation/Registering'), localization.GetByLabel('UI/CharacterCreation/FailedForSomeReason'), 3, total) 1233 else: 1234 sm.GetService('loading').ProgressWnd(localization.GetByLabel('UI/CharacterCreation/Registering'), localization.GetByLabel('UI/CharacterCreation/InsertingRecord'), 2, total) 1235 sm.GetService('photo').AddPortrait(self.portraitManager.GetPortraitSnapshotPath(portraitID), charID) 1236 sm.GetService('loading').ProgressWnd(localization.GetByLabel('UI/CharacterCreation/Registering'), localization.GetByLabel('UI/Generic/Done'), 3, total) 1237 return charID 1238 finally: 1239 self.sessionSounds = [] 1240 1241 @telemetry.ZONE_METHOD 1242 def UpdateExistingCharacter(self, *args): 1243 charID = self._activeCharID 1244 activePortraitInfo = self.portraitManager.GetActivePortraitInfo() 1245 if activePortraitInfo is None: 1246 raise UserError('CharCreationNoPortrait') 1247 dollExists = self._characterData[charID].dna is not None 1248 dollInfo = self.characterSvc.GetCharacterAppearanceInfo(charID) 1249 availableTypeIDs = sm.GetService('cc').GetMyApparel() 1250 metadata = self.characterSvc.characterMetadata[charID] 1251 typesInUse = metadata.types 1252 for resourceID in typesInUse.itervalues(): 1253 if resourceID: 1254 info = cfg.paperdollResources.Get(resourceID) 1255 if info.typeID is not None and info.typeID not in availableTypeIDs: 1256 raise UserError('ItemNotAtStation', {'item': info.typeID}) 1257 1258 bgInfo = cfg.paperdollPortraitResources.Get(activePortraitInfo.backgroundID) 1259 if bgInfo and bgInfo.typeID is not None and bgInfo.typeID not in availableTypeIDs: 1260 raise UserError('ItemNotAtStation', {'item': bgInfo.typeID}) 1261 info = self.GetInfo() 1262 if self.mode == ccConst.MODE_FULL_RECUSTOMIZATION: 1263 sm.GetService('cc').UpdateExistingCharacterBloodline(charID, info.bloodlineID, False) 1264 sm.GetService('cc').UpdateExistingCharacterFull(charID, dollInfo, activePortraitInfo, dollExists, flush=True) 1265 elif self.mode == ccConst.MODE_LIMITED_RECUSTOMIZATION: 1266 sm.GetService('cc').UpdateExistingCharacterLimited(charID, dollInfo, activePortraitInfo, dollExists) 1267 elif self.mode == ccConst.MODE_FULL_BLOODLINECHANGE: 1268 sm.GetService('cc').UpdateExistingCharacterBloodline(charID, info.bloodlineID, True) 1269 sm.GetService('photo').AddPortrait(self.portraitManager.GetPortraitSnapshotPath(self.portraitManager.activePortraitIndex), charID) 1270 self.characterSvc.CachePortraitInfo(self._activeCharID, self.portraitManager.GetActivePortraitInfo()) 1271 self.metrics.complete_cc(charid=charID) 1272 if self.dollState != paperdoll.State.force_recustomize: 1273 self.ExitToStation() 1274 else: 1275 uthread.pool('GameUI::ActivateView::charsel', sm.GetService('viewState').ActivateView, 'charsel') 1276 1277 @telemetry.ZONE_METHOD 1278 def StartEditMode(self, callback = None, **kwds): 1279 if callback is None and kwds.get('mode', None) == 'sculpt': 1280 callback = getattr(self.step, 'ChangeSculptingCursor', None) 1281 info = self.GetInfo() 1282 self.characterSvc.StartEditMode(info.charID, self.sceneManager.scene, self.sceneManager.camera, callback=callback, **kwds) 1283 1284 @telemetry.ZONE_METHOD 1285 def UpdateBackdropLite(self, raceID, mouseEnter = False, *args): 1286 bdScene = self.sceneManagerSvc.Get2DBackdropScene() 1287 if not bdScene: 1288 return 1289 blue.resMan.SetUrgentResourceLoads(True) 1290 for each in bdScene.children: 1291 each.display = False 1292 if mouseEnter: 1293 if raceID: 1294 if each.name == 'mouseoverSprite_%d' % raceID: 1295 each.display = True 1296 else: 1297 each.display = True 1298 elif each.name == 'backdropSprite': 1299 each.texturePrimary.resPath = 'res:/UI/Texture/CharacterCreation/bg/RACE_Background_%d.dds' % raceID 1300 each.display = True 1301 1302 blue.resMan.SetUrgentResourceLoads(False) 1303 1304 @telemetry.ZONE_METHOD 1305 def CapturePortrait(self, portraitID, *args): 1306 if self.sceneManager.camera is None: 1307 return 1308 poseData = self.characterSvc.GetPoseData() 1309 if poseData is None: 1310 return 1311 return self.portraitManager.CapturePortrait(portraitID, self.sceneManager.camera, poseData, self.sceneManager.lightingID, self.sceneManager.lightColorID, self.sceneManager.GetLightIntensity()) 1312 1313 @telemetry.ZONE_METHOD 1314 def OnHideUI(self, *args): 1315 self.uiContainer.state = uiconst.UI_HIDDEN 1316 1317 @telemetry.ZONE_METHOD 1318 def OnShowUI(self, *args): 1319 self.uiContainer.state = uiconst.UI_PICKCHILDREN 1320 1321 def OnMapShortcut(self, *args): 1322 uicore.cmd.commandMap.UnloadAllAccelerators() 1323 uicore.cmd.commandMap.LoadAcceleratorsByCategory('general') 1324 1325 @telemetry.ZONE_METHOD 1326 def ShowLoading(self, why = '', top = 200, forceOn = 0, *args): 1327 wheel = self.loadingWheel 1328 wheel.top = top 1329 wheel.hint = why 1330 wheel.forcedOn = forceOn 1331 wheel.Show() 1332 1333 @telemetry.ZONE_METHOD 1334 def HideLoading(self, why = '', forceOff = 0, *args): 1335 wheel = self.loadingWheel 1336 if not wheel.forcedOn or forceOff: 1337 self.loadingWheel.Hide() 1338 wheel.forcedOn = 0 1339 1340 @telemetry.ZONE_METHOD 1341 def OnCloseView(self): 1342 uicore.cmd.LoadAllAccelerators() 1343 self.TearDown() 1344 self.audioService.SendUIEvent('ui_icc_sculpting_mouse_over_loop_stop') 1345 if self.audioService.GetWorldVolume() == 0.0: 1346 self.audioService.SetWorldVolume(self.worldLevel) 1347 sm.GetService('cc').ClearMyAvailabelTypeIDs() 1348 self.Flush() 1349 self.step = None 1350 if self.previewCharWindowWasOpenOn is not None: 1351 charID = self.previewCharWindowWasOpenOn[0] 1352 self.previewCharWindowWasOpenOn = None 1353 sm.GetService('preview').PreviewCharacter(charID) 1354 if self.previewWindowWasOpenOn is not None: 1355 typeID = self.previewWindowWasOpenOn 1356 sm.GetService('preview').PreviewType(typeID) 1357 1358 @telemetry.ZONE_METHOD 1359 def ExitToStation(self, updateDoll = True): 1360 self.OnCloseView() 1361 if session.structureid: 1362 change = {'structureid': (None, session.structureid)} 1363 else: 1364 change = {'stationid': (None, session.stationid)} 1365 sm.GetService('gameui').OnSessionChanged(isRemote=False, session=session, change=change) 1366 1367 def RemoveBodyModifications(self, *args): 1368 try: 1369 if getattr(self, 'bodyModRemoved', 0): 1370 return 1371 modifiersToRemove = [ccConst.p_earslow, 1372 ccConst.p_earshigh, 1373 ccConst.p_nose, 1374 ccConst.p_nostril, 1375 ccConst.p_brow, 1376 ccConst.p_lips, 1377 ccConst.p_chin, 1378 ccConst.t_head, 1379 ccConst.s_head] 1380 character = self.characterSvc.GetSingleCharacter(self._activeCharID) 1381 for mod in modifiersToRemove: 1382 modifiers = self.characterSvc.GetModifiersByCategory(self._activeCharID, mod) 1383 for m in modifiers: 1384 character.GetDoll(self._activeCharID).buildDataManager.RemoveModifier(m) 1385 self.characterSvc.RemoveFromCharacterMetadata(self._activeCharID, mod) 1386 1387 self.bodyModRemoved = 1 1388 sm.GetService('character').UpdateDollsAvatar(character) 1389 except Exception: 1390 pass 1391 1392 def TryStoreDna(self, lastUpdateRedundant, fromWhere, sculpting = 0, force = 0, allowReduntant = 0, *args): 1393 if not lastUpdateRedundant or fromWhere in ('RandomizeCharacterGroups', 'RandomizeCharacter', 'AddCharacter'): 1394 if not self.parent.isopen: 1395 return 1396 if self.stepID == ccConst.CUSTOMIZATIONSTEP: 1397 if self.step is None: 1398 return 1399 if not force and self.step.menuMode == self.step.TATTOOMENU: 1400 self.step.tattooChangeMade = 1 1401 return 1402 try: 1403 currentIndex, _ = self.step.historySlider.GetCurrentIndexAndMaxIndex() 1404 self.dollManager.TryStoreDna(lastUpdateRedundant, currentIndex, self._activeCharID, force=force, allowRedundant=allowReduntant) 1405 except: 1406 pass 1407 1408 @telemetry.ZONE_METHOD 1409 def PassMouseEventToSculpt(self, type, x, y): 1410 if not hasattr(self, 'characterSvc'): 1411 return 1412 if self.dollManager.GetDoll(self._activeCharID) and self.dollManager.GetDoll(self._activeCharID).IsBusyUpdating(): 1413 return 1414 sculpting = self.characterSvc.GetSculpting() 1415 if not uicore.uilib.leftbtn and sculpting and sculpting.startXY is not None and self.characterSvc.GetSculptingActive(): 1416 type = 'LeftUp' 1417 pickValue = None 1418 if sculpting and self.characterSvc.GetSculptingActive(): 1419 if type == 'LeftDown': 1420 pickValue = sculpting.PickWrapper(x, y) 1421 elif type == 'LeftUp': 1422 pickValue = sculpting.EndMotion(x, y) 1423 elif type == 'Motion': 1424 pickValue = sculpting.MotionWrapper(x, y) 1425 return pickValue 1426 1427 def PickPortrait(self, newPortraitID): 1428 if self.stepID != ccConst.PORTRAITSTEP: 1429 return 1430 self.step.PickPortrait(newPortraitID) 1431 1432 def AnimateToStoredPortrait(self, newPortraitID): 1433 if self.stepID == ccConst.PORTRAITSTEP: 1434 info = self.GetInfo() 1435 self.portraitManager.AnimateToStoredPortrait(newPortraitID, info.charID) 1436 1437 def TryFreezeAnimation(self, *args): 1438 if sm.GetService('machoNet').GetGlobalConfig().get('disableFreezeAnimationInNCC'): 1439 return 1440 if self.stepID != ccConst.CUSTOMIZATIONSTEP: 1441 return 1442 info = self.GetInfo() 1443 avatar = self.characterSvc.GetSingleCharactersAvatar(info.charID) 1444 if avatar is not None: 1445 network = animparams.GetParamsPerAvatar(avatar, info.charID) 1446 network.update = False 1447 self.freezingAnimation = True 1448 1449 def UnfreezeAnimationIfNeeded(self, *args): 1450 if self.freezingAnimation: 1451 info = self.GetInfo() 1452 avatar = self.characterSvc.GetSingleCharactersAvatar(info.charID) 1453 if avatar is not None: 1454 network = animparams.GetParamsPerAvatar(avatar, info.charID) 1455 network.update = True 1456 self.freezingAnimation = False