class AvatarInputHandler(CallbackDelayer, ComponentSystem): bootcampCtrl = dependency.descriptor(IBootcampController) ctrl = property(lambda self: self.__curCtrl) ctrls = property(lambda self: self.__ctrls) isSPG = property(lambda self: self.__isSPG) isATSPG = property(lambda self: self.__isATSPG) isFlashBangAllowed = property(lambda self: self.__ctrls['video'] != self.__curCtrl) isDetached = property(lambda self: self.__isDetached) isGuiVisible = property(lambda self: self.__isGUIVisible) isStarted = property(lambda self: self.__isStarted) isObserverFPV = property(lambda self: BigWorld.player().isObserver() and BigWorld.player().isObserverFPV) remoteCameraSender = property(lambda self: self.__remoteCameraSender) __ctrlModeName = aih_global_binding.bindRW(_BINDING_ID.CTRL_MODE_NAME) __aimOffset = aih_global_binding.bindRW(_BINDING_ID.AIM_OFFSET) _DYNAMIC_CAMERAS_ENABLED_KEY = 'global/dynamicCameraEnabled' settingsCore = dependency.descriptor(ISettingsCore) @staticmethod def enableDynamicCamera(enable, useHorizontalStabilizer=True): for dynamicCameraClass in _DYNAMIC_CAMERAS: dynamicCameraClass.enableDynamicCamera(enable) SniperAimingSystem.setStabilizerSettings(useHorizontalStabilizer, True) @staticmethod def isCameraDynamic(): for dynamicCameraClass in _DYNAMIC_CAMERAS: if not dynamicCameraClass.isCameraDynamic(): return False return True @staticmethod def isSniperStabilized(): return SniperAimingSystem.getStabilizerSettings() @property def ctrlModeName(self): return self.__ctrlModeName siegeModeControl = ComponentDescriptor() siegeModeSoundNotifications = ComponentDescriptor() steadyVehicleMatrixCalculator = ComponentDescriptor() def __init__(self): CallbackDelayer.__init__(self) ComponentSystem.__init__(self) self.__alwaysShowAimKey = None self.__showMarkersKey = None sec = self._readCfg() self.onCameraChanged = Event() self.onPostmortemVehicleChanged = Event() self.onPostmortemKillerVisionEnter = Event() self.onPostmortemKillerVisionExit = Event() self.__isArenaStarted = False self.__isStarted = False self.__targeting = _Targeting() self.__vertScreenshotCamera = _VertScreenshotCamera() self.__ctrls = dict() self.__killerVehicleID = None self.__isAutorotation = True self.__prevModeAutorotation = None self.__isSPG = False self.__isATSPG = False self.__setupCtrls(sec) self.__curCtrl = self.__ctrls[_CTRLS_FIRST] self.__ctrlModeName = _CTRLS_FIRST self.__isDetached = False self.__waitObserverCallback = None self.__observerVehicle = None self.__observerIsSwitching = False self.__commands = [] self.__remoteCameraSender = None self.__isGUIVisible = False return def __constructComponents(self): player = BigWorld.player() if player.vehicleTypeDescriptor.hasSiegeMode: if not self.siegeModeControl: self.siegeModeControl = SiegeModeControl() self.__commands.append(self.siegeModeControl) self.siegeModeControl.onSiegeStateChanged += lambda *args: self.steadyVehicleMatrixCalculator.relinkSources() self.siegeModeSoundNotifications = SiegeModeSoundNotifications() self.siegeModeControl.onSiegeStateChanged += self.siegeModeSoundNotifications.onSiegeStateChanged self.siegeModeControl.onRequestFail += self.__onRequestFail self.siegeModeControl.onSiegeStateChanged += SiegeModeCameraShaker.shake if self.bootcampCtrl.isInBootcamp() and constants.HAS_DEV_RESOURCES: self.__commands.append(BootcampModeControl()) def prerequisites(self): out = [] for ctrl in self.__ctrls.itervalues(): out += ctrl.prerequisites() return out def handleKeyEvent(self, event): import game isDown, key, mods, isRepeat = game.convertKeyEvent(event) if isRepeat: return False elif self.__isStarted and self.__isDetached: if self.__curCtrl.alwaysReceiveKeyEvents() and not self.isObserverFPV or CommandMapping.g_instance.isFired(CommandMapping.CMD_CM_LOCK_TARGET, key): self.__curCtrl.handleKeyEvent(isDown, key, mods, event) return BigWorld.player().handleKey(isDown, key, mods) elif not self.__isStarted or self.__isDetached: return False for command in self.__commands: if command.handleKeyEvent(isDown, key, mods, event): return True if isDown and BigWorld.isKeyDown(Keys.KEY_CAPSLOCK): if self.__alwaysShowAimKey is not None and key == self.__alwaysShowAimKey: gui_event_dispatcher.toggleCrosshairVisibility() return True if self.__showMarkersKey is not None and key == self.__showMarkersKey and not self.__isGUIVisible: gui_event_dispatcher.toggleMarkers2DVisibility() return True if key == Keys.KEY_F5 and constants.HAS_DEV_RESOURCES: self.__vertScreenshotCamera.enable(not self.__vertScreenshotCamera.isEnabled) return True if key == Keys.KEY_SPACE and isDown and BigWorld.player().isObserver(): BigWorld.player().cell.switchObserverFPV(not BigWorld.player().isObserverFPV) return True else: return True if not self.isObserverFPV and self.__curCtrl.handleKeyEvent(isDown, key, mods, event) else BigWorld.player().handleKey(isDown, key, mods) def handleMouseEvent(self, dx, dy, dz): return False if not self.__isStarted or self.__isDetached else self.__curCtrl.handleMouseEvent(dx, dy, dz) def setForcedGuiControlMode(self, flags): result = False detached = flags & GUI_CTRL_MODE_FLAG.CURSOR_ATTACHED > 0 if detached ^ self.__isDetached: self.__isDetached = detached self.__targeting.detach(self.__isDetached) if detached: g_appLoader.attachCursor(settings.APP_NAME_SPACE.SF_BATTLE, flags=flags) result = True if flags & GUI_CTRL_MODE_FLAG.AIMING_ENABLED > 0: self.setAimingMode(False, AIMING_MODE.USER_DISABLED) else: g_appLoader.detachCursor(settings.APP_NAME_SPACE.SF_BATTLE) result = True self.__curCtrl.setForcedGuiControlMode(detached) elif detached: g_appLoader.syncCursor(settings.APP_NAME_SPACE.SF_BATTLE, flags=flags) return result def updateShootingStatus(self, canShoot): return None if self.__isDetached else self.__curCtrl.updateShootingStatus(canShoot) def getDesiredShotPoint(self, ignoreAimingMode=False): return None if self.__isDetached else self.__curCtrl.getDesiredShotPoint(ignoreAimingMode) def getMarkerPoint(self): point = None if self.__ctrlModeName in (_CTRL_MODE.ARCADE, _CTRL_MODE.STRATEGIC, _CTRL_MODE.ARTY): AimingSystems.shootInSkyPoint.has_been_called = False point = self.getDesiredShotPoint(ignoreAimingMode=True) if AimingSystems.shootInSkyPoint.has_been_called: point = None return point def showGunMarker(self, isShown): self.__curCtrl.setGunMarkerFlag(isShown, _GUN_MARKER_FLAG.CLIENT_MODE_ENABLED) def showGunMarker2(self, isShown): if not BattleReplay.isPlaying(): self.__curCtrl.setGunMarkerFlag(isShown, _GUN_MARKER_FLAG.SERVER_MODE_ENABLED) if gun_marker_ctrl.useDefaultGunMarkers(): self.__curCtrl.setGunMarkerFlag(not isShown, _GUN_MARKER_FLAG.CLIENT_MODE_ENABLED) replayCtrl = BattleReplay.g_replayCtrl replayCtrl.setUseServerAim(isShown) def updateGunMarker(self, pos, direction, size, relaxTime, collData): self.__curCtrl.updateGunMarker(_GUN_MARKER_TYPE.CLIENT, pos, direction, size, relaxTime, collData) def updateGunMarker2(self, pos, direction, size, relaxTime, collData): self.__curCtrl.updateGunMarker(_GUN_MARKER_TYPE.SERVER, pos, direction, size, relaxTime, collData) def setAimingMode(self, enable, mode): self.__curCtrl.setAimingMode(enable, mode) def getAimingMode(self, mode): return self.__curCtrl.getAimingMode(mode) def setAutorotation(self, bValue): if not self.__curCtrl.enableSwitchAutorotationMode(): return elif not BigWorld.player().isOnArena: return else: if self.__isAutorotation != bValue: self.__isAutorotation = bValue BigWorld.player().enableOwnVehicleAutorotation(self.__isAutorotation) self.__prevModeAutorotation = None return def getAutorotation(self): return self.__isAutorotation def switchAutorotation(self): self.setAutorotation(not self.__isAutorotation) def activatePostmortem(self, isRespawn): if self.siegeModeSoundNotifications is not None: self.siegeModeSoundNotifications = None BigWorld.player().autoAim(None) for ctlMode in self.__ctrls.itervalues(): ctlMode.resetAimingMode() try: params = self.__curCtrl.postmortemCamParams except Exception: params = None onPostmortemActivation = getattr(self.__curCtrl, 'onPostmortemActivation', None) if onPostmortemActivation is not None: onPostmortemActivation(_CTRL_MODE.POSTMORTEM, postmortemParams=params, bPostmortemDelay=True, respawn=isRespawn) else: self.onControlModeChanged(_CTRL_MODE.POSTMORTEM, postmortemParams=params, bPostmortemDelay=True, respawn=isRespawn) return def deactivatePostmortem(self): self.onControlModeChanged('arcade') arcadeMode = self.__ctrls['arcade'] arcadeMode.camera.setToVehicleDirection() self.__identifySPG() self.__constructComponents() def setKillerVehicleID(self, killerVehicleID): self.__killerVehicleID = killerVehicleID def getKillerVehicleID(self): return self.__killerVehicleID def start(self): g_guiResetters.add(self.__onRecreateDevice) self.steadyVehicleMatrixCalculator = SteadyVehicleMatrixCalculator() self.__identifySPG() self.__constructComponents() for control in self.__ctrls.itervalues(): control.create() avatar = BigWorld.player() if not self.__curCtrl.isManualBind(): avatar.positionControl.bindToVehicle(True) self.__curCtrl.enable() tmp = self.__curCtrl.getPreferredAutorotationMode() if tmp is not None: self.__isAutorotation = tmp self.__prevModeAutorotation = True else: self.__isAutorotation = True self.__prevModeAutorotation = None avatar.enableOwnVehicleAutorotation(self.__isAutorotation) self.__targeting.enable(True) self.__isStarted = True self.__isGUIVisible = True self.__killerVehicleID = None arena = avatar.arena arena.onPeriodChange += self.__onArenaStarted self.settingsCore.onSettingsChanged += self.__onSettingsChanged avatar.consistentMatrices.onVehicleMatrixBindingChanged += self.__onVehicleChanged self.__onArenaStarted(arena.period) if not avatar.isObserver() and arena.hasObservers: self.__remoteCameraSender = RemoteCameraSender(self) self.onCameraChanged('arcade') return def stop(self): self.__isStarted = False import SoundGroups SoundGroups.g_instance.changePlayMode(0) aih_global_binding.clear() for control in self.__ctrls.itervalues(): control.destroy() replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isRecording: replayCtrl.setPlayerVehicleID(0) if self.__remoteCameraSender is not None: self.__remoteCameraSender.destroy() self.__remoteCameraSender = None self.onCameraChanged.clear() self.onCameraChanged = None self.onPostmortemVehicleChanged.clear() self.onPostmortemVehicleChanged = None self.onPostmortemKillerVisionEnter.clear() self.onPostmortemKillerVisionEnter = None self.onPostmortemKillerVisionExit.clear() self.onPostmortemKillerVisionExit = None self.__targeting.enable(False) self.__killerVehicleID = None if self.__onRecreateDevice in g_guiResetters: g_guiResetters.remove(self.__onRecreateDevice) BigWorld.player().arena.onPeriodChange -= self.__onArenaStarted self.settingsCore.onSettingsChanged -= self.__onSettingsChanged BigWorld.player().consistentMatrices.onVehicleMatrixBindingChanged -= self.__onVehicleChanged ComponentSystem.destroy(self) CallbackDelayer.destroy(self) return def __onVehicleChanged(self, isStatic): self.steadyVehicleMatrixCalculator.relinkSources() self.__identifySPG() if self.__waitObserverCallback is not None and self.__observerVehicle is not None: player = BigWorld.player() ownVehicle = BigWorld.entity(player.playerVehicleID) vehicle = player.getVehicleAttached() if vehicle != ownVehicle: self.__waitObserverCallback() self.__observerIsSwitching = False self.__observerVehicle = None return def setObservedVehicle(self, vehicleID): for control in self.__ctrls.itervalues(): control.setObservedVehicle(vehicleID) def onControlModeChanged(self, eMode, **args): if self.steadyVehicleMatrixCalculator is not None: self.steadyVehicleMatrixCalculator.relinkSources() if not self.__isArenaStarted and eMode != _CTRL_MODE.POSTMORTEM: return else: player = BigWorld.player() isObserverMode = 'observer' in player.vehicleTypeDescriptor.type.tags if player is not None else True if self.__waitObserverCallback is not None: self.__waitObserverCallback = None if isObserverMode and eMode == _CTRL_MODE.POSTMORTEM: if self.__observerVehicle is not None and not self.__observerIsSwitching: self.__waitObserverCallback = partial(self.onControlModeChanged, eMode, **args) self.__observerIsSwitching = True player.positionControl.followCamera(False) player.positionControl.bindToVehicle(True, self.__observerVehicle) return if isObserverMode and self.__ctrlModeName == _CTRL_MODE.POSTMORTEM: player = BigWorld.player() self.__observerVehicle = player.vehicle.id if player.vehicle else None self.__observerIsSwitching = False replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isRecording: replayCtrl.setControlMode(eMode) self.__curCtrl.disable() prevCtrl = self.__curCtrl self.__curCtrl = self.__ctrls[eMode] self.__ctrlModeName = eMode if player is not None: if not prevCtrl.isManualBind() and self.__curCtrl.isManualBind(): if isObserverMode: player.positionControl.bindToVehicle(False, -1) else: player.positionControl.bindToVehicle(False) elif prevCtrl.isManualBind() and not self.__curCtrl.isManualBind(): if isObserverMode: player.positionControl.followCamera(False) player.positionControl.bindToVehicle(True, self.__observerVehicle) else: player.positionControl.bindToVehicle(True) elif not prevCtrl.isManualBind() and not self.__curCtrl.isManualBind(): if isObserverMode and not self.isObserverFPV: player.positionControl.bindToVehicle(True) newAutoRotationMode = self.__curCtrl.getPreferredAutorotationMode() if newAutoRotationMode is not None: if prevCtrl.getPreferredAutorotationMode() is None: self.__prevModeAutorotation = self.__isAutorotation if self.__isAutorotation != newAutoRotationMode: self.__isAutorotation = newAutoRotationMode BigWorld.player().enableOwnVehicleAutorotation(self.__isAutorotation) elif prevCtrl.getPreferredAutorotationMode() is not None: if self.__prevModeAutorotation is None: self.__prevModeAutorotation = True if self.__isAutorotation != self.__prevModeAutorotation: self.__isAutorotation = self.__prevModeAutorotation BigWorld.player().enableOwnVehicleAutorotation(self.__isAutorotation) self.__prevModeAutorotation = None if not isObserverMode and self.__ctrlModeName in (_CTRL_MODE.ARCADE, _CTRL_MODE.SNIPER): lockEnabled = prevCtrl.getAimingMode(AIMING_MODE.TARGET_LOCK) self.__curCtrl.setAimingMode(lockEnabled, AIMING_MODE.TARGET_LOCK) self.__targeting.onRecreateDevice() self.__curCtrl.setGUIVisible(self.__isGUIVisible) if isObserverMode: args.update(vehicleID=self.__observerVehicle) self.__curCtrl.enable(**args) else: self.__curCtrl.enable(**args) isReplayPlaying = replayCtrl.isPlaying vehicleID = None vehicle = player.getVehicleAttached() if isObserverMode: vehicleID = self.__observerVehicle elif vehicle is not None and isReplayPlaying: vehicleID = vehicle.id self.onCameraChanged(eMode, vehicleID) if not isReplayPlaying: self.__curCtrl.handleMouseEvent(0.0, 0.0, 0.0) return def onVehicleControlModeChanged(self, eMode): LOG_DEBUG('onVehicleControlModeChanged: ', eMode, self.isObserverFPV) if not self.isObserverFPV: self.onControlModeChanged(_CTRL_MODE.POSTMORTEM) return else: if eMode is None: eMode = _CTRL_MODES[BigWorld.player().observerFPVControlMode] targetPos = self.getDesiredShotPoint() or Math.Vector3(0, 0, 0) LOG_DEBUG('onVehicleControlModeChanged: ', eMode, targetPos) self.onControlModeChanged(eMode, preferredPos=targetPos, aimingMode=0, saveZoom=False, saveDist=True, equipmentID=None, curVehicleID=BigWorld.player().getVehicleAttached()) return def getTargeting(self): return self.__targeting def setGUIVisible(self, isVisible): self.__isGUIVisible = isVisible self.__curCtrl.setGUIVisible(isVisible) def selectPlayer(self, vehId): self.__curCtrl.selectPlayer(vehId) def onMinimapClicked(self, worldPos): self.__curCtrl.onMinimapClicked(worldPos) def onVehicleShaken(self, vehicle, impulsePosition, impulseDir, caliber, shakeReason): if shakeReason == _ShakeReason.OWN_SHOT_DELAYED: shakeFuncBound = functools.partial(self.onVehicleShaken, vehicle, impulsePosition, impulseDir, caliber, _ShakeReason.OWN_SHOT) delayTime = self.__dynamicCameraSettings.settings['ownShotImpulseDelay'] self.delayCallback(delayTime, shakeFuncBound) return else: camera = getattr(self.ctrl, 'camera', None) if camera is None: return impulseValue = self.__dynamicCameraSettings.getGunImpulse(caliber) vehicleSensitivity = 0.0 avatarVehicle = BigWorld.player().getVehicleAttached() if avatarVehicle is None or not avatarVehicle.isAlive(): return avatarVehicleTypeDesc = getattr(avatarVehicle, 'typeDescriptor', None) if avatarVehicleTypeDesc is not None: avatarVehWeightTons = avatarVehicleTypeDesc.physics['weight'] / 1000.0 vehicleSensitivity = self.__dynamicCameraSettings.getSensitivityToImpulse(avatarVehWeightTons) vehicleSensitivity *= avatarVehicleTypeDesc.hull.swinging.sensitivityToImpulse impulseReason = None isDistant = False if shakeReason == _ShakeReason.OWN_SHOT: if vehicle is avatarVehicle: impulseReason = cameras.ImpulseReason.MY_SHOT isDistant = False else: impulseReason = cameras.ImpulseReason.OTHER_SHOT isDistant = True elif vehicle is avatarVehicle: if shakeReason == _ShakeReason.HIT or shakeReason == _ShakeReason.HIT_NO_DAMAGE: impulseValue *= 1.0 if shakeReason == _ShakeReason.HIT else self.__dynamicCameraSettings.settings['zeroDamageHitSensitivity'] impulseReason = cameras.ImpulseReason.ME_HIT isDistant = False else: impulseReason = cameras.ImpulseReason.SPLASH isDistant = True impulseDir, impulseValue = self.__adjustImpulse(impulseDir, impulseValue, camera, impulsePosition, vehicleSensitivity, impulseReason) if isDistant: camera.applyDistantImpulse(impulsePosition, impulseValue, impulseReason) else: camera.applyImpulse(impulsePosition, impulseDir * impulseValue, impulseReason) return def onVehicleCollision(self, vehicle, impactVelocity): if impactVelocity < self.__dynamicCameraSettings.settings['minCollisionSpeed']: return else: camera = getattr(self.ctrl, 'camera', None) if camera is None: return avatarVehicle = BigWorld.player().getVehicleAttached() if avatarVehicle is None or not avatarVehicle.isAlive(): return if vehicle is avatarVehicle: impulse = Math.Vector3(0, impactVelocity * self.__dynamicCameraSettings.settings['collisionSpeedToImpulseRatio'], 0) camera.applyImpulse(vehicle.position, impulse, cameras.ImpulseReason.COLLISION) return def onVehicleDeath(self, vehicle, exploded): if not exploded: return else: camera = getattr(self.ctrl, 'camera', None) if camera is None: return avatarVehicle = BigWorld.player().getVehicleAttached() if avatarVehicle is None or avatarVehicle is vehicle: return caliber = vehicle.typeDescriptor.shot.shell.caliber impulseValue = self.__dynamicCameraSettings.getGunImpulse(caliber) avatarVehicleWeightInTons = avatarVehicle.typeDescriptor.physics['weight'] / 1000.0 vehicleSensitivity = self.__dynamicCameraSettings.getSensitivityToImpulse(avatarVehicleWeightInTons) vehicleSensitivity *= avatarVehicle.typeDescriptor.hull.swinging.sensitivityToImpulse _, impulseValue = self.__adjustImpulse(Math.Vector3(0, 0, 0), impulseValue, camera, vehicle.position, vehicleSensitivity, cameras.ImpulseReason.VEHICLE_EXPLOSION) camera.applyDistantImpulse(vehicle.position, impulseValue, cameras.ImpulseReason.VEHICLE_EXPLOSION) return def onExplosionImpulse(self, position, impulseValue): camera = getattr(self.ctrl, 'camera', None) if camera is None: return else: avatarVehicle = BigWorld.player().getVehicleAttached() if avatarVehicle is None: return avatarVehicleWeightInTons = avatarVehicle.typeDescriptor.physics['weight'] / 1000.0 vehicleSensitivity = self.__dynamicCameraSettings.getSensitivityToImpulse(avatarVehicleWeightInTons) vehicleSensitivity *= avatarVehicle.typeDescriptor.hull.swinging.sensitivityToImpulse _, impulseValue = self.__adjustImpulse(Math.Vector3(0, 0, 0), impulseValue, camera, position, vehicleSensitivity, cameras.ImpulseReason.HE_EXPLOSION) camera.applyDistantImpulse(position, impulseValue, cameras.ImpulseReason.HE_EXPLOSION) return def onProjectileHit(self, position, caliber, isOwnShot): if not isOwnShot: return else: camera = getattr(self.ctrl, 'camera', None) if camera is None: return impulseValue = self.__dynamicCameraSettings.getGunImpulse(caliber) vehicleSensitivity = 1.0 avatarVehicle = BigWorld.player().getVehicleAttached() if avatarVehicle is not None: avatarVehicleWeightInTons = avatarVehicle.typeDescriptor.physics['weight'] / 1000.0 vehicleSensitivity = self.__dynamicCameraSettings.getSensitivityToImpulse(avatarVehicleWeightInTons) vehicleSensitivity *= avatarVehicle.typeDescriptor.hull.swinging.sensitivityToImpulse _, impulseValue = self.__adjustImpulse(Math.Vector3(0, 0, 0), impulseValue, camera, position, vehicleSensitivity, cameras.ImpulseReason.VEHICLE_EXPLOSION) camera.applyDistantImpulse(position, impulseValue, cameras.ImpulseReason.PROJECTILE_HIT) return def onSpecificImpulse(self, position, impulse, specificCtrl=None): if specificCtrl is None: camera = getattr(self.ctrl, 'camera', None) else: camera = self.ctrls[specificCtrl].camera if camera is None: return else: camera.applyImpulse(position, impulse, cameras.ImpulseReason.MY_SHOT) return def __adjustImpulse(self, impulseDir, impulseValue, camera, impulsePosition, vehicleSensitivity, impulseReason): if impulseReason in camera.getReasonsAffectCameraDirectly(): dirToCamera = camera.camera.position - impulsePosition dirToCamera.normalise() impulseDir = dirToCamera else: impulseValue *= vehicleSensitivity return (impulseDir, impulseValue) def __identifySPG(self): veh = BigWorld.entity(BigWorld.player().playerVehicleID) if veh is None: return else: vehTypeDesc = veh.typeDescriptor.type self.__isSPG = 'SPG' in vehTypeDesc.tags self.__isATSPG = 'AT-SPG' in vehTypeDesc.tags return def reloadDynamicSettings(self): if not constants.HAS_DEV_RESOURCES: return ResMgr.purge(INPUT_HANDLER_CFG) sec = ResMgr.openSection(INPUT_HANDLER_CFG) self.__dynamicCameraSettings = DynamicCameraSettings(sec['dynamicCameraCommon']) try: self.__ctrls['sniper'].camera.aimingSystem.reloadConfig(sec['sniperMode']['camera']) except Exception: pass def _readCfg(self): sec = ResMgr.openSection(INPUT_HANDLER_CFG) if sec is None: LOG_ERROR('can not open <%s>.' % INPUT_HANDLER_CFG) return else: self.__checkSections(sec) keySec = sec['keys'] if keySec is not None: self.__showMarkersKey = getattr(Keys, keySec.readString('showMarkersKey', ''), None) self.__alwaysShowAimKey = getattr(Keys, keySec.readString('alwaysShowAimKey', ''), None) self.__dynamicCameraSettings = DynamicCameraSettings(sec['dynamicCameraCommon']) return sec def __setupCtrls(self, section): modules = (control_modes, MapCaseMode, RespawnDeathMode, epic_battle_death_mode) bonusType = BigWorld.player().arenaBonusType bonusTypeCtrlsMap = _OVERWRITE_CTRLS_DESC_MAP.get(bonusType, {}) for name, desc in _CTRLS_DESC_MAP.items(): if bonusTypeCtrlsMap.has_key(name): desc = bonusTypeCtrlsMap.get(name) try: if desc[2] != _CTRL_TYPE.DEVELOPMENT or desc[2] == _CTRL_TYPE.DEVELOPMENT and constants.HAS_DEV_RESOURCES: if name not in self.__ctrls: for module in modules: classType = getattr(module, desc[0], None) if classType is None: pass self.__ctrls[name] = classType(section[desc[1]] if desc[1] else None, self) break except Exception: LOG_DEBUG('Error while setting ctrls', name, desc, constants.HAS_DEV_RESOURCES) LOG_CURRENT_EXCEPTION() return def __checkSections(self, section): for _, desc in _CTRLS_DESC_MAP.items(): if desc[1] is None or desc[2] == _CTRL_TYPE.OPTIONAL or desc[2] == _CTRL_TYPE.DEVELOPMENT and not constants.HAS_DEV_RESOURCES: continue if not section.has_key(desc[1]): LOG_ERROR('Invalid section <%s> in <%s>.' % (desc[1], INPUT_HANDLER_CFG)) return def __onArenaStarted(self, period, *args): self.__isArenaStarted = period == ARENA_PERIOD.BATTLE self.__curCtrl.setGunMarkerFlag(self.__isArenaStarted, _GUN_MARKER_FLAG.CONTROL_ENABLED) self.showGunMarker2(gun_marker_ctrl.useServerGunMarker()) self.showGunMarker(gun_marker_ctrl.useClientGunMarker()) def __onRecreateDevice(self): self.__curCtrl.onRecreateDevice() self.__targeting.onRecreateDevice() def __onSettingsChanged(self, diff): if 'dynamicCamera' in diff or 'horStabilizationSnp' in diff: dynamicCamera = self.settingsCore.getSetting('dynamicCamera') horStabilizationSnp = self.settingsCore.getSetting('horStabilizationSnp') self.enableDynamicCamera(dynamicCamera, horStabilizationSnp) def __onRequestFail(self): player = BigWorld.player() if player is not None: player.showVehicleError('cantSwitchEngineDestroyed') return
class CompoundAppearance(ComponentSystem, CallbackDelayer): compoundModel = property(lambda self: self.__compoundModel) boundEffects = property(lambda self: self.__boundEffects) fashion = property(lambda self: self.__fashions.chassis) typeDescriptor = property(lambda self: self.__typeDesc) id = property(lambda self: self.__vID) isAlive = property(lambda self: self.__isAlive) isObserver = property(lambda self: self.__isObserver) def __setFashions(self, fashions, isTurretDetached = False): self.__fashions = fashions self.__fashion = fashions.chassis if isTurretDetached: self.__compoundModel.setupFashions((fashions.chassis, fashions.hull)) else: self.__compoundModel.setupFashions(fashions) fashions = property(lambda self: self.__fashions, __setFashions) terrainMatKind = property(lambda self: self.__currTerrainMatKind) terrainEffectMaterialNames = property(lambda self: self.__terrainEffectMaterialNames) isInWater = property(lambda self: self.waterSensor.isInWater) isUnderwater = property(lambda self: self.waterSensor.isUnderWater) waterHeight = property(lambda self: self.waterSensor.waterHeight) damageState = property(lambda self: self.__currentDamageState) frameTimeStamp = 0 rightTrackScroll = property(lambda self: self.__rightTrackScroll) leftTrackScroll = property(lambda self: self.__leftTrackScroll) splineTracks = property(lambda self: self.__splineTracks) activated = property(lambda self: self.__activated) isFlying = property(lambda self: self.flyingInfoProvider is not None and self.flyingInfoProvider.isFlying) isLeftSideFlying = property(lambda self: self.flyingInfoProvider is not None and self.flyingInfoProvider.isLeftSideFlying) isRightSideFlying = property(lambda self: self.flyingInfoProvider is not None and self.flyingInfoProvider.isRightSideFlying) @property def rpm(self): if self.detailedEngineState is not None: return self.detailedEngineState.rpm else: return 0.0 @property def gear(self): if self.detailedEngineState is not None: return self.detailedEngineState.gearNum else: return 0.0 trackScrollController = property(lambda self: self.__trackScrollCtl) filter = AutoProperty() detailedEngineState = ComponentDescriptor() engineAudition = ComponentDescriptor() trackCrashAudition = ComponentDescriptor() customEffectManager = ComponentDescriptor() highlighter = ComponentDescriptor() gunRecoil = ComponentDescriptor() gunLinkedNodesAnimator = ComponentDescriptor() swingingAnimator = ComponentDescriptor() suspensionSound = ComponentDescriptor() siegeEffects = ComponentDescriptor() lodCalculator = ComponentDescriptor() frictionAudition = ComponentDescriptor() suspension = ComponentDescriptor() leveredSuspension = ComponentDescriptor() suspensionController = ComponentDescriptor() wheelsAnimator = ComponentDescriptor() trackNodesAnimator = ComponentDescriptor() vehicleTraces = ComponentDescriptor() flyingInfoProvider = ComponentDescriptor() terrainMatKindSensor = ComponentDescriptor() waterSensor = ComponentDescriptor() peripheralsController = ComponentDescriptor() def __init__(self): CallbackDelayer.__init__(self) ComponentSystem.__init__(self) self.turretMatrix = Math.WGAdaptiveMatrixProvider() self.gunMatrix = Math.WGAdaptiveMatrixProvider() self.__vehicle = None self.__filter = None self.__originalFilter = None self.__typeDesc = None self.__fashion = None self.__crashedTracksCtrl = None self.__currentDamageState = VehicleDamageState() self.__effectsPlayer = None self.__engineMode = (0, 0) self.__currTerrainMatKind = [-1] * _MATKIND_COUNT self.__terrainEffectMaterialNames = [''] * _MATKIND_COUNT self.__chassisDecal = VehicleDecal(self) self.__splodge = None self.__vehicleStickers = None self.onModelChanged = Event() self.__leftTrackScroll = 0.0 self.__rightTrackScroll = 0.0 self.__fashions = None self.__compoundModel = None self.__boundEffects = None self.__splineTracks = None self.flyingInfoProvider = Vehicular.FlyingInfoProvider() self.__trackScrollCtl = BigWorld.PyTrackScroll() self.__trackScrollCtl.setFlyingInfo(DataLinks.createBoolLink(self.flyingInfoProvider, 'isLeftSideFlying'), DataLinks.createBoolLink(self.flyingInfoProvider, 'isRightSideFlying')) self.__weaponEnergy = 0.0 self.__activated = False self.__systemStarted = False self.__vID = 0 self.__isAlive = True self.__isTurretDetached = False self.__periodicTimerID = None self.__wasDeactivated = False self.__inSpeedTreeCollision = False self.__isObserver = False return def prerequisites(self, typeDescriptor, vID, health, isCrewActive, isTurretDetached, outfitCD): self.__currentDamageState.update(health, isCrewActive, False) outfit = Outfit(outfitCD) out = camouflages.getCamoPrereqs(outfit, typeDescriptor) splineDesc = typeDescriptor.chassis.splineDesc if splineDesc is not None: out.append(splineDesc.segmentModelLeft) out.append(splineDesc.segmentModelRight) if splineDesc.segment2ModelLeft is not None: out.append(splineDesc.segment2ModelLeft) if splineDesc.segment2ModelRight is not None: out.append(splineDesc.segment2ModelRight) self.__vID = vID self.__typeDesc = typeDescriptor self.__isTurretDetached = isTurretDetached return out def setVehicle(self, vehicle): self.__vehicle = vehicle if self.customEffectManager is not None: self.customEffectManager.setVehicle(vehicle) if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.setVehicle(vehicle) if self.frictionAudition is not None: self.frictionAudition.setVehicleMatrix(vehicle.matrix) self.highlighter.setVehicle(vehicle) self.__applyVehicleOutfit() return def __arenaPeriodChanged(self, period, *otherArgs): if self.detailedEngineState is None: return else: periodEndTime = BigWorld.player().arena.periodEndTime serverTime = BigWorld.serverTime() engine_state.notifyEngineOnArenaPeriodChange(self.detailedEngineState, period, periodEndTime, serverTime) return def activate(self): if self.__activated or self.__vehicle is None: return else: super(CompoundAppearance, self).activate() isPlayerVehicle = self.__vehicle.isPlayerVehicle self.__isObserver = 'observer' in self.__typeDesc.type.tags player = BigWorld.player() self.__originalFilter = self.__vehicle.filter self.__vehicle.filter = self.__filter self.__vehicle.filter.enableStabilisedMatrix(isPlayerVehicle) self.__filter.isStrafing = self.__vehicle.isStrafing self.__filter.vehicleCollisionCallback = player.handleVehicleCollidedVehicle self.__compoundModel.isHighPriorityReflection = isPlayerVehicle if isPlayerVehicle: if player.inputHandler is not None: player.inputHandler.addVehicleToCameraCollider(self.__vehicle) self.__inSpeedTreeCollision = True BigWorld.setSpeedTreeCollisionBody(self.__compoundModel.getBoundsForPart(TankPartIndexes.HULL)) self.__linkCompound() if not self.__isObserver: self.__chassisDecal.attach() self.__createAndAttachStickers() self.__startSystems() self.setupGunMatrixTargets() if not self.__isObserver: self.__vehicle.filter.enableLagDetection(not self.__currentDamageState.isCurrentModelDamaged) self.onModelChanged() if self.lodCalculator is not None: self.lodCalculator.setupPosition(DataLinks.linkMatrixTranslation(self.__compoundModel.matrix)) if hasattr(self.filter, 'placingCompensationMatrix') and self.swingingAnimator is not None: self.swingingAnimator.placingCompensationMatrix = self.filter.placingCompensationMatrix self.swingingAnimator.worldMatrix = self.__compoundModel.matrix if self.__periodicTimerID is not None: BigWorld.cancelCallback(self.__periodicTimerID) self.__periodicTimerID = BigWorld.callback(_PERIODIC_TIME, self.__onPeriodicTimer) if self.fashion is not None: self.fashion.activate() if self.__isObserver: self.__compoundModel.visible = False BigWorld.player().arena.onPeriodChange += self.__arenaPeriodChanged BigWorld.player().inputHandler.onCameraChanged += self.__onCameraChanged if self.detailedEngineState is not None: engine_state.checkEngineStart(self.detailedEngineState, BigWorld.player().arena.period) self.__activated = True return def deactivate(self, stopEffects = True): if not self.__activated: return else: self.__activated = False self.__wasDeactivated = True if self.fashion is not None: self.fashion.deactivate() self.__stopSystems() super(CompoundAppearance, self).deactivate() self.__chassisDecal.detach() if self.__inSpeedTreeCollision: BigWorld.setSpeedTreeCollisionBody(None) BigWorld.player().inputHandler.removeVehicleFromCameraCollider(self.__vehicle) self.__vehicle.filter.enableLagDetection(False) self.turretMatrix.target = None self.gunMatrix.target = None self.__vehicle.filter = self.__originalFilter self.__filter.reset() self.__originalFilter = None self.__vehicleStickers.detach() if stopEffects: self.__stopEffects() self.__boundEffects.stop() self.__vehicle.model = None self.__compoundModel.matrix = Math.Matrix() self.__vehicle = None if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.deactivate() BigWorld.player().arena.onPeriodChange -= self.__arenaPeriodChanged BigWorld.player().inputHandler.onCameraChanged -= self.__onCameraChanged return def __startSystems(self): if self.__systemStarted or self.__currentDamageState.isCurrentModelDamaged: return else: if self.flyingInfoProvider is not None: self.flyingInfoProvider.setData(self.__vehicle.filter, self.suspension) if self.__trackScrollCtl is not None: self.__trackScrollCtl.activate() self.__trackScrollCtl.setData(self.__vehicle.filter) if self.__vehicle.isPlayerVehicle: self.delayCallback(_PERIODIC_TIME_ENGINE, self.__onPeriodicTimerEngine) self.highlighter.highlight(True) if self.engineAudition is not None: self.engineAudition.setWeaponEnergy(self.__weaponEnergy) self.engineAudition.attachToModel(self.__compoundModel) if self.peripheralsController is not None: self.peripheralsController.attachToVehicle(self.__vehicle) if self.suspensionController is not None: self.suspensionController.setData(self.__vehicle.filter, self.__vehicle.typeDescriptor) if self.detailedEngineState is not None: self.detailedEngineState.onGearUpCbk = self.__onEngineStateGearUp self.__systemStarted = True return def __stopSystems(self): if not self.__systemStarted: return else: self.__systemStarted = False if self.__periodicTimerID is not None: BigWorld.cancelCallback(self.__periodicTimerID) self.__periodicTimerID = None if self.flyingInfoProvider is not None: self.flyingInfoProvider.setData(None, None) if self.__vehicle.isPlayerVehicle: self.highlighter.highlight(False) self.stopCallback(self.__onPeriodicTimerEngine) if self.__trackScrollCtl is not None: self.__trackScrollCtl.deactivate() self.__trackScrollCtl.setData(None) if self.detailedEngineState is not None: self.detailedEngineState.onGearUpCbk = None return def __destroySystems(self): if self.__periodicTimerID is not None: BigWorld.cancelCallback(self.__periodicTimerID) self.__periodicTimerID = None if self.__trackScrollCtl is not None: self.__trackScrollCtl.deactivate() self.__trackScrollCtl = None if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.destroy() self.__crashedTracksCtrl = None self.__systemStarted = False return def __destroyEngineAudition(self): self.engineAudition = None if self.detailedEngineState is not None: self.detailedEngineState.onEngineStart = None self.detailedEngineState.onStateChanged = None return def __prepareSystemsForDamagedVehicle(self, vehicle, isTurretDetached): if self.flyingInfoProvider is not None: self.flyingInfoProvider.setData(vehicle.filter, None) self.vehicleTraces = None self.suspensionSound = None self.swingingAnimator = None self.gunRecoil = None self.gunLinkedNodesAnimator = None self.suspension = None self.leveredSuspension = None self.trackNodesAnimator = None self.wheelsAnimator = None fashions = VehiclePartsTuple(None, None, None, None) self.__setFashions(fashions, isTurretDetached) self.customEffectManager = None self.__destroyEngineAudition() self.detailedEngineState = None self.trackCrashAudition = None self.frictionAudition = None self.terrainMatKindSensor = None self.__splineTracks = None model = self.compoundModel self.waterSensor.sensorPlaneLink = model.root self.peripheralsController = None self.__destroySystems() return def destroy(self): if self.__vehicle is not None: self.deactivate() self.__destroySystems() ComponentSystem.destroy(self) self.__typeDesc = None if self.__boundEffects is not None: self.__boundEffects.destroy() self.__vehicleStickers = None self.onModelChanged = None self.__chassisDecal.destroy() self.__chassisDecal = None self.__compoundModel = None CallbackDelayer.destroy(self) return def start(self, prereqs = None): for hitTester in self.__typeDesc.getHitTesters(): hitTester.loadBspModel() self.__compoundModel = prereqs[self.__typeDesc.name] self.__boundEffects = bound_effects.ModelBoundEffects(self.__compoundModel) isCurrentModelDamaged = self.__currentDamageState.isCurrentModelDamaged fashions = camouflages.prepareFashions(isCurrentModelDamaged) if not isCurrentModelDamaged: model_assembler.setupVehicleFashion(fashions.chassis, self.__typeDesc) self.__setFashions(fashions, self.__isTurretDetached) self.__setupModels() if not isCurrentModelDamaged: self.__splineTracks = model_assembler.setupSplineTracks(self.__fashion, self.__typeDesc, self.__compoundModel, prereqs) self.__crashedTracksCtrl = CrashedTrackController(self.__typeDesc, self.__fashion) else: self.__trackScrollCtl = None if self.__currentDamageState.effect is not None: self.__playEffect(self.__currentDamageState.effect, SpecialKeyPointNames.STATIC) self.__chassisDecal.create() return def showStickers(self, show): self.__vehicleStickers.show = show def updateTurretVisibility(self): self.__requestModelsRefresh() def changeVisibility(self, modelVisible): self.compoundModel.visible = modelVisible self.showStickers(modelVisible) if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.setVisible(modelVisible) return def changeDrawPassVisibility(self, visibilityMask): colorPassEnabled = visibilityMask & BigWorld.ColorPassBit != 0 self.compoundModel.visible = visibilityMask self.compoundModel.skipColorPass = not colorPassEnabled self.showStickers(colorPassEnabled) if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.setVisible(visibilityMask) return def onVehicleHealthChanged(self, showEffects = True): vehicle = self.__vehicle if not vehicle.isAlive() and vehicle.health > 0: self.changeEngineMode((0, 0)) currentState = self.__currentDamageState previousState = currentState.state isUnderWater = self.waterSensor.isUnderWater currentState.update(vehicle.health, vehicle.isCrewActive, isUnderWater) if previousState != currentState.state: if currentState.effect is not None and showEffects: self.__playEffect(currentState.effect) if vehicle.health <= 0: BigWorld.player().inputHandler.onVehicleDeath(vehicle, currentState.state == 'ammoBayExplosion') self.processVehicleDeath(currentState) self.__requestModelsRefresh() elif not vehicle.isCrewActive: self.__onCrewKilled() return @ComponentSystem.groupCall def processVehicleDeath(self, vehicleDamageState): pass def showAmmoBayEffect(self, mode, fireballVolume): if mode == constants.AMMOBAY_DESTRUCTION_MODE.POWDER_BURN_OFF: self.__playEffect('ammoBayBurnOff') return volumes = items.vehicles.g_cache.commonConfig['miscParams']['explosionCandleVolumes'] candleIdx = 0 for idx, volume in enumerate(volumes): if volume >= fireballVolume: break candleIdx = idx + 1 if candleIdx > 0: self.__playEffect('explosionCandle%d' % candleIdx) else: self.__playEffect('explosion') def changeEngineMode(self, mode, forceSwinging = False): self.__engineMode = mode if self.detailedEngineState is not None: self.detailedEngineState.mode = self.__engineMode[0] if self.__trackScrollCtl is not None: self.__trackScrollCtl.setMode(self.__engineMode) if BattleReplay.isPlaying() and BattleReplay.g_replayCtrl.isTimeWarpInProgress: return else: return def stopSwinging(self): if self.swingingAnimator is not None: self.swingingAnimator.accelSwingingPeriod = 0.0 return def removeDamageSticker(self, code): self.__vehicleStickers.delDamageSticker(code) def addDamageSticker(self, code, componentName, stickerID, segStart, segEnd): self.__vehicleStickers.addDamageSticker(code, componentName, stickerID, segStart, segEnd) def receiveShotImpulse(self, dir, impulse): if BattleReplay.isPlaying() and BattleReplay.g_replayCtrl.isTimeWarpInProgress: return else: if not VehicleDamageState.isDamagedModel(self.__currentDamageState.modelState): self.swingingAnimator.receiveShotImpulse(dir, impulse) if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.receiveShotImpulse(dir, impulse) return def recoil(self): gunNode = self.compoundModel.node(TankNodeNames.GUN_INCLINATION) impulseDir = Math.Matrix(gunNode).applyVector(Math.Vector3(0, 0, -1)) impulseValue = self.__typeDesc.gun.impulse self.receiveShotImpulse(impulseDir, impulseValue) self.gunRecoil.recoil() node = self.compoundModel.node('HP_gunFire') gunPos = Math.Matrix(node).translation BigWorld.player().inputHandler.onVehicleShaken(self.__vehicle, gunPos, impulseDir, self.__typeDesc.shot.shell.caliber, ShakeReason.OWN_SHOT_DELAYED) def addCrashedTrack(self, isLeft): if not self.__vehicle.isAlive(): return else: if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.addTrack(isLeft, self.isLeftSideFlying if isLeft else self.isRightSideFlying) if not self.__vehicle.isEnteringWorld and self.trackCrashAudition: self.trackCrashAudition.playCrashSound(isLeft) return def delCrashedTrack(self, isLeft): if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.delTrack(isLeft) if not self.__vehicle.isEnteringWorld and self.trackCrashAudition and self.__vehicle.isPlayerVehicle: self.trackCrashAudition.playCrashSound(isLeft, True) return def __getVehicleOutfit(self): if not self.__vehicle: return Outfit() outfitCD = self.__vehicle.publicInfo['outfit'] outfit = Outfit(outfitCD) if not (self.__vehicle.isPlayerVehicle or outfit.isHistorical()): if BigWorld.player().isC11nHistorical: outfit = Outfit() return outfit def __applyVehicleOutfit(self): outfit = self.__getVehicleOutfit() camouflages.updateFashions(self.__fashions, self.__typeDesc, self.__currentDamageState.isCurrentModelDamaged, outfit) def __requestModelsRefresh(self): currentModelState = self.__currentDamageState.modelState assembler = model_assembler.prepareCompoundAssembler(self.__typeDesc, currentModelState, self.__vehicle.spaceID, self.__vehicle.isTurretDetached) BigWorld.loadResourceListBG((assembler,), makeCallbackWeak(self.__onModelsRefresh, currentModelState)) def __onModelsRefresh(self, modelState, resourceList): if not self.damageState.isCurrentModelDamaged: raise AssertionError return BattleReplay.isFinished() and None elif not modelState == self.__currentDamageState.modelState: raise AssertionError return self.__vehicle is None and None else: prevTurretYaw = Math.Matrix(self.turretMatrix).yaw prevGunPitch = Math.Matrix(self.gunMatrix).pitch vehicle = self.__vehicle newCompoundModel = resourceList[self.__typeDesc.name] self.deactivate(False) self.__compoundModel = newCompoundModel self.__isTurretDetached = vehicle.isTurretDetached self.__prepareSystemsForDamagedVehicle(vehicle, self.__isTurretDetached) self.__setupModels() self.setVehicle(vehicle) self.activate() self.__reattachComponents(self.__compoundModel, self.__weaponEnergy) self.__filter.syncGunAngles(prevTurretYaw, prevGunPitch) model_assembler.setupTurretRotations(self) return None def __setupModels(self): self.__isAlive = not self.__currentDamageState.isCurrentModelDamaged if self.__isAlive: _, gunLength = self.__computeVehicleHeight() self.__weaponEnergy = gunLength * self.__typeDesc.shot.shell.caliber self.__setupHavok() if MAX_DISTANCE > 0: transform = self.__typeDesc.chassis.AODecals[0] self.__attachSplodge(BigWorld.Splodge(transform, MAX_DISTANCE, self.__typeDesc.chassis.hullPosition.y)) def __setupHavok(self): vDesc = self.__typeDesc node = self.compoundModel.node(TankPartNames.HULL) hkm = BigWorld.wg_createHKAttachment(node, vDesc.hull.hitTester.getBspModel()) if hkm is not None: node.attach(hkm) node = self.compoundModel.node(TankPartNames.TURRET) hkm = BigWorld.wg_createHKAttachment(node, vDesc.turret.hitTester.getBspModel()) if hkm is not None: node.attach(hkm) node = self.compoundModel.node(TankPartNames.CHASSIS) hkm = BigWorld.wg_createHKAttachment(node, vDesc.chassis.hitTester.getBspModel()) if hkm is not None: node.attach(hkm) node = self.compoundModel.node(TankPartNames.GUN) hkm = BigWorld.wg_createHKAttachment(node, vDesc.gun.hitTester.getBspModel()) if hkm is not None: node.attach(hkm) return def __reattachComponents(self, model, weaponEnergy): self.__boundEffects.reattachTo(model) if self.__effectsPlayer is not None: self.__effectsPlayer.reattachTo(model) if self.engineAudition is not None: self.engineAudition.setWeaponEnergy(weaponEnergy) self.engineAudition.attachToModel(model) return def __playEffect(self, kind, *modifs): self.__stopEffects() if kind == 'empty' or self.__vehicle is None: return else: enableDecal = True if kind in ('explosion', 'destruction') and self.isFlying: enableDecal = False if self.isUnderwater: if kind not in ('submersionDeath',): return effects = self.typeDescriptor.type.effects[kind] if not effects: return vehicle = self.__vehicle effects = random.choice(effects) self.__effectsPlayer = EffectsListPlayer(effects[1], effects[0], showShockWave=vehicle.isPlayerVehicle, showFlashBang=vehicle.isPlayerVehicle, isPlayer=vehicle.isPlayerVehicle, showDecal=enableDecal, start=vehicle.position + Math.Vector3(0.0, -1.0, 0.0), end=vehicle.position + Math.Vector3(0.0, 1.0, 0.0), entity_id=vehicle.id) self.__effectsPlayer.play(self.__compoundModel, *modifs) return __SPORT_ACTIONS_CAMOUFLAGES = {'ussr:T62A_sport': (95, 94), 'usa:M24_Chaffee_GT': (82, 83)} def __getCamouflageParams(self, vDesc, vID): vehicleInfo = BigWorld.player().arena.vehicles.get(vID) if vehicleInfo is not None: camouflageIdPerTeam = CompoundAppearance.__SPORT_ACTIONS_CAMOUFLAGES.get(vDesc.name) if camouflageIdPerTeam is not None: camouflageId = camouflageIdPerTeam[0] if vehicleInfo['team'] == 1 else camouflageIdPerTeam[1] return (camouflageId, time.time(), 100.0) camouflagePseudoname = vehicleInfo['events'].get('hunting', None) if camouflagePseudoname is not None: camouflIdsByNation = {0: {'black': 29, 'gold': 30, 'red': 31, 'silver': 32}, 1: {'black': 25, 'gold': 26, 'red': 27, 'silver': 28}, 2: {'black': 52, 'gold': 50, 'red': 51, 'silver': 53}, 3: {'black': 48, 'gold': 46, 'red': 47, 'silver': 49}, 4: {'black': 60, 'gold': 58, 'red': 59, 'silver': 61}, 5: {'black': 56, 'gold': 54, 'red': 55, 'silver': 57}, 6: {'black': 133, 'gold': 134, 'red': 135, 'silver': 136}, 7: {'black': 141, 'gold': 142, 'red': 143, 'silver': 144}, 8: {'black': 154, 'gold': 155, 'red': 156, 'silver': 157}} camouflIds = camouflIdsByNation.get(vDesc.type.customizationNationID) if camouflIds is not None: ret = camouflIds.get(camouflagePseudoname) if ret is not None: return (ret, time.time(), 100.0) arenaType = BigWorld.player().arena.arenaType camouflageKind = arenaType.vehicleCamouflageKind return vDesc.camouflages[camouflageKind] def __stopEffects(self): if self.__effectsPlayer is not None: self.__effectsPlayer.stop() self.__effectsPlayer = None return def __onCrewKilled(self): self.__destroyEngineAudition() if self.customEffectManager is not None: self.customEffectManager = None return def onWaterSplash(self, waterHitPoint, isHeavySplash): effectName = 'waterCollisionHeavy' if isHeavySplash else 'waterCollisionLight' self.__vehicle.showCollisionEffect(waterHitPoint, effectName, Math.Vector3(0.0, 1.0, 0.0)) def onUnderWaterSwitch(self, isUnderWater): if isUnderWater and self.__effectsPlayer is not None and self.__currentDamageState.effect not in ('submersionDeath',): self.__stopEffects() extra = self.__vehicle.typeDescriptor.extrasDict['fire'] if extra.isRunningFor(self.__vehicle): extra.checkUnderwater(self.__vehicle, isUnderWater) return def updateTracksScroll(self, leftScroll, rightScroll): self.__leftTrackScroll = leftScroll self.__rightTrackScroll = rightScroll if self.__trackScrollCtl is not None: self.__trackScrollCtl.setExternal(leftScroll, rightScroll) return def __onPeriodicTimerEngine(self): if self.detailedEngineState is None or self.engineAudition is None: return else: if self.siegeEffects is not None: self.siegeEffects.tick(_PERIODIC_TIME_ENGINE) return _PERIODIC_TIME_ENGINE def __onPeriodicTimer(self): timeStamp = BigWorld.wg_getFrameTimestamp() if CompoundAppearance.frameTimeStamp >= timeStamp: self.__periodicTimerID = BigWorld.callback(0.0, self.__onPeriodicTimer) return else: CompoundAppearance.frameTimeStamp = timeStamp self.__periodicTimerID = BigWorld.callback(_PERIODIC_TIME, self.__onPeriodicTimer) if self.__vehicle is None: return vehicle = self.__vehicle if self.peripheralsController is not None: self.peripheralsController.update(vehicle, self.__crashedTracksCtrl) if not vehicle.isAlive(): return distanceFromPlayer = (BigWorld.camera().position - vehicle.position).length self.__updateCurrTerrainMatKinds() if not self.__vehicle.isPlayerVehicle: if self.siegeEffects is not None: self.siegeEffects.tick(_PERIODIC_TIME) self.__updateEffectsLOD(distanceFromPlayer) if self.customEffectManager: self.customEffectManager.update() return def __updateEffectsLOD(self, distanceFromPlayer): if self.customEffectManager: enableExhaust = distanceFromPlayer <= _LOD_DISTANCE_EXHAUST and not self.isUnderwater enableTrails = distanceFromPlayer <= _LOD_DISTANCE_TRAIL_PARTICLES and BigWorld.wg_isVehicleDustEnabled() self.customEffectManager.enable(enableTrails, EffectSettings.SETTING_DUST) self.customEffectManager.enable(enableExhaust, EffectSettings.SETTING_EXHAUST) def __updateCurrTerrainMatKinds(self): if self.terrainMatKindSensor is None: return else: matKinds = self.terrainMatKindSensor.matKinds matKindsCount = len(matKinds) for i in xrange(_MATKIND_COUNT): matKind = matKinds[i] if i < matKindsCount else 0 self.__currTerrainMatKind[i] = matKind effectIndex = calcEffectMaterialIndex(matKind) effectMaterialName = '' if effectIndex is not None: effectMaterialName = material_kinds.EFFECT_MATERIALS[effectIndex] self.__terrainEffectMaterialNames[i] = effectMaterialName if self.vehicleTraces is not None: self.vehicleTraces.setCurrTerrainMatKinds(self.__currTerrainMatKind[0], self.__currTerrainMatKind[1]) return def switchFireVibrations(self, bStart): if self.peripheralsController is not None: self.peripheralsController.switchFireVibrations(bStart) return def executeHitVibrations(self, hitEffectCode): if self.peripheralsController is not None: self.peripheralsController.executeHitVibrations(hitEffectCode) return def executeRammingVibrations(self, matKind = None): if self.peripheralsController is not None: self.peripheralsController.executeRammingVibrations(self.__vehicle, matKind) return def executeShootingVibrations(self, caliber): if self.peripheralsController is not None: self.peripheralsController.executeShootingVibrations(caliber) return def executeCriticalHitVibrations(self, vehicle, extrasName): if self.peripheralsController is not None: self.peripheralsController.executeCriticalHitVibrations(vehicle, extrasName) return def deviceStateChanged(self, deviceName, state): if not self.isUnderwater and self.detailedEngineState is not None and deviceName == 'engine': engineState = engine_state.getEngineStateFromName(state) self.detailedEngineState.engineState = engineState return def __linkCompound(self): vehicle = self.__vehicle vehicle.model = None vehicle.model = self.__compoundModel vehicleMatrix = vehicle.matrix self.__compoundModel.matrix = vehicleMatrix return def __createStickers(self): if self.__vehicleStickers is not None: return else: insigniaRank = self.__vehicle.publicInfo['marksOnGun'] outfit = self.__getVehicleOutfit() self.__vehicleStickers = VehicleStickers(self.__typeDesc, insigniaRank, outfit) clanID = BigWorld.player().arena.vehicles[self.__vehicle.id]['clanDBID'] self.__vehicleStickers.setClanID(clanID) return def __attachStickers(self, alpha = _DEFAULT_STICKERS_ALPHA, emblemsOnly = False): raise self.__vehicleStickers is not None or AssertionError self.__vehicleStickers.alpha = alpha self.__vehicleStickers.attach(self.compoundModel, self.__currentDamageState.isCurrentModelDamaged, not emblemsOnly) return def __createAndAttachStickers(self): isCurrentModelDamaged = self.__currentDamageState.isCurrentModelDamaged stickersAlpha = _DEFAULT_STICKERS_ALPHA if isCurrentModelDamaged: stickersAlpha = items.vehicles.g_cache.commonConfig['miscParams']['damageStickerAlpha'] self.__createStickers() self.__attachStickers(stickersAlpha, isCurrentModelDamaged) def __attachSplodge(self, splodge): node = self.__compoundModel.node(TankPartNames.HULL) if splodge is not None and self.__splodge is None: self.__splodge = splodge node.attach(splodge) return def __disableStipple(self): self.compoundModel.stipple = False def __computeVehicleHeight(self): desc = self.__typeDesc turretBBox = desc.turret.hitTester.bbox gunBBox = desc.gun.hitTester.bbox hullBBox = desc.hull.hitTester.bbox hullTopY = desc.chassis.hullPosition[1] + hullBBox[1][1] turretTopY = desc.chassis.hullPosition[1] + desc.hull.turretPositions[0][1] + turretBBox[1][1] gunTopY = desc.chassis.hullPosition[1] + desc.hull.turretPositions[0][1] + desc.turret.gunPosition[1] + gunBBox[1][1] return (max(hullTopY, max(turretTopY, gunTopY)), math.fabs(gunBBox[1][2] - gunBBox[0][2])) def setupGunMatrixTargets(self, target = None): if target is None: target = self.__filter self.turretMatrix.target = target.turretMatrix self.gunMatrix.target = target.gunMatrix return def onFriction(self, otherID, frictionPoint, state): if self.frictionAudition is not None: self.frictionAudition.processFriction(otherID, frictionPoint, state) return def assembleStipple(self): compound = self.compoundModel compound.matrix = Math.Matrix(compound.matrix) hullNode = compound.node(TankPartNames.HULL) compound.node(TankPartNames.HULL, hullNode.localMatrix) turretRotation = compound.node(TankPartNames.TURRET) if turretRotation is not None: compound.node(TankPartNames.TURRET, turretRotation.localMatrix) gunInclination = compound.node(TankNodeNames.GUN_INCLINATION) if gunInclination is not None: compound.node(TankNodeNames.GUN_INCLINATION, gunInclination.localMatrix) gunRecoil = compound.node(TankNodeNames.GUN_RECOIL) if gunRecoil is not None: compound.node(TankNodeNames.GUN_RECOIL, gunRecoil.localMatrix) self.fashions = VehiclePartsTuple(None, None, None, None) return def onSiegeStateChanged(self, newState): if self.engineAudition is not None: self.engineAudition.onSiegeStateChanged(newState) if self.suspensionController is not None: self.suspensionController.onSiegeStateChanged(newState) if self.suspensionSound is not None: self.__suspensionSound.vehicleState = newState if self.siegeEffects is not None: self.siegeEffects.onSiegeStateChanged(newState) return def __onCameraChanged(self, cameraName, currentVehicleId = None): if self.engineAudition is not None: self.engineAudition.onCameraChanged(cameraName, currentVehicleId if currentVehicleId is not None else 0) return def __onEngineStateGearUp(self): if self.customEffectManager is not None: self.customEffectManager.onGearUp() if self.engineAudition is not None: self.engineAudition.onEngineGearUp() return
class CompoundAppearance(ComponentSystem, CallbackDelayer): distanceFromPlayer = property(lambda self: self.__distanceFromPlayer) compoundModel = property(lambda self: self.__compoundModel) boundEffects = property(lambda self: self.__boundEffects) fashion = property(lambda self: self.__fashions.chassis) filter = property(lambda self: self.__filter) typeDescriptor = property(lambda self: self.__typeDesc) id = property(lambda self: self.__vID) isAlive = property(lambda self: self.__isAlive) def __setFashions(self, fashions, isTurretDetached = False): self.__fashions = fashions self.__fashion = fashions.chassis if isTurretDetached: self.__compoundModel.setupFashions((fashions.chassis, fashions.hull)) else: self.__compoundModel.setupFashions(fashions) fashions = property(lambda self: self.__fashions, __setFashions) terrainMatKind = property(lambda self: self.__currTerrainMatKind) isInWater = property(lambda self: self.__isInWater) isUnderwater = property(lambda self: self.__isUnderWater) waterHeight = property(lambda self: self.__waterHeight) damageState = property(lambda self: self.__currentDamageState) frameTimeStamp = 0 engineMode = property(lambda self: self.__engineMode) rightTrackScroll = property(lambda self: self.__rightTrackScroll) leftTrackScroll = property(lambda self: self.__leftTrackScroll) gunSound = property(lambda self: self.__gunSound) isPillbox = property(lambda self: self.__isPillbox) activated = property(lambda self: self.__activated) @property def rpm(self): if self.detailedEngineState is not None: return self.detailedEngineState.rpm else: return 0.0 return @property def gear(self): if self.detailedEngineState is not None: return self.detailedEngineState.gearNum else: return 0.0 return trackScrollController = property(lambda self: self.__trackScrollCtl) detailedEngineState = ComponentDescriptor() engineAudition = ComponentDescriptor() trackCrashAudition = ComponentDescriptor() customEffectManager = ComponentDescriptor() highlighter = ComponentDescriptor() gunRecoil = ComponentDescriptor() swingingAnimator = ComponentDescriptor() lodCalculator = ComponentDescriptor() def __init__(self): CallbackDelayer.__init__(self) ComponentSystem.__init__(self) self.turretMatrix = Math.WGAdaptiveMatrixProvider() self.gunMatrix = Math.WGAdaptiveMatrixProvider() self.__vehicle = None self.__filter = None self.__originalFilter = None self.__typeDesc = None self.__waterHeight = -1.0 self.__isInWater = False self.__isUnderWater = False self.__splashedWater = False self.__vibrationsCtrl = None self.__lightFxCtrl = None self.__auxiliaryFxCtrl = None self.__fashion = None self.__crashedTracksCtrl = None self.__gunRecoil = None self.__currentDamageState = VehicleDamageState() self.__loadingProgress = 0 self.__effectsPlayer = None self.__engineMode = (0, 0) self.__swingMoveFlags = 0 self.__currTerrainMatKind = [-1] * _MATKIND_COUNT self.__leftLightRotMat = None self.__rightLightRotMat = None self.__leftFrontLight = None self.__rightFrontLight = None self.__prevVelocity = None self.__prevTime = None self.__isPillbox = False self.__chassisOcclusionDecal = OcclusionDecal() self.__chassisShadowForwardDecal = ShadowForwardDecal() self.__splodge = None self.__vehicleStickers = None self.onModelChanged = Event() self.__speedInfo = Math.Vector4(0.0, 0.0, 0.0, 0.0) self.__wasOnSoftTerrain = False self.__vehicleMatrixProv = None self.__leftTrackScroll = 0.0 self.__rightTrackScroll = 0.0 self.__distanceFromPlayer = 0.0 self.__fashions = None self.__compoundModel = None self.__boundEffects = None self.__swingingAnimator = None self.__splineTracks = None self.__customEffectManager = None self.__trackScrollCtl = BigWorld.PyTrackScroll() self.__weaponEnergy = 0.0 self.__activated = False self.__systemStarted = False self.__vID = 0 self.__isAlive = True self.__isTurretDetached = False self.__trackFashionSet = False self.__periodicTimerID = None self.__wasDeactivated = False return def prerequisites(self, typeDescriptor, vID, health, isCrewActive, isTurretDetached): self.__currentDamageState.update(health, isCrewActive, self.__isUnderWater) out = [] out.append(typeDescriptor.type.camouflageExclusionMask) splineDesc = typeDescriptor.chassis['splineDesc'] if splineDesc is not None: out.append(splineDesc['segmentModelLeft']) out.append(splineDesc['segmentModelRight']) if splineDesc['segment2ModelLeft'] is not None: out.append(splineDesc['segment2ModelLeft']) if splineDesc['segment2ModelRight'] is not None: out.append(splineDesc['segment2ModelRight']) customization = items.vehicles.g_cache.customization(typeDescriptor.type.customizationNationID) camouflageParams = self.__getCamouflageParams(typeDescriptor, vID) if camouflageParams is not None and customization is not None: camouflageId = camouflageParams[0] camouflageDesc = customization['camouflages'].get(camouflageId) if camouflageDesc is not None and camouflageDesc['texture'] != '': out.append(camouflageDesc['texture']) for tgDesc in (typeDescriptor.turret, typeDescriptor.gun): exclMask = tgDesc.get('camouflageExclusionMask') if exclMask is not None and exclMask != '': out.append(exclMask) self.__vID = vID self.__typeDesc = typeDescriptor self.__isTurretDetached = isTurretDetached return out def setVehicle(self, vehicle): self.__vehicle = vehicle if self.__customEffectManager is not None: self.__customEffectManager.setVehicle(vehicle) if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.setVehicle(vehicle) self.highlighter.setVehicle(vehicle) return def activate(self): if self.__activated or self.__vehicle is None: return else: if self.__currentDamageState.isCurrentModelDamaged: if self.__customEffectManager is not None: self.__customEffectManager.destroy() self.__customEffectManager = None if self.detailedEngineState is not None: self.detailedEngineState.destroy() self.detailedEngineState = None super(CompoundAppearance, self).activate() isPlayerVehicle = self.__vehicle.isPlayerVehicle isObserver = 'observer' in self.__typeDesc.type.tags player = BigWorld.player() self.__originalFilter = self.__vehicle.filter self.__createFilter() self.__vehicle.filter = self.__filter self.__vehicle.filter.enableNewPhysics(True) self.__vehicle.filter.enableStabilisedMatrix(isPlayerVehicle) self.__filter.isStrafing = self.__vehicle.isStrafing self.__filter.vehicleCollisionCallback = player.handleVehicleCollidedVehicle self.__compoundModel.isHighPriorityReflection = isPlayerVehicle self.__vehicleMatrixProv = self.__compoundModel.matrix if isPlayerVehicle: if player.inputHandler is not None: player.inputHandler.addVehicleToCameraCollider(self.__vehicle) BigWorld.setSpeedTreeCollisionBody(self.__compoundModel.getBoundsForPart(TankPartIndexes.HULL)) self.__linkCompound() self.__chassisShadowForwardDecal.attach(self.__typeDesc, self.__compoundModel) if not isObserver: self.__chassisOcclusionDecal.attach(self.__typeDesc, self.__compoundModel) self.__createStickers() if self.__currentDamageState.isCurrentModelDamaged: self.__attachStickers(items.vehicles.g_cache.commonConfig['miscParams']['damageStickerAlpha'], True) else: self.__startSystems() self.__attachStickers() self.setupGunMatrixTargets() if not isObserver: self.__vehicle.filter.enableLagDetection(True) self.onModelChanged() if self.lodCalculator is not None: self.lodCalculator.setupPosition(DataLinks.linkMatrixTranslation(self.__compoundModel.matrix)) if hasattr(self.filter, 'placingCompensationMatrix') and self.swingingAnimator is not None: self.swingingAnimator.placingCompensationMatrix = self.filter.placingCompensationMatrix self.swingingAnimator.worldMatrix = self.__compoundModel.matrix if self.__periodicTimerID is not None: BigWorld.cancelCallback(self.__periodicTimerID) self.__periodicTimerID = BigWorld.callback(_PERIODIC_TIME, self.__onPeriodicTimer) self.__activated = True if 'observer' in self.__vehicle.typeDescriptor.type.tags: self.__compoundModel.visible = False if self.__currentDamageState.isCurrentModelDamaged: if not self.__wasDeactivated: if not self.__vehicle.isPlayerVehicle: self.setupGunMatrixTargets() else: self.setupGunMatrixTargets(self.__vehicle.filter) return def deactivate(self, stopEffects = True): if not self.__activated: return else: self.__activated = False self.__wasDeactivated = True self.__stopSystems() super(CompoundAppearance, self).deactivate() self.__chassisOcclusionDecal.detach() self.__chassisShadowForwardDecal.detach() self.__vibrationsCtrl = None if self.__vehicle.isPlayerVehicle: BigWorld.setSpeedTreeCollisionBody(None) BigWorld.player().inputHandler.removeVehicleFromCameraCollider(self.__vehicle) self.__vehicle.filter.enableLagDetection(False) self.turretMatrix.setStaticTransform(self.turretMatrix) self.turretMatrix.target = None self.gunMatrix.setStaticTransform(self.gunMatrix) self.gunMatrix.target = None self.__vehicle.filter = self.__originalFilter self.__filter = None self.__originalFilter = None self.__vehicleStickers.detach() if stopEffects: self.__stopEffects() self.__boundEffects.stop() self.__vehicle.model = None self.__compoundModel.matrix = Math.Matrix() self.__vehicle = None self.__vehicleMatrixProv = None if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.deactivate() return def __startSystems(self): if self.__trackScrollCtl is not None: self.__trackScrollCtl.activate() self.__trackScrollCtl.setData(self.__vehicle.filter, self.fashions.chassis) if self.__vehicle.isPlayerVehicle: self.delayCallback(_PERIODIC_TIME_ENGINE, self.__onPeriodicTimerEngine) self.highlighter.highlight(True) if self.detailedEngineState is not None: self.detailedEngineState.setVehicle(self.__vehicle) self.detailedEngineState.activate() if self.engineAudition is not None: self.engineAudition.vehicleFilter = self.filter self.engineAudition.activate() self.engineAudition.attachToModel(self.__compoundModel, self.__weaponEnergy) if self.__customEffectManager is not None: self.__customEffectManager.activate() if self.__vehicle.isAlive() and self.__vehicle.isPlayerVehicle: if self.__vibrationsCtrl is None: self.__vibrationsCtrl = VibrationControllersManager() if LightFx.LightManager.g_instance is not None and LightFx.LightManager.g_instance.isEnabled(): self.__lightFxCtrl = LightFxControllersManager(self.__vehicle) if AuxiliaryFx.g_instance is not None: self.__auxiliaryFxCtrl = AuxiliaryFx.g_instance.createFxController(self.__vehicle) self.__systemStarted = True return def __stopSystems(self): if not self.__systemStarted: return else: self.__systemStarted = False if self.__periodicTimerID is not None: BigWorld.cancelCallback(self.__periodicTimerID) self.__periodicTimerID = None if self.detailedEngineState is not None: self.detailedEngineState.deactivate() if self.__vehicle.isPlayerVehicle: self.highlighter.highlight(False) self.stopCallback(self.__onPeriodicTimerEngine) if self.__trackScrollCtl is not None: self.__trackScrollCtl.deactivate() self.__trackScrollCtl.setData(None, None) if self.engineAudition is not None: self.engineAudition.deactivate() if self.trackCrashAudition is not None: self.trackCrashAudition.deactivate() if self.__customEffectManager is not None: self.__customEffectManager.deactivate() if self.engineAudition is not None: self.engineAudition.destroy() if self.__lightFxCtrl is not None: self.__lightFxCtrl.destroy() self.__lightFxCtrl = None if self.__auxiliaryFxCtrl is not None: self.__auxiliaryFxCtrl.destroy() self.__auxiliaryFxCtrl = None return def __destroySystems(self): if self.__periodicTimerID is not None: BigWorld.cancelCallback(self.__periodicTimerID) self.__periodicTimerID = None if self.customEffectManager is not None: self.customEffectManager.destroy() self.customEffectManager = None if self.__trackScrollCtl is not None: self.__trackScrollCtl.deactivate() self.__trackScrollCtl = None if self.engineAudition is not None: self.engineAudition.destroy() self.engineAudition = None if self.__vibrationsCtrl is not None: self.__vibrationsCtrl.destroy() self.__vibrationsCtrl = None if self.__lightFxCtrl is not None: self.__lightFxCtrl.destroy() self.__lightFxCtrl = None if self.__auxiliaryFxCtrl is not None: self.__auxiliaryFxCtrl.destroy() self.__auxiliaryFxCtrl = None if self.detailedEngineState is not None: self.detailedEngineState.destroy() self.detailedEngineState = None self.trackCrashAudition = None if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.destroy() self.__crashedTracksCtrl = None return def destroy(self): self.__trackScrollCtl = None if self.__vehicle is not None: self.deactivate() self.__destroySystems() ComponentSystem.destroy(self) self.__typeDesc = None self.highlighter.destroy() if self.__vibrationsCtrl is not None: self.__vibrationsCtrl.destroy() self.__vibrationsCtrl = None if self.__lightFxCtrl is not None: self.__lightFxCtrl.destroy() self.__lightFxCtrl = None if self.__auxiliaryFxCtrl is not None: self.__auxiliaryFxCtrl.destroy() self.__auxiliaryFxCtrl = None if self.__boundEffects is not None: self.__boundEffects.destroy() self.__vehicleStickers = None self.onModelChanged = None if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.destroy() self.__crashedTracksCtrl = None self.__chassisOcclusionDecal.destroy() self.__chassisOcclusionDecal = None self.__chassisShadowForwardDecal.destroy() self.__chassisShadowForwardDecal = None self.__compoundModel = None CallbackDelayer.destroy(self) return def __createFilter(self): self.__isPillbox = 'pillbox' in self.__typeDesc.type.tags if self.__isPillbox: self.__filter = BigWorld.WGPillboxFilter() else: self.__filter = BigWorld.WGVehicleFilter() self.__filter.vehicleWidth = self.__typeDesc.chassis['topRightCarryingPoint'][0] * 2 self.__filter.maxMove = self.__typeDesc.physics['speedLimits'][0] * 2.0 self.__filter.vehicleMinNormalY = self.__typeDesc.physics['minPlaneNormalY'] for p1, p2, p3 in self.__typeDesc.physics['carryingTriangles']: self.__filter.addTriangle((p1[0], 0, p1[1]), (p2[0], 0, p2[1]), (p3[0], 0, p3[1])) fashion = self.__fashions[0] if fashion is not None: fashion.physicsInfo = self.__filter.physicsInfo fashion.movementInfo = self.__filter.movementInfo else: self.__trackFashionSet = False self.__filter.placingOnGround = self.__filter.placingOnGround if self.__trackFashionSet else False return def start(self, prereqs = None): if prereqs is None: self.__typeDesc.chassis['hitTester'].loadBspModel() self.__typeDesc.hull['hitTester'].loadBspModel() self.__typeDesc.turret['hitTester'].loadBspModel() for hitTester in self.__typeDesc.getHitTesters(): hitTester.loadBspModel() self.__compoundModel = prereqs[self.__typeDesc.name] self.__boundEffects = bound_effects.ModelBoundEffects(self.__compoundModel) fashions = camouflages.prepareFashions(self.__typeDesc, self.__currentDamageState.isCurrentModelDamaged, self.__getCamouflageParams(self.__typeDesc, self.__vID)[0]) if not self.__currentDamageState.isCurrentModelDamaged: self.__trackFashionSet = _setupVehicleFashion(fashions[0], self.__typeDesc) self.__compoundModel.setupFashions(fashions) fashions = camouflages.applyCamouflage(self.__typeDesc, fashions, self.__currentDamageState.isCurrentModelDamaged, self.__getCamouflageParams(self.__typeDesc, self.__vID)[0]) fashions = camouflages.applyRepaint(self.__typeDesc, fashions) self.__setFashions(fashions, self.__isTurretDetached) self.__setupModels() if not VehicleDamageState.isDamagedModel(self.__currentDamageState.modelState): self.__splineTracks = setupSplineTracks(self.__fashion, self.__typeDesc, self.__compoundModel, prereqs) if self.__currentDamageState.effect is not None: self.__playEffect(self.__currentDamageState.effect, SpecialKeyPointNames.STATIC) if self.__currentDamageState.isCurrentModelDamaged: self.__trackScrollCtl = None self.__crashedTracksCtrl = None else: self.__crashedTracksCtrl = CrashedTrackController(self.__typeDesc, self.__fashion) return def showStickers(self, show): self.__vehicleStickers.show = show def updateTurretVisibility(self): self.__requestModelsRefresh() def changeVisibility(self, modelVisible): self.compoundModel.visible = modelVisible self.showStickers(modelVisible) if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.setVisible(modelVisible) return def changeDrawPassVisibility(self, visibilityMask): colorPassEnabled = visibilityMask & BigWorld.ColorPassBit != 0 self.compoundModel.visible = visibilityMask self.compoundModel.skipColorPass = not colorPassEnabled self.showStickers(colorPassEnabled) if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.setVisible(visibilityMask) return def onVehicleHealthChanged(self): vehicle = self.__vehicle if not vehicle.isAlive(): if vehicle.health > 0: self.changeEngineMode((0, 0)) currentState = self.__currentDamageState previousState = currentState.state currentState.update(vehicle.health, vehicle.isCrewActive, self.__isUnderWater) if previousState != currentState.state: if currentState.effect is not None: self.__playEffect(currentState.effect) if vehicle.health <= 0: BigWorld.player().inputHandler.onVehicleDeath(vehicle, currentState.state == 'ammoBayExplosion') self.processVehicleDeath(currentState) self.__requestModelsRefresh() return @ComponentSystem.groupCall def processVehicleDeath(self, vehicleDamageState): pass def showAmmoBayEffect(self, mode, fireballVolume): if mode == constants.AMMOBAY_DESTRUCTION_MODE.POWDER_BURN_OFF: self.__playEffect('ammoBayBurnOff') return volumes = items.vehicles.g_cache.commonConfig['miscParams']['explosionCandleVolumes'] candleIdx = 0 for idx, volume in enumerate(volumes): if volume >= fireballVolume: break candleIdx = idx + 1 if candleIdx > 0: self.__playEffect('explosionCandle%d' % candleIdx) else: self.__playEffect('explosion') def changeEngineMode(self, mode, forceSwinging = False): self.__engineMode = mode if self.detailedEngineState is not None: self.detailedEngineState.setMode(self.__engineMode[0]) if self.__trackScrollCtl is not None: self.__trackScrollCtl.setMode(self.__engineMode) if BattleReplay.isPlaying() and BattleReplay.g_replayCtrl.isTimeWarpInProgress: return else: isOldPhysicsMode = self.__vehicle.physicsMode == VEHICLE_PHYSICS_MODE.STANDARD if isOldPhysicsMode and forceSwinging: flags = mode[1] prevFlags = self.__swingMoveFlags swingingAnimator = self.__swingingAnimator if swingingAnimator is not None: moveMask = 3 rotMask = 12 if flags & moveMask ^ prevFlags & moveMask: swingPeriod = 2.0 if flags & 1: swingingAnimator.accelSwingingDirection = -1 elif flags & 2: swingingAnimator.accelSwingingDirection = 1 else: swingingAnimator.accelSwingingDirection = 0 elif not flags & moveMask and flags & rotMask ^ prevFlags & rotMask: swingPeriod = 1.0 swingingAnimator.accelSwingingDirection = 0 else: swingPeriod = 0.0 if swingPeriod > swingingAnimator.accelSwingingPeriod: swingingAnimator.accelSwingingPeriod = swingPeriod self.__swingMoveFlags = flags return def stopSwinging(self): if self.__swingingAnimator is not None: self.__swingingAnimator.accelSwingingPeriod = 0.0 return def removeDamageSticker(self, code): self.__vehicleStickers.delDamageSticker(code) def addDamageSticker(self, code, componentName, stickerID, segStart, segEnd): self.__vehicleStickers.addDamageSticker(code, componentName, stickerID, segStart, segEnd) def receiveShotImpulse(self, dir, impulse): if BattleReplay.isPlaying() and BattleReplay.g_replayCtrl.isTimeWarpInProgress: return else: if not VehicleDamageState.isDamagedModel(self.__currentDamageState.modelState): self.__swingingAnimator.receiveShotImpulse(dir, impulse) if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.receiveShotImpulse(dir, impulse) return def recoil(self): gunNode = self.compoundModel.node(TankNodeNames.GUN_INCLINATION) impulseDir = Math.Matrix(gunNode).applyVector(Math.Vector3(0, 0, -1)) impulseValue = self.__typeDesc.gun['impulse'] self.receiveShotImpulse(impulseDir, impulseValue) self.__gunRecoil.recoil() node = self.compoundModel.node('HP_gunFire') gunPos = Math.Matrix(node).translation BigWorld.player().inputHandler.onVehicleShaken(self.__vehicle, gunPos, impulseDir, self.__typeDesc.shot['shell']['caliber'], ShakeReason.OWN_SHOT_DELAYED) def addCrashedTrack(self, isLeft): if not self.__vehicle.isAlive(): return else: if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.addTrack(isLeft) if not self.__vehicle.isEnteringWorld and self.trackCrashAudition: self.trackCrashAudition.playCrashSound(isLeft) return def delCrashedTrack(self, isLeft): if self.__crashedTracksCtrl is not None: self.__crashedTracksCtrl.delTrack(isLeft) if not self.__vehicle.isEnteringWorld and self.trackCrashAudition and self.__vehicle.isPlayerVehicle: self.trackCrashAudition.playCrashSound(isLeft, True) return def __requestModelsRefresh(self): currentModelState = self.__currentDamageState.modelState assembler = model_assembler.prepareCompoundAssembler(self.__typeDesc, currentModelState, self.__vehicle.spaceID, self.__vehicle.isTurretDetached) BigWorld.loadResourceListBG([assembler], functools.partial(self.__onModelsRefresh, currentModelState)) def __onModelsRefresh(self, modelState, resourceList): if BattleReplay.isFinished(): return elif modelState != self.__currentDamageState.modelState: self.__requestModelsRefresh() return elif self.__vehicle is None: return else: vehicle = self.__vehicle newCompoundModel = resourceList[self.__typeDesc.name] self.deactivate(False) self.__compoundModel = newCompoundModel self.__isTurretDetached = vehicle.isTurretDetached if self.__currentDamageState.isCurrentModelDamaged: fashions = VehiclePartsTuple(None, None, None, None) self.swingingAnimator = None self.gunRecoil = None self.__setFashions(fashions, self.__isTurretDetached) self.__destroySystems() self.__trackFashionSet = False self.__setupModels() self.setVehicle(vehicle) self.activate() self.__reattachComponents(self.__compoundModel) lodLink = DataLinks.createFloatLink(self.lodCalculator, 'lodDistance') if not self.damageState.isCurrentModelDamaged: model_assembler.assembleRecoil(self, lodLink) model_assembler.setupTurretRotations(self) return def __setupModels(self): if not self.__currentDamageState.isCurrentModelDamaged: self.__gunFireNode = self.__compoundModel.node('HP_gunFire') self.__isAlive = True _, gunLength = self.__computeVehicleHeight() self.__weaponEnergy = gunLength * self.__typeDesc.shot['shell']['caliber'] self.__setupHavok() else: self.__isAlive = False self.__gunFireNode = None if MAX_DISTANCE > 0: transform = self.__typeDesc.chassis['AODecals'][0] self.__attachSplodge(BigWorld.Splodge(transform, MAX_DISTANCE, self.__typeDesc.chassis['hullPosition'].y)) return def __setupHavok(self): vDesc = self.__typeDesc node = self.compoundModel.node(TankPartNames.HULL) hkm = BigWorld.wg_createHKAttachment(node, vDesc.hull['hitTester'].getBspModel()) if hkm is not None: node.attach(hkm) node = self.compoundModel.node(TankPartNames.TURRET) hkm = BigWorld.wg_createHKAttachment(node, vDesc.turret['hitTester'].getBspModel()) if hkm is not None: node.attach(hkm) node = self.compoundModel.node(TankPartNames.CHASSIS) hkm = BigWorld.wg_createHKAttachment(node, vDesc.chassis['hitTester'].getBspModel()) if hkm is not None: node.attach(hkm) node = self.compoundModel.node(TankPartNames.GUN) hkm = BigWorld.wg_createHKAttachment(node, vDesc.gun['hitTester'].getBspModel()) if hkm is not None: node.attach(hkm) return def __reattachComponents(self, model): self.__boundEffects.reattachTo(model) if self.__effectsPlayer is not None: self.__effectsPlayer.reattachTo(model) if self.engineAudition is not None: self.engineAudition.attachToModel(model) return def __playEffect(self, kind, *modifs): self.__stopEffects() if kind == 'empty' or self.__vehicle is None: return else: enableDecal = True if not self.__isPillbox and kind in ('explosion', 'destruction'): filter = self.__vehicle.filter isFlying = filter.numLeftTrackContacts < 2 and filter.numRightTrackContacts < 2 if isFlying: enableDecal = False if self.isUnderwater: if kind not in ('submersionDeath',): return effects = self.typeDescriptor.type.effects[kind] if not effects: return vehicle = self.__vehicle effects = random.choice(effects) self.__effectsPlayer = EffectsListPlayer(effects[1], effects[0], showShockWave=vehicle.isPlayerVehicle, showFlashBang=vehicle.isPlayerVehicle, isPlayer=vehicle.isPlayerVehicle, showDecal=enableDecal, start=vehicle.position + Math.Vector3(0.0, -1.0, 0.0), end=vehicle.position + Math.Vector3(0.0, 1.0, 0.0), entity_id=vehicle.id) self.__effectsPlayer.play(self.__compoundModel, *modifs) return __SPORT_ACTIONS_CAMOUFLAGES = {'ussr:T62A_sport': (95, 94), 'usa:M24_Chaffee_GT': (82, 83)} def __getCamouflageParams(self, vDesc, vID): vehicleInfo = BigWorld.player().arena.vehicles.get(vID) if vehicleInfo is not None: camouflageIdPerTeam = VehicleAppearance.SPORT_ACTIONS_CAMOUFLAGES.get(vDesc.name) if camouflageIdPerTeam is not None: camouflageId = camouflageIdPerTeam[0] if vehicleInfo['team'] == 1 else camouflageIdPerTeam[1] return (camouflageId, time.time(), 100.0) camouflagePseudoname = vehicleInfo['events'].get('hunting', None) if camouflagePseudoname is not None: camouflIdsByNation = {0: {'black': 29, 'gold': 30, 'red': 31, 'silver': 32}, 1: {'black': 25, 'gold': 26, 'red': 27, 'silver': 28}, 2: {'black': 52, 'gold': 50, 'red': 51, 'silver': 53}, 3: {'black': 48, 'gold': 46, 'red': 47, 'silver': 49}, 4: {'black': 60, 'gold': 58, 'red': 59, 'silver': 61}, 5: {'black': 56, 'gold': 54, 'red': 55, 'silver': 57}, 6: {'black': 133, 'gold': 134, 'red': 135, 'silver': 136}, 7: {'black': 141, 'gold': 142, 'red': 143, 'silver': 144}, 8: {'black': 154, 'gold': 155, 'red': 156, 'silver': 157}} camouflIds = camouflIdsByNation.get(vDesc.type.customizationNationID) if camouflIds is not None: ret = camouflIds.get(camouflagePseudoname) if ret is not None: return (ret, time.time(), 100.0) arenaType = BigWorld.player().arena.arenaType camouflageKind = arenaType.vehicleCamouflageKind return vDesc.camouflages[camouflageKind] def __stopEffects(self): if self.__effectsPlayer is not None: self.__effectsPlayer.stop() self.__effectsPlayer = None return def __calcIsUnderwater(self): if not self.__isInWater: return False turretOffs = self.__vehicle.typeDescriptor.chassis['hullPosition'] + self.__vehicle.typeDescriptor.hull['turretPositions'][0] turretOffsetMat = Math.Matrix() turretOffsetMat.setTranslate(turretOffs) turretJointMat = Math.Matrix(self.__vehicle.matrix) turretJointMat.preMultiply(turretOffsetMat) turretHeight = turretJointMat.translation.y - self.__vehicle.position.y return turretHeight < self.__waterHeight def __updateWaterStatus(self): vehiclePosition = self.__vehicle.position self.__waterHeight = BigWorld.wg_collideWater(vehiclePosition, vehiclePosition + Math.Vector3(0.0, 1.0, 0.0), False) self.__isInWater = self.__waterHeight != -1 self.__isUnderWater = self.__calcIsUnderwater() wasSplashed = self.__splashedWater waterHitPoint = None if self.__isInWater: self.__splashedWater = True waterHitPoint = vehiclePosition + Math.Vector3(0.0, self.__waterHeight, 0.0) else: trPoint = self.__typeDesc.chassis['topRightCarryingPoint'] cornerPoints = (Math.Vector3(trPoint.x, 0.0, trPoint.y), Math.Vector3(trPoint.x, 0.0, -trPoint.y), Math.Vector3(-trPoint.x, 0.0, -trPoint.y), Math.Vector3(-trPoint.x, 0.0, trPoint.y)) vehMat = Math.Matrix(self.__vehicleMatrixProv) for cornerPoint in cornerPoints: pointToTest = vehMat.applyPoint(cornerPoint) dist = BigWorld.wg_collideWater(pointToTest, pointToTest + Math.Vector3(0.0, 1.0, 0.0)) if dist != -1: self.__splashedWater = True waterHitPoint = pointToTest + Math.Vector3(0.0, dist, 0.0) break self.__splashedWater = False if self.__splashedWater and not wasSplashed: lightVelocityThreshold = self.__typeDesc.type.collisionEffectVelocities['waterContact'] heavyVelocityThreshold = self.__typeDesc.type.heavyCollisionEffectVelocities['waterContact'] vehicleVelocity = abs(self.__speedInfo[0]) if vehicleVelocity >= lightVelocityThreshold: collRes = BigWorld.wg_collideSegment(self.__vehicle.spaceID, waterHitPoint, waterHitPoint + (0.0, -_MIN_DEPTH_FOR_HEAVY_SPLASH, 0.0), 18, 8) deepEnough = collRes is None effectName = 'waterCollisionLight' if vehicleVelocity < heavyVelocityThreshold or not deepEnough else 'waterCollisionHeavy' self.__vehicle.showCollisionEffect(waterHitPoint, effectName, Math.Vector3(0.0, 1.0, 0.0)) if self.__effectsPlayer is not None: if self.isUnderwater != (self.__currentDamageState.effect in ('submersionDeath',)): self.__stopEffects() return def updateTracksScroll(self, leftScroll, rightScroll): self.__leftTrackScroll = leftScroll self.__rightTrackScroll = rightScroll if self.__trackScrollCtl is not None: self.__trackScrollCtl.setExternal(leftScroll, rightScroll) return def __onPeriodicTimerEngine(self): if self.detailedEngineState is None or self.engineAudition is None: return else: self.detailedEngineState.refresh(_PERIODIC_TIME_ENGINE) self.engineAudition.tick() return _PERIODIC_TIME_ENGINE def __onPeriodicTimer(self): timeStamp = BigWorld.wg_getFrameTimestamp() if VehicleAppearance.frameTimeStamp >= timeStamp: self.__periodicTimerID = BigWorld.callback(0.0, self.__onPeriodicTimer) return else: VehicleAppearance.frameTimeStamp = timeStamp self.__periodicTimerID = BigWorld.callback(_PERIODIC_TIME, self.__onPeriodicTimer) if self.__isPillbox or self.__vehicle is None: return vehicle = self.__vehicle self.__speedInfo = vehicle.speedInfo.value if not self.__vehicle.isPlayerVehicle and self.detailedEngineState is not None: self.detailedEngineState.refresh(_PERIODIC_TIME) try: self.__updateVibrations() if self.__lightFxCtrl is not None: self.__lightFxCtrl.update(vehicle) if self.__auxiliaryFxCtrl is not None: self.__auxiliaryFxCtrl.update(vehicle) self.__updateWaterStatus() if not vehicle.isAlive(): return self.__distanceFromPlayer = (BigWorld.camera().position - vehicle.position).length extra = vehicle.typeDescriptor.extrasDict['fire'] if extra.isRunningFor(vehicle): extra.checkUnderwater(vehicle, self.isUnderwater) if self.__fashion is None: return self.__updateCurrTerrainMatKinds() if not self.__vehicle.isPlayerVehicle: self.engineAudition.tick() self.__updateEffectsLOD() vehicle.filter.placingOnGround = not self.__fashion.suspensionWorking if self.customEffectManager: self.__customEffectManager.update() self.__vehicle.filter.placingOnGround = not self.__fashion.suspensionWorking except: LOG_CURRENT_EXCEPTION() return def __updateEffectsLOD(self): if self.customEffectManager: enableExhaust = self.__distanceFromPlayer <= _LOD_DISTANCE_EXHAUST enableTrails = self.__distanceFromPlayer <= _LOD_DISTANCE_TRAIL_PARTICLES and BigWorld.wg_isVehicleDustEnabled() self.__customEffectManager.enable(enableTrails, EffectSettings.SETTING_DUST) self.__customEffectManager.enable(enableExhaust, EffectSettings.SETTING_EXHAUST) def __updateCurrTerrainMatKinds(self): leftNode = self.compoundModel.node(TankNodeNames.TRACK_LEFT_MID) rightNode = self.compoundModel.node(TankNodeNames.TRACK_RIGHT_MID) testPoints = (Math.Matrix(leftNode).translation, Math.Matrix(rightNode).translation, self.__vehicle.position) isOnSoftTerrain = False for i in xrange(_MATKIND_COUNT): testPoint = testPoints[i] res = BigWorld.wg_collideSegment(self.__vehicle.spaceID, testPoint + Math.Vector3(0.0, 2.0, 0.0), testPoint + Math.Vector3(0.0, -2.0, 0.0), 18) matKind = res[2] if res is not None else 0 self.__currTerrainMatKind[i] = matKind if not isOnSoftTerrain: groundStr = material_kinds.GROUND_STRENGTHS_BY_IDS.get(matKind) isOnSoftTerrain = groundStr == 'soft' if self.__vehicle.isPlayerVehicle and self.__wasOnSoftTerrain != isOnSoftTerrain: self.__wasOnSoftTerrain = isOnSoftTerrain if isOnSoftTerrain: TriggersManager.g_manager.activateTrigger(TRIGGER_TYPE.PLAYER_VEHICLE_ON_SOFT_TERRAIN) else: TriggersManager.g_manager.deactivateTrigger(TRIGGER_TYPE.PLAYER_VEHICLE_ON_SOFT_TERRAIN) self.__fashion.setCurrTerrainMatKinds(self.__currTerrainMatKind[0], self.__currTerrainMatKind[1]) return def switchFireVibrations(self, bStart): if self.__vibrationsCtrl is not None: self.__vibrationsCtrl.switchFireVibrations(bStart) return def executeHitVibrations(self, hitEffectCode): if self.__vibrationsCtrl is not None: self.__vibrationsCtrl.executeHitVibrations(hitEffectCode) return def executeRammingVibrations(self, matKind = None): if self.__vibrationsCtrl is not None: self.__vibrationsCtrl.executeRammingVibrations(self.__vehicle.getSpeed(), matKind) return def executeShootingVibrations(self, caliber): if self.__vibrationsCtrl is not None: self.__vibrationsCtrl.executeShootingVibrations(caliber) return def executeCriticalHitVibrations(self, vehicle, extrasName): if self.__vibrationsCtrl is not None: self.__vibrationsCtrl.executeCriticalHitVibrations(vehicle, extrasName) return def deviceStateChanged(self, deviceName, state): if self.detailedEngineState is not None and deviceName == 'engine': self.detailedEngineState.deviceStateChanged(state) return def __updateVibrations(self): if self.__vibrationsCtrl is None: return else: vehicle = self.__vehicle if self.__crashedTracksCtrl is not None: crashedTrackCtrl = self.__crashedTracksCtrl self.__vibrationsCtrl.update(vehicle, crashedTrackCtrl.isLeftTrackBroken(), crashedTrackCtrl.isRightTrackBroken()) return def __linkCompound(self): vehicle = self.__vehicle vehicle.model = None vehicle.model = self.__compoundModel vehicleMatrix = vehicle.matrix self.__compoundModel.matrix = vehicleMatrix return def __createStickers(self): if self.__vehicleStickers is not None: return else: insigniaRank = self.__vehicle.publicInfo['marksOnGun'] self.__vehicleStickers = VehicleStickers(self.__typeDesc, insigniaRank) clanID = BigWorld.player().arena.vehicles[self.__vehicle.id]['clanDBID'] self.__vehicleStickers.setClanID(clanID) return def __attachStickers(self, alpha = 1.0, emblemsOnly = False): try: self.__vehicleStickers.alpha = alpha self.__vehicleStickers.attach(self.compoundModel, self.__currentDamageState.isCurrentModelDamaged, not emblemsOnly) except: LOG_CURRENT_EXCEPTION() def __attachSplodge(self, splodge): node = self.__compoundModel.node(TankPartNames.HULL) if splodge is not None and self.__splodge is None: self.__splodge = splodge node.attach(splodge) return def __disableStipple(self): self.compoundModel.stipple = False def __computeVehicleHeight(self): desc = self.__typeDesc turretBBox = desc.turret['hitTester'].bbox gunBBox = desc.gun['hitTester'].bbox hullBBox = desc.hull['hitTester'].bbox hullTopY = desc.chassis['hullPosition'][1] + hullBBox[1][1] turretTopY = desc.chassis['hullPosition'][1] + desc.hull['turretPositions'][0][1] + turretBBox[1][1] gunTopY = desc.chassis['hullPosition'][1] + desc.hull['turretPositions'][0][1] + desc.turret['gunPosition'][1] + gunBBox[1][1] return (max(hullTopY, max(turretTopY, gunTopY)), math.fabs(gunBBox[1][2] - gunBBox[0][2])) def setupGunMatrixTargets(self, target = None): if target is None: target = self.__filter self.turretMatrix.target = target.turretMatrix self.gunMatrix.target = target.gunMatrix return def assembleStipple(self): compound = self.compoundModel compound.matrix = Math.Matrix(compound.matrix) hullNode = compound.node(TankPartNames.HULL) compound.node(TankPartNames.HULL, hullNode.localMatrix) turretRotation = compound.node(TankPartNames.TURRET) if turretRotation is not None: compound.node(TankPartNames.TURRET, turretRotation.localMatrix) gunInclination = compound.node(TankNodeNames.GUN_INCLINATION) if gunInclination is not None: compound.node(TankNodeNames.GUN_INCLINATION, gunInclination.localMatrix) gunRecoil = compound.node(TankNodeNames.GUN_RECOIL) if gunRecoil is not None: compound.node(TankNodeNames.GUN_RECOIL, gunRecoil.localMatrix) self.fashions = VehiclePartsTuple(None, None, None, None) return
class ClientSelectableObject(BigWorld.Entity, ComponentSystem): collisions = ComponentDescriptor() @property def enabled(self): return self.__enabled def __init__(self): BigWorld.Entity.__init__(self) ComponentSystem.__init__(self) self.__enabled = True self.__edged = False self.__clickSound = None self.model = None return def prerequisites(self): if self.modelName != '': bspModels = ((0, self.modelName), ) collisionAssembler = BigWorld.CollisionAssembler( bspModels, self.spaceID) return [self.modelName, collisionAssembler] return [] def onEnterWorld(self, prereqs): if self.modelName == '': return if self.modelName not in prereqs.failedIDs: model = prereqs[self.modelName] self.model = model self.filter = BigWorld.DumbFilter() self.model.addMotor(BigWorld.Servo(self.matrix)) self.collisions = prereqs['collisionAssembler'] collisionData = ((0, self.model.matrix), ) self.collisions.connect(self.id, ColliderTypes.DYNAMIC_COLLIDER, collisionData) ComponentSystem.activate(self) def onLeaveWorld(self): ComponentSystem.deactivate(self) ComponentSystem.destroy(self) if self.__clickSound is not None: if self.__clickSound.isPlaying: self.__clickSound.stop() self.__clickSound.releaseMatrix() self.__clickSound = None self.highlight(False) return def enable(self, enabled): self.__enabled = enabled if not self.__enabled: self.highlight(False) def highlight(self, show): if show: if not self.__edged and self.__enabled: BigWorld.wgAddEdgeDetectEntity(self, 0, self.edgeMode, True) self.__edged = True elif self.__edged: BigWorld.wgDelEdgeDetectEntity(self) self.__edged = False def onClicked(self): if self.__clickSound is None: if self.clickSoundName: self.__clickSound = SoundGroups.g_instance.getSound3D( self.model.root, self.clickSoundName) self.__clickSound.play() elif self.__clickSound.isPlaying: self.__clickSound.stop() else: self.__clickSound.play() return def _getModelHeight(self): return self.model.height
class DetachedTurret(BigWorld.Entity, ComponentSystem): allTurrets = list() collisions = ComponentDescriptor() def __init__(self): ComponentSystem.__init__(self) self.__vehDescr = vehicles.VehicleDescr( compactDescr=self.vehicleCompDescr) self.filter = BigWorld.WGTurretFilter() self.__detachConfirmationTimer = SynchronousDetachment(self) self.__detachConfirmationTimer.onInit() self.__detachmentEffects = None self.targetFullBounds = True self.targetCaps = [1] self.__isBeingPulledCallback = None self.__hitEffects = None self.__vehicleStickers = None return def reload(self): pass def __prepareModelAssembler(self): assembler = BigWorld.CompoundAssembler(self.__vehDescr.name, self.spaceID) turretModel = self.__vehDescr.turret.models.exploded gunModel = self.__vehDescr.gun.models.exploded assembler.addRootPart(turretModel, TankPartNames.TURRET) assembler.emplacePart(gunModel, TankNodeNames.GUN_JOINT, TankPartNames.GUN) bspModels = ((TankPartNames.getIdx(TankPartNames.TURRET), self.__vehDescr.turret.hitTester.bspModelName), (TankPartNames.getIdx(TankPartNames.GUN), self.__vehDescr.gun.hitTester.bspModelName)) collisionAssembler = BigWorld.CollisionAssembler( bspModels, BigWorld.player().spaceID) return [assembler, collisionAssembler] def prerequisites(self): prereqs = self.__prepareModelAssembler() prereqs += self.__vehDescr.prerequisites() return prereqs def onEnterWorld(self, prereqs): self.model = prereqs[self.__vehDescr.name] self.model.matrix = self.matrix self.collisions = prereqs['collisionAssembler'] self.__detachConfirmationTimer.onEnterWorld() self.__vehDescr.keepPrereqs(prereqs) turretDescr = self.__vehDescr.turret if self.isUnderWater == 0: self.__detachmentEffects = _TurretDetachmentEffects( self.model, turretDescr.turretDetachmentEffects, self.isCollidingWithWorld == 1) self.addComponent(self.__detachmentEffects) else: self.__detachmentEffects = None self.__hitEffects = _HitEffects(self.model) self.addComponent(self.__hitEffects) self.__componentsDesc = (self.__vehDescr.turret, self.__vehDescr.gun) from helpers.CallbackDelayer import CallbackDelayer self.__isBeingPulledCallback = CallbackDelayer() self.__isBeingPulledCallback.delayCallback(self.__checkIsBeingPulled(), self.__checkIsBeingPulled) DetachedTurret.allTurrets.append(self) collisionData = ((TankPartNames.getIdx(TankPartNames.TURRET), self.model.matrix), (TankPartNames.getIdx(TankPartNames.GUN), self.model.node(TankPartNames.GUN))) self.collisions.connect(self.id, ColliderTypes.DYNAMIC_COLLIDER, collisionData) ComponentSystem.activate(self) return def isAlive(self): return False def removeEdge(self): pass def drawEdge(self): pass def __createAndAttachStickers(self): vehicle = BigWorld.entity(self.vehicleID) if not vehicle: return if self.__vehicleStickers: return self.__vehicleStickers = VehicleStickers( self.__vehDescr, vehicle.publicInfo['marksOnGun']) self.__vehicleStickers.alpha = vehicles.g_cache.commonConfig[ 'miscParams']['damageStickerAlpha'] self.__vehicleStickers.attach(self.model, True, False, True) def onLeaveWorld(self): ComponentSystem.deactivate(self) ComponentSystem.destroy(self) DetachedTurret.allTurrets.remove(self) self.__detachConfirmationTimer.cancel() self.__detachConfirmationTimer = None self.__isBeingPulledCallback.destroy() self.__isBeingPulledCallback = None if self.__vehicleStickers is not None: self.__vehicleStickers.detach() self.__vehicleStickers = None return def onStaticCollision(self, energy, point, normal): if self.__detachmentEffects is not None: surfaceMaterial = calcSurfaceMaterialNearPoint( point, normal, self.spaceID) effectIdx = surfaceMaterial.effectIdx groundEffect = True distToWater = BigWorld.wg_collideWater(self.position, surfaceMaterial.point) if distToWater != -1: vel = Math.Vector3(self.velocity).length if vel < _MIN_COLLISION_SPEED: groundEffect = False effectIdx = material_kinds.EFFECT_MATERIAL_INDEXES_BY_NAMES[ 'water'] self.__detachmentEffects.notifyAboutCollision( energy, point, effectIdx, groundEffect, self.isUnderWater) return def showDamageFromShot(self, points, effectsIndex): _, decodedPoints, _ = DamageFromShotDecoder.decodeHitPoints( points, self.collisions) for shotPoint in decodedPoints: if shotPoint.componentName == TankPartNames.TURRET or shotPoint.componentName == TankPartNames.GUN: self.__hitEffects.showHit(shotPoint, effectsIndex, shotPoint.componentName) LOG_ERROR( "Detached turret got hit into %s component, but it's impossible" % shotPoint.componentName) def set_isUnderWater(self, prev): if self.__detachmentEffects is not None: if self.isUnderWater: self.__detachmentEffects.stopEffects() return def set_isCollidingWithWorld(self, prev): pass def changeAppearanceVisibility(self, isVisible): self.model.visible = isVisible def __checkIsBeingPulled(self): if self.__detachmentEffects is not None: if self.isCollidingWithWorld and not self.isUnderWater and self.velocity.lengthSquared > 0.1: extent = Math.Matrix( self.model.getBoundsForRoot()).applyVector( Math.Vector3(0.5, 0.5, 0.5)).length surfaceMaterial = calcSurfaceMaterialNearPoint( self.position, Math.Vector3(0, extent, 0), self.spaceID) self.__detachmentEffects.notifyAboutBeingPulled( True, surfaceMaterial.effectIdx) if surfaceMaterial.matKind == 0: LOG_ERROR( 'calcSurfaceMaterialNearPoint failed to find the collision point at: ', self.position) else: self.__detachmentEffects.notifyAboutBeingPulled(False, None) return SERVER_TICK_LENGTH
class HangarVehicleAppearance(ComponentSystem): __ROOT_NODE_NAME = 'V' itemsCache = dependency.descriptor(IItemsCache) itemsFactory = dependency.descriptor(IGuiItemsFactory) settingsCore = dependency.descriptor(ISettingsCore) wheelsAnimator = ComponentDescriptor() trackNodesAnimator = ComponentDescriptor() collisions = ComponentDescriptor() shadowManager = ComponentDescriptor() dirtComponent = ComponentDescriptor() tracks = ComponentDescriptor() collisionObstaclesCollector = ComponentDescriptor() tessellationCollisionSensor = ComponentDescriptor() @property def compoundModel(self): return self.__vEntity.model if self.__vEntity else None fashion = property(lambda self: self.__fashions[0]) def __init__(self, spaceId, vEntity): ComponentSystem.__init__(self) self.__loadState = _LoadStateNotifier() self.__curBuildInd = 0 self.__vDesc = None self.__vState = None self.__fashions = VehiclePartsTuple(None, None, None, None) self.__repaintHandlers = [None, None, None, None] self.__camoHandlers = [None, None, None, None] self.__spaceId = spaceId self.__vEntity = weakref.proxy(vEntity) self.__onLoadedCallback = None self.__onLoadedAfterRefreshCallback = None self.__vehicleStickers = None self.__isVehicleDestroyed = False self.__outfit = None self.shadowManager = None cfg = hangarCFG() self.__currentEmblemsAlpha = cfg['emblems_alpha_undamaged'] self.__showMarksOnGun = self.settingsCore.getSetting('showMarksOnGun') self.settingsCore.onSettingsChanged += self.__onSettingsChanged self.itemsCache.onSyncCompleted += self.__onItemsCacheSyncCompleted g_eventBus.addListener(CameraRelatedEvents.CAMERA_ENTITY_UPDATED, self.__handleEntityUpdated) return def recreate(self, vDesc, vState, callback): self.__onLoadedCallback = callback self.__reload(vDesc, vState, self._getActiveOutfit()) def remove(self): self.__loadState.unload() self.__vDesc = None self.__vState = None self.__isVehicleDestroyed = False self.__vEntity.model = None if self.shadowManager: self.shadowManager.updatePlayerTarget(None) if self.collisions: BigWorld.removeCameraCollider(self.collisions.getColliderID()) return def refresh(self, outfit=None, callback=None): if self.__loadState.isLoaded and self.__vDesc: if callback is not None: self.__onLoadedAfterRefreshCallback = callback self.__reload(self.__vDesc, self.__vState, outfit or self.__outfit) return def destroy(self): ComponentSystem.deactivate(self) ComponentSystem.destroy(self) self.__vDesc = None self.__vState = None self.__loadState.unload() self.__loadState.destroy() self.__loadState = None self.__curBuildInd = 0 self.__vEntity = None self.__onLoadedCallback = None self.__onLoadedAfterRefreshCallback = None self.settingsCore.onSettingsChanged -= self.__onSettingsChanged self.itemsCache.onSyncCompleted -= self.__onItemsCacheSyncCompleted g_eventBus.removeListener(CameraRelatedEvents.CAMERA_ENTITY_UPDATED, self.__handleEntityUpdated) return @property def loadState(self): return self.__loadState @property def fakeShadowDefinedInHullTexture(self): return self.__vDesc.hull.hangarShadowTexture if self.__vDesc else None def isLoaded(self): return self.__loadState.isLoaded def computeVehicleHeight(self): gunLength = 0.0 height = 0.0 if self.collisions is not None: desc = self.__vDesc hullBB = self.collisions.getBoundingBox( TankPartNames.getIdx(TankPartNames.HULL)) turretBB = self.collisions.getBoundingBox( TankPartNames.getIdx(TankPartNames.TURRET)) gunBB = self.collisions.getBoundingBox( TankPartNames.getIdx(TankPartNames.GUN)) hullTopY = desc.chassis.hullPosition[1] + hullBB[1][1] turretTopY = desc.chassis.hullPosition[ 1] + desc.hull.turretPositions[0][1] + turretBB[1][1] gunTopY = desc.chassis.hullPosition[1] + desc.hull.turretPositions[ 0][1] + desc.turret.gunPosition[1] + gunBB[1][1] gunLength = math.fabs(gunBB[1][2] - gunBB[0][2]) height = max(hullTopY, max(turretTopY, gunTopY)) return (height, gunLength) def computeVehicleLength(self): vehicleLength = 0.0 if self.collisions is not None: hullBB = self.collisions.getBoundingBox( TankPartNames.getIdx(TankPartNames.HULL)) vehicleLength = abs(hullBB[1][2] - hullBB[0][2]) return vehicleLength def __reload(self, vDesc, vState, outfit): self.__loadState.unload() ComponentSystem.deactivate(self) self.tracks = None self.collisionObstaclesCollector = None self.tessellationCollisionSensor = None self.shadowManager = VehicleShadowManager() self.shadowManager.updatePlayerTarget(None) self.__outfit = outfit self.__startBuild(vDesc, vState) return def __startBuild(self, vDesc, vState): self.__curBuildInd += 1 self.__vState = vState self.__resources = {} self.__vehicleStickers = None cfg = hangarCFG() if vState == 'undamaged': self.__currentEmblemsAlpha = cfg['emblems_alpha_undamaged'] self.__isVehicleDestroyed = False else: self.__currentEmblemsAlpha = cfg['emblems_alpha_damaged'] self.__isVehicleDestroyed = True self.__vDesc = vDesc resources = camouflages.getCamoPrereqs(self.__outfit, vDesc) splineDesc = vDesc.chassis.splineDesc if splineDesc is not None: resources.append(splineDesc.segmentModelLeft) resources.append(splineDesc.segmentModelRight) if splineDesc.leftDesc is not None: resources.append(splineDesc.leftDesc) if splineDesc.rightDesc is not None: resources.append(splineDesc.rightDesc) if splineDesc.segment2ModelLeft is not None: resources.append(splineDesc.segment2ModelLeft) if splineDesc.segment2ModelRight is not None: resources.append(splineDesc.segment2ModelRight) from vehicle_systems import model_assembler resources.append( model_assembler.prepareCompoundAssembler( self.__vDesc, ModelsSetParams(self.__outfit.modelsSet, self.__vState), self.__spaceId)) g_eventBus.handleEvent(CameraRelatedEvents( CameraRelatedEvents.VEHICLE_LOADING, ctx={ 'started': True, 'vEntityId': self.__vEntity.id }), scope=EVENT_BUS_SCOPE.DEFAULT) cfg = hangarCFG() gunScale = Math.Vector3(1.0, 1.0, 1.1) capsuleScale = Math.Vector3(1.5, 1.5, 1.5) loadedGunScale = cfg.get('cam_capsule_gun_scale', gunScale) if loadedGunScale is not None: gunScale = loadedGunScale loadedCapsuleScale = cfg.get('cam_capsule_scale', capsuleScale) if loadedCapsuleScale is not None: capsuleScale = loadedCapsuleScale bspModels = ((TankPartNames.getIdx(TankPartNames.CHASSIS), vDesc.chassis.hitTester.bspModelName), (TankPartNames.getIdx(TankPartNames.HULL), vDesc.hull.hitTester.bspModelName), (TankPartNames.getIdx(TankPartNames.TURRET), vDesc.turret.hitTester.bspModelName), (TankPartNames.getIdx(TankPartNames.GUN), vDesc.gun.hitTester.bspModelName), (TankPartNames.getIdx(TankPartNames.GUN) + 1, vDesc.hull.hitTester.bspModelName, capsuleScale), (TankPartNames.getIdx(TankPartNames.GUN) + 2, vDesc.turret.hitTester.bspModelName, capsuleScale), (TankPartNames.getIdx(TankPartNames.GUN) + 3, vDesc.gun.hitTester.bspModelName, gunScale)) collisionAssembler = BigWorld.CollisionAssembler( bspModels, self.__spaceId) resources.append(collisionAssembler) physicalTracksBuilders = vDesc.chassis.physicalTracks for name, builder in physicalTracksBuilders.iteritems(): resources.append( builder.createLoader('{0}PhysicalTrack'.format(name))) BigWorld.loadResourceListBG( tuple(resources), makeCallbackWeak(self.__onResourcesLoaded, self.__curBuildInd)) return def __onResourcesLoaded(self, buildInd, resourceRefs): if not self.__vDesc: return if buildInd != self.__curBuildInd: return failedIDs = resourceRefs.failedIDs resources = self.__resources succesLoaded = True for resID, resource in resourceRefs.items(): if resID not in failedIDs: resources[resID] = resource LOG_ERROR('Could not load %s' % resID) succesLoaded = False self.collisions = resourceRefs['collisionAssembler'] if succesLoaded: self.__setupModel(buildInd) g_eventBus.handleEvent(CameraRelatedEvents( CameraRelatedEvents.VEHICLE_LOADING, ctx={ 'started': False, 'vEntityId': self.__vEntity.id }), scope=EVENT_BUS_SCOPE.DEFAULT) super(HangarVehicleAppearance, self).activate() def __onSettingsChanged(self, diff): if 'showMarksOnGun' in diff: self.__showMarksOnGun = not diff['showMarksOnGun'] self.refresh() def _getActiveOutfit(self): if g_currentPreviewVehicle.isPresent( ) or not g_currentVehicle.isPresent(): return self.itemsFactory.createOutfit() else: vehicle = g_currentVehicle.item if not vehicle: return None season = g_tankActiveCamouflage.get(vehicle.intCD, SeasonType.UNDEFINED) if season == SeasonType.UNDEFINED or not vehicle.hasOutfitWithItems( season): season = vehicle.getAnyOutfitSeason() g_tankActiveCamouflage[vehicle.intCD] = season outfit = vehicle.getOutfit(season) if not outfit: outfit = self.itemsFactory.createOutfit() return outfit def __assembleModel(self): from vehicle_systems import model_assembler resources = self.__resources self.__vEntity.model = resources[self.__vDesc.name] if not self.__isVehicleDestroyed: self.__fashions = VehiclePartsTuple( BigWorld.WGVehicleFashion(False), BigWorld.WGBaseFashion(), BigWorld.WGBaseFashion(), BigWorld.WGBaseFashion()) model_assembler.setupTracksFashion(self.__vDesc, self.__fashions.chassis) self.__vEntity.model.setupFashions(self.__fashions) self.__initMaterialHandlers() model_assembler.assembleCollisionObstaclesCollector(self, None) model_assembler.assembleTessellationCollisionSensor(self, None) self.wheelsAnimator = model_assembler.createWheelsAnimator( self.__vEntity.model, self.__vDesc, None) self.trackNodesAnimator = model_assembler.createTrackNodesAnimator( self.__vEntity.model, self.__vDesc, self.wheelsAnimator) chassisFashion = self.__fashions.chassis splineTracksImpl = model_assembler.setupSplineTracks( chassisFashion, self.__vDesc, self.__vEntity.model, self.__resources) model_assembler.assembleTracks(self.__resources, self.__vDesc, self, splineTracksImpl, True) self.updateCustomization(self.__outfit) dirtEnabled = BigWorld.WG_dirtEnabled( ) and 'HD' in self.__vDesc.type.tags if dirtEnabled: dirtHandlers = [ BigWorld.PyDirtHandler( True, self.__vEntity.model.node( TankPartNames.CHASSIS).position.y), BigWorld.PyDirtHandler( False, self.__vEntity.model.node( TankPartNames.HULL).position.y), BigWorld.PyDirtHandler( False, self.__vEntity.model.node( TankPartNames.TURRET).position.y), BigWorld.PyDirtHandler( False, self.__vEntity.model.node( TankPartNames.GUN).position.y) ] modelHeight, _ = self.computeVehicleHeight() self.dirtComponent = Vehicular.DirtComponent( dirtHandlers, modelHeight) for fashionIdx, _ in enumerate(TankPartNames.ALL): self.__fashions[fashionIdx].addMaterialHandler( dirtHandlers[fashionIdx]) self.dirtComponent.setBase() else: self.__fashions = VehiclePartsTuple(BigWorld.WGBaseFashion(), BigWorld.WGBaseFashion(), BigWorld.WGBaseFashion(), BigWorld.WGBaseFashion()) self.__vEntity.model.setupFashions(self.__fashions) self.wheelsAnimator = None self.trackNodesAnimator = None self.dirtComponent = None cfg = hangarCFG() turretYaw = self.__vDesc.gun.staticTurretYaw gunPitch = self.__vDesc.gun.staticPitch if not ('AT-SPG' in self.__vDesc.type.tags or 'SPG' in self.__vDesc.type.tags): if turretYaw is None: turretYaw = cfg['vehicle_turret_yaw'] turretYawLimits = self.__vDesc.gun.turretYawLimits if turretYawLimits is not None: turretYaw = mathUtils.clamp(turretYawLimits[0], turretYawLimits[1], turretYaw) if gunPitch is None: gunPitch = cfg['vehicle_gun_pitch'] gunPitchLimits = self.__vDesc.gun.pitchLimits['absolute'] gunPitch = mathUtils.clamp(gunPitchLimits[0], gunPitchLimits[1], gunPitch) else: if turretYaw is None: turretYaw = 0.0 if gunPitch is None: gunPitch = 0.0 turretYawMatrix = mathUtils.createRotationMatrix((turretYaw, 0.0, 0.0)) self.__vEntity.model.node(TankPartNames.TURRET, turretYawMatrix) gunPitchMatrix = mathUtils.createRotationMatrix((0.0, gunPitch, 0.0)) self.__vEntity.model.node(TankPartNames.GUN, gunPitchMatrix) return def __onItemsCacheSyncCompleted(self, updateReason, _): if updateReason == CACHE_SYNC_REASON.DOSSIER_RESYNC and self.__vehicleStickers is not None and self.__getThisVehicleDossierInsigniaRank( ) != self.__vehicleStickers.getCurrentInsigniaRank(): self.refresh() return def __getThisVehicleDossierInsigniaRank(self): vehicleDossier = self.itemsCache.items.getVehicleDossier( self.__vDesc.type.compactDescr) return vehicleDossier.getRandomStats().getAchievement( MARK_ON_GUN_RECORD).getValue() def __setupEmblems(self, outfit): if self.__vehicleStickers is not None: self.__vehicleStickers.detach() insigniaRank = 0 if self.__showMarksOnGun: insigniaRank = self.__getThisVehicleDossierInsigniaRank() self.__vehicleStickers = VehicleStickers.VehicleStickers( self.__vDesc, insigniaRank, outfit) self.__vehicleStickers.alpha = self.__currentEmblemsAlpha self.__vehicleStickers.attach(self.__vEntity.model, self.__isVehicleDestroyed, False) BigWorld.player().stats.get('clanDBID', self.__onClanDBIDRetrieved) return def __onClanDBIDRetrieved(self, _, clanID): self.__vehicleStickers.setClanID(clanID) def __setupModel(self, buildIdx): self.__assembleModel() cfg = hangarCFG() matrix = mathUtils.createSRTMatrix( Math.Vector3(cfg['v_scale'], cfg['v_scale'], cfg['v_scale']), Math.Vector3(self.__vEntity.yaw, self.__vEntity.pitch, self.__vEntity.roll), self.__vEntity.position) self.__vEntity.model.matrix = matrix self.__doFinalSetup(buildIdx) self.__vEntity.typeDescriptor = self.__vDesc gunColBox = self.collisions.getBoundingBox( TankPartNames.getIdx(TankPartNames.GUN) + 3) center = 0.5 * (gunColBox[1] - gunColBox[0]) gunoffset = Math.Matrix() gunoffset.setTranslate((0.0, 0.0, center.z + gunColBox[0].z)) gunLink = mathUtils.MatrixProviders.product( gunoffset, self.__vEntity.model.node(TankPartNames.GUN)) collisionData = ((TankPartNames.getIdx(TankPartNames.CHASSIS), self.__vEntity.model.matrix), (TankPartNames.getIdx(TankPartNames.HULL), self.__vEntity.model.node(TankPartNames.HULL)), (TankPartNames.getIdx(TankPartNames.TURRET), self.__vEntity.model.node(TankPartNames.TURRET)), (TankPartNames.getIdx(TankPartNames.GUN), self.__vEntity.model.node(TankPartNames.GUN))) self.collisions.connect(self.__vEntity.id, ColliderTypes.VEHICLE_COLLIDER, collisionData) collisionData = ((TankPartNames.getIdx(TankPartNames.GUN) + 1, self.__vEntity.model.node(TankPartNames.HULL)), (TankPartNames.getIdx(TankPartNames.GUN) + 2, self.__vEntity.model.node(TankPartNames.TURRET)), (TankPartNames.getIdx(TankPartNames.GUN) + 3, gunLink)) self.collisions.connect(self.__vEntity.id, ColliderTypes.HANGAR_VEHICLE_COLLIDER, collisionData) self.__reloadColliderType(self.__vEntity.state) self.__reloadShadowManagerTarget(self.__vEntity.state) def __handleEntityUpdated(self, event): ctx = event.ctx if ctx['entityId'] == self.__vEntity.id: self.__reloadColliderType(ctx['state']) self.__reloadShadowManagerTarget(ctx['state']) def __reloadColliderType(self, state): if not self.collisions: return if state != CameraMovementStates.FROM_OBJECT: colliderData = (self.collisions.getColliderID(), (TankPartNames.getIdx(TankPartNames.GUN) + 1, TankPartNames.getIdx(TankPartNames.GUN) + 2, TankPartNames.getIdx(TankPartNames.GUN) + 3)) BigWorld.appendCameraCollider(colliderData) else: BigWorld.removeCameraCollider(self.collisions.getColliderID()) def __reloadShadowManagerTarget(self, state): if not self.shadowManager or not self.__vEntity.model: return else: if state == CameraMovementStates.ON_OBJECT: self.shadowManager.updatePlayerTarget(self.__vEntity.model) elif state == CameraMovementStates.MOVING_TO_OBJECT: self.shadowManager.updatePlayerTarget(None) return def __doFinalSetup(self, buildIdx): if buildIdx != self.__curBuildInd: return else: self.__loadState.load() if self.__onLoadedCallback is not None: self.__onLoadedCallback() self.__onLoadedCallback = None if self.__onLoadedAfterRefreshCallback is not None: self.__onLoadedAfterRefreshCallback() self.__onLoadedAfterRefreshCallback = None if self.__vDesc is not None and 'observer' in self.__vDesc.type.tags: self.__vEntity.model.visible = False return def getSlotPositions(self): slots = { area: { GUI_ITEM_TYPE.INSCRIPTION: [], GUI_ITEM_TYPE.EMBLEM: [] } for area in Area.ALL } hullEmblemSlots = EmblemSlotHelper( self.__vDesc.hull.emblemSlots, Area.HULL, Math.Matrix(self.__vEntity.model.node(TankPartNames.HULL))) if self.__vDesc.turret.showEmblemsOnGun: turretEmblemSlots = EmblemSlotHelper( self.__vDesc.turret.emblemSlots, Area.GUN, Math.Matrix(self.__vEntity.model.node(TankPartNames.GUN))) else: turretEmblemSlots = EmblemSlotHelper( self.__vDesc.turret.emblemSlots, Area.TURRET, Math.Matrix(self.__vEntity.model.node(TankPartNames.TURRET))) for emblemSlotHelper in (hullEmblemSlots, turretEmblemSlots): for emblemSlot in emblemSlotHelper.tankAreaSlot: startPos = emblemSlot.rayStart endPos = emblemSlot.rayEnd normal = startPos - endPos normal.normalise() worldEmblemNormal = emblemSlotHelper.worldMatrix.applyVector( normal) sub = endPos - startPos half = sub / 2.0 midPos = startPos + half worldEmblemPos = emblemSlotHelper.worldMatrix.applyPoint( midPos) container = slots[emblemSlotHelper.tankAreaId] if emblemSlot.type == 'inscription': container[GUI_ITEM_TYPE.INSCRIPTION].append( Anchor(worldEmblemPos, worldEmblemNormal)) if emblemSlot.type == 'player': container[GUI_ITEM_TYPE.EMBLEM].append( Anchor(worldEmblemPos, worldEmblemNormal)) return slots def getEmblemPos(self, onHull, emblemType, emblemIdx): if onHull: emblemsDesc = self.__vDesc.hull.emblemSlots worldMat = Math.Matrix( self.__vEntity.model.node(TankPartNames.HULL)) else: if self.__vDesc.turret.showEmblemsOnGun: node = self.__vEntity.model.node(TankPartNames.GUN) else: node = self.__vEntity.model.node(TankPartNames.TURRET) emblemsDesc = self.__vDesc.turret.emblemSlots worldMat = Math.Matrix(node) desiredEmblems = [ emblem for emblem in emblemsDesc if emblem.type == emblemType ] if emblemIdx >= len(desiredEmblems): return None else: emblem = desiredEmblems[emblemIdx] direction = emblem[1] - emblem[0] direction.normalise() startPos = emblem[0] endPos = emblem[1] sub = endPos - startPos half = sub / 2.0 hitPos = startPos + half hitPos = worldMat.applyPoint(hitPos) upVecWorld = worldMat.applyVector(emblem[2]) upVecWorld.normalise() if abs(direction.pitch - math.pi / 2) < 0.1: direction = Math.Vector3(0, -1, 0) + upVecWorld * 0.01 direction.normalise() direction = self.__correctEmblemLookAgainstGun( hitPos, direction, upVecWorld, emblem) return EmblemPositionParams(hitPos, direction, emblem) def getCentralPointForArea(self, areaIdx): def _getBBCenter(tankPartName): partIdx = TankPartNames.getIdx(tankPartName) boundingBox = Math.Matrix( self.__vEntity.model.getBoundsForPart(partIdx)) bbCenter = boundingBox.applyPoint((0.5, 0.5, 0.5)) return bbCenter if areaIdx == ApplyArea.HULL: trackLeftUpFront = self.__vEntity.model.node( 'HP_TrackUp_LFront').position trackRightUpRear = self.__vEntity.model.node( 'HP_TrackUp_RRear').position position = (trackLeftUpFront + trackRightUpRear) / 2.0 bbCenter = _getBBCenter(TankPartNames.HULL) turretJointPosition = self.__vEntity.model.node( 'HP_turretJoint').position position.y = min(turretJointPosition.y, bbCenter.y) elif areaIdx == ApplyArea.TURRET: position = _getBBCenter(TankPartNames.TURRET) position.y = self.__vEntity.model.node('HP_gunJoint').position.y elif areaIdx == ApplyArea.GUN_2: position = self.__vEntity.model.node('HP_gunJoint').position elif areaIdx == ApplyArea.GUN: gunJointPos = self.__vEntity.model.node('HP_gunJoint').position gunFirePos = self.__vEntity.model.node('HP_gunFire').position position = (gunFirePos + gunJointPos) / 2.0 else: position = _getBBCenter(TankPartNames.CHASSIS) return position def __getEmblemCorners(self, hitPos, dir, up, emblem): cfg = hangarCFG() size = emblem[3] * cfg['v_scale'] m = Math.Matrix() m.lookAt(hitPos, dir, up) m.invert() result = (Math.Vector3(size * 0.5, size * 0.5, -0.25), Math.Vector3(size * 0.5, -size * 0.5, -0.25), Math.Vector3(-size * 0.5, -size * 0.5, -0.25), Math.Vector3(-size * 0.5, size * 0.5, -0.25)) return [m.applyPoint(vec) for vec in result] def __correctEmblemLookAgainstGun(self, hitPos, dir, up, emblem): checkDirWorld = dir * -10.0 cornersWorld = self.__getEmblemCorners(hitPos, dir, up, emblem) result = self.collisions.collideShape( TankPartNames.getIdx(TankPartNames.GUN), (cornersWorld[0], cornersWorld[1], cornersWorld[2], cornersWorld[3]), checkDirWorld) if result < 0.0: return dir dirRot = Math.Matrix() angle = _HANGAR_UNDERGUN_EMBLEM_ANGLE_SHIFT turretMat = Math.Matrix(self.__vEntity.model.node( TankPartNames.TURRET)) fromTurretToHit = hitPos - turretMat.translation gunDir = turretMat.applyVector(Math.Vector3(0, 0, 1)) if Math.Vector3(0, 1, 0).dot(gunDir * fromTurretToHit) < 0: angle = -angle dirRot.setRotateY(angle) normRot = Math.Matrix() normRot.setRotateYPR((dir.yaw, dir.pitch, 0)) dirRot.postMultiply(normRot) dir = dirRot.applyVector(Math.Vector3(0, 0, 1)) return dir def __initMaterialHandlers(self): for fashionIdx, _ in enumerate(TankPartNames.ALL): camoHandler = self.__camoHandlers[ fashionIdx] = BigWorld.PyCamoHandler() repaintHandler = self.__repaintHandlers[ fashionIdx] = BigWorld.PyRepaintHandler() self.__fashions[fashionIdx].addMaterialHandler(camoHandler) self.__fashions[fashionIdx].addMaterialHandler(repaintHandler) def updateCustomization(self, outfit=None, callback=None): if self.__isVehicleDestroyed: return outfit = outfit or self.itemsFactory.createOutfit() if self.__outfit.modelsSet != outfit.modelsSet: self.refresh(outfit, callback) return self.__updateCamouflage(outfit) self.__updatePaint(outfit) self.__updateDecals(outfit) def __updatePaint(self, outfit): for fashionIdx, _ in enumerate(TankPartNames.ALL): repaint = camouflages.getRepaint(outfit, fashionIdx, self.__vDesc) self.__repaintHandlers[fashionIdx].setRepaintParams(repaint) def __updateCamouflage(self, outfit): for fashionIdx, descId in enumerate(TankPartNames.ALL): camo = camouflages.getCamo(outfit, fashionIdx, self.__vDesc, descId, self.__vState != 'undamaged') if camo: self.__fashions[fashionIdx].setCamouflage() self.__camoHandlers[fashionIdx].setCamoParams(camo) self.__fashions[fashionIdx].removeCamouflage() def __updateDecals(self, outfit): self.__setupEmblems(outfit)
class _VehicleAppearance(ComponentSystem): __ROOT_NODE_NAME = 'V' itemsCache = dependency.descriptor(IItemsCache) settingsCore = dependency.descriptor(ISettingsCore) wheelsAnimator = ComponentDescriptor() trackNodesAnimator = ComponentDescriptor() def __init__(self, spaceId, vEntityId, hangarSpace): ComponentSystem.__init__(self) self.__isLoaded = False self.__curBuildInd = 0 self.__vDesc = None self.__vState = None self.__fashions = VehiclePartsTuple(None, None, None, None) self.__spaceId = spaceId self.__vEntityId = vEntityId self.__onLoadedCallback = None self.__emblemsAlpha = _CFG['emblems_alpha_undamaged'] self.__vehicleStickers = None self.__isVehicleDestroyed = False self.__smCb = None self.__smRemoveCb = None self.__hangarSpace = weakref.proxy(hangarSpace) self.__removeHangarShadowMap() self.__showMarksOnGun = self.settingsCore.getSetting('showMarksOnGun') self.settingsCore.onSettingsChanged += self.__onSettingsChanged self.itemsCache.onSyncCompleted += self.__onItemsCacheSyncCompleted return def recreate(self, vDesc, vState, onVehicleLoadedCallback=None): ComponentSystem.deactivate(self) self.__onLoadedCallback = onVehicleLoadedCallback self.__isLoaded = False self.__startBuild(vDesc, vState) def refresh(self): if self.__isLoaded: self.__onLoadedCallback = None self.__isLoaded = False self.__startBuild(self.__vDesc, self.__vState) entity = BigWorld.entity(self.__vEntityId) if isinstance(entity, HangarVehicle): entity.releaseBspModels() return def destroy(self): ComponentSystem.deactivate(self) ComponentSystem.destroy(self) self.__onLoadedCallback = None self.__vDesc = None self.__vState = None self.__isLoaded = False self.__curBuildInd = 0 self.__vEntityId = None if self.__smCb is not None: BigWorld.cancelCallback(self.__smCb) self.__smCb = None if self.__smRemoveCb is not None: BigWorld.cancelCallback(self.__smRemoveCb) self.__smRemoveCb = None self.settingsCore.onSettingsChanged -= self.__onSettingsChanged self.itemsCache.onSyncCompleted -= self.__onItemsCacheSyncCompleted return def isLoaded(self): return self.__isLoaded def __startBuild(self, vDesc, vState): self.__curBuildInd += 1 self.__vDesc = vDesc self.__vState = vState self.__resources = {} self.__vehicleStickers = None camouflageResources = { 'camouflageExclusionMask': vDesc.type.camouflage.exclusionMask } customization = items.vehicles.g_cache.customization( vDesc.type.customizationNationID) if customization is not None and vDesc.camouflages is not None: activeCamo = g_tankActiveCamouflage['historical'].get( vDesc.type.compactDescr) if activeCamo is None: activeCamo = g_tankActiveCamouflage.get( vDesc.type.compactDescr, 0) camouflageID = vDesc.camouflages[activeCamo][0] camouflageDesc = customization['camouflages'].get(camouflageID) if camouflageDesc is not None: camouflageResources['camouflageTexture'] = camouflageDesc[ 'texture'] if vState == 'undamaged': self.__emblemsAlpha = _CFG['emblems_alpha_undamaged'] self.__isVehicleDestroyed = False else: self.__emblemsAlpha = _CFG['emblems_alpha_damaged'] self.__isVehicleDestroyed = True resources = camouflageResources.values() splineDesc = vDesc.chassis.splineDesc if splineDesc is not None: resources.append(splineDesc.segmentModelLeft) resources.append(splineDesc.segmentModelRight) resources.append(splineDesc.leftDesc) resources.append(splineDesc.rightDesc) resources.append(splineDesc.segment2ModelLeft) resources.append(splineDesc.segment2ModelRight) resources.append( model_assembler.prepareCompoundAssembler(self.__vDesc, self.__vState, self.__spaceId)) BigWorld.loadResourceListBG( tuple(resources), makeCallbackWeak(self.__onResourcesLoaded, self.__curBuildInd)) return def __onResourcesLoaded(self, buildInd, resourceRefs): if buildInd != self.__curBuildInd: return failedIDs = resourceRefs.failedIDs resources = self.__resources succesLoaded = True for resID, resource in resourceRefs.items(): if resID not in failedIDs: resources[resID] = resource else: LOG_ERROR('Could not load %s' % resID) succesLoaded = False if succesLoaded: self.__setupModel(buildInd) super(_VehicleAppearance, self).activate() def __onSettingsChanged(self, diff): if 'showMarksOnGun' in diff: self.__showMarksOnGun = not diff['showMarksOnGun'] self.refresh() elif 'dynamicFov' in diff or 'fov' in diff: if 'fov' in diff: staticFOV, dynamicFOVLow, dynamicFOVTop = diff['fov'] defaultHorizontalFov = math.radians(dynamicFOVTop) def resetFov(value): FovExtended.instance().defaultHorizontalFov = value BigWorld.callback(0.0, partial(resetFov, defaultHorizontalFov)) self.__hangarSpace.updateCameraByMouseMove(0, 0, 0) def __assembleModel(self): resources = self.__resources self.__model = resources[self.__vDesc.name] self.__setupEmblems(self.__vDesc) if not self.__isVehicleDestroyed: self.__fashions = VehiclePartsTuple( BigWorld.WGVehicleFashion(False), None, None, None) model_assembler.setupTracksFashion(self.__fashions.chassis, self.__vDesc, self.__isVehicleDestroyed) self.__model.setupFashions(self.__fashions) chassisFashion = self.__fashions.chassis model_assembler.setupSplineTracks(chassisFashion, self.__vDesc, self.__model, self.__resources) self.wheelsAnimator = model_assembler.createWheelsAnimator( self.__model, self.__vDesc, None) self.trackNodesAnimator = model_assembler.createTrackNodesAnimator( self.__model, self.__vDesc, self.wheelsAnimator) else: self.__fashions = VehiclePartsTuple(None, None, None, None) self.wheelsAnimator = None self.trackNodesAnimator = None self.updateCamouflage() yaw = self.__vDesc.gun.staticTurretYaw pitch = self.__vDesc.gun.staticPitch if yaw is None: yaw = 0.0 if pitch is None: pitch = 0.0 gunMatrix = mathUtils.createRTMatrix(Math.Vector3(yaw, pitch, 0.0), (0.0, 0.0, 0.0)) self.__model.node('gun', gunMatrix) return self.__model def __removeHangarShadowMap(self): if self.__smCb is not None: BigWorld.cancelCallback(self.__smCb) self.__smCb = None if BigWorld.spaceLoadStatus() < 1.0: self.__smRemoveCb = BigWorld.callback(0, self.__removeHangarShadowMap) return else: self.__smRemoveCb = None self.__hangarSpace.modifyFakeShadowAsset( _CFG['shadow_empty_texture_name']) return VehicleProxy = namedtuple('VehicleProxy', 'typeDescriptor') def __setupHangarShadow(self): if self.__smCb is None: self.__setupHangarShadowMap() return def __setupHangarShadowMap(self): if self.__smRemoveCb is not None: BigWorld.cancelCallback(self.__smRemoveCb) self.__smRemoveCb = None if BigWorld.spaceLoadStatus() < 1.0: self.__smCb = BigWorld.callback(0.0, self.__setupHangarShadowMap) return else: self.__smCb = None if 'observer' in self.__vDesc.type.tags: self.__removeHangarShadowMap() return shadowMapTexFileName = self.__vDesc.hull.hangarShadowTexture if shadowMapTexFileName is None: shadowMapTexFileName = _CFG['shadow_default_texture_name'] self.__hangarSpace.modifyFakeShadowAsset(shadowMapTexFileName) return def __onItemsCacheSyncCompleted(self, updateReason, invalidItems): if updateReason == CACHE_SYNC_REASON.DOSSIER_RESYNC and self.__vehicleStickers is not None and self.__getThisVehicleDossierInsigniaRank( ) != self.__vehicleStickers.getCurrentInsigniaRank(): self.refresh() return def __getThisVehicleDossierInsigniaRank(self): vehicleDossier = self.itemsCache.items.getVehicleDossier( self.__vDesc.type.compactDescr) return vehicleDossier.getRandomStats().getAchievement( MARK_ON_GUN_RECORD).getValue() def __setupEmblems(self, vDesc): if self.__vehicleStickers is not None: self.__vehicleStickers.detach() insigniaRank = 0 if self.__showMarksOnGun: insigniaRank = self.__getThisVehicleDossierInsigniaRank() self.__vehicleStickers = VehicleStickers.VehicleStickers( vDesc, insigniaRank) self.__vehicleStickers.alpha = self.__emblemsAlpha self.__vehicleStickers.attach(self.__model, self.__isVehicleDestroyed, False) BigWorld.player().stats.get('clanDBID', self.__onClanDBIDRetrieved) return def updateVehicleSticker(self, playerEmblems, playerInscriptions): initialEmblems = copy.deepcopy(self.__vDesc.playerEmblems) initialInscriptions = copy.deepcopy(self.__vDesc.playerInscriptions) for idx, (emblemId, startTime, duration) in enumerate(playerEmblems): self.__vDesc.setPlayerEmblem(idx, emblemId, startTime, duration) for idx, (inscriptionId, startTime, duration, color) in enumerate(playerInscriptions): self.__vDesc.setPlayerInscription(idx, inscriptionId, startTime, duration, color) self.__setupEmblems(self.__vDesc) self.__vDesc.playerEmblems = initialEmblems self.__vDesc.playerInscriptions = initialInscriptions def __onClanDBIDRetrieved(self, _, clanID): if self.__vehicleStickers is not None: self.__vehicleStickers.setClanID(clanID) return def __setupModel(self, buildIdx): model = self.__assembleModel() matrix = mathUtils.createSRTMatrix( Math.Vector3(_CFG['v_scale'], _CFG['v_scale'], _CFG['v_scale']), _CFG['v_start_angles'], _CFG['v_start_pos']) model.matrix = matrix self.__doFinalSetup(buildIdx, model) entity = BigWorld.entity(self.__vEntityId) if isinstance(entity, HangarVehicle): entity.typeDescriptor = self.__vDesc def __doFinalSetup(self, buildIdx, model): if buildIdx != self.__curBuildInd: return else: entity = BigWorld.entity(self.__vEntityId) if entity: entity.model = model self.__isLoaded = True if isinstance(entity, HangarVehicle): entity.canDoHitTest(True) if self.__onLoadedCallback is not None: self.__onLoadedCallback() self.__onLoadedCallback = None if self.__smCb is None: self.__setupHangarShadowMap() if self.__vDesc is not None and 'observer' in self.__vDesc.type.tags: model.visible = False return def getEmblemPos(self, onHull, emblemType, emblemIdx): emblemsDesc = None hitTester = ModelHitTester() worldMat = None if onHull: hitTester.bspModelName = self.__vDesc.hull.models.undamaged emblemsDesc = self.__vDesc.hull.emblemSlots worldMat = Math.Matrix(self.__model.node(TankPartNames.HULL)) else: if self.__vDesc.turret.showEmblemsOnGun: node = self.__model.node(TankPartNames.GUN) hitTester.bspModelName = self.__vDesc.gun.models.undamaged else: node = self.__model.node(TankPartNames.TURRET) hitTester.bspModelName = self.__vDesc.turret.models.undamaged emblemsDesc = self.__vDesc.turret.emblemSlots worldMat = Math.Matrix(node) desiredEmblems = [ emblem for emblem in emblemsDesc if emblem.type == emblemType ] if emblemIdx >= len(desiredEmblems): return else: emblem = desiredEmblems[emblemIdx] dir = emblem[1] - emblem[0] dir.normalise() startPos = emblem[0] - dir * 5 endPos = emblem[1] + dir * 5 hitTester.loadBspModel() collideRes = hitTester.localHitTest(startPos, endPos) hitTester.releaseBspModel() if collideRes is not None: collideRes = sorted(collideRes, lambda t1, t2: cmp(t1[0], t2[0])) distanceFromStart, normal = collideRes[0][0], collideRes[0][1] hitPos = startPos + dir * distanceFromStart hitPos = worldMat.applyPoint(hitPos) dir = -worldMat.applyVector(normal) dir.normalise() upVecWorld = worldMat.applyVector(emblem[2]) upVecWorld.normalise() if abs(dir.pitch - math.pi / 2) < 0.1: dir = Math.Vector3(0, -1, 0) + upVecWorld * 0.01 dir.normalise() dir = self.__correctEmblemLookAgainstGun( hitPos, dir, upVecWorld, emblem) return (hitPos, dir, emblem) return return def __getEmblemCorners(self, hitPos, dir, up, emblem): size = emblem[3] * _CFG['v_scale'] m = Math.Matrix() m.lookAt(hitPos, dir, up) m.invert() result = (Math.Vector3(size * 0.5, size * 0.5, -0.25), Math.Vector3(size * 0.5, -size * 0.5, -0.25), Math.Vector3(-size * 0.5, -size * 0.5, -0.25), Math.Vector3(-size * 0.5, size * 0.5, -0.25)) return [m.applyPoint(vec) for vec in result] def __correctEmblemLookAgainstGun(self, hitPos, dir, up, emblem): hitTester = self.__vDesc.gun.hitTester hitTester.loadBspModel() toLocalGun = Math.Matrix(self.__model.node(TankPartNames.GUN)) toLocalGun.invert() checkDirLocal = toLocalGun.applyVector(dir) * -10 cornersLocal = self.__getEmblemCorners(hitPos, dir, up, emblem) cornersLocal = [toLocalGun.applyPoint(vec) for vec in cornersLocal] testResult = hitTester.localCollidesWithTriangle( (cornersLocal[0], cornersLocal[2], cornersLocal[1]), checkDirLocal) testResult = testResult or hitTester.localCollidesWithTriangle( (cornersLocal[0], cornersLocal[3], cornersLocal[2]), checkDirLocal) hitTester.releaseBspModel() if not testResult: return dir dirRot = Math.Matrix() angle = _HANGAR_UNDERGUN_EMBLEM_ANGLE_SHIFT turretMat = Math.Matrix(self.__model.node(TankPartNames.TURRET)) fromTurretToHit = hitPos - turretMat.translation gunDir = turretMat.applyVector(Math.Vector3(0, 0, 1)) if Math.Vector3(0, 1, 0).dot(gunDir * fromTurretToHit) < 0: angle = -angle dirRot.setRotateY(angle) normRot = Math.Matrix() normRot.setRotateYPR((dir.yaw, dir.pitch, 0)) dirRot.postMultiply(normRot) dir = dirRot.applyVector(Math.Vector3(0, 0, 1)) return dir def __getCurrentCamouflage(self): if self.__vDesc.camouflages is not None: activeCamo = g_tankActiveCamouflage['historical'].get( self.__vDesc.type.compactDescr) if activeCamo is None: activeCamo = g_tankActiveCamouflage.get( self.__vDesc.type.compactDescr, 0) camouflageID = self.__vDesc.camouflages[activeCamo][0] if camouflageID is None: for camouflageData in self.__vDesc.camouflages: if camouflageData[0] is not None: camouflageID = camouflageData[0] break return camouflageID def initFashions(self): fashions = list(self.__fashions) for fashionIdx, descId in enumerate(TankPartNames.ALL): fashion = self.__fashions[fashionIdx] if fashion is None: fashions[fashionIdx] = BigWorld.WGBaseFashion() self.__fashions = fashions self.__model.setupFashions(self.__fashions) self.__fashions[0].activate() return def updateCamouflage(self, camouflageID=None): if camouflageID is None: camouflageID = self.__getCurrentCamouflage() self.initFashions() self.__fashions = camouflages.applyCamouflage( self.__vDesc, self.__fashions, self.__vState != 'undamaged', camouflageID) self.__fashions = camouflages.applyRepaint(self.__vDesc, self.__fashions) return