示例#1
0
class ParachuteCargo(ScriptGameObject, CallbackDelayer):
    model = ComponentDescriptorTyped(ModelComponent)
    landingAnimation = ComponentDescriptorTyped(SequenceComponent)
    descendSimulator = ComponentDescriptor()
    LANDING_TRIGGER = 'Landed'
    LANDING_ANIMATION_TRIGGER_OFFSET = -0.3

    def __init__(self, yaw, dropPoint, landingPosition, descendTime):
        ScriptGameObject.__init__(self, BigWorld.player().spaceID)
        CallbackDelayer.__init__(self)
        self.descendSimulator = DescendSimulator(yaw, dropPoint,
                                                 landingPosition, descendTime)
        self.__descendTime = descendTime
        self.__dropPoint = dropPoint

    def activate(self):
        ScriptGameObject.activate(self)
        self.model.compoundModel.position = self.__dropPoint
        self.model.compoundModel.matrix = self.descendSimulator.matrix
        self.landingAnimation.bindToCompound(self.model.compoundModel)
        self.landingAnimation.start()
        self.delayCallback(
            self.__descendTime + self.LANDING_ANIMATION_TRIGGER_OFFSET,
            self.__animateLanding)

    def deactivate(self):
        super(ParachuteCargo, self).deactivate()
        if self.landingAnimation is not None:
            self.landingAnimation.stop()
            self.landingAnimation.unbind()
        return

    def destroy(self):
        ScriptGameObject.destroy(self)
        CallbackDelayer.destroy(self)

    def __animateLanding(self):
        if self.landingAnimation is not None:
            self.landingAnimation.setTrigger(self.LANDING_TRIGGER)
        return
class HangarVehicleAppearance(ScriptGameObject):
    __ROOT_NODE_NAME = 'V'
    itemsCache = dependency.descriptor(IItemsCache)
    itemsFactory = dependency.descriptor(IGuiItemsFactory)
    settingsCore = dependency.descriptor(ISettingsCore)
    turretAndGunAngles = dependency.descriptor(ITurretAndGunAngles)
    customizationService = dependency.descriptor(ICustomizationService)
    wheelsAnimator = ComponentDescriptor()
    trackNodesAnimator = ComponentDescriptor()
    collisions = ComponentDescriptor()
    shadowManager = ComponentDescriptor()
    dirtComponent = ComponentDescriptor()
    c11nComponent = ComponentDescriptor()
    tracks = ComponentDescriptor()
    collisionObstaclesCollector = ComponentDescriptor()
    tessellationCollisionSensor = ComponentDescriptor()
    flagComponent = ComponentDescriptor()

    @property
    def compoundModel(self):
        return self.__vEntity.model if self.__vEntity else None

    @property
    def id(self):
        return self.__vEntity.id

    fashion = property(lambda self: self.__fashions[0])

    @property
    def filter(self):
        return None

    isVehicleDestroyed = property(lambda self: self.__isVehicleDestroyed)

    def __init__(self, spaceId, vEntity):
        ScriptGameObject.__init__(self, vEntity.spaceID)
        self.__loadState = _LoadStateNotifier()
        self.__curBuildInd = 0
        self.__vDesc = None
        self.__vState = None
        size = len(TankPartNames.ALL)
        self.__fashions = VehiclePartsTuple(*([None] * size))
        self.__repaintHandlers = [None] * size
        self.__camoHandlers = [None] * size
        self.__projectionDecalsHandlers = [None] * size
        self.__projectionDecalsUpdater = 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.__staticTurretYaw = 0.0
        self.__staticGunPitch = 0.0
        self.__anchorsHelpers = None
        self.__anchorsParams = None
        self.__attachments = []
        self.__modelAnimators = []
        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)
        g_currentVehicle.onChanged += self.__onVehicleChanged
        return

    def recreate(self, vDesc, vState=None, callback=None, outfit=None):
        self.__onLoadedCallback = callback
        self.__reload(vDesc, vState or self.__vState, outfit
                      or self._getActiveOutfit(vDesc))

    def remove(self):
        self.__clearModelAnimators()
        self.__loadState.unload()
        self.__vDesc = None
        self.__vState = None
        self.__isVehicleDestroyed = False
        self.__vEntity.model = None
        if self.shadowManager is not None:
            self.shadowManager.updatePlayerTarget(None)
        if self.collisions:
            BigWorld.removeCameraCollider(self.collisions.getColliderID())
            self.collisions = None
        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):
        if self.fashion is not None:
            self.fashion.removePhysicalTracks()
        if self.shadowManager is not None:
            self.shadowManager.updatePlayerTarget(None)
        self.__clearModelAnimators()
        ScriptGameObject.deactivate(self)
        ScriptGameObject.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.turretRotator = None
        self.settingsCore.onSettingsChanged -= self.__onSettingsChanged
        self.itemsCache.onSyncCompleted -= self.__onItemsCacheSyncCompleted
        g_eventBus.removeListener(CameraRelatedEvents.CAMERA_ENTITY_UPDATED,
                                  self.__handleEntityUpdated)
        g_currentVehicle.onChanged -= self.__onVehicleChanged
        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 recreateRequired(self, newOutfit):
        shouldUpdateModelsSet = self.__outfit.modelsSet != newOutfit.modelsSet
        shouldUpdateAttachments = not self.__outfit.attachments.isEqual(
            newOutfit.attachments)
        return shouldUpdateModelsSet or shouldUpdateAttachments

    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 computeFullVehicleLength(self):
        hullBB = Math.Matrix(
            self.__vEntity.model.getBoundsForPart(TankPartIndexes.HULL))
        return hullBB.applyVector(Math.Vector3(0.0, 0.0, 1.0)).length

    def _getTurretYaw(self):
        return self.turretAndGunAngles.getTurretYaw()

    def _getGunPitch(self):
        return self.turretAndGunAngles.getGunPitch()

    def __reload(self, vDesc, vState, outfit):
        self.__clearModelAnimators()
        self.__loadState.unload()
        if self.fashion is not None:
            self.fashion.removePhysicalTracks()
        ScriptGameObject.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)
        if not self.__isVehicleDestroyed:
            self.__attachments = camouflages.getAttachments(
                self.__outfit, vDesc)
        modelsSet = self.__outfit.modelsSet
        splineDesc = vDesc.chassis.splineDesc
        if splineDesc is not None:
            resources.append(splineDesc.segmentModelLeft(modelsSet))
            resources.append(splineDesc.segmentModelRight(modelsSet))
            if splineDesc.leftDesc is not None:
                resources.append(splineDesc.leftDesc)
            if splineDesc.rightDesc is not None:
                resources.append(splineDesc.rightDesc)
            segment2ModelLeft = splineDesc.segment2ModelLeft(modelsSet)
            if segment2ModelLeft is not None:
                resources.append(segment2ModelLeft)
            segment2ModelRight = splineDesc.segment2ModelRight(modelsSet)
            if segment2ModelRight is not None:
                resources.append(segment2ModelRight)
        from vehicle_systems import model_assembler
        resources.append(
            model_assembler.prepareCompoundAssembler(
                self.__vDesc,
                ModelsSetParams(modelsSet, self.__vState, self.__attachments),
                self.__spaceId))
        g_eventBus.handleEvent(CameraRelatedEvents(
            CameraRelatedEvents.VEHICLE_LOADING,
            ctx={
                'started': True,
                'vEntityId': self.__vEntity.id,
                'intCD': self.__vDesc.type.compactDescr
            }),
                               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, builders in physicalTracksBuilders.iteritems():
            for index, builder in enumerate(builders):
                resources.append(
                    builder.createLoader(
                        self.__spaceId,
                        '{0}{1}PhysicalTrack'.format(name, index), modelsSet))

        BigWorld.loadResourceListBG(
            tuple(resources),
            makeCallbackWeak(self.__onResourcesLoaded, self.__curBuildInd))
        return

    def __onResourcesLoaded(self, buildInd, resourceRefs):
        if not self.__vDesc:
            self.__fireResourcesLoadedEvent()
            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
            _logger.error('Could not load %s', resID)
            succesLoaded = False

        if self.collisions:
            BigWorld.removeCameraCollider(self.collisions.getColliderID())
        self.collisions = resourceRefs['collisionAssembler']
        if succesLoaded:
            self.__setupModel(buildInd)
        self.turretRotator = SimpleTurretRotator(
            self.compoundModel, easingCls=math_utils.Easing.squareEasing)
        self.__applyAttachmentsVisibility()
        self.__fireResourcesLoadedEvent()
        super(HangarVehicleAppearance, self).activate()

    def __fireResourcesLoadedEvent(self):
        compDescr = self.__vDesc.type.compactDescr if self.__vDesc is not None else None
        g_eventBus.handleEvent(CameraRelatedEvents(
            CameraRelatedEvents.VEHICLE_LOADING,
            ctx={
                'started': False,
                'vEntityId': self.__vEntity.id,
                'intCD': compDescr
            }),
                               scope=EVENT_BUS_SCOPE.DEFAULT)
        return

    def __onAnimatorsLoaded(self, buildInd, outfit, resourceRefs):
        if not self.__vDesc:
            return
        if buildInd != self.__curBuildInd:
            return
        self.__clearModelAnimators()
        self.__modelAnimators = camouflages.getModelAnimators(
            outfit, self.__vDesc, self.__spaceId, resourceRefs,
            self.compoundModel)
        if not self.__isVehicleDestroyed:
            self.__modelAnimators.extend(
                camouflages.getAttachmentsAnimators(self.__attachments,
                                                    self.__spaceId,
                                                    resourceRefs,
                                                    self.compoundModel))
        from vehicle_systems import model_assembler
        model_assembler.assembleCustomLogicComponents(self, self.__attachments,
                                                      self.__modelAnimators)
        for modelAnimator in self.__modelAnimators:
            modelAnimator.animator.start()

    def __onSettingsChanged(self, diff):
        if 'showMarksOnGun' in diff:
            self.__showMarksOnGun = not diff['showMarksOnGun']
            self.refresh()

    def _getActiveOutfit(self, vDesc):
        if g_currentPreviewVehicle.isPresent(
        ) and not g_currentPreviewVehicle.isHeroTank:
            vehicleCD = g_currentPreviewVehicle.item.descriptor.makeCompactDescr(
            )
            return self.customizationService.getEmptyOutfitWithNationalEmblems(
                vehicleCD=vehicleCD)
        elif not g_currentVehicle.isPresent():
            if vDesc is not None:
                vehicleCD = vDesc.makeCompactDescr()
                outfit = self.customizationService.getEmptyOutfitWithNationalEmblems(
                    vehicleCD=vehicleCD)
            else:
                _logger.error(
                    'Failed to get base vehicle outfit. VehicleDescriptor is None.'
                )
                outfit = self.itemsFactory.createOutfit()
            return outfit
        else:
            vehicle = g_currentVehicle.item
            season = g_tankActiveCamouflage.get(vehicle.intCD,
                                                SeasonType.UNDEFINED)
            if season == SeasonType.UNDEFINED:
                season = vehicle.getAnyOutfitSeason()
            g_tankActiveCamouflage[vehicle.intCD] = season
            outfit = vehicle.getOutfit(season)
            if not outfit:
                vehicleCD = vehicle.descriptor.makeCompactDescr()
                outfit = self.customizationService.getEmptyOutfitWithNationalEmblems(
                    vehicleCD=vehicleCD)
            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(),
                                                BigWorld.WGBaseFashion(),
                                                BigWorld.WGBaseFashion(),
                                                BigWorld.WGBaseFashion())
            model_assembler.setupTracksFashion(self.__vDesc,
                                               self.__fashions.chassis)
            self.__vEntity.model.setupFashions(self.__fashions)
            model_assembler.assembleCollisionObstaclesCollector(
                self, None, self.__vDesc,
                BigWorld.player().spaceID)
            model_assembler.assembleTessellationCollisionSensor(self, None)
            wheelsScroll = None
            wheelsSteering = None
            if self.__vDesc.chassis.generalWheelsAnimatorConfig is not None:
                scrollableWheelsCount = self.__vDesc.chassis.generalWheelsAnimatorConfig.getWheelsCount(
                )
                wheelsScroll = [(lambda: 0.0)
                                for _ in xrange(scrollableWheelsCount)]
                steerableWheelsCount = self.__vDesc.chassis.generalWheelsAnimatorConfig.getSteerableWheelsCount(
                )
                wheelsSteering = [(lambda: 0.0)
                                  for _ in xrange(steerableWheelsCount)]
            chassisFashion = self.__fashions.chassis
            splineTracksImpl = model_assembler.setupSplineTracks(
                chassisFashion, self.__vDesc, self.__vEntity.model,
                self.__resources, self.__outfit.modelsSet)
            self.wheelsAnimator = model_assembler.createWheelsAnimator(
                self, ColliderTypes.VEHICLE_COLLIDER, self.__vDesc, lambda: 0,
                wheelsScroll, wheelsSteering, splineTracksImpl)
            self.trackNodesAnimator = model_assembler.createTrackNodesAnimator(
                self, self.__vDesc)
            model_assembler.assembleTracks(self.__resources, self.__vDesc,
                                           self, splineTracksImpl, True)
            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 = self.createComponent(
                    Vehicular.DirtComponent, dirtHandlers, modelHeight)
                for fashionIdx, _ in enumerate(TankPartNames.ALL):
                    self.__fashions[fashionIdx].addMaterialHandler(
                        dirtHandlers[fashionIdx])

                self.dirtComponent.setBase()
            outfitData = camouflages.getOutfitData(
                self, self.__outfit, self.__vDesc,
                self.__vState != 'undamaged')
            self.c11nComponent = self.createComponent(
                Vehicular.C11nEditComponent, self.__fashions,
                self.compoundModel, outfitData)
            self.__updateDecals(self.__outfit)
            self.__updateSequences(self.__outfit)
        else:
            self.__fashions = VehiclePartsTuple(BigWorld.WGVehicleFashion(),
                                                BigWorld.WGBaseFashion(),
                                                BigWorld.WGBaseFashion(),
                                                BigWorld.WGBaseFashion())
            self.__vEntity.model.setupFashions(self.__fashions)
            self.wheelsAnimator = None
            self.trackNodesAnimator = None
            self.dirtComponent = None
            self.flagComponent = None
        self.__staticTurretYaw = self.__vDesc.gun.staticTurretYaw
        self.__staticGunPitch = self.__vDesc.gun.staticPitch
        if not ('AT-SPG' in self.__vDesc.type.tags
                or 'SPG' in self.__vDesc.type.tags):
            if self.__staticTurretYaw is None:
                self.__staticTurretYaw = self._getTurretYaw()
                turretYawLimits = self.__vDesc.gun.turretYawLimits
                if turretYawLimits is not None:
                    self.__staticTurretYaw = math_utils.clamp(
                        turretYawLimits[0], turretYawLimits[1],
                        self.__staticTurretYaw)
            if self.__staticGunPitch is None:
                self.__staticGunPitch = self._getGunPitch()
                gunPitchLimits = self.__vDesc.gun.pitchLimits['absolute']
                self.__staticGunPitch = math_utils.clamp(
                    gunPitchLimits[0], gunPitchLimits[1],
                    self.__staticGunPitch)
        else:
            if self.__staticTurretYaw is None:
                self.__staticTurretYaw = 0.0
            if self.__staticGunPitch is None:
                self.__staticGunPitch = 0.0
        turretYawMatrix = math_utils.createRotationMatrix(
            (self.__staticTurretYaw, 0.0, 0.0))
        self.__vEntity.model.node(TankPartNames.TURRET, turretYawMatrix)
        gunPitchMatrix = math_utils.createRotationMatrix(
            (0.0, self.__staticGunPitch, 0.0))
        self.__setGunMatrix(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):
        if self.__vDesc:
            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()
        matrix = math_utils.createSRTMatrix(
            Math.Vector3(1.0, 1.0, 1.0),
            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))
        gunNode = self.__getGunNode()
        gunLink = math_utils.MatrixProviders.product(gunoffset, gunNode)
        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), gunNode))
        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 __applyAttachmentsVisibility(self):
        if self.compoundModel is None:
            return False
        else:
            partHandleNotFoundErrorCode = 4294967295L
            for attachment in self.__attachments:
                partNode = self.compoundModel.node(attachment.partNodeAlias)
                if partNode is None:
                    _logger.error('Attachment node "%s" is not found.',
                                  attachment.partNodeAlias)
                    continue
                partId = self.compoundModel.findPartHandleByNode(partNode)
                if partId == partHandleNotFoundErrorCode:
                    _logger.error('Part handle is not found, see node "%s"',
                                  attachment.partNodeAlias)
                    continue
                if not attachment.initialVisibility:
                    self.compoundModel.setPartVisible(partId, False)

            return True

    def getAnchorParams(self, slotId, areaId, regionIdx):
        if self.__anchorsParams is None:
            self.__initAnchorsParams()
        anchorParams = self.__anchorsParams.get(slotId,
                                                {}).get(areaId,
                                                        {}).get(regionIdx)
        return anchorParams

    def updateAnchorsParams(self, tankPartsToUpdate=TankPartIndexes.ALL):
        if self.__anchorsHelpers is None or self.__anchorsParams is None:
            return
        else:
            self.__updateAnchorsParams(tankPartsToUpdate)
            return

    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 updateCustomization(self, outfit=None, callback=None):
        if self.__isVehicleDestroyed:
            return
        vehicleCD = g_currentVehicle.item.descriptor.makeCompactDescr()
        outfit = outfit or self.customizationService.getEmptyOutfitWithNationalEmblems(
            vehicleCD=vehicleCD)
        if self.recreateRequired(outfit):
            self.refresh(outfit, callback)
            return
        self.__updateCamouflage(outfit)
        self.__updatePaint(outfit)
        self.__updateDecals(outfit)
        self.__updateProjectionDecals(outfit)
        self.__updateSequences(outfit)

    def rotateTurretForAnchor(self, anchorId):
        if self.compoundModel is None or self.__vDesc is None:
            return False
        else:
            defaultYaw = self._getTurretYaw()
            turretYaw = self.__getTurretYawForAnchor(anchorId, defaultYaw)
            self.turretRotator.start(turretYaw,
                                     rotationTime=EASING_TRANSITION_DURATION)
            return

    def rotateGunToDefault(self):
        if self.compoundModel is None:
            return False
        else:
            localGunMatrix = self.__getGunNode().local
            currentGunPitch = localGunMatrix.pitch
            gunPitchAngle = self._getGunPitch()
            if abs(currentGunPitch - gunPitchAngle) < 0.0001:
                return False
            gunPitchMatrix = math_utils.createRotationMatrix(
                (0.0, gunPitchAngle, 0.0))
            self.__setGunMatrix(gunPitchMatrix)
            return True

    def __getAnchorHelperById(self, anchorId):
        if anchorId.slotType not in self.__anchorsHelpers:
            return None
        else:
            slotTypeAnchorHelpers = self.__anchorsHelpers[anchorId.slotType]
            if anchorId.areaId not in slotTypeAnchorHelpers:
                return None
            areaAnchorHelpers = slotTypeAnchorHelpers[anchorId.areaId]
            return None if anchorId.regionIdx not in areaAnchorHelpers else areaAnchorHelpers[
                anchorId.regionIdx]

    def __updateAnchorHelperWithId(self, anchorId, newAnchorHelper):
        self.__anchorsHelpers[anchorId.slotType][anchorId.areaId][
            anchorId.regionIdx] = newAnchorHelper

    def __getTurretYawForAnchor(self, anchorId, defaultYaw):
        turretYaw = defaultYaw
        if anchorId is not None and hasTurretRotator(self.__vDesc):
            anchorHelper = self.__getAnchorHelperById(anchorId)
            if anchorHelper is not None:
                if anchorHelper.turretYaw is not None:
                    turretYaw = anchorHelper.turretYaw
                else:
                    if anchorHelper.attachedPartIdx == TankPartIndexes.HULL:
                        needsCorrection = anchorId.slotType in (
                            GUI_ITEM_TYPE.EMBLEM, GUI_ITEM_TYPE.INSCRIPTION
                        ) or anchorId.slotType == GUI_ITEM_TYPE.PROJECTION_DECAL and anchorHelper.descriptor.showOn == ApplyArea.HULL
                        if needsCorrection:
                            turretYaw = self.__correctTurretYaw(
                                anchorHelper, defaultYaw)
                    anchorHelper = AnchorHelper(anchorHelper.location,
                                                anchorHelper.descriptor,
                                                turretYaw,
                                                anchorHelper.partIdx,
                                                anchorHelper.attachedPartIdx)
                    self.__updateAnchorHelperWithId(anchorId, anchorHelper)
        turretYawLimits = self.__vDesc.gun.turretYawLimits
        if turretYawLimits is not None:
            turretYaw = math_utils.clamp(turretYawLimits[0],
                                         turretYawLimits[1], turretYaw)
        return turretYaw

    def __updatePaint(self, outfit):
        for fashionIdx, _ in enumerate(TankPartNames.ALL):
            repaint = camouflages.getRepaint(outfit, fashionIdx, self.__vDesc)
            self.c11nComponent.setPartPaint(fashionIdx, repaint)

    def __updateCamouflage(self, outfit):
        for fashionIdx, descId in enumerate(TankPartNames.ALL):
            camo = camouflages.getCamo(self, outfit, fashionIdx, self.__vDesc,
                                       descId, self.__vState != 'undamaged')
            self.c11nComponent.setPartCamo(fashionIdx, camo)

    def __updateDecals(self, outfit):
        self.__setupEmblems(outfit)

    def __updateProjectionDecals(self, outfit):
        decals = camouflages.getGenericProjectionDecals(outfit, self.__vDesc)
        self.c11nComponent.setDecals(decals)

    def __updateSequences(self, outfit):
        resources = camouflages.getModelAnimatorsPrereqs(
            outfit, self.__spaceId)
        resources.extend(
            camouflages.getAttachmentsAnimatorsPrereqs(self.__attachments,
                                                       self.__spaceId))
        if not resources:
            self.__clearModelAnimators()
            return
        BigWorld.loadResourceListBG(
            tuple(resources),
            makeCallbackWeak(self.__onAnimatorsLoaded, self.__curBuildInd,
                             outfit))

    def __clearModelAnimators(self):
        self.flagComponent = None
        for modelAnimator in self.__modelAnimators:
            modelAnimator.animator.stop()

        self.__modelAnimators = []
        return

    def __onVehicleChanged(self):
        self.__anchorsParams = None
        self.__anchorsHelpers = None
        return

    def __initAnchorsParams(self):
        self.__anchorsParams = {
            cType: {area: {}
                    for area in Area.ALL}
            for cType in SLOT_TYPES
        }
        if self.__anchorsHelpers is None:
            self.__initAnchorsHelpers()
        self.__updateAnchorsParams(TankPartIndexes.ALL)
        return

    def __updateAnchorsParams(self, tankPartsToUpdate):
        tankPartsMatrices = {}
        for tankPartIdx in TankPartIndexes.ALL:
            tankPartName = TankPartIndexes.getName(tankPartIdx)
            tankPartsMatrices[tankPartIdx] = Math.Matrix(
                self.__vEntity.model.node(tankPartName))

        for slotType in SLOT_TYPES:
            for areaId in Area.ALL:
                anchorHelpers = self.__anchorsHelpers[slotType][areaId]
                for regionIdx, anchorHelper in anchorHelpers.iteritems():
                    attachedPartIdx = anchorHelper.attachedPartIdx
                    if attachedPartIdx not in tankPartsToUpdate:
                        continue
                    anchorLocationWS = self.__getAnchorLocationWS(
                        anchorHelper.location, anchorHelper.partIdx)
                    self.__anchorsParams[slotType][areaId][
                        regionIdx] = AnchorParams(
                            anchorLocationWS, anchorHelper.descriptor,
                            AnchorId(slotType, areaId, regionIdx))

    def __initAnchorsHelpers(self):
        anchorsHelpers = {
            cType: {area: {}
                    for area in Area.ALL}
            for cType in SLOT_TYPES
        }
        for slotType in SLOT_TYPES:
            for areaId in Area.ALL:
                for regionIdx, anchor in g_currentVehicle.item.getAnchors(
                        slotType, areaId):
                    if isinstance(anchor, EmblemSlot):
                        getAnchorHelper = self.__getEmblemAnchorHelper
                    elif isinstance(anchor, BaseCustomizationSlot):
                        getAnchorHelper = self.__getAnchorHelper
                    else:
                        continue
                    anchorsHelpers[slotType][areaId][
                        regionIdx] = getAnchorHelper(anchor)

        self.__anchorsHelpers = anchorsHelpers

    def __getEmblemAnchorHelper(self, anchor):
        startPos = anchor.rayStart
        endPos = anchor.rayEnd
        normal = startPos - endPos
        normal.normalise()
        up = normal * (anchor.descriptor.rayUp * normal)
        up.normalise()
        position = startPos + (endPos - startPos) * 0.5
        anchorLocation = AnchorLocation(position, normal, up)
        partIdx = anchor.areaId
        attachedPartIdx = self.__getAttachedPartIdx(position, normal, partIdx)
        return AnchorHelper(anchorLocation, anchor.descriptor, None, partIdx,
                            attachedPartIdx)

    def __getAnchorHelper(self, anchor):
        slotType = ANCHOR_TYPE_TO_SLOT_TYPE_MAP[anchor.descriptor.type]
        if slotType in (GUI_ITEM_TYPE.MODIFICATION, GUI_ITEM_TYPE.STYLE):
            hullAABB = self.collisions.getBoundingBox(TankPartIndexes.HULL)
            position = Math.Vector3((hullAABB[1].x + hullAABB[0].x) / 2.0,
                                    hullAABB[1].y / 2.0,
                                    (hullAABB[1].z + hullAABB[0].z) / 2.0)
            partIdx = TankPartIndexes.HULL
        else:
            position = anchor.anchorPosition
            partIdx = anchor.areaId
        normal = anchor.anchorDirection
        normal.normalise()
        if slotType == GUI_ITEM_TYPE.PROJECTION_DECAL:
            ypr = anchor.descriptor.rotation
            rotationMatrix = Math.Matrix()
            rotationMatrix.setRotateYPR((ypr.y, ypr.x, ypr.z))
            up = rotationMatrix.applyVector((0, 0, -1))
        else:
            up = normal * (Math.Vector3(0, 1, 0) * normal)
        anchorLocation = AnchorLocation(position, normal, up)
        attachedPartIdx = self.__getAttachedPartIdx(position, normal, partIdx)
        return AnchorHelper(anchorLocation, anchor.descriptor, None, partIdx,
                            attachedPartIdx)

    def __getAttachedPartIdx(self, position, normal, tankPartIdx):
        partMatrix = Math.Matrix(
            self.__vEntity.model.node(TankPartIndexes.getName(tankPartIdx)))
        startPos = position + normal * 0.1
        endPos = position - normal * 0.6
        startPos = partMatrix.applyPoint(startPos)
        endPos = partMatrix.applyPoint(endPos)
        collisions = self.collisions.collideAllWorld(startPos, endPos)
        if collisions is not None:
            for collision in collisions:
                partIdx = collision[3]
                if partIdx in TankPartIndexes.ALL:
                    return partIdx

        return tankPartIdx

    def __correctTurretYaw(self, anchorHelper, defaultYaw):
        if not _SHOULD_CHECK_DECAL_UNDER_GUN:
            return defaultYaw
        else:
            partMatrix = Math.Matrix(
                self.__vEntity.model.node(
                    TankPartIndexes.getName(anchorHelper.partIdx)))
            turretMat = Math.Matrix(
                self.compoundModel.node(TankPartNames.TURRET))
            transformMatrix = math_utils.createRTMatrix(
                (turretMat.yaw, partMatrix.pitch, partMatrix.roll),
                partMatrix.translation)
            anchorLocationWS = self.__applyToAnchorLocation(
                anchorHelper.location, transformMatrix)
            position = anchorLocationWS.position
            direction = anchorLocationWS.normal
            up = anchorLocationWS.up
            fromTurretToHit = position - turretMat.translation
            if fromTurretToHit.dot(turretMat.applyVector((0, 0, 1))) < 0:
                return defaultYaw
            checkDirWorld = direction * 10.0
            cornersWorldSpace = self.__getDecalCorners(position, direction, up,
                                                       anchorHelper.descriptor)
            if cornersWorldSpace is None:
                return defaultYaw
            slotType = ANCHOR_TYPE_TO_SLOT_TYPE_MAP[
                anchorHelper.descriptor.type]
            if slotType == GUI_ITEM_TYPE.PROJECTION_DECAL:
                turretLeftDir = turretMat.applyVector((1, 0, 0))
                turretLeftDir.normalise()
                gunJoin = self.__vEntity.model.node('HP_gunJoint')
                fromGunJointToAnchor = gunJoin.position - position
                decalDiags = (cornersWorldSpace[0] - cornersWorldSpace[2],
                              cornersWorldSpace[1] - cornersWorldSpace[3])
                fromGunToHit = abs(fromGunJointToAnchor.dot(turretLeftDir))
                halfDecalWidth = max((abs(decalDiag.dot(turretLeftDir))
                                      for decalDiag in decalDiags)) * 0.5
                if fromGunToHit > halfDecalWidth * _PROJECTION_DECAL_OVERLAPPING_FACTOR:
                    return defaultYaw
            result = self.collisions.collideShape(TankPartIndexes.GUN,
                                                  cornersWorldSpace,
                                                  checkDirWorld)
            if result < 0.0:
                return defaultYaw
            turretYaw = _HANGAR_TURRET_SHIFT
            gunDir = turretMat.applyVector(Math.Vector3(0, 0, 1))
            if Math.Vector3(0, 1, 0).dot(gunDir * fromTurretToHit) > 0.0:
                turretYaw = -turretYaw
            return turretYaw

    def __getDecalCorners(self, position, direction, up, slotDescriptor):
        slotType = ANCHOR_TYPE_TO_SLOT_TYPE_MAP[slotDescriptor.type]
        if slotType == GUI_ITEM_TYPE.PROJECTION_DECAL:
            width = slotDescriptor.scale[0]
            aspect = getProgectionDecalAspect(slotDescriptor)
            height = slotDescriptor.scale[2] * aspect
        else:
            width = slotDescriptor.size
            aspect = SLOT_ASPECT_RATIO.get(slotType)
            if aspect is not None:
                height = width * aspect
            else:
                return
        transformMatrix = Math.Matrix()
        transformMatrix.lookAt(position, direction, up)
        transformMatrix.invert()
        result = (Math.Vector3(width * 0.5, height * 0.5,
                               0), Math.Vector3(width * 0.5, -height * 0.5, 0),
                  Math.Vector3(-width * 0.5, -height * 0.5,
                               0), Math.Vector3(-width * 0.5, height * 0.5, 0))
        return tuple((transformMatrix.applyPoint(vec) for vec in result))

    def __applyToAnchorLocation(self, anchorLocation, transform):
        position = transform.applyPoint(anchorLocation.position)
        normal = transform.applyVector(anchorLocation.normal)
        up = transform.applyVector(anchorLocation.up)
        if abs(normal.pitch - math.pi / 2) < 0.1:
            normal = Math.Vector3(0, -1, 0) + up * 0.01
            normal.normalise()
        return AnchorLocation(position, normal, up)

    def __getAnchorLocationWS(self, anchorLocation, partIdx):
        partMatrix = Math.Matrix(
            self.__vEntity.model.node(TankPartIndexes.getName(partIdx)))
        return self.__applyToAnchorLocation(anchorLocation, partMatrix)

    def __getGunNode(self):
        gunNode = self.compoundModel.node(TankNodeNames.GUN_INCLINATION)
        if gunNode is None:
            gunNode = self.compoundModel.node(TankPartNames.GUN)
        return gunNode

    def __setGunMatrix(self, gunMatrix):
        gunNode = self.__getGunNode()
        gunNode.local = gunMatrix
示例#3
0
class PlaneLootAirdrop(ScriptGameObject, CallbackDelayer, ISelfAssembler):
    __dynamicObjectsCache = dependency.descriptor(IBattleDynamicObjectsCache)
    __sessionProvider = dependency.descriptor(IBattleSessionProvider)
    FLY_TIME_BEFORE_DROP = DropPlane.FLY_TIME_BEFORE_DROP
    FLY_TIME_AFTER_DROP = DropPlane.FLY_TIME_AFTER_DROP
    DESCEND_TIME = 7
    DROP_ALTITUDE = 50
    POST_DELIVERY_CARGO_LIFETIME = 12.0
    cargo = ComponentDescriptor()
    plane = ComponentDescriptor()

    def __init__(self, dropID, deliveryPosition, deliveryTime):
        ScriptGameObject.__init__(self, BigWorld.player().spaceID)
        CallbackDelayer.__init__(self)
        self.owner = Svarog.GameObject(BigWorld.player().spaceID)
        self.owner.activate()
        self.owner.addComponent(self)
        Svarog.addGameObject(BigWorld.player().spaceID, self.owner)
        self.id = dropID
        self.deliveryPosition = deliveryPosition
        self.deliveryTime = deliveryTime + BigWorld.time(
        ) - BigWorld.serverTime()
        self.onFlightEnd = Event()

    def start(self, *args, **kwargs):
        planeStartTime = self.deliveryTime - self.FLY_TIME_BEFORE_DROP
        self.delayCallback(planeStartTime - BigWorld.time(),
                           self.__launchPlane)
        dropStartTime = self.deliveryTime - self.DESCEND_TIME
        self.delayCallback(dropStartTime - BigWorld.time(), self.__dropCrate)
        self.inactiveCargo = None
        self.activate()
        return

    def destroy(self):
        if self.inactiveCargo is not None:
            self.inactiveCargo.stopLoading = True
            self.inactiveCargo.destroy()
        self.inactiveCargo = None
        if self.cargo:
            self.cargo.stopLoading = True
        ScriptGameObject.destroy(self)
        CallbackDelayer.destroy(self)
        return

    def __launchPlane(self):
        self.plane = DropPlane(self.deliveryPosition, self.DROP_ALTITUDE,
                               self.deliveryTime - self.DESCEND_TIME)
        self.delayCallback(
            self.deliveryTime + self.FLY_TIME_AFTER_DROP - BigWorld.time(),
            self.__processFlightEnd)

    def __dropCrate(self):
        airDropConfig = self.__dynamicObjectsCache.getConfig(
            self.__sessionProvider.arenaVisitor.getArenaGuiType()).getAirDrop(
            )
        spaceId = BigWorld.player().spaceID
        compoundName = 'crateModel'
        modelAssembler = BigWorld.CompoundAssembler(compoundName, spaceId)
        modelAssembler.addRootPart(airDropConfig.model, 'root')
        animationPath = airDropConfig.dropAnimation
        animationBuilder = AnimationSequence.Loader(animationPath, spaceId)
        dropPoint = self.deliveryPosition + Math.Vector3(
            0, self.DROP_ALTITUDE, 0)
        crateYaw = 0
        if self.plane is not None:
            crateYaw = self.plane.flightYaw
        self.inactiveCargo = parachuteCargo = ParachuteCargo(
            crateYaw, dropPoint, self.deliveryPosition, self.DESCEND_TIME)
        loadComponentSystem(
            parachuteCargo, self.__onCargoLoad, {
                'model': Loader(modelAssembler),
                'landingAnimation': Loader(animationBuilder)
            })
        self.delayCallback(
            self.deliveryTime - BigWorld.time() +
            self.POST_DELIVERY_CARGO_LIFETIME, self.__killCargo)
        return

    def __onCargoLoad(self, cargo):
        self.cargo = cargo
        self.inactiveCargo = None
        cargo.activate()
        return

    def __killCargo(self):
        self.cargo = None
        return

    def __processFlightEnd(self):
        self.onFlightEnd(self)
        self.plane = None
        Svarog.removeGameObject(self.owner.worldID, self.owner)
        return
class ClientSelectableObject(BigWorld.Entity, ScriptGameObject,
                             ISelectableObject):
    collisions = ComponentDescriptor()

    @property
    def enabled(self):
        return self.__enabled

    def __init__(self):
        BigWorld.Entity.__init__(self)
        ScriptGameObject.__init__(self, self.spaceID)
        ISelectableObject.__init__(self)
        self.__enabled = True
        self.__edged = False
        self.__clickSound = None
        self.model = None
        return

    def prerequisites(self):
        if not self.modelName:
            return []
        collisionModels = self._getCollisionModelsPrereqs()
        collisionAssembler = BigWorld.CollisionAssembler(
            collisionModels, self.spaceID)
        return [self.modelName, collisionAssembler]

    def onEnterWorld(self, prereqs):
        if not 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)
        ScriptGameObject.activate(self)

    def onLeaveWorld(self):
        ScriptGameObject.deactivate(self)
        ScriptGameObject.destroy(self)
        if self.__clickSound is not None:
            if self.__clickSound.isPlaying:
                self.__clickSound.stop()
            self.__clickSound.releaseMatrix()
            self.__clickSound = None
        self.setHighlight(False)
        return

    def setEnable(self, enabled):
        self.__enabled = enabled
        if not self.__enabled:
            self.setHighlight(False)

    def setHighlight(self, show):
        if show:
            if not self.__edged and self.__enabled:
                self._addEdgeDetect()
                self.__edged = True
        elif self.__edged:
            self._delEdgeDetect()
            self.__edged = False

    def onMouseDown(self):
        pass

    def onMouseUp(self):
        pass

    def onMouseClick(self):
        if self.__clickSound is None:
            if self.clickSoundName and self.__enabled:
                if self.isClick3DSound:
                    self.__clickSound = SoundGroups.g_instance.getSound3D(
                        self.model.root, self.clickSoundName)
                else:
                    self.__clickSound = SoundGroups.g_instance.getSound2D(
                        self.clickSoundName)
                self.__clickSound.play()
        elif self.__clickSound.isPlaying:
            self.__clickSound.stop()
        else:
            self.__clickSound.play()
        return

    def _getModelHeight(self):
        return self.model.height

    def _getCollisionModelsPrereqs(self):
        collisionModels = ((0, self.modelName), )
        return collisionModels

    def _addEdgeDetect(self):
        BigWorld.wgAddEdgeDetectEntity(self, 0, self.edgeMode, False)

    def _delEdgeDetect(self):
        BigWorld.wgDelEdgeDetectEntity(self)
示例#5
0
class AvatarInputHandler(CallbackDelayer, ScriptGameObject):
    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)
    isDualGun = property(lambda self: self.__isDualGun)
    isMagneticAimEnabled = property(lambda self: self.__isMagnetAimEnabled)
    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)
    appLoader = dependency.descriptor(IAppLoader)

    @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()
    dualGunControl = ComponentDescriptor()
    siegeModeSoundNotifications = ComponentDescriptor()
    steadyVehicleMatrixCalculator = ComponentDescriptor()

    def __init__(self):
        CallbackDelayer.__init__(self)
        ScriptGameObject.__init__(self, BigWorld.player().spaceID)
        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.__isDualGun = False
        self.__isMagnetAimEnabled = 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.__detachedCommands = []
        self.__remoteCameraSender = None
        self.__isGUIVisible = False
        return

    def __constructComponents(self):
        player = BigWorld.player()
        typeDescr = player.vehicleTypeDescriptor
        if typeDescr.hasSiegeMode:
            if not self.siegeModeControl:
                self.siegeModeControl = SiegeModeControl()
            self.__commands.append(self.siegeModeControl)
            self.siegeModeControl.onSiegeStateChanged += lambda *args: self.steadyVehicleMatrixCalculator.relinkSources()
            if not self.siegeModeSoundNotifications:
                notifications = None
                if typeDescr.hasHydraulicChassis:
                    notifications = SiegeModeSoundNotifications()
                elif typeDescr.hasTurboshaftEngine:
                    notifications = TurboshaftModeSoundNotifications()
                if notifications:
                    self.siegeModeSoundNotifications = notifications
                    self.siegeModeControl.onSiegeStateChanged += self.siegeModeSoundNotifications.onSiegeStateChanged
            self.siegeModeControl.onRequestFail += self.__onRequestFail
            self.siegeModeControl.onSiegeStateChanged += SiegeModeCameraShaker.shake
        if typeDescr.isDualgunVehicle and not self.dualGunControl:
            self.dualGunControl = DualGunController(typeDescr)
        elif not typeDescr.isDualgunVehicle:
            self.dualGunControl = None
        if self.bootcampCtrl.isInBootcamp() and constants.HAS_DEV_RESOURCES:
            self.__commands.append(BootcampModeControl())
        if ARENA_BONUS_TYPE_CAPS.checkAny(player.arena.bonusType, ARENA_BONUS_TYPE_CAPS.RADAR):
            self.__commands.append(RadarControl())
        if ARENA_BONUS_TYPE_CAPS.checkAny(player.arena.bonusType, ARENA_BONUS_TYPE_CAPS.BATTLEROYALE):
            self.__commands.append(VehicleUpdateControl())
            self.__commands.append(VehicleUpgradePanelControl())
            self.__detachedCommands.append(VehicleUpgradePanelControl())
        return

    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(isDown=isDown) and not self.isObserverFPV or CommandMapping.g_instance.isFired(CommandMapping.CMD_CM_LOCK_TARGET, key):
                self.__curCtrl.handleKeyEvent(isDown, key, mods, event)
            for command in self.__detachedCommands:
                if command.handleKeyEvent(isDown, key, mods, event):
                    return True

            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:
                self.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:
                self.appLoader.detachCursor(settings.APP_NAME_SPACE.SF_BATTLE)
                result = True
            self.__curCtrl.setForcedGuiControlMode(detached)
        elif detached:
            self.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.__identifyVehicleType()
        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.__identifyVehicleType()
        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
        ScriptGameObject.destroy(self)
        CallbackDelayer.destroy(self)
        return

    def __onVehicleChanged(self, isStatic):
        self.steadyVehicleMatrixCalculator.relinkSources()
        self.__commands = []
        self.__identifyVehicleType()
        self.__constructComponents()
        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 not isObserverMode and self.__isDualGun:
                gui_event_dispatcher.controlModeChange(eMode)
            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 and not vehicle.isUpgrading:
                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)
            vehicle = BigWorld.player().getVehicleAttached()
            self.onControlModeChanged(eMode, preferredPos=targetPos, aimingMode=0, saveZoom=False, saveDist=True, equipmentID=None, curVehicleID=vehicle.id if vehicle is not None else BigWorld.player().playerVehicleID)
            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):
        return 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 __identifyVehicleType(self):
        avatar = BigWorld.player()
        magnetAimTags = avatar.magneticAutoAimTags
        veh = BigWorld.entity(avatar.playerVehicleID)
        if veh is None:
            return
        else:
            vehTypeDesc = veh.typeDescriptor.type
            self.__isSPG = 'SPG' in vehTypeDesc.tags
            self.__isATSPG = 'AT-SPG' in vehTypeDesc.tags
            self.__isDualGun = veh.typeDescriptor.isDualgunVehicle
            self.__isMagnetAimEnabled = bool(magnetAimTags & 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):
        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 _CTRL_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
示例#6
0
class DetachedTurret(BigWorld.Entity, ScriptGameObject):
    allTurrets = list()
    collisions = ComponentDescriptor()

    def __init__(self):
        ScriptGameObject.__init__(self, self.spaceID)
        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):
        LOG_DEBUG('__prepareModelAssembler', self.__vehDescr.name,
                  self.spaceID)
        assembler = BigWorld.CompoundAssembler(self.__vehDescr.name,
                                               self.spaceID)
        turretModel, gunModel = self.__getModels()
        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 __getModels(self):
        outfit = prepareBattleOutfit(self.outfitCD, self.__vehDescr,
                                     self.vehicleID)
        style = outfit.style
        if style is None:
            return (self.__vehDescr.turret.models.exploded,
                    self.__vehDescr.gun.models.exploded)
        else:
            modelsSetParams = ModelsSetParams(style.modelsSet,
                                              ModelStates.EXPLODED, [])
            _, _, turretModel, gunModel = getPartModelsFromDesc(
                self.__vehDescr, modelsSetParams)
            return (turretModel, gunModel)

    def prerequisites(self):
        LOG_DEBUG('prerequisites')
        prereqs = self.__prepareModelAssembler()
        prereqs += self.__vehDescr.prerequisites()
        return prereqs

    def onEnterWorld(self, prereqs):
        LOG_DEBUG('onEnterWorld', self.__vehDescr.name, self.spaceID)
        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)
        ScriptGameObject.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):
        LOG_DEBUG('onLeaveWorld')
        ScriptGameObject.deactivate(self)
        ScriptGameObject.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)
            collisionPointDest = surfaceMaterial.point - self.position
            if distToWater != -1 and distToWater <= collisionPointDest.length:
                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 CommonTankAppearance(ScriptGameObject):
    compoundModel = property(lambda self: self._compoundModel)
    boundEffects = property(lambda self: self.__boundEffects)
    fashions = property(lambda self: self.__fashions)
    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)
    outfit = property(lambda self: self.__outfit)
    renderState = property(lambda self: self.__renderState)

    def _setFashions(self, fashions, isTurretDetached=False):
        self.__fashions = fashions
        if isTurretDetached:
            self.compoundModel.setupFashions((fashions.chassis, fashions.hull))
        else:
            self.compoundModel.setupFashions(fashions)

    terrainMatKind = property(lambda self: self.__currTerrainMatKind)
    terrainGroundType = property(lambda self: self.__currTerrainGroundType)
    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)
    modelsSetParams = property(lambda self: ModelsSetParams(self.outfit.modelsSet, self.damageState.modelState, self.__attachments))
    splineTracks = property(lambda self: self._splineTracks)
    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)
    trackScrollController = property(lambda self: self.__trackScrollCtl)
    wheelsState = property(lambda self: 0)
    burnoutLevel = property(lambda self: 0.0)
    filterRetrievers = property(lambda self: self.__filterRetrievers)
    allLodCalculators = property(lambda self: self.__allLodCalculators)
    transmissionSlip = property(lambda self: self._commonSlip)
    transmissionScroll = property(lambda self: self._commonScroll)
    vehicleStickers = property(lambda self: self._vehicleStickers)
    isTurretDetached = property(lambda self: self._isTurretDetached)
    _weaponEnergy = property(lambda self: self.__weaponEnergy)
    filter = AutoProperty()
    areaTriggerTarget = ComponentDescriptor()
    burnoutProcessor = ComponentDescriptor()
    c11nComponent = ComponentDescriptor()
    collisionObstaclesCollector = ComponentDescriptor()
    collisions = ComponentDescriptor()
    crashedTracksController = ComponentDescriptor()
    customEffectManager = ComponentDescriptor()
    detailedEngineState = ComponentDescriptor()
    dirtComponent = ComponentDescriptor()
    engineAudition = ComponentDescriptor()
    flyingInfoProvider = ComponentDescriptor()
    frictionAudition = ComponentDescriptor()
    gearbox = ComponentDescriptor()
    gunLinkedNodesAnimator = ComponentDescriptor()
    gunRecoil = ComponentDescriptor()
    gunAnimators = [ComponentDescriptor()]
    gunRotatorAudition = ComponentDescriptor()
    hullAimingController = ComponentDescriptor()
    leveredSuspension = ComponentDescriptor()
    lodCalculator = ComponentDescriptor()
    shadowManager = ComponentDescriptor()
    siegeEffects = ComponentDescriptor()
    suspension = ComponentDescriptor()
    suspensionSound = ComponentDescriptor()
    swingingAnimator = ComponentDescriptor()
    terrainMatKindSensor = ComponentDescriptor()
    tessellationCollisionSensor = ComponentDescriptor()
    trackNodesAnimator = ComponentDescriptor()
    tracks = ComponentDescriptor()
    transform = ComponentDescriptor()
    vehicleTraces = ComponentDescriptor()
    waterSensor = ComponentDescriptor()
    wheeledLodCalculator = ComponentDescriptor()
    wheelsAnimator = ComponentDescriptor()
    flagComponent = ComponentDescriptor()

    def __init__(self, spaceID):
        ScriptGameObject.__init__(self, spaceID)
        self._vehicle = None
        self.__filter = None
        self.__typeDesc = None
        self.crashedTracksController = None
        self.__currentDamageState = VehicleDamageState()
        self.__currTerrainMatKind = [-1] * MATKIND_COUNT
        self.__currTerrainGroundType = [-1] * MATKIND_COUNT
        self.__terrainEffectMaterialNames = [''] * MATKIND_COUNT
        self._chassisDecal = VehicleDecal(self)
        self.__splodge = None
        self.__boundEffects = None
        self._splineTracks = None
        self.flyingInfoProvider = self.createComponent(Vehicular.FlyingInfoProvider)
        self.__trackScrollCtl = BigWorld.PyTrackScroll()
        self.__trackScrollCtl.setFlyingInfo(DataLinks.createBoolLink(self.flyingInfoProvider, 'isLeftSideFlying'), DataLinks.createBoolLink(self.flyingInfoProvider, 'isRightSideFlying'))
        self.__weaponEnergy = 0.0
        self.__outfit = None
        self.__systemStarted = False
        self.__isAlive = True
        self._isTurretDetached = False
        self.__isObserver = False
        self.__attachments = []
        self.__modelAnimators = []
        self.turretMatrix = None
        self.gunMatrix = None
        self.__allLodCalculators = []
        self._commonScroll = 0.0
        self._commonSlip = 0.0
        self._compoundModel = None
        self.__fashions = None
        self.__filterRetrievers = []
        self._vehicleStickers = None
        self.__vID = 0
        self.__renderState = None
        self.__frameTimestamp = 0
        self.__periodicTimerID = None
        return

    def prerequisites(self, typeDescriptor, vID, health, isCrewActive, isTurretDetached, outfitCD, renderState=None):
        self.damageState.update(health, isCrewActive, False)
        self.__typeDesc = typeDescriptor
        self.__vID = vID
        self._isTurretDetached = isTurretDetached
        self.__outfit = self._prepareOutfit(outfitCD)
        if self.damageState.isCurrentModelUndamaged:
            self.__attachments = camouflages.getAttachments(self.outfit, self.typeDescriptor)
        self.__renderState = renderState
        prereqs = self.typeDescriptor.prerequisites(True)
        prereqs.extend(camouflages.getCamoPrereqs(self.outfit, self.typeDescriptor))
        prereqs.extend(camouflages.getModelAnimatorsPrereqs(self.outfit, self.worldID))
        prereqs.extend(camouflages.getAttachmentsAnimatorsPrereqs(self.__attachments, self.worldID))
        splineDesc = self.typeDescriptor.chassis.splineDesc
        if splineDesc is not None:
            modelsSet = self.outfit.modelsSet
            prereqs.append(splineDesc.segmentModelLeft(modelsSet))
            prereqs.append(splineDesc.segmentModelRight(modelsSet))
            segment2ModelLeft = splineDesc.segment2ModelLeft(modelsSet)
            if segment2ModelLeft is not None:
                prereqs.append(segment2ModelLeft)
            segment2ModelRight = splineDesc.segment2ModelRight(modelsSet)
            if segment2ModelRight is not None:
                prereqs.append(segment2ModelRight)
        modelsSetParams = self.modelsSetParams
        compoundAssembler = model_assembler.prepareCompoundAssembler(self.typeDescriptor, modelsSetParams, self.worldID, self.isTurretDetached, renderState=self.renderState)
        prereqs.append(compoundAssembler)
        if renderState == RenderStates.OVERLAY_COLLISION:
            self.damageState.update(0, isCrewActive, False)
        if not isTurretDetached:
            bspModels = ((TankPartNames.getIdx(TankPartNames.CHASSIS), typeDescriptor.chassis.hitTester.bspModelName),
             (TankPartNames.getIdx(TankPartNames.HULL), typeDescriptor.hull.hitTester.bspModelName),
             (TankPartNames.getIdx(TankPartNames.TURRET), typeDescriptor.turret.hitTester.bspModelName),
             (TankPartNames.getIdx(TankPartNames.GUN), typeDescriptor.gun.hitTester.bspModelName))
        else:
            bspModels = ((TankPartNames.getIdx(TankPartNames.CHASSIS), typeDescriptor.chassis.hitTester.bspModelName), (TankPartNames.getIdx(TankPartNames.HULL), typeDescriptor.hull.hitTester.bspModelName))
        collisionAssembler = BigWorld.CollisionAssembler(bspModels, self.worldID)
        prereqs.append(collisionAssembler)
        physicalTracksBuilders = self.typeDescriptor.chassis.physicalTracks
        for name, builders in physicalTracksBuilders.iteritems():
            for index, builder in enumerate(builders):
                prereqs.append(builder.createLoader(self.worldID, '{0}{1}PhysicalTrack'.format(name, index), modelsSetParams.skin))

        return prereqs

    def construct(self, isPlayer, resourceRefs):
        self.collisions = resourceRefs['collisionAssembler']
        self.typeDescriptor.chassis.hitTester.bbox = self.collisions.getBoundingBox(TankPartNames.getIdx(TankPartNames.CHASSIS))
        self.typeDescriptor.hull.hitTester.bbox = self.collisions.getBoundingBox(TankPartNames.getIdx(TankPartNames.HULL))
        self.typeDescriptor.turret.hitTester.bbox = self.collisions.getBoundingBox(TankPartNames.getIdx(TankPartNames.TURRET))
        self.typeDescriptor.gun.hitTester.bbox = self.collisions.getBoundingBox(TankPartNames.getIdx(TankPartNames.GUN))
        self.__isObserver = 'observer' in self.typeDescriptor.type.tags
        self._compoundModel = resourceRefs[self.typeDescriptor.name]
        self.__boundEffects = bound_effects.ModelBoundEffects(self.compoundModel)
        isCurrentModelDamaged = self.damageState.isCurrentModelDamaged
        fashions = camouflages.prepareFashions(isCurrentModelDamaged)
        if not isCurrentModelDamaged:
            model_assembler.setupTracksFashion(self.typeDescriptor, fashions.chassis)
        self._setFashions(fashions, self.isTurretDetached)
        self._setupModels()
        if not isCurrentModelDamaged:
            modelsSet = self.outfit.modelsSet
            self._splineTracks = model_assembler.setupSplineTracks(self.fashion, self.typeDescriptor, self.compoundModel, resourceRefs, modelsSet)
            self.crashedTracksController = CrashedTrackController(self.typeDescriptor, self.fashion, modelsSet)
        else:
            self.__trackScrollCtl = None
        self._chassisDecal.create()
        self.__modelAnimators = camouflages.getModelAnimators(self.outfit, self.typeDescriptor, self.worldID, resourceRefs, self.compoundModel)
        if self.modelsSetParams.state == 'undamaged':
            self.__modelAnimators.extend(camouflages.getAttachmentsAnimators(self.__attachments, self.worldID, resourceRefs, self.compoundModel))
        self.transform = self.createComponent(GenericComponents.TransformComponent, Math.Vector3(0, 0, 0))
        self.areaTriggerTarget = self.createComponent(Triggers.AreaTriggerTarget)
        self.__filter = model_assembler.createVehicleFilter(self.typeDescriptor)
        compoundModel = self.compoundModel
        if self.isAlive:
            self.detailedEngineState, self.gearbox = model_assembler.assembleDrivetrain(self, isPlayer)
            if not gEffectsDisabled():
                self.customEffectManager = CustomEffectManager(self)
                if self.typeDescriptor.hasSiegeMode:
                    self.siegeEffects = SiegeEffectsController(self, isPlayer)
                model_assembler.assembleVehicleAudition(isPlayer, self)
                self.detailedEngineState.onEngineStart = self._onEngineStart
                self.detailedEngineState.onStateChanged = self.engineAudition.onEngineStateChanged
            if isPlayer:
                turret = self.typeDescriptor.turret
                gunRotatorAudition = self.createComponent(Vehicular.GunRotatorAudition, turret.turretRotatorSoundManual, turret.weight / 1000.0, compoundModel.node(TankPartNames.TURRET))
                gunRotatorAudition.vehicleMatrixLink = self.compoundModel.root
                gunRotatorAudition.damaged = lambda : self.turretDamaged()
                gunRotatorAudition.maxTurretRotationSpeed = lambda : self.maxTurretRotationSpeed()
                self.gunRotatorAudition = gunRotatorAudition
                self.frictionAudition = self.createComponent(Vehicular.FrictionAudition, TANK_FRICTION_EVENT)
        isLodTopPriority = isPlayer
        lodCalcInst = self.createComponent(Vehicular.LodCalculator, DataLinks.linkMatrixTranslation(compoundModel.matrix), True, VEHICLE_PRIORITY_GROUP, isLodTopPriority)
        self.lodCalculator = lodCalcInst
        self.allLodCalculators.append(lodCalcInst)
        lodLink = DataLinks.createFloatLink(lodCalcInst, 'lodDistance')
        lodStateLink = lodCalcInst.lodStateLink
        if IS_EDITOR:
            matrixBinding = None
            changeCamera = None
        else:
            matrixBinding = BigWorld.player().consistentMatrices.onVehicleMatrixBindingChanged
            changeCamera = BigWorld.player().inputHandler.onCameraChanged
        self.shadowManager = VehicleShadowManager(compoundModel, matrixBinding, changeCamera)
        if not self.damageState.isCurrentModelDamaged:
            self.__assembleNonDamagedOnly(resourceRefs, isPlayer, lodLink, lodStateLink)
            dirtEnabled = BigWorld.WG_dirtEnabled() and 'HD' in self.typeDescriptor.type.tags
            if dirtEnabled and self.fashions is not None:
                dirtHandlers = [BigWorld.PyDirtHandler(True, compoundModel.node(TankPartNames.CHASSIS).position.y),
                 BigWorld.PyDirtHandler(False, compoundModel.node(TankPartNames.HULL).position.y),
                 BigWorld.PyDirtHandler(False, compoundModel.node(TankPartNames.TURRET).position.y),
                 BigWorld.PyDirtHandler(False, compoundModel.node(TankPartNames.GUN).position.y)]
                modelHeight, _ = self.computeVehicleHeight()
                self.dirtComponent = self.createComponent(Vehicular.DirtComponent, dirtHandlers, modelHeight)
                for fashionIdx, _ in enumerate(TankPartNames.ALL):
                    self.fashions[fashionIdx].addMaterialHandler(dirtHandlers[fashionIdx])
                    self.fashions[fashionIdx].addTrackMaterialHandler(dirtHandlers[fashionIdx])

        model_assembler.setupTurretRotations(self)
        self.waterSensor = model_assembler.assembleWaterSensor(self.typeDescriptor, self, lodStateLink, self.worldID)
        if self.engineAudition is not None:
            self.engineAudition.setIsUnderwaterInfo(DataLinks.createBoolLink(self.waterSensor, 'isUnderWater'))
            self.engineAudition.setIsInWaterInfo(DataLinks.createBoolLink(self.waterSensor, 'isInWater'))
        self.__postSetupFilter()
        compoundModel.setPartBoundingBoxAttachNode(TankPartIndexes.GUN, TankNodeNames.GUN_INCLINATION)
        camouflages.updateFashions(self)
        model_assembler.assembleCustomLogicComponents(self, self.__attachments, self.__modelAnimators)
        return

    def destroy(self):
        self.flagComponent = None
        self.__modelAnimators = []
        self._destroySystems()
        fashions = VehiclePartsTuple(None, None, None, None)
        self._setFashions(fashions, self._isTurretDetached)
        super(CommonTankAppearance, self).destroy()
        self.__typeDesc = None
        if self.boundEffects is not None:
            self.boundEffects.destroy()
        self._vehicleStickers = None
        self._chassisDecal.destroy()
        self._chassisDecal = None
        self._compoundModel = None
        return

    def activate(self):
        if self.collisions is not None and self.isTurretDetached:
            self.collisions.removeAttachment(TankPartNames.getIdx(TankPartNames.TURRET))
            self.collisions.removeAttachment(TankPartNames.getIdx(TankPartNames.GUN))
        super(CommonTankAppearance, self).activate()
        if not self.isObserver:
            self._chassisDecal.attach()
        self._createAndAttachStickers()
        if not self.isObserver:
            if not self.damageState.isCurrentModelDamaged and not self.__systemStarted:
                self._startSystems()
            self.filter.enableLagDetection(not self.damageState.isCurrentModelDamaged)
            if self.__periodicTimerID is not None:
                BigWorld.cancelCallback(self.__periodicTimerID)
            self.__periodicTimerID = BigWorld.callback(PERIODIC_UPDATE_TIME, self.__onPeriodicTimer)
        self.setupGunMatrixTargets(self.filter)
        for lodCalculator in self.allLodCalculators:
            lodCalculator.setupPosition(DataLinks.linkMatrixTranslation(self.compoundModel.matrix))

        for modelAnimator in self.__modelAnimators:
            modelAnimator.animator.start()

        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.isObserver:
            self.compoundModel.visible = False
        if self.collisions is not None:
            chassisColisionMatrix, gunNodeName = self._vehicleColliderInfo
            collisionData = ((TankPartNames.getIdx(TankPartNames.HULL), self.compoundModel.node(TankPartNames.HULL)),
             (TankPartNames.getIdx(TankPartNames.TURRET), self.compoundModel.node(TankPartNames.TURRET)),
             (TankPartNames.getIdx(TankPartNames.CHASSIS), chassisColisionMatrix),
             (TankPartNames.getIdx(TankPartNames.GUN), self.compoundModel.node(gunNodeName)))
            self.collisions.connect(self.id, ColliderTypes.VEHICLE_COLLIDER, collisionData)
        return

    def deactivate(self):
        for modelAnimator in self.__modelAnimators:
            modelAnimator.animator.stop()

        if self.damageState and self.damageState.isCurrentModelDamaged:
            self.__modelAnimators = []
        self.shadowManager.unregisterCompoundModel(self.compoundModel)
        if self.__systemStarted:
            self._stopSystems()
        super(CommonTankAppearance, self).deactivate()
        self._chassisDecal.detach()
        self.filter.enableLagDetection(False)
        if self.vehicleStickers:
            self.vehicleStickers.detach()

    def setupGunMatrixTargets(self, target):
        self.turretMatrix = target.turretMatrix
        self.gunMatrix = target.gunMatrix

    def receiveShotImpulse(self, direction, impulse):
        if not VehicleDamageState.isDamagedModel(self.damageState.modelState):
            self.swingingAnimator.receiveShotImpulse(direction, impulse)
            if self.crashedTracksController is not None:
                self.crashedTracksController.receiveShotImpulse(direction, impulse)
        return

    def computeVehicleHeight(self):
        gunLength = 0.0
        height = 0.0
        if self.collisions is not None:
            desc = self.typeDescriptor
            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 onWaterSplash(self, waterHitPoint, isHeavySplash):
        pass

    def onUnderWaterSwitch(self, isUnderWater):
        pass

    def getWheelsSteeringMax(self):
        pass

    def _prepareOutfit(self, outfitCD):
        outfitComponent = camouflages.getOutfitComponent(outfitCD)
        return Outfit(component=outfitComponent, vehicleCD=self.typeDescriptor.makeCompactDescr())

    def _setupModels(self):
        self.__isAlive = not self.damageState.isCurrentModelDamaged
        if self.isAlive:
            _, gunLength = self.computeVehicleHeight()
            self.__weaponEnergy = gunLength * self.typeDescriptor.shot.shell.caliber
        if MAX_DISTANCE > 0 and not self.isObserver:
            transform = self.typeDescriptor.chassis.AODecals[0]
            splodge = BigWorld.Splodge(transform, MAX_DISTANCE, self.typeDescriptor.chassis.hullPosition.y)
            if splodge:
                self.__splodge = splodge
                node = self.compoundModel.node(TankPartNames.HULL)
                node.attach(splodge)

    def _createStickers(self):
        return VehicleStickers(self.typeDescriptor, 0, self.outfit)

    @property
    def _vehicleColliderInfo(self):
        chassisColisionMatrix = self.compoundModel.matrix
        if self.damageState.isCurrentModelDamaged:
            gunNodeName = 'gun'
        else:
            gunNodeName = TankNodeNames.GUN_INCLINATION
        return (chassisColisionMatrix, gunNodeName)

    def _startSystems(self):
        self.__systemStarted = True
        if self.flyingInfoProvider is not None:
            self.flyingInfoProvider.setData(self.filter, self.suspension)
        if self.trackScrollController is not None:
            self.trackScrollController.activate()
            self.trackScrollController.setData(self.filter)
        if self.engineAudition is not None:
            self.engineAudition.setWeaponEnergy(self._weaponEnergy)
            self.engineAudition.attachToModel(self.compoundModel)
        if self.hullAimingController is not None:
            self.hullAimingController.setData(self.filter, self.typeDescriptor)
        return

    def _stopSystems(self):
        self.__systemStarted = False
        if self.flyingInfoProvider is not None:
            self.flyingInfoProvider.setData(None, None)
        if self.trackScrollController is not None:
            self.trackScrollController.deactivate()
            self.trackScrollController.setData(None)
        if self.__periodicTimerID is not None:
            BigWorld.cancelCallback(self.__periodicTimerID)
            self.__periodicTimerID = None
        return

    def _destroySystems(self):
        self.__systemStarted = False
        if self.trackScrollController is not None:
            self.trackScrollController.deactivate()
            self.__trackScrollCtl = None
        if self.crashedTracksController is not None:
            self.crashedTracksController.destroy()
            self.crashedTracksController = None
        if self.__periodicTimerID is not None:
            BigWorld.cancelCallback(self.__periodicTimerID)
            self.__periodicTimerID = None
        return

    def _onRequestModelsRefresh(self):
        self.flagComponent = None
        return

    def _onEngineStart(self):
        if self.engineAudition is not None:
            self.engineAudition.onEngineStart()
        return

    def __assembleNonDamagedOnly(self, resourceRefs, isPlayer, lodLink, lodStateLink):
        model_assembler.assembleTerrainMatKindSensor(self, lodStateLink, self.worldID)
        model_assembler.assembleRecoil(self, lodLink)
        model_assembler.assembleMultiGunRecoil(self, lodLink)
        model_assembler.assembleGunLinkedNodesAnimator(self)
        model_assembler.assembleCollisionObstaclesCollector(self, lodStateLink, self.typeDescriptor, self.worldID)
        model_assembler.assembleTessellationCollisionSensor(self, lodStateLink)
        wheelsScroll = None
        wheelsSteering = None
        generalWheelsAnimatorConfig = self.typeDescriptor.chassis.generalWheelsAnimatorConfig
        if generalWheelsAnimatorConfig is not None:
            scrollableWheelsCount = generalWheelsAnimatorConfig.getNonTrackWheelsCount()
            wheelsScroll = []
            for _ in xrange(scrollableWheelsCount):
                retriever = self.createComponent(NetworkFilters.FloatFilterRetriever)
                wheelsScroll.append(DataLinks.createFloatLink(retriever, 'value'))
                self.filterRetrievers.append(retriever)

            steerableWheelsCount = generalWheelsAnimatorConfig.getSteerableWheelsCount()
            wheelsSteering = []
            for _ in xrange(steerableWheelsCount):
                retriever = self.createComponent(NetworkFilters.FloatFilterRetriever)
                wheelsSteering.append(DataLinks.createFloatLink(retriever, 'value'))
                self.filterRetrievers.append(retriever)

        self.wheelsAnimator = model_assembler.createWheelsAnimator(self, ColliderTypes.VEHICLE_COLLIDER, self.typeDescriptor, lambda : self.wheelsState, wheelsScroll, wheelsSteering, self.splineTracks, lodStateLink)
        if self.customEffectManager is not None:
            self.customEffectManager.setWheelsData(self)
        suspensionLodLink = lodStateLink
        if 'wheeledVehicle' in self.typeDescriptor.type.tags:
            wheeledLodCalculator = Vehicular.LodCalculator(self.worldID, DataLinks.linkMatrixTranslation(self.compoundModel.matrix), True, WHEELED_CHASSIS_PRIORITY_GROUP, isPlayer)
            self.wheeledLodCalculator = wheeledLodCalculator
            self.allLodCalculators.append(wheeledLodCalculator)
            suspensionLodLink = wheeledLodCalculator.lodStateLink
        model_assembler.assembleSuspensionIfNeed(self, suspensionLodLink)
        model_assembler.assembleLeveredSuspensionIfNeed(self, suspensionLodLink)
        self.__assembleSwinging(lodLink)
        model_assembler.assembleBurnoutProcessor(self)
        model_assembler.assembleSuspensionSound(self, lodLink, isPlayer)
        model_assembler.assembleHullAimingController(self)
        self.trackNodesAnimator = model_assembler.createTrackNodesAnimator(self, self.typeDescriptor, lodStateLink)
        model_assembler.assembleTracks(resourceRefs, self.typeDescriptor, self, self.splineTracks, False, lodStateLink)
        model_assembler.assembleVehicleTraces(self, self.filter, lodStateLink)
        return

    def __assembleSwinging(self, lodLink):
        self.swingingAnimator = model_assembler.createSwingingAnimator(self, self.typeDescriptor, self.compoundModel.node(TankPartNames.HULL).localMatrix, self.compoundModel.matrix, lodLink)
        self.compoundModel.node(TankPartNames.HULL, self.swingingAnimator.animatedMProv)
        if hasattr(self.filter, 'placingCompensationMatrix'):
            self.swingingAnimator.placingCompensationMatrix = self.filter.placingCompensationMatrix

    def __postSetupFilter(self):
        suspensionWorking = self.suspension is not None and self.suspension.hasGroundNodes
        placingOnGround = not (suspensionWorking or self.leveredSuspension is not None)
        self.filter.placingOnGround = placingOnGround
        return

    def _createAndAttachStickers(self):
        isCurrentModelDamaged = self.damageState.isCurrentModelDamaged
        stickersAlpha = DEFAULT_STICKERS_ALPHA
        if isCurrentModelDamaged:
            stickersAlpha = items.vehicles.g_cache.commonConfig['miscParams']['damageStickerAlpha']
        if self.vehicleStickers is None:
            self._vehicleStickers = self._createStickers()
        self.vehicleStickers.alpha = stickersAlpha
        self.vehicleStickers.attach(compoundModel=self.compoundModel, isDamaged=self.damageState.isCurrentModelDamaged, showDamageStickers=not isCurrentModelDamaged)
        return

    def __onPeriodicTimer(self):
        timeStamp = BigWorld.wg_getFrameTimestamp()
        if self.__frameTimestamp >= timeStamp:
            self.__periodicTimerID = BigWorld.callback(0.0, self.__onPeriodicTimer)
        else:
            self.__frameTimestamp = timeStamp
            self.__periodicTimerID = BigWorld.callback(PERIODIC_UPDATE_TIME, self.__onPeriodicTimer)
            self._periodicUpdate()

    def _periodicUpdate(self):
        if self._vehicle is None or not self._vehicle.isAlive():
            return
        else:
            self._updateCurrTerrainMatKinds()
            self.__updateEffectsLOD()
            if self.customEffectManager:
                self.customEffectManager.update()
            return

    def __updateEffectsLOD(self):
        if self.customEffectManager:
            distanceFromPlayer = self.lodCalculator.lodDistance
            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 _stopEffects(self):
        self.boundEffects.stop()

    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)
            args = dict(isPlayerVehicle=vehicle.isPlayerVehicle, showShockWave=vehicle.isPlayerVehicle, showFlashBang=vehicle.isPlayerVehicle, entity_id=vehicle.id, 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))
            if isSpawnedBot(self.typeDescriptor.type.tags) and kind in ('explosion', 'destruction'):
                player = BigWorld.player()
                if player is not None and isPlayerAvatar():
                    player.terrainEffects.addNew(self._vehicle.position, effects[1], effects[0], None, **args)
            else:
                self.boundEffects.addNew(None, effects[1], effects[0], **args)
            return

    def _updateCurrTerrainMatKinds(self):
        if self.terrainMatKindSensor is None:
            return
        else:
            matKinds = self.terrainMatKindSensor.matKinds
            groundTypes = self.terrainMatKindSensor.groundTypes
            materialsCount = len(matKinds)
            for i in xrange(MATKIND_COUNT):
                matKind = matKinds[i] if i < materialsCount else 0
                groundType = groundTypes[i] if i < materialsCount else 0
                self.terrainMatKind[i] = matKind
                self.terrainGroundType[i] = groundType
                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.terrainMatKind[0], self.terrainMatKind[1])
            return

    def changeEngineMode(self, mode, forceSwinging=False):
        if self.detailedEngineState is not None:
            self.detailedEngineState.mode = mode[0]
        if self.trackScrollController is not None:
            self.trackScrollController.setMode(mode)
        return

    def changeSiegeState(self, siegeState):
        if self.engineAudition is not None:
            self.engineAudition.onSiegeStateChanged(siegeState)
        return

    def turretDamaged(self):
        pass

    def maxTurretRotationSpeed(self):
        pass
示例#8
0
class CompoundAppearance(CommonTankAppearance, CallbackDelayer):
    activated = property(lambda self: self.__activated)
    wheelsState = property(lambda self: self._vehicle.wheelsState
                           if self._vehicle is not None else 0)
    wheelsSteering = property(lambda self: self._vehicle.wheelsSteeringSmoothed
                              if self._vehicle is not None else None)
    wheelsScroll = property(lambda self: self._vehicle.wheelsScrollSmoothed
                            if self._vehicle is not None else None)
    burnoutLevel = property(lambda self: self._vehicle.burnoutLevel / 255.0
                            if self._vehicle is not None else 0.0)
    isConstructed = property(lambda self: self.__isConstructed)
    highlighter = ComponentDescriptor()
    peripheralsController = ComponentDescriptor()
    tutorialMatKindsController = ComponentDescriptor()

    def __init__(self):
        CallbackDelayer.__init__(self)
        CommonTankAppearance.__init__(self, BigWorld.player().spaceID)
        self.turretMatrix = Math.WGAdaptiveMatrixProvider()
        self.gunMatrix = Math.WGAdaptiveMatrixProvider()
        self.__originalFilter = None
        self.__terrainCircle = None
        self.onModelChanged = Event()
        self.__activated = False
        self.__dirtUpdateTime = 0.0
        self.__inSpeedTreeCollision = False
        self.__isConstructed = False
        self.__tmpGameObjectNames = []
        return

    def setVehicle(self, vehicle):
        self._vehicle = vehicle
        if self.customEffectManager is not None:
            self.customEffectManager.setVehicle(vehicle)
        if self.crashedTracksController is not None:
            self.crashedTracksController.setVehicle(vehicle)
        if self.frictionAudition is not None:
            self.frictionAudition.setVehicleMatrix(vehicle.matrix)
        self.highlighter.setVehicle(vehicle)
        self.__applyVehicleOutfit()
        fstList = vehicle.wheelsScrollFilters if vehicle.wheelsScrollFilters else []
        scndList = vehicle.wheelsSteeringFilters if vehicle.wheelsSteeringFilters else []
        for retriever, floatFilter in zip(self.filterRetrievers,
                                          fstList + scndList):
            retriever.setupFilter(floatFilter)

        self.transform.translation = Math.Matrix(vehicle.matrix).translation
        self.createComponent(NetworkComponents.NetworkEntity, vehicle)
        self.createComponent(NetworkComponents.EntityTransformSyncer)
        return

    def getVehicle(self):
        return self._vehicle

    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

    @property
    def _vehicleColliderInfo(self):
        if self.damageState.isCurrentModelDamaged:
            chassisCollisionMatrix = self.compoundModel.matrix
            gunNodeName = 'gun'
        else:
            chassisCollisionMatrix = self._vehicle.filter.groundPlacingMatrix
            gunNodeName = TankNodeNames.GUN_INCLINATION
        return (chassisCollisionMatrix, gunNodeName)

    def activate(self):
        if self.__activated or self._vehicle is None:
            return
        else:
            isPlayerVehicle = self._vehicle.isPlayerVehicle
            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
            if isPlayerVehicle and self.collisions is not None:
                colliderData = (self.collisions.getColliderID(),
                                (TankPartNames.getIdx(TankPartNames.HULL),
                                 TankPartNames.getIdx(TankPartNames.TURRET),
                                 TankPartNames.getIdx(TankPartNames.GUN)))
                BigWorld.appendCameraCollider(colliderData)
                self.__inSpeedTreeCollision = True
                BigWorld.setSpeedTreeCollisionBody(
                    self.compoundModel.getBoundsForPart(TankPartIndexes.HULL))
            self.__linkCompound()
            self.__createTerrainCircle()
            super(CompoundAppearance, self).activate()
            self.onModelChanged()
            if not self.isObserver:
                self.__dirtUpdateTime = BigWorld.time()
            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.highlighter.removeHighlight()
            super(CompoundAppearance, self).deactivate()
            if self.__inSpeedTreeCollision:
                BigWorld.setSpeedTreeCollisionBody(None)
            if self.collisions is not None:
                BigWorld.removeCameraCollider(self.collisions.getColliderID())
            self.turretMatrix.target = None
            self.gunMatrix.target = None
            self._vehicle.filter = self.__originalFilter
            self.filter.reset()
            self.__originalFilter = None
            if self.__terrainCircle.isAttached():
                self.__terrainCircle.detach()
            if stopEffects:
                self._stopEffects()
            self._vehicle.model = None
            self.compoundModel.matrix = Math.Matrix()
            self._vehicle = None
            BigWorld.player().arena.onPeriodChange -= self.__arenaPeriodChanged
            BigWorld.player(
            ).inputHandler.onCameraChanged -= self.__onCameraChanged
            return

    def _startSystems(self):
        super(CompoundAppearance, self)._startSystems()
        if self._vehicle.isPlayerVehicle:
            self.delayCallback(_PERIODIC_TIME_ENGINE,
                               self.__onPeriodicTimerEngine)
            self.highlighter.highlight(True)
        if self.peripheralsController is not None:
            self.peripheralsController.attachToVehicle(self._vehicle)
        if self.detailedEngineState is not None:
            self.detailedEngineState.onGearUpCbk = self.__onEngineStateGearUp
        self.delayCallback(_PERIODIC_TIME_DIRT[0][0],
                           self.__onPeriodicTimerDirt)
        return

    def _stopSystems(self):
        super(CompoundAppearance, self)._stopSystems()
        if self._vehicle.isPlayerVehicle:
            self.highlighter.highlight(False)
            self.stopCallback(self.__onPeriodicTimerEngine)
        self.stopCallback(self.__onPeriodicTimerDirt)

    def _onEngineStart(self):
        super(CompoundAppearance, self)._onEngineStart()
        hasTurbocharger = False
        if self._vehicle is not None:
            for device in self.getVehicle().getOptionalDevices():
                if device is not None and device.groupName == 'turbocharger':
                    hasTurbocharger = True

        if hasTurbocharger and self.engineAudition is not None:
            engineSoundObject = self.engineAudition.getSoundObject(
                TankSoundObjectsIndexes.ENGINE)
            engineSoundObject.play('cons_turbine')
        return

    def __destroyEngineAudition(self):
        self.engineAudition = None
        if self.detailedEngineState is not None:
            self.detailedEngineState.onEngineStart = None
            self.detailedEngineState.onStateChanged = None
        return

    def __processPostmortemComponents(self):
        if self.wheelsAnimator is not None and self.wheelsAnimator.activePostmortem:
            self.wheelsAnimator.reattachToCrash(self.compoundModel,
                                                self.fashion)
        if self.suspension is not None and self.suspension.activePostmortem:
            self.suspension.reattachCompound(self.compoundModel)
        if self.leveredSuspension is not None and self.leveredSuspension.activePostmortem:
            self.leveredSuspension.reattachCompound(self.compoundModel)
        if self.vehicleTraces is not None and self.vehicleTraces.activePostmortem:
            self.vehicleTraces.setCompound(self.compoundModel)
        if self.collisionObstaclesCollector is not None and self.collisionObstaclesCollector.activePostmortem:
            self.collisionObstaclesCollector.reattachCompound(
                self.compoundModel)
        if self.tessellationCollisionSensor is not None and self.tessellationCollisionSensor.activePostmortem:
            self.tessellationCollisionSensor.reattachCompound(
                self.compoundModel)
        return

    def __prepareSystemsForDamagedVehicle(self, vehicle, isTurretDetached):
        if self.flyingInfoProvider is not None:
            self.flyingInfoProvider.setData(vehicle.filter, None)
        if self.vehicleTraces is not None and not self.vehicleTraces.activePostmortem:
            self.vehicleTraces = None
        self.suspensionSound = None
        self.swingingAnimator = None
        self.burnoutProcessor = None
        self.gunRecoil = None
        self.gunAnimators = []
        self.gunLinkedNodesAnimator = None
        if self.suspension is not None and not self.suspension.activePostmortem:
            self.suspension = None
        if self.leveredSuspension is not None and not self.leveredSuspension.activePostmortem:
            self.leveredSuspension = None
        self.trackNodesAnimator = None
        if self.wheelsAnimator is not None and not self.wheelsAnimator.activePostmortem:
            self.wheelsAnimator = None
        self.gearbox = None
        self.gunRotatorAudition = None
        while self.__tmpGameObjectNames:
            tmpName = self.__tmpGameObjectNames.pop()
            tmpCmp = self.findComponent(tmpName)
            if tmpCmp:
                self.removeComponent(tmpCmp)
            _logger.warning('Component "%s" has not been found', tmpName)

        fashions = VehiclePartsTuple(BigWorld.WGVehicleFashion(), None, None,
                                     None)
        self._setFashions(fashions, isTurretDetached)
        model_assembler.setupTracksFashion(self.typeDescriptor, self.fashion)
        self.showStickers(False)
        self.customEffectManager = None
        self.__destroyEngineAudition()
        self.detailedEngineState = None
        self.frictionAudition = None
        self.terrainMatKindSensor = None
        self._splineTracks = None
        model = self.compoundModel
        self.waterSensor.sensorPlaneLink = model.root
        self.peripheralsController = None
        self.dirtComponent = None
        self.tracks = None
        if self.collisionObstaclesCollector is not None and not self.collisionObstaclesCollector.activePostmortem:
            self.collisionObstaclesCollector = None
        if self.tessellationCollisionSensor is not None and not self.tessellationCollisionSensor.activePostmortem:
            self.tessellationCollisionSensor = None
        self.siegeEffects = None
        self._destroySystems()
        return

    def destroy(self):
        if self._vehicle is not None:
            self.deactivate()
        super(CompoundAppearance, self).destroy()
        if self.fashion is not None:
            self.fashion.removePhysicalTracks()
        if self.__terrainCircle is not None:
            self.__terrainCircle.destroy()
            self.__terrainCircle = None
        self.onModelChanged.clear()
        self.onModelChanged = None
        CallbackDelayer.destroy(self)
        return

    def construct(self, isPlayer, resourceRefs):
        super(CompoundAppearance, self).construct(isPlayer, resourceRefs)
        if self.damageState.effect is not None:
            self.playEffect(self.damageState.effect,
                            SpecialKeyPointNames.STATIC)
        if self.isAlive and isPlayer:
            self.peripheralsController = PeripheralsController()
        self.highlighter = Highlighter(self.isAlive)
        if isPlayer and BigWorld.player().isInTutorial:
            self.tutorialMatKindsController = TutorialMatKindsController()
            self.tutorialMatKindsController.terrainGroundTypesLink = lambda: self.terrainGroundType
        self.__isConstructed = True
        return

    def addTempGameObject(self, component, name):
        if name in self.__tmpGameObjectNames:
            _logger.warning('Attempt to add existed Game Object %s', name)
        else:
            self.__tmpGameObjectNames.append(name)
            self.addComponent(component, name)

    def removeTempGameObject(self, name):
        if name in self.__tmpGameObjectNames:
            self.__tmpGameObjectNames.remove(name)
            tmpCmp = self.findComponent(name)
            if tmpCmp:
                self.removeComponent(name)
                return
        _logger.warning('Component "%s" has not been found', name)

    def showStickers(self, show):
        self.vehicleStickers.show = show

    def showTerrainCircle(self, radius=None, terrainCircleSettings=None):
        if (radius is None) != (terrainCircleSettings is None):
            LOG_ERROR(
                'showTerrainCircle: radius or terrainCircleSetting is not set. You need to set both or none of them.'
            )
            return
        else:
            if radius is not None:
                self.__terrainCircle.configure(radius, terrainCircleSettings)
            if not self.__terrainCircle.isAttached():
                self.__attachTerrainCircle()
            self.__terrainCircle.setVisible()
            return

    def hideTerrainCircle(self):
        self.__terrainCircle.setVisible(False)

    def updateTurretVisibility(self):
        self.__requestModelsRefresh()

    def changeVisibility(self, modelVisible):
        self.compoundModel.visible = modelVisible
        self.showStickers(modelVisible)
        if self.crashedTracksController is not None:
            self.crashedTracksController.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.crashedTracksController is not None:
            self.crashedTracksController.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.damageState
        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.__requestModelsRefresh()
            elif not vehicle.isCrewActive:
                self.__onCrewKilled()
        return

    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 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, componentIdx, stickerID, segStart,
                         segEnd):
        self.vehicleStickers.addDamageSticker(code, componentIdx, stickerID,
                                              segStart, segEnd,
                                              self.collisions)

    def receiveShotImpulse(self, direction, impulse):
        if BattleReplay.isPlaying(
        ) and BattleReplay.g_replayCtrl.isTimeWarpInProgress:
            return
        else:
            if not VehicleDamageState.isDamagedModel(
                    self.damageState.modelState):
                self.swingingAnimator.receiveShotImpulse(direction, impulse)
                if self.crashedTracksController is not None:
                    self.crashedTracksController.receiveShotImpulse(
                        direction, impulse)
            return

    def recoil(self):
        self.__initiateRecoil(TankNodeNames.GUN_INCLINATION, 'HP_gunFire',
                              self.gunRecoil)

    def multiGunRecoil(self, indexes):
        if self.gunAnimators is None:
            return
        else:
            for index in indexes:
                typeDescr = self.typeDescriptor
                gunNodeName = typeDescr.turret.multiGun[index].node
                gunFireNodeName = typeDescr.turret.multiGun[index].gunFire
                gunAnimator = self.gunAnimators[index]
                self.__initiateRecoil(gunNodeName, gunFireNodeName,
                                      gunAnimator)

            return

    def addCrashedTrack(self, isLeft):
        if not self._vehicle.isAlive():
            return
        else:
            if self.crashedTracksController is not None:
                self.crashedTracksController.addTrack(
                    isLeft, self.isLeftSideFlying
                    if isLeft else self.isRightSideFlying)
            self.onChassisDestroySound(isLeft, True)
            return

    def delCrashedTrack(self, isLeft):
        if self.crashedTracksController is not None:
            self.crashedTracksController.delTrack(isLeft)
        self.onChassisDestroySound(isLeft, False)
        return

    def onChassisDestroySound(self, isLeft, destroy, wheelsIdx=-1):
        if not self._vehicle.isEnteringWorld and self.engineAudition:
            if wheelsIdx == -1:
                if isLeft:
                    position = Math.Matrix(
                        self.compoundModel.node(
                            TankNodeNames.TRACK_LEFT_MID)).translation
                else:
                    position = Math.Matrix(
                        self.compoundModel.node(
                            TankNodeNames.TRACK_RIGHT_MID)).translation
                materialType = 0
            else:
                position = self.wheelsAnimator.getWheelWorldTransform(
                    wheelsIdx).translation
                materialType = 0 if self.wheelsAnimator.isWheelDeflatable(
                    wheelsIdx) else 1
            vehicle = self.getVehicle()
            if not destroy and vehicle.isPlayerVehicle and any(
                (device.groupName == 'extraHealthReserve'
                 for device in vehicle.getOptionalDevices()
                 if device is not None)):
                SoundGroups.g_instance.playSound2D('cons_springs')
            self.engineAudition.onChassisDestroy(position, destroy,
                                                 materialType)

    def turretDamaged(self):
        player = BigWorld.player()
        if player is None or self._vehicle is None or not self._vehicle.isPlayerVehicle:
            return 0
        else:
            deviceStates = getattr(player, 'deviceStates', None)
            if deviceStates is not None:
                if deviceStates.get('turretRotator', None) is None:
                    return 0
                return 1
            return 0

    def maxTurretRotationSpeed(self):
        player = BigWorld.player()
        if player is None or self._vehicle is None or not self._vehicle.isPlayerVehicle:
            return 0
        else:
            gunRotator = getattr(player, 'gunRotator', None)
            return gunRotator.maxturretRotationSpeed if gunRotator is not None else 0

    def _destroySystems(self):
        super(CompoundAppearance, self)._destroySystems()
        self.highlighter.destroy()

    def _prepareOutfit(self, outfitCD):
        outfit = camouflages.prepareBattleOutfit(outfitCD, self.typeDescriptor,
                                                 self.id)
        return outfit

    def __initiateRecoil(self, gunNodeName, gunFireNodeName, gunAnimator):
        gunNode = self.compoundModel.node(gunNodeName)
        impulseDir = Math.Matrix(gunNode).applyVector(Math.Vector3(0, 0, -1))
        impulseValue = self.typeDescriptor.gun.impulse
        self.receiveShotImpulse(impulseDir, impulseValue)
        gunAnimator.recoil()
        node = self.compoundModel.node(gunFireNodeName)
        gunPos = Math.Matrix(node).translation
        BigWorld.player().inputHandler.onVehicleShaken(
            self._vehicle, gunPos, impulseDir,
            self.typeDescriptor.shot.shell.caliber,
            ShakeReason.OWN_SHOT_DELAYED)

    def __applyVehicleOutfit(self):
        camouflages.updateFashions(self)

    def getBounds(self, partIdx):
        return self.collisions.getBoundingBox(
            DamageFromShotDecoder.convertComponentIndex(partIdx)
        ) if self.collisions is not None else (Math.Vector3(0.0, 0.0, 0.0),
                                               Math.Vector3(0.0, 0.0, 0.0), 0)

    def __requestModelsRefresh(self):
        self._onRequestModelsRefresh()
        modelsSetParams = self.modelsSetParams
        assembler = model_assembler.prepareCompoundAssembler(
            self.typeDescriptor, modelsSetParams, self._vehicle.spaceID,
            self._vehicle.isTurretDetached)
        BigWorld.loadResourceListBG((assembler, ),
                                    makeCallbackWeak(self.__onModelsRefresh,
                                                     modelsSetParams.state),
                                    loadingPriority(self._vehicle.id))

    def __onModelsRefresh(self, modelState, resourceList):
        if BattleReplay.isFinished():
            return
        elif self._vehicle is None:
            return
        else:
            prevTurretYaw = Math.Matrix(self.turretMatrix).yaw
            prevGunPitch = Math.Matrix(self.gunMatrix).pitch
            vehicle = self._vehicle
            newCompoundModel = resourceList[self.typeDescriptor.name]
            isRightSideFlying = self.isRightSideFlying
            isLeftSideFlying = self.isLeftSideFlying
            self.deactivate(False)
            self.shadowManager.reattachCompoundModel(vehicle,
                                                     self.compoundModel,
                                                     newCompoundModel)
            self._compoundModel = newCompoundModel
            self._isTurretDetached = vehicle.isTurretDetached
            self.__prepareSystemsForDamagedVehicle(vehicle,
                                                   self.isTurretDetached)
            self.__processPostmortemComponents()
            if isRightSideFlying:
                self.fashion.changeTrackVisibility(False, False)
            if isLeftSideFlying:
                self.fashion.changeTrackVisibility(True, False)
            self._setupModels()
            self.setVehicle(vehicle)
            self.activate()
            self.__reattachComponents(self.compoundModel)
            self.filter.syncGunAngles(prevTurretYaw, prevGunPitch)
            model_assembler.setupTurretRotations(self)
            return

    def __reattachComponents(self, model):
        self.boundEffects.reattachTo(model)
        if self.engineAudition is not None:
            self.engineAudition.setWeaponEnergy(self._weaponEnergy)
            self.engineAudition.attachToModel(model)
        return

    def __onCrewKilled(self):
        self.__destroyEngineAudition()
        if self.customEffectManager is not None:
            self.customEffectManager = None
            self.siegeEffects = 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.damageState.effect not in (
                'submersionDeath', ):
            self._stopEffects()
        extra = self._vehicle.typeDescriptor.extrasDict['fire']
        if extra.isRunningFor(self._vehicle):
            extra.checkUnderwater(self._vehicle, isUnderWater)

    def updateTracksScroll(self, leftScroll, rightScroll):
        if self.trackScrollController is not None:
            self.trackScrollController.setExternal(leftScroll, rightScroll)
        return

    def __onPeriodicTimerEngine(self):
        return None if self.detailedEngineState is None or self.engineAudition is None else _PERIODIC_TIME_ENGINE

    def _periodicUpdate(self):
        super(CompoundAppearance, self)._periodicUpdate()
        if self._vehicle is None:
            return
        else:
            if self.peripheralsController is not None:
                self.peripheralsController.update(self._vehicle,
                                                  self.crashedTracksController)
            if not self._vehicle.isAlive():
                return
            self.__updateTransmissionScroll()
            return

    def __onPeriodicTimerDirt(self):
        if self.fashion is None:
            return
        else:
            dt = 1.0
            distanceFromPlayer = self.lodCalculator.lodDistance
            if 0.0 <= distanceFromPlayer < _PERIODIC_TIME_DIRT[1][1]:
                time = BigWorld.time()
                simDt = time - self.__dirtUpdateTime
                if simDt > 0.0:
                    if self.dirtComponent:
                        roll = Math.Matrix(self.compoundModel.matrix).roll
                        hasContact = 0
                        waterHeight = self.waterHeight
                        if math.fabs(roll) > math.radians(120.0):
                            hasContact = 2
                            if self.waterSensor.isInWater:
                                waterHeight = 1.0
                        elif self.trackScrollController is not None:
                            hasContact = 0 if self.trackScrollController.hasContact(
                            ) else 1
                        self.dirtComponent.update(
                            self.filter.averageSpeed, waterHeight,
                            self.waterSensor.waterHeightWorld,
                            self.terrainMatKind[2], hasContact, simDt)
                    self.__dirtUpdateTime = time
                if distanceFromPlayer <= _PERIODIC_TIME_DIRT[1][
                        0] or self._vehicle.isPlayerVehicle:
                    dt = _PERIODIC_TIME_DIRT[0][0]
                else:
                    dt = _PERIODIC_TIME_DIRT[0][
                        0] + _DIRT_ALPHA * distanceFromPlayer
            return dt

    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):
        insigniaRank = self._vehicle.publicInfo['marksOnGun']
        vehicleStickers = VehicleStickers(self.typeDescriptor, insigniaRank,
                                          self.outfit)
        clanID = BigWorld.player().arena.vehicles[self._vehicle.id]['clanDBID']
        vehicleStickers.setClanID(clanID)
        return vehicleStickers

    def __createTerrainCircle(self):
        if self.__terrainCircle is not None:
            return
        else:
            self.__terrainCircle = TerrainCircleComponent()
            return

    def __attachTerrainCircle(self):
        self.__terrainCircle.attach(self._vehicle.id)

    def computeFullVehicleLength(self):
        vehicleLength = 0.0
        if self.compoundModel is not None:
            hullBB = Math.Matrix(
                self.compoundModel.getBoundsForPart(TankPartIndexes.HULL))
            vehicleLength = hullBB.applyVector(Math.Vector3(0.0, 0.0,
                                                            1.0)).length
        return vehicleLength

    def setupGunMatrixTargets(self, target):
        self.turretMatrix.target = target.turretMatrix
        self.gunMatrix.target = target.gunMatrix

    def onFriction(self, otherID, frictionPoint, state):
        if self.frictionAudition is not None:
            self.frictionAudition.processFriction(otherID, frictionPoint,
                                                  state)
        return

    def onSiegeStateChanged(self, newState, timeToNextMode):
        if self.engineAudition is not None:
            self.engineAudition.onSiegeStateChanged(newState)
        if self.hullAimingController is not None:
            self.hullAimingController.onSiegeStateChanged(newState)
        if self.suspensionSound is not None:
            self.suspensionSound.vehicleState = newState
        if self.siegeEffects is not None:
            self.siegeEffects.onSiegeStateChanged(newState, timeToNextMode)
        enabled = newState == VEHICLE_SIEGE_STATE.ENABLED or newState == VEHICLE_SIEGE_STATE.SWITCHING_ON
        if self.suspension is not None:
            self.suspension.setLiftMode(enabled)
        if self.leveredSuspension is not None:
            self.leveredSuspension.setLiftMode(enabled)
        if self.vehicleTraces is not None:
            self.vehicleTraces.setLiftMode(enabled)
        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)
        if self.tracks is not None:
            if cameraName == 'sniper':
                self.tracks.sniperMode(True)
            else:
                self.tracks.sniperMode(False)
        return

    def __onEngineStateGearUp(self):
        if self.customEffectManager is not None:
            self.customEffectManager.onGearUp()
        if self.engineAudition is not None:
            self.engineAudition.onEngineGearUp()
        return

    def __updateTransmissionScroll(self):
        self._commonSlip = 0.0
        self._commonScroll = 0.0
        worldMatrix = Math.Matrix(self.compoundModel.matrix)
        zAxis = worldMatrix.applyToAxis(2)
        vehicleSpeed = zAxis.dot(self.filter.velocity)
        if self.wheelsScroll is not None:
            wheelsSpeed = self.wheelsAnimator.getWheelsSpeed()
            wheelCount = len(wheelsSpeed)
            skippedWheelsCount = 0
            for wheelIndex in xrange(0, wheelCount):
                flying = self.wheelsAnimator.wheelIsFlying(wheelIndex)
                if not flying:
                    self._commonScroll += wheelsSpeed[wheelIndex]
                    self._commonSlip += wheelsSpeed[wheelIndex] - vehicleSpeed
                skippedWheelsCount += 1

            activeWheelCount = max(wheelCount - skippedWheelsCount, 1)
            self._commonSlip /= activeWheelCount
            self._commonScroll /= activeWheelCount
        elif self.trackScrollController is not None:
            self._commonScroll = max(self.trackScrollController.leftScroll(),
                                     self.trackScrollController.rightScroll())
            self._commonSlip = max(self.trackScrollController.leftSlip(),
                                   self.trackScrollController.rightSlip())
        return

    def addCameraCollider(self):
        collider = self.collisions
        if collider is not None:
            colliderData = (collider.getColliderID(),
                            (TankPartNames.getIdx(TankPartNames.HULL),
                             TankPartNames.getIdx(TankPartNames.TURRET),
                             TankPartNames.getIdx(TankPartNames.GUN)))
            BigWorld.appendCameraCollider(colliderData)
        return

    def removeCameraCollider(self):
        collider = self.collisions
        if collider is not None:
            BigWorld.removeCameraCollider(collider.getColliderID())
        return

    def onEngineDamageRisk(self, risk):
        if self.engineAudition is not None:
            self.engineAudition.onEngineDamageRisk(risk)
        return

    def getWheelsSteeringMax(self):
        if self.wheelsSteering is not None and len(self.wheelsSteering) >= 2:
            wheelSteeringMax = self.wheelsSteering[0]
            if math.fabs(self.wheelsSteering[1]) > math.fabs(wheelSteeringMax):
                wheelSteeringMax = self.wheelsSteering[1]
            return -wheelSteeringMax
        else:
            return 0