Exemple #1
0
    def update(self):
        global printedVehicle
        self.vehicle = BigWorld.entity(self.vehicleID)
        if self.vehicle is not None:
            if self.vehicle.health > 0 and self.vehicle.isAlive():
                self.isAlive = True
        if self.isAlive is False or self.vehicle is None or (self.vehicle is not None and self.vehicle.health <= 0):
            print('[predictAim] enemy died or does not exists')
            self.hideVisible()
            return
        if not hasattr(BigWorld.player(), 'vehicleTypeDescriptor') or not hasattr(BigWorld.player(), 'gunRotator') or (hasattr(self.vehicle,"health") and self.vehicle.health <= 0):
            print('[predictAim] player has no vehicleTypeDescriptor or gunRotator OR enemy is has no health or health is lower/same as zero')
            self.hideVisible()
            return
        if self.modelDot is not None and self.modelDot._StaticObjectMarker3D__model:
            playerVehicleID = BigWorld.player().playerVehicleID
            if playerVehicleID:
                playerVehicle = BigWorld.entity(playerVehicleID)
                playerPosition = playerVehicle.model.node("hull").position
                self.vehicle = BigWorld.entity(self.vehicleID)
                shotSpeed = BigWorld.player().vehicleTypeDescriptor.shot.speed
                distance = playerPosition.flatDistTo(self.vehicle.model.node("hull").position)
                traveltime = distance / shotSpeed
                enemyCurrentSpeed = self.vehicle.speedInfo.value
                if self.lastSpeedValue is None or self.lastSpeedValue is enemyCurrentSpeed:
                    self.lastSpeedValue = enemyCurrentSpeed
                enemyCurrentSpeed = (enemyCurrentSpeed + self.lastSpeedValue) / 2
                self.lastSpeedValue = enemyCurrentSpeed
                centerFront = self.vehicle.model.node("hull").position

                cMin , cMax , _ = self.vehicle.getBounds(TankPartIndexes.CHASSIS)
                _ , hMax , _ = self.vehicle.getBounds(TankPartIndexes.HULL)
                hMax.y += cMax.y
                _ , tMax , _ =self.vehicle.getBounds(TankPartIndexes.TURRET)
                tMax.y += hMax.y
                cMax.y = tMax.y
                matrix = Matrix(self.vehicle.matrix)

                FRONT_RIGTH_BOTTOM = matrix.applyVector(Vector3(cMax.x , cMin.y , cMax.z )) + self.vehicle.position
                FRONT_LEFT_BOTTOM = matrix.applyVector(Vector3(cMin.x , cMin.y , cMax.z )) + self.vehicle.position
                centerFront = (FRONT_RIGTH_BOTTOM + FRONT_LEFT_BOTTOM)/2
                #print("[predictAim]: center Front pos: %s" % centerFront)
                #print("[predictAim]: hull: %s" % self.vehicle.model.node("hull").position)
                #print("[predictAim]: center Back pos: %s" % centerBack)

                travel_distance_0 = enemyCurrentSpeed[0] * traveltime
                #travel_distance_2 = enemyCurrentSpeed[2] * traveltime

                v = centerFront - self.vehicle.model.node("hull").position
                v3 = Vector3(v)
                #v3.normalise()
                predPos_test = self.vehicle.model.node("hull").position + (v3*travel_distance_0)
                tmp_veh = BigWorld.entity(self.vehicleID)
                predPos_test[1] = tmp_veh.model.node("hull").position[1]

                self.modelDot._StaticObjectMarker3D__model.position = predPos_test
                self.modelDot._StaticObjectMarker3D__model.visible = True
 def __update(self, dx, dy, dz, rotateMode = True, zoomMode = True, isCallback = False):
     prevPos = self.__inputInertia.calcWorldPos(self.__aimingSystem.matrix)
     distChanged = False
     if zoomMode and dz != 0:
         prevDist = self.__aimingSystem.distanceFromFocus
         distDelta = dz * float(self.__curScrollSense)
         distMinMax = self.__cfg['distRange']
         newDist = mathUtils.clamp(distMinMax.min, distMinMax.max, prevDist - distDelta)
         if abs(newDist - prevDist) > 0.001:
             self.__aimingSystem.distanceFromFocus = newDist
             self.__userCfg['startDist'] = newDist
             self.__inputInertia.glideFov(self.__calcRelativeDist())
             self.__aimingSystem.aimMatrix = self.__calcAimMatrix()
             distChanged = True
         changeControlMode = prevDist == newDist and mathUtils.almostZero(newDist - distMinMax.min)
         if changeControlMode and self.__onChangeControlMode is not None:
             self.__onChangeControlMode()
             return
     if rotateMode:
         self.__updateAngles(dx, dy)
     if ENABLE_INPUT_ROTATION_INERTIA and not distChanged:
         self.__aimingSystem.update(0.0)
     if ENABLE_INPUT_ROTATION_INERTIA or distChanged:
         worldDeltaPos = prevPos - self.__aimingSystem.matrix.translation
         matInv = Matrix(self.__aimingSystem.matrix)
         matInv.invert()
         self.__inputInertia.glide(matInv.applyVector(worldDeltaPos))
     return
Exemple #3
0
 def __update(self, dx, dy, dz, rotateMode = True, zoomMode = True, isCallback = False):
     prevPos = self.__inputInertia.calcWorldPos(self.__aimingSystem.matrix)
     distChanged = False
     if zoomMode and dz != 0:
         prevDist = self.__aimingSystem.distanceFromFocus
         distDelta = dz * float(self.__curScrollSense)
         distMinMax = self.__cfg['distRange']
         newDist = mathUtils.clamp(distMinMax.min, distMinMax.max, prevDist - distDelta)
         if abs(newDist - prevDist) > 0.001:
             self.__aimingSystem.distanceFromFocus = newDist
             self.__userCfg['startDist'] = newDist
             self.__inputInertia.glideFov(self.__calcRelativeDist())
             self.__aimingSystem.aimMatrix = self.__calcAimMatrix()
             distChanged = True
         changeControlMode = prevDist == newDist and mathUtils.almostZero(newDist - distMinMax.min)
         if changeControlMode and self.__onChangeControlMode is not None:
             self.__onChangeControlMode()
             return
     if rotateMode:
         self.__updateAngles(dx, dy)
     if ENABLE_INPUT_ROTATION_INERTIA and not distChanged:
         self.__aimingSystem.update(0.0)
     if ENABLE_INPUT_ROTATION_INERTIA or distChanged:
         worldDeltaPos = prevPos - self.__aimingSystem.matrix.translation
         matInv = Matrix(self.__aimingSystem.matrix)
         matInv.invert()
         self.__inputInertia.glide(matInv.applyVector(worldDeltaPos))
 def __calcCurOscillatorAcceleration(self, deltaTime):
     vehicle = BigWorld.player().vehicle
     if vehicle is None or not vehicle.isAlive():
         return Vector3(0, 0, 0)
     else:
         curVelocity = vehicle.filter.velocity
         relativeSpeed = curVelocity.length / vehicle.typeDescriptor.physics[
             'speedLimits'][0]
         if relativeSpeed >= SniperCamera._MIN_REL_SPEED_ACC_SMOOTHING:
             self.__accelerationSmoother.maxAllowedAcceleration = self.__dynamicCfg[
                 'accelerationThreshold']
         else:
             self.__accelerationSmoother.maxAllowedAcceleration = self.__dynamicCfg[
                 'accelerationMax']
         acceleration = self.__accelerationSmoother.update(
             vehicle, deltaTime)
         camMat = Matrix(self.__cam.matrix)
         acceleration = camMat.applyVector(-acceleration)
         accelSensitivity = self.__dynamicCfg['accelerationSensitivity']
         acceleration.x *= accelSensitivity.x
         acceleration.y *= accelSensitivity.y
         acceleration.z *= accelSensitivity.z
         oscillatorAcceleration = Vector3(0,
                                          -acceleration.y + acceleration.z,
                                          -acceleration.x)
         return oscillatorAcceleration
 def update(self, vehicle, deltaTime):
     try:
         curVelocity = vehicle.filter.velocity
         acceleration = vehicle.filter.acceleration
         acceleration = self.__accelerationFilter.add(acceleration)
         movementFlags = vehicle.engineMode[1]
         moveMask = 3
         self.__hasChangedDirection = movementFlags & moveMask ^ self.__prevMovementFlags & moveMask or curVelocity.dot(
             self.__prevVelocity) <= 0.01
         self.__prevMovementFlags = movementFlags
         self.__prevVelocity = curVelocity
         self.__timeLapsedSinceDirChange += deltaTime
         if self.__hasChangedDirection:
             self.__timeLapsedSinceDirChange = 0.0
         elif self.__timeLapsedSinceDirChange > self.__maxAccelerationDuration:
             invVehMat = Matrix(vehicle.matrix)
             invVehMat.invert()
             accelerationRelativeToVehicle = invVehMat.applyVector(
                 acceleration)
             accelerationRelativeToVehicle.x = 0.0
             accelerationRelativeToVehicle.z = 0.0
             acceleration = Matrix(
                 vehicle.matrix).applyVector(accelerationRelativeToVehicle)
         self.__acceleration = acceleration
         return acceleration
     except:
         return Math.Vector3(0.0, 0.0, 0.0)
Exemple #6
0
 def applyImpulse(self, position, impulse, reason = ImpulseReason.ME_HIT):
     adjustedImpulse, noiseMagnitude = self.__dynamicCfg.adjustImpulse(impulse, reason)
     camMatrix = Matrix(self.__cam.matrix)
     impulseLocal = camMatrix.applyVector(adjustedImpulse)
     impulseAsYPR = Vector3(impulseLocal.x, -impulseLocal.y + impulseLocal.z, 0)
     rollPart = self.__dynamicCfg['impulsePartToRoll']
     impulseAsYPR.z = -rollPart * impulseAsYPR.x
     impulseAsYPR.x *= 1 - rollPart
     self.__impulseOscillator.applyImpulse(impulseAsYPR)
     self.__applyNoiseImpulse(noiseMagnitude)
 def applyImpulse(self, position, impulse, reason=ImpulseReason.ME_HIT):
     adjustedImpulse, noiseMagnitude = self.__dynamicCfg.adjustImpulse(impulse, reason)
     camMatrix = Matrix(self.__cam.matrix)
     impulseLocal = camMatrix.applyVector(adjustedImpulse)
     impulseAsYPR = Vector3(impulseLocal.x, -impulseLocal.y + impulseLocal.z, 0)
     rollPart = self.__dynamicCfg['impulsePartToRoll']
     impulseAsYPR.z = -rollPart * impulseAsYPR.x
     impulseAsYPR.x *= 1 - rollPart
     self.__impulseOscillator.applyImpulse(impulseAsYPR)
     self.__applyNoiseImpulse(noiseMagnitude)
Exemple #8
0
 def __calcCurOscillatorAcceleration(self, deltaTime):
     vehicle = BigWorld.player().vehicle
     if vehicle is None:
         return Vector3(0, 0, 0)
     curVelocity = vehicle.filter.velocity
     relativeSpeed = curVelocity.length / vehicle.typeDescriptor.physics['speedLimits'][0]
     if relativeSpeed >= SniperCamera._MIN_REL_SPEED_ACC_SMOOTHING:
         self.__accelerationSmoother.maxAllowedAcceleration = self.__dynamicCfg['accelerationThreshold']
     else:
         self.__accelerationSmoother.maxAllowedAcceleration = self.__dynamicCfg['accelerationMax']
     acceleration = self.__accelerationSmoother.update(vehicle, deltaTime)
     camMat = Matrix(self.__cam.matrix)
     acceleration = camMat.applyVector(-acceleration)
     accelSensitivity = self.__dynamicCfg['accelerationSensitivity']
     acceleration.x *= accelSensitivity.x
     acceleration.y *= accelSensitivity.y
     acceleration.z *= accelSensitivity.z
     oscillatorAcceleration = Vector3(0, -acceleration.y + acceleration.z, -acceleration.x)
     return oscillatorAcceleration
Exemple #9
0
    def checkTurretDetachment(self, worldPos):
        if self.__vehicle is None:
            return
        if self.__vehicle.isTurretDetached and not self.__placement == _VehicleBounder.SELECT_DETACHED_TURRET:
            turretFound = None
            for turret in DetachedTurret.allTurrets:
                if turret.vehicleID == self.__vehicle.id and turret.model.visible:
                    turretFound = turret
                    break

            if turretFound is None:
                return
            turretToGoalShift = worldPos - turretFound.position
            toTurretMat = Matrix(turretFound.matrix)
            toTurretMat.invert()
            turretToGoalShift = toTurretMat.applyVector(turretToGoalShift)
            self.matrix = turretFound.matrix
            self.__lookAtProvider = None
            self.__placement = _VehicleBounder.SELECT_DETACHED_TURRET
            return turretToGoalShift
Exemple #10
0
 def update(self, vehicle, deltaTime):
     curVelocity = vehicle.filter.velocity
     acceleration = vehicle.filter.acceleration
     acceleration = self.__accelerationFilter.add(acceleration)
     movementFlags = vehicle.engineMode[1]
     moveMask = 3
     self.__hasChangedDirection = movementFlags & moveMask ^ self.__prevMovementFlags & moveMask or curVelocity.dot(self.__prevVelocity) <= 0.01
     self.__prevMovementFlags = movementFlags
     self.__prevVelocity = curVelocity
     self.__timeLapsedSinceDirChange += deltaTime
     if self.__hasChangedDirection:
         self.__timeLapsedSinceDirChange = 0.0
     elif self.__timeLapsedSinceDirChange > self.__maxAccelerationDuration:
         invVehMat = Matrix(vehicle.matrix)
         invVehMat.invert()
         accelerationRelativeToVehicle = invVehMat.applyVector(acceleration)
         accelerationRelativeToVehicle.x = 0.0
         accelerationRelativeToVehicle.z = 0.0
         acceleration = Matrix(vehicle.matrix).applyVector(accelerationRelativeToVehicle)
     self.__acceleration = acceleration
     return acceleration
    def checkTurretDetachment(self, worldPos):
        if self.__vehicle is None:
            return
        elif self.__vehicle.isTurretDetached and not self.__placement == _VehicleBounder.SELECT_DETACHED_TURRET:
            turretFound = None
            for turret in DetachedTurret.allTurrets:
                if turret.vehicleID == self.__vehicle.id and turret.model.visible:
                    turretFound = turret
                    break

            if turretFound is None:
                return
            turretToGoalShift = worldPos - turretFound.position
            toTurretMat = Matrix(turretFound.matrix)
            toTurretMat.invert()
            turretToGoalShift = toTurretMat.applyVector(turretToGoalShift)
            self.matrix = turretFound.matrix
            self.__lookAtProvider = None
            self.__placement = _VehicleBounder.SELECT_DETACHED_TURRET
            return turretToGoalShift
        else:
            return
class ArtyCamera(ICamera, CallbackDelayer):
    _DYNAMIC_ENABLED = True

    @staticmethod
    def enableDynamicCamera(enable):
        ArtyCamera._DYNAMIC_ENABLED = enable

    @staticmethod
    def isCameraDynamic():
        return ArtyCamera._DYNAMIC_ENABLED

    camera = property(lambda self: self.__cam)
    aimingSystem = property(lambda self: self.__aimingSystem)
    settingsCore = dependency.descriptor(ISettingsCore)
    __aimOffset = aih_global_binding.bindRW(
        aih_global_binding.BINDING_ID.AIM_OFFSET)

    def __init__(self, dataSec):
        CallbackDelayer.__init__(self)
        self.__positionOscillator = None
        self.__positionNoiseOscillator = None
        self.__dynamicCfg = CameraDynamicConfig()
        self.__readCfg(dataSec)
        self.__cam = BigWorld.CursorCamera()
        self.__curSense = self.__cfg['sensitivity']
        self.__onChangeControlMode = None
        self.__camDist = 0.0
        self.__desiredCamDist = 0.0
        self.__aimingSystem = None
        self.__prevTime = 0.0
        self.__dxdydz = Vector3(0.0, 0.0, 0.0)
        self.__autoUpdatePosition = False
        self.__needReset = 0
        self.__sourceMatrix = None
        self.__targetMatrix = None
        self.__rotation = 0.0
        self.__positionHysteresis = None
        self.__timeHysteresis = None
        return

    def create(self, onChangeControlMode=None):
        self.__onChangeControlMode = onChangeControlMode
        aimingSystemClass = ArtyAimingSystemRemote if BigWorld.player(
        ).isObserver() else ArtyAimingSystem
        self.__aimingSystem = aimingSystemClass()
        self.__camDist = self.__cfg['camDist']
        self.__desiredCamDist = self.__camDist
        self.__positionHysteresis = PositionHysteresis(
            self.__cfg['hPositionThresholdSq'])
        self.__timeHysteresis = TimeHysteresis(self.__cfg['hTimeThreshold'])
        self.__cam.pivotMaxDist = 0.0
        self.__cam.maxDistHalfLife = 0.01
        self.__cam.movementHalfLife = 0.0
        self.__cam.turningHalfLife = -1
        self.__cam.pivotPosition = Vector3(0.0, 0.0, 0.0)
        self.__sourceMatrix = Matrix()
        self.__targetMatrix = Matrix()
        self.__rotation = 0.0

    def destroy(self):
        CallbackDelayer.destroy(self)
        self.disable()
        self.__onChangeControlMode = None
        self.__cam = None
        if self.__aimingSystem is not None:
            self.__aimingSystem.destroy()
            self.__aimingSystem = None
        return

    def enable(self, targetPos, saveDist):
        self.__prevTime = 0.0
        self.__aimingSystem.enable(targetPos)
        self.__positionHysteresis.update(Vector3(0.0, 0.0, 0.0))
        self.__timeHysteresis.update(BigWorld.timeExact())
        camTarget = MatrixProduct()
        self.__cam.target = camTarget
        self.__cam.source = self.__sourceMatrix
        self.__cam.wg_applyParams()
        BigWorld.camera(self.__cam)
        BigWorld.player().positionControl.moveTo(self.__aimingSystem.hitPoint)
        BigWorld.player().positionControl.followCamera(False)
        self.__rotation = 0.0
        self.__cameraUpdate()
        self.delayCallback(0.0, self.__cameraUpdate)
        self.__needReset = 1

    def disable(self):
        if self.__aimingSystem is not None:
            self.__aimingSystem.disable()
        self.stopCallback(self.__cameraUpdate)
        BigWorld.camera(None)
        self.__positionOscillator.reset()
        return

    def teleport(self, pos):
        self.__aimingSystem.updateTargetPos(pos)
        self.update(0.0, 0.0, 0.0)

    def getConfigValue(self, name):
        return self.__cfg.get(name)

    def getUserConfigValue(self, name):
        return self.__userCfg.get(name)

    def setUserConfigValue(self, name, value):
        if name not in self.__userCfg:
            return
        self.__userCfg[name] = value
        if name not in ('keySensitivity', 'sensitivity', 'scrollSensitivity'):
            self.__cfg[name] = self.__userCfg[name]
        else:
            self.__cfg[name] = self.__baseCfg[name] * self.__userCfg[name]

    def update(self, dx, dy, dz, updateByKeyboard=False):
        self.__curSense = self.__cfg[
            'keySensitivity'] if updateByKeyboard else self.__cfg['sensitivity']
        self.__autoUpdatePosition = updateByKeyboard
        self.__dxdydz = Vector3(dx if not self.__cfg['horzInvert'] else -dx,
                                dy if not self.__cfg['vertInvert'] else -dy,
                                dz)

    def applyImpulse(self, position, impulse, reason=ImpulseReason.ME_HIT):
        adjustedImpulse, noiseMagnitude = self.__dynamicCfg.adjustImpulse(
            impulse, reason)
        impulseFlatDir = Vector3(adjustedImpulse.x, 0, adjustedImpulse.z)
        impulseFlatDir.normalise()
        impulseLocal = self.__sourceMatrix.applyVector(
            impulseFlatDir * (-1 * adjustedImpulse.length))
        self.__positionOscillator.applyImpulse(impulseLocal)
        self.__applyNoiseImpulse(noiseMagnitude)

    def applyDistantImpulse(self,
                            position,
                            impulseValue,
                            reason=ImpulseReason.ME_HIT):
        if reason != ImpulseReason.SPLASH and reason != ImpulseReason.PROJECTILE_HIT:
            return
        impulse = BigWorld.player().getOwnVehiclePosition() - position
        distance = impulse.length
        if distance <= 1.0:
            distance = 1.0
        impulse.normalise()
        if reason == ImpulseReason.PROJECTILE_HIT:
            if not cameras.isPointOnScreen(position):
                return
            distance = 1.0
        impulse *= impulseValue / distance
        self.applyImpulse(position, impulse, reason)

    def writeUserPreferences(self):
        ds = Settings.g_instance.userPrefs
        if not ds.has_key(Settings.KEY_CONTROL_MODE):
            ds.write(Settings.KEY_CONTROL_MODE, '')
        ucfg = self.__userCfg
        ds = ds[Settings.KEY_CONTROL_MODE]
        ds.writeBool('artyMode/camera/horzInvert', ucfg['horzInvert'])
        ds.writeBool('artyMode/camera/vertInvert', ucfg['vertInvert'])
        ds.writeFloat('artyMode/camera/keySensitivity', ucfg['keySensitivity'])
        ds.writeFloat('artyMode/camera/sensitivity', ucfg['sensitivity'])
        ds.writeFloat('artyMode/camera/scrollSensitivity',
                      ucfg['scrollSensitivity'])
        ds.writeFloat('artyMode/camera/camDist', self.__cfg['camDist'])

    def __applyNoiseImpulse(self, noiseMagnitude):
        noiseImpulse = mathUtils.RandomVectors.random3Flat(noiseMagnitude)
        self.__positionNoiseOscillator.applyImpulse(noiseImpulse)

    def __calculateAimOffset(self, aimWorldPos):
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying and replayCtrl.isControllingCamera:
            aimOffset = replayCtrl.getAimClipPosition()
        else:
            aimOffset = cameras.projectPoint(aimWorldPos)
            aimOffset = Vector2(mathUtils.clamp(-0.95, 0.95, aimOffset.x),
                                mathUtils.clamp(-0.95, 0.95, aimOffset.y))
            if replayCtrl.isRecording:
                replayCtrl.setAimClipPosition(aimOffset)
        return aimOffset

    def __handleMovement(self):
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying:
            if self.__needReset != 0:
                if self.__needReset > 1:
                    from helpers import isPlayerAvatar
                    player = BigWorld.player()
                    if isPlayerAvatar():
                        if player.inputHandler.ctrl is not None:
                            player.inputHandler.ctrl.resetGunMarkers()
                    self.__needReset = 0
                else:
                    self.__needReset += 1
            if replayCtrl.isControllingCamera:
                self.__aimingSystem.updateTargetPos(
                    replayCtrl.getGunRotatorTargetPoint())
            else:
                self.__aimingSystem.handleMovement(
                    self.__dxdydz.x * self.__curSense,
                    -self.__dxdydz.y * self.__curSense)
                if self.__dxdydz.x != 0 or self.__dxdydz.y != 0 or self.__dxdydz.z != 0:
                    self.__needReset = 2
        else:
            self.__aimingSystem.handleMovement(
                self.__dxdydz.x * self.__curSense,
                -self.__dxdydz.y * self.__curSense)
        return

    def __getCameraDirection(self):
        direction = Vector3()
        direction.setPitchYaw(self.__rotation,
                              self.__aimingSystem.direction.yaw)
        direction.normalise()
        return direction

    def __getDesiredCameraDistance(self):
        distRange = self.__cfg['distRange']
        self.__desiredCamDist -= self.__dxdydz.z * self.__curSense
        self.__desiredCamDist = mathUtils.clamp(distRange[0], distRange[1],
                                                self.__desiredCamDist)
        self.__desiredCamDist = self.__aimingSystem.overrideCamDist(
            self.__desiredCamDist)
        self.__cfg['camDist'] = self.__camDist
        return self.__desiredCamDist

    def __updateTrajectoryDrawer(self):
        shotDescr = BigWorld.player().getVehicleDescriptor().shot
        BigWorld.wg_trajectory_drawer().setParams(
            shotDescr.maxDistance, Vector3(0, -shotDescr.gravity, 0),
            self.__aimOffset)

    def __updateTime(self):
        curTime = BigWorld.timeExact()
        deltaTime = curTime - self.__prevTime
        self.__prevTime = curTime
        return deltaTime

    def __choosePitchLevel(self, aimPoint):
        useHighPitch = (aimPoint - self.__aimingSystem.hitPoint
                        ).lengthSquared > self.__cfg['highPitchThresholdSq']
        if useHighPitch:
            useHighPitch = self.__positionHysteresis.check(
                aimPoint) or self.__timeHysteresis.check(self.__prevTime)
        else:
            self.__positionHysteresis.update(aimPoint)
            self.__timeHysteresis.update(self.__prevTime)
        return useHighPitch

    def __getCollisionTestOrigin(self, aimPoint, direction):
        distRange = self.__cfg['distRange']
        vehiclePosition = BigWorld.player().getVehicleAttached().position
        collisionTestOrigin = Vector3(vehiclePosition)
        if direction.x * direction.x > direction.z * direction.z and not mathUtils.almostZero(
                direction.x):
            collisionTestOrigin.y = direction.y / direction.x * (
                vehiclePosition.x - aimPoint.x) + aimPoint.y
        elif not mathUtils.almostZero(direction.z):
            collisionTestOrigin.y = direction.y / direction.z * (
                vehiclePosition.z - aimPoint.z) + aimPoint.y
        else:
            collisionTestOrigin = aimPoint - direction.scale(
                (distRange[1] - distRange[0]) / 2.0)
            LOG_WARNING(
                "Can't find point on direction ray. Using half point as collision test origin"
            )
        return collisionTestOrigin

    def __resolveCollisions(self, aimPoint, distance, direction):
        distRange = self.__cfg['distRange']
        collisionTestOrigin = self.__getCollisionTestOrigin(
            aimPoint, direction)
        sign = copysign(
            1.0, distance * distance -
            (aimPoint - collisionTestOrigin).lengthSquared)
        srcPoint = collisionTestOrigin
        endPoint = aimPoint - direction.scale(distance + sign * distRange[0])
        collision = collideDynamicAndStatic(
            srcPoint, endPoint, (BigWorld.player().playerVehicleID, ))
        if collision:
            collisionDistance = (aimPoint - collision[0]).length
            if sign * (collisionDistance - distance) < distRange[0]:
                distance = collisionDistance - sign * distRange[0]
        if mathUtils.almostZero(self.__rotation):
            srcPoint = aimPoint - direction.scale(distance)
            endPoint = aimPoint
            collision = collideDynamicAndStatic(
                srcPoint, endPoint, (BigWorld.player().playerVehicleID, ))
            if collision:
                self.__aimingSystem.aimPoint = collision[0]
                if collision[1]:
                    self.__positionHysteresis.update(aimPoint)
                    self.__timeHysteresis.update(self.__prevTime)
        return distance

    def __calculateIdealState(self, deltaTime):
        aimPoint = self.__aimingSystem.aimPoint
        direction = self.__aimingSystem.direction
        impactPitch = max(direction.pitch, self.__cfg['minimalPitch'])
        self.__rotation = max(self.__rotation, impactPitch)
        distRange = self.__cfg['distRange']
        distanceCurSq = (
            aimPoint -
            BigWorld.player().getVehicleAttached().position).lengthSquared
        distanceMinSq = distRange[0]**2.0
        forcedPitch = impactPitch
        if distanceCurSq < distanceMinSq:
            forcedPitch = atan2(sqrt(distanceMinSq - distanceCurSq),
                                sqrt(distanceCurSq))
        angularShift = self.__cfg['angularSpeed'] * deltaTime
        angularShift = angularShift if self.__choosePitchLevel(
            aimPoint) else -angularShift
        minPitch = max(forcedPitch, impactPitch)
        maxPitch = max(forcedPitch, self.__cfg['maximalPitch'])
        self.__rotation = mathUtils.clamp(minPitch, maxPitch,
                                          self.__rotation + angularShift)
        desiredDistance = self.__getDesiredCameraDistance()
        cameraDirection = self.__getCameraDirection()
        desiredDistance = self.__resolveCollisions(aimPoint, desiredDistance,
                                                   cameraDirection)
        desiredDistance = mathUtils.clamp(distRange[0], distRange[1],
                                          desiredDistance)
        translation = aimPoint - cameraDirection.scale(desiredDistance)
        rotation = Vector3(cameraDirection.yaw, -cameraDirection.pitch, 0.0)
        return (translation, rotation)

    def __interpolateStates(self, deltaTime, translation, rotation):
        lerpParam = mathUtils.clamp(
            0.0, 1.0, deltaTime * self.__cfg['interpolationSpeed'])
        self.__sourceMatrix = slerp(self.__sourceMatrix, rotation, lerpParam)
        self.__targetMatrix.translation = mathUtils.lerp(
            self.__targetMatrix.translation, translation, lerpParam)
        return (self.__sourceMatrix, self.__targetMatrix)

    def __cameraUpdate(self):
        deltaTime = self.__updateTime()
        self.__handleMovement()
        aimPoint = Vector3(self.__aimingSystem.aimPoint)
        self.__aimOffset = self.__calculateAimOffset(aimPoint)
        self.__updateTrajectoryDrawer()
        translation, rotation = self.__calculateIdealState(deltaTime)
        self.__interpolateStates(deltaTime, translation,
                                 mathUtils.createRotationMatrix(rotation))
        self.__camDist = aimPoint - self.__targetMatrix.translation
        self.__camDist = self.__camDist.length
        self.__cam.source = self.__sourceMatrix
        self.__cam.target.b = self.__targetMatrix
        self.__cam.pivotPosition = Vector3(0, 0, 0)
        BigWorld.player().positionControl.moveTo(aimPoint)
        self.__updateOscillator(deltaTime)
        self.__aimingSystem.update(deltaTime)
        if not self.__autoUpdatePosition:
            self.__dxdydz = Vector3(0, 0, 0)
        return 0.0

    def __updateOscillator(self, deltaTime):
        if ArtyCamera.isCameraDynamic():
            self.__positionOscillator.update(deltaTime)
            self.__positionNoiseOscillator.update(deltaTime)
        else:
            self.__positionOscillator.reset()
            self.__positionNoiseOscillator.reset()
        self.__cam.target.a = mathUtils.createTranslationMatrix(
            self.__positionOscillator.deviation +
            self.__positionNoiseOscillator.deviation)

    def __readCfg(self, dataSec):
        if not dataSec:
            LOG_WARNING(
                'Invalid section <artyMode/camera> in avatar_input_handler.xml'
            )
        self.__baseCfg = dict()
        bcfg = self.__baseCfg
        bcfg['keySensitivity'] = readFloat(dataSec, 'keySensitivity', 0.005,
                                           10.0, 0.025)
        bcfg['sensitivity'] = readFloat(dataSec, 'sensitivity', 0.005, 10.0,
                                        0.025)
        bcfg['scrollSensitivity'] = readFloat(dataSec, 'scrollSensitivity',
                                              0.005, 10.0, 0.025)
        bcfg['angularSpeed'] = readFloat(dataSec, 'angularSpeed', pi / 720.0,
                                         pi / 0.5, pi / 360.0)
        bcfg['distRange'] = readVec2(dataSec, 'distRange', (1.0, 1.0),
                                     (10000.0, 10000.0), (2.0, 30.0))
        bcfg['minimalPitch'] = readFloat(dataSec, 'minimalPitch', pi / 36.0,
                                         pi / 3.0, pi / 18.0)
        bcfg['maximalPitch'] = readFloat(dataSec, 'maximalPitch', pi / 6.0,
                                         pi / 3.0, pi / 3.5)
        bcfg['interpolationSpeed'] = readFloat(dataSec, 'interpolationSpeed',
                                               0.0, 10.0, 5.0)
        bcfg['highPitchThreshold'] = readFloat(dataSec, 'highPitchThreshold',
                                               0.1, 10.0, 3.0)
        bcfg['hTimeThreshold'] = readFloat(dataSec, 'hysteresis/timeThreshold',
                                           0.0, 10.0, 0.5)
        bcfg['hPositionThreshold'] = readFloat(dataSec,
                                               'hysteresis/positionThreshold',
                                               0.0, 100.0, 7.0)
        ds = Settings.g_instance.userPrefs[Settings.KEY_CONTROL_MODE]
        if ds is not None:
            ds = ds['artyMode/camera']
        self.__userCfg = dict()
        ucfg = self.__userCfg
        ucfg['horzInvert'] = self.settingsCore.getSetting('mouseHorzInvert')
        ucfg['vertInvert'] = self.settingsCore.getSetting('mouseVertInvert')
        ucfg['keySensitivity'] = readFloat(ds, 'keySensitivity', 0.0, 10.0,
                                           1.0)
        ucfg['sensitivity'] = readFloat(ds, 'sensitivity', 0.0, 10.0, 1.0)
        ucfg['scrollSensitivity'] = readFloat(ds, 'scrollSensitivity', 0.0,
                                              10.0, 1.0)
        ucfg['camDist'] = readFloat(ds, 'camDist', 0.0, 60.0, 0.0)
        self.__cfg = dict()
        cfg = self.__cfg
        cfg['keySensitivity'] = bcfg['keySensitivity']
        cfg['sensitivity'] = bcfg['sensitivity']
        cfg['scrollSensitivity'] = bcfg['scrollSensitivity']
        cfg['distRange'] = bcfg['distRange']
        cfg['angularSpeed'] = bcfg['angularSpeed']
        cfg['minimalPitch'] = bcfg['minimalPitch']
        cfg['maximalPitch'] = bcfg['maximalPitch']
        cfg['interpolationSpeed'] = bcfg['interpolationSpeed']
        cfg['highPitchThresholdSq'] = bcfg['highPitchThreshold'] * bcfg[
            'highPitchThreshold']
        cfg['hTimeThreshold'] = bcfg['hTimeThreshold']
        cfg['hPositionThresholdSq'] = bcfg['hPositionThreshold'] * bcfg[
            'hPositionThreshold']
        cfg['keySensitivity'] *= ucfg['keySensitivity']
        cfg['sensitivity'] *= ucfg['sensitivity']
        cfg['scrollSensitivity'] *= ucfg['scrollSensitivity']
        cfg['camDist'] = ucfg['camDist']
        cfg['horzInvert'] = ucfg['horzInvert']
        cfg['vertInvert'] = ucfg['vertInvert']
        dynamicSection = dataSec['dynamics']
        self.__dynamicCfg.readImpulsesConfig(dynamicSection)
        self.__positionOscillator = createOscillatorFromSection(
            dynamicSection['oscillator'], False)
        self.__positionNoiseOscillator = createOscillatorFromSection(
            dynamicSection['randomNoiseOscillatorFlat'], False)
        return
Exemple #13
0
class ArtyCamera(CameraWithSettings, CallbackDelayer):
    _DYNAMIC_ENABLED = True

    @staticmethod
    def enableDynamicCamera(enable):
        ArtyCamera._DYNAMIC_ENABLED = enable

    @staticmethod
    def isCameraDynamic():
        return ArtyCamera._DYNAMIC_ENABLED

    camera = property(lambda self: self.__cam)
    aimingSystem = property(lambda self: self.__aimingSystem)
    __aimOffset = aih_global_binding.bindRW(
        aih_global_binding.BINDING_ID.AIM_OFFSET)

    def __init__(self, dataSec):
        super(ArtyCamera, self).__init__()
        CallbackDelayer.__init__(self)
        self.isAimOffsetEnabled = True
        self.__positionOscillator = None
        self.__positionNoiseOscillator = None
        self.__switchers = CameraSwitcherCollection(cameraSwitchers=[
            CameraSwitcher(switchType=SwitchTypes.FROM_TRANSITION_DIST_AS_MAX,
                           switchToName=CTRL_MODE_NAME.STRATEGIC,
                           switchToPos=0.0)
        ],
                                                    isEnabled=True)
        self.__dynamicCfg = CameraDynamicConfig()
        self._readConfigs(dataSec)
        self.__cam = BigWorld.CursorCamera()
        self.__curSense = self._cfg['sensitivity']
        self.__onChangeControlMode = None
        self.__camDist = 0.0
        self.__desiredCamDist = 0.0
        self.__aimingSystem = None
        self.__prevTime = 0.0
        self.__prevAimPoint = Vector3()
        self.__dxdydz = Vector3(0.0, 0.0, 0.0)
        self.__autoUpdatePosition = False
        self.__needReset = 0
        self.__sourceMatrix = None
        self.__targetMatrix = None
        self.__rotation = 0.0
        self.__positionHysteresis = None
        self.__timeHysteresis = None
        self.__transitionEnabled = True
        self.__scrollSmoother = SPGScrollSmoother(0.3)
        self.__collisionDist = 0.0
        self.__camViewPoint = Vector3()
        return

    @staticmethod
    def _getConfigsKey():
        return ArtyCamera.__name__

    def create(self, onChangeControlMode=None):
        super(ArtyCamera, self).create()
        self.__onChangeControlMode = onChangeControlMode
        aimingSystemClass = ArtyAimingSystemRemote if BigWorld.player(
        ).isObserver() else ArtyAimingSystem
        self.__aimingSystem = aimingSystemClass()
        self.__camDist = self._cfg['camDist']
        self.__desiredCamDist = self.__camDist
        self.__positionHysteresis = PositionHysteresis(
            self._cfg['hPositionThresholdSq'])
        self.__timeHysteresis = TimeHysteresis(self._cfg['hTimeThreshold'])
        self.__cam.pivotMaxDist = 0.0
        self.__cam.maxDistHalfLife = 0.01
        self.__cam.movementHalfLife = 0.0
        self.__cam.turningHalfLife = -1
        self.__cam.pivotPosition = Vector3(0.0, 0.0, 0.0)
        self.__sourceMatrix = Matrix()
        self.__targetMatrix = Matrix()
        self.__rotation = 0.0
        self.__enableSwitchers()
        self.__scrollSmoother.setTime(self._cfg['scrollSmoothingTime'])

    def destroy(self):
        self.disable()
        self.__onChangeControlMode = None
        self.__cam = None
        if self.__aimingSystem is not None:
            self.__aimingSystem.destroy()
            self.__aimingSystem = None
        CallbackDelayer.destroy(self)
        CameraWithSettings.destroy(self)
        return

    def enable(self,
               targetPos,
               saveDist,
               switchToPos=None,
               switchToPlace=None):
        BigWorld.wg_trajectory_drawer().setStrategicMode(False)
        self.__prevTime = 0.0
        if switchToPlace == SwitchToPlaces.TO_TRANSITION_DIST:
            self.__camDist = math_utils.clamp(self._cfg['distRange'][0],
                                              self._cfg['distRange'][1],
                                              self._cfg['transitionDist'])
        elif switchToPlace == SwitchToPlaces.TO_RELATIVE_POS and switchToPos is not None:
            minDist, maxDist = self._cfg['distRange']
            self.__camDist = (maxDist - minDist) * switchToPos + minDist
        elif switchToPlace == SwitchToPlaces.TO_NEAR_POS and switchToPos is not None:
            minDist, maxDist = self._cfg['distRange']
            self.__camDist = math_utils.clamp(minDist, maxDist, switchToPos)
        elif self.settingsCore.getSetting(SPGAim.AUTO_CHANGE_AIM_MODE):
            self.__camDist = math_utils.clamp(self._cfg['distRange'][0],
                                              self._cfg['transitionDist'],
                                              self.__camDist)
        self.__desiredCamDist = self.__camDist
        self.__scrollSmoother.start(self.__desiredCamDist)
        self.__enableSwitchers()
        self.__aimingSystem.enable(targetPos)
        self.__positionHysteresis.update(Vector3(0.0, 0.0, 0.0))
        self.__timeHysteresis.update(BigWorld.timeExact())
        camTarget = MatrixProduct()
        self.__rotation = max(self.__aimingSystem.direction.pitch,
                              self._cfg['minimalPitch'])
        cameraDirection = self.__getCameraDirection()
        self.__targetMatrix.translation = self.aimingSystem.aimPoint - cameraDirection.scale(
            self.__camDist)
        self.__cam.target = camTarget
        self.__cam.target.b = self.__targetMatrix
        self.__sourceMatrix = math_utils.createRotationMatrix(
            (cameraDirection.yaw, -cameraDirection.pitch, 0.0))
        self.__cam.source = self.__sourceMatrix
        self.__cam.forceUpdate()
        BigWorld.camera(self.__cam)
        BigWorld.player().positionControl.moveTo(self.__aimingSystem.hitPoint)
        BigWorld.player().positionControl.followCamera(False)
        self.__cameraUpdate()
        self.delayCallback(0.01, self.__cameraUpdate)
        self.__needReset = 1
        return

    def disable(self):
        self.__scrollSmoother.stop()
        if self.__aimingSystem is not None:
            self.__aimingSystem.disable()
        self.stopCallback(self.__cameraUpdate)
        self.__switchers.clear()
        self.__positionOscillator.reset()
        return

    def teleport(self, pos):
        self.__aimingSystem.updateTargetPos(pos)
        self.update(0.0, 0.0, 0.0)

    def getDistRatio(self):
        minDist, maxDist = self._cfg['distRange']
        return (self.__desiredCamDist - minDist) / (maxDist - minDist)

    def getCurrentCamDist(self):
        return self.__desiredCamDist

    def getCamDistRange(self):
        return self._cfg['distRange']

    def getCamTransitionDist(self):
        return self._cfg['transitionDist']

    def update(self, dx, dy, dz, updateByKeyboard=False):
        self.__curSense = self._cfg[
            'keySensitivity'] if updateByKeyboard else self._cfg['sensitivity']
        self.__autoUpdatePosition = updateByKeyboard
        self.__dxdydz = Vector3(dx if not self._cfg['horzInvert'] else -dx,
                                dy if not self._cfg['vertInvert'] else -dy, dz)

    def applyImpulse(self, position, impulse, reason=ImpulseReason.ME_HIT):
        adjustedImpulse, noiseMagnitude = self.__dynamicCfg.adjustImpulse(
            impulse, reason)
        impulseFlatDir = Vector3(adjustedImpulse.x, 0, adjustedImpulse.z)
        impulseFlatDir.normalise()
        impulseLocal = self.__sourceMatrix.applyVector(
            impulseFlatDir * (-1 * adjustedImpulse.length))
        self.__positionOscillator.applyImpulse(impulseLocal)
        self.__applyNoiseImpulse(noiseMagnitude)

    def applyDistantImpulse(self,
                            position,
                            impulseValue,
                            reason=ImpulseReason.ME_HIT):
        if reason != ImpulseReason.SPLASH and reason != ImpulseReason.PROJECTILE_HIT:
            return
        impulse = BigWorld.player().getOwnVehiclePosition() - position
        distance = impulse.length
        if distance <= 1.0:
            distance = 1.0
        impulse.normalise()
        if reason == ImpulseReason.PROJECTILE_HIT:
            if not cameras.isPointOnScreen(position):
                return
            distance = 1.0
        impulse *= impulseValue / distance
        self.applyImpulse(position, impulse, reason)

    def writeUserPreferences(self):
        ds = Settings.g_instance.userPrefs
        if not ds.has_key(Settings.KEY_CONTROL_MODE):
            ds.write(Settings.KEY_CONTROL_MODE, '')
        ucfg = self._userCfg
        ds = ds[Settings.KEY_CONTROL_MODE]
        ds.writeBool('artyMode/camera/horzInvert', ucfg['horzInvert'])
        ds.writeBool('artyMode/camera/vertInvert', ucfg['vertInvert'])
        ds.writeFloat('artyMode/camera/keySensitivity', ucfg['keySensitivity'])
        ds.writeFloat('artyMode/camera/sensitivity', ucfg['sensitivity'])
        ds.writeFloat('artyMode/camera/scrollSensitivity',
                      ucfg['scrollSensitivity'])
        ds.writeFloat('artyMode/camera/camDist', self._cfg['camDist'])

    def __applyNoiseImpulse(self, noiseMagnitude):
        noiseImpulse = math_utils.RandomVectors.random3Flat(noiseMagnitude)
        self.__positionNoiseOscillator.applyImpulse(noiseImpulse)

    def __calculateAimOffset(self, aimWorldPos):
        if not self.isAimOffsetEnabled:
            return Vector2(0.0, 0.0)
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying and replayCtrl.isControllingCamera:
            aimOffset = replayCtrl.getAimClipPosition()
        else:
            proj = BigWorld.projection()
            aimLocalPos = Matrix(self.__cam.matrix).applyPoint(aimWorldPos)
            if aimLocalPos.z < 0:
                aimLocalPos.z = max(0.0,
                                    proj.nearPlane - _OFFSET_FROM_NEAR_PLANE)
                aimWorldPos = Matrix(
                    self.__cam.invViewMatrix).applyPoint(aimLocalPos)
            aimOffset = cameras.projectPoint(aimWorldPos)
            aimOffset = Vector2(math_utils.clamp(-0.95, 0.95, aimOffset.x),
                                math_utils.clamp(-0.95, 0.95, aimOffset.y))
            if replayCtrl.isRecording:
                replayCtrl.setAimClipPosition(aimOffset)
        return aimOffset

    def __handleMovement(self):
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying:
            if self.__needReset != 0:
                if self.__needReset > 1:
                    from helpers import isPlayerAvatar
                    player = BigWorld.player()
                    if isPlayerAvatar():
                        if player.inputHandler.ctrl is not None:
                            player.inputHandler.ctrl.resetGunMarkers()
                    self.__needReset = 0
                else:
                    self.__needReset += 1
            if replayCtrl.isControllingCamera:
                self.__aimingSystem.updateTargetPos(
                    replayCtrl.getGunRotatorTargetPoint())
            else:
                self.__aimingSystem.handleMovement(
                    self.__dxdydz.x * self.__curSense,
                    -self.__dxdydz.y * self.__curSense)
                if self.__dxdydz.x != 0 or self.__dxdydz.y != 0 or self.__dxdydz.z != 0:
                    self.__needReset = 2
        else:
            self.__aimingSystem.handleMovement(
                self.__dxdydz.x * self.__curSense,
                -self.__dxdydz.y * self.__curSense)
        return

    def __getCameraDirection(self):
        direction = Vector3()
        direction.setPitchYaw(self.__rotation,
                              self.__aimingSystem.direction.yaw)
        direction.normalise()
        return direction

    def __getDesiredCameraDistance(self):
        distRange = self.__switchersDistRange()
        self.__desiredCamDist -= self.__dxdydz.z * self.__curSense
        self.__desiredCamDist = math_utils.clamp(distRange[0], distRange[1],
                                                 self.__desiredCamDist)
        self.__desiredCamDist = self.__aimingSystem.overrideCamDist(
            self.__desiredCamDist)
        self._cfg['camDist'] = self.__camDist
        self.__scrollSmoother.moveTo(self.__desiredCamDist, distRange)
        return self.__desiredCamDist

    def __updateTrajectoryDrawer(self):
        shotDescr = BigWorld.player().getVehicleDescriptor().shot
        BigWorld.wg_trajectory_drawer().setParams(
            shotDescr.maxDistance, Vector3(0, -shotDescr.gravity, 0),
            self.__aimOffset)

    def __updateTime(self):
        curTime = BigWorld.timeExact()
        deltaTime = curTime - self.__prevTime
        self.__prevTime = curTime
        return deltaTime

    def __choosePitchLevel(self, aimPoint):
        useHighPitch = (aimPoint - self.__aimingSystem.hitPoint
                        ).lengthSquared > self._cfg['highPitchThresholdSq']
        if useHighPitch:
            useHighPitch = self.__positionHysteresis.check(
                aimPoint) or self.__timeHysteresis.check(self.__prevTime)
        else:
            self.__positionHysteresis.update(aimPoint)
            self.__timeHysteresis.update(self.__prevTime)
        return useHighPitch

    def __getCollisionTestOrigin(self, aimPoint, direction):
        distRange = self.__switchersDistRange()
        vehiclePosition = BigWorld.player().getVehicleAttached().position
        collisionTestOrigin = Vector3(vehiclePosition)
        if direction.x * direction.x > direction.z * direction.z and not math_utils.almostZero(
                direction.x):
            collisionTestOrigin.y = direction.y / direction.x * (
                vehiclePosition.x - aimPoint.x) + aimPoint.y
        elif not math_utils.almostZero(direction.z):
            collisionTestOrigin.y = direction.y / direction.z * (
                vehiclePosition.z - aimPoint.z) + aimPoint.y
        else:
            collisionTestOrigin = aimPoint - direction.scale(
                (distRange[1] - distRange[0]) / 2.0)
            LOG_WARNING(
                "Can't find point on direction ray. Using half point as collision test origin"
            )
        return collisionTestOrigin

    def __resolveCollisions(self, aimPoint, distance, direction):
        distRange = self.__switchersDistRange()
        collisionDist = 0.0
        collisionTestOrigin = self.__getCollisionTestOrigin(
            aimPoint, direction)
        sign = copysign(
            1.0, distance * distance -
            (aimPoint - collisionTestOrigin).lengthSquared)
        srcPoint = collisionTestOrigin
        endPoint = aimPoint - direction.scale(
            distance + sign * (distRange[0] + _SEARCH_COLLISION_DEPTH))
        collision = collideDynamicAndStatic(
            srcPoint, endPoint, (BigWorld.player().playerVehicleID, ))
        if collision:
            collisionDistance = (aimPoint - collision[0]).length
            collisionDist = collisionDistance - sign * distRange[0]
            if sign * (collisionDistance - distance) < distRange[0]:
                distance = collisionDist
        if math_utils.almostZero(self.__rotation):
            srcPoint = aimPoint - direction.scale(distance)
            endPoint = aimPoint
            collision = collideDynamicAndStatic(
                srcPoint, endPoint, (BigWorld.player().playerVehicleID, ))
            if collision:
                self.__aimingSystem.aimPoint = collision[0]
                if collision[1]:
                    self.__positionHysteresis.update(aimPoint)
                    self.__timeHysteresis.update(self.__prevTime)
        return collisionDist

    def __calculateIdealState(self, deltaTime):
        aimPoint = self.__aimingSystem.aimPoint
        direction = self.__aimingSystem.direction
        impactPitch = max(direction.pitch, self._cfg['minimalPitch'])
        self.__rotation = max(self.__rotation, impactPitch)
        distRange = self.__switchersDistRange()
        distanceCurSq = (
            aimPoint -
            BigWorld.player().getVehicleAttached().position).lengthSquared
        distanceMinSq = distRange[0]**2.0
        forcedPitch = impactPitch
        if distanceCurSq < distanceMinSq:
            forcedPitch = atan2(sqrt(distanceMinSq - distanceCurSq),
                                sqrt(distanceCurSq))
        angularShift = self._cfg['angularSpeed'] * deltaTime
        angularShift = angularShift if self.__choosePitchLevel(
            aimPoint) else -angularShift
        minPitch = max(forcedPitch, impactPitch)
        maxPitch = max(forcedPitch, self._cfg['maximalPitch'])
        self.__rotation = math_utils.clamp(minPitch, maxPitch,
                                           self.__rotation + angularShift)
        desiredDistance = self.__getDesiredCameraDistance()
        cameraDirection = self.__getCameraDirection()
        collisionDist = self.__resolveCollisions(aimPoint, desiredDistance,
                                                 cameraDirection)
        collisionDist = max(distRange[0], collisionDist)
        desiredDistance = self.__scrollSmoother.update(deltaTime)
        rotation = Vector3(cameraDirection.yaw, -cameraDirection.pitch, 0.0)
        return (rotation, desiredDistance, collisionDist)

    def __interpolateStates(self, deltaTime, rotation, desiredDistance,
                            collisionDist):
        lerpParam = math_utils.clamp(
            0.0, 1.0, deltaTime * self._cfg['interpolationSpeed'])
        collisionLerpParam = math_utils.clamp(
            0.0, 1.0, deltaTime * self._cfg['distInterpolationSpeed'])
        self.__sourceMatrix = slerp(self.__sourceMatrix, rotation, lerpParam)
        camDirection = Vector3()
        camDirection.setPitchYaw(-self.__sourceMatrix.pitch,
                                 self.__sourceMatrix.yaw)
        camDirection.normalise()
        self.__camViewPoint = math_utils.lerp(self.__camViewPoint,
                                              self.__aimingSystem.aimPoint,
                                              lerpParam)
        self.__collisionDist = math_utils.lerp(self.__collisionDist,
                                               collisionDist,
                                               collisionLerpParam)
        desiredDistance = max(desiredDistance, self.__collisionDist)
        self.__targetMatrix.translation = self.__camViewPoint - camDirection.scale(
            desiredDistance)
        return (self.__sourceMatrix, self.__targetMatrix)

    def __cameraUpdate(self):
        deltaTime = self.__updateTime()
        self.__aimOffset = self.__calculateAimOffset(
            self.__aimingSystem.aimPoint)
        self.__handleMovement()
        aimPoint = Vector3(self.__aimingSystem.aimPoint)
        self.__updateTrajectoryDrawer()
        rotation, desiredDistance, collisionDist = self.__calculateIdealState(
            deltaTime)
        self.__interpolateStates(deltaTime,
                                 math_utils.createRotationMatrix(rotation),
                                 desiredDistance, collisionDist)
        self.__camDist = aimPoint - self.__targetMatrix.translation
        self.__camDist = self.__camDist.length
        self.__cam.source = self.__sourceMatrix
        self.__cam.target.b = self.__targetMatrix
        self.__cam.pivotPosition = Vector3(0, 0, 0)
        if aimPoint.distSqrTo(self.__prevAimPoint) > 0.010000000000000002:
            BigWorld.player().positionControl.moveTo(aimPoint)
            self.__prevAimPoint = aimPoint
        self.__updateOscillator(deltaTime)
        self.__aimingSystem.update(deltaTime)
        if self.__onChangeControlMode is not None and self.__switchers.needToSwitch(
                self.__dxdydz.z, self.__desiredCamDist,
                self._cfg['distRange'][0], self._cfg['distRange'][1],
                self._cfg['transitionDist']):
            self.__onChangeControlMode(*self.__switchers.getSwitchParams())
        if not self.__transitionEnabled and self.__desiredCamDist - TRANSITION_DIST_HYSTERESIS <= self._cfg[
                'transitionDist']:
            self.__transitionEnabled = True
            self.__enableSwitchers(False)
        if not self.__autoUpdatePosition:
            self.__dxdydz = Vector3(0, 0, 0)
        return 0.01

    def __updateOscillator(self, deltaTime):
        if ArtyCamera.isCameraDynamic():
            self.__positionOscillator.update(deltaTime)
            self.__positionNoiseOscillator.update(deltaTime)
        else:
            self.__positionOscillator.reset()
            self.__positionNoiseOscillator.reset()
        self.__cam.target.a = math_utils.createTranslationMatrix(
            self.__positionOscillator.deviation +
            self.__positionNoiseOscillator.deviation)

    def __switchersDistRange(self):
        distRange = self._cfg['distRange']
        if self.__switchers.isEnabled():
            distRange = self.__switchers.getDistLimitationForSwitch(
                distRange[0], distRange[1], self._cfg['transitionDist'])
        return distRange

    def _readConfigs(self, dataSec):
        if not dataSec:
            LOG_WARNING(
                'Invalid section <artyMode/camera> in avatar_input_handler.xml'
            )
        super(ArtyCamera, self)._readConfigs(dataSec)
        dynamicSection = dataSec['dynamics']
        self.__dynamicCfg.readImpulsesConfig(dynamicSection)
        self.__positionOscillator = createOscillatorFromSection(
            dynamicSection['oscillator'], False)
        self.__positionNoiseOscillator = createOscillatorFromSection(
            dynamicSection['randomNoiseOscillatorFlat'])

    def _readBaseCfg(self, dataSec):
        bcfg = self._baseCfg
        bcfg['keySensitivity'] = readFloat(dataSec, 'keySensitivity', 0.005,
                                           10.0, 0.025)
        bcfg['sensitivity'] = readFloat(dataSec, 'sensitivity', 0.005, 10.0,
                                        0.025)
        bcfg['scrollSensitivity'] = readFloat(dataSec, 'scrollSensitivity',
                                              0.005, 10.0, 0.025)
        bcfg['angularSpeed'] = readFloat(dataSec, 'angularSpeed', pi / 720.0,
                                         pi / 0.5, pi / 360.0)
        bcfg['distRange'] = readVec2(dataSec, 'distRange', (1.0, 1.0),
                                     (10000.0, 10000.0), (2.0, 30.0))
        bcfg['transitionDist'] = readFloat(dataSec, 'transitionDist', 1.0,
                                           10000.0, 60.0)
        bcfg['minimalPitch'] = readFloat(dataSec, 'minimalPitch', pi / 36.0,
                                         pi / 3.0, pi / 18.0)
        bcfg['maximalPitch'] = readFloat(dataSec, 'maximalPitch', pi / 6.0,
                                         pi / 3.0, pi / 3.5)
        bcfg['interpolationSpeed'] = readFloat(dataSec, 'interpolationSpeed',
                                               0.0, 100.0, 5.0)
        bcfg['distInterpolationSpeed'] = readFloat(dataSec,
                                                   'distInterpolationSpeed',
                                                   0.0, 10.0, 5.0)
        bcfg['highPitchThreshold'] = readFloat(dataSec, 'highPitchThreshold',
                                               0.1, 10.0, 3.0)
        bcfg['hTimeThreshold'] = readFloat(dataSec, 'hysteresis/timeThreshold',
                                           0.0, 10.0, 0.5)
        bcfg['hPositionThreshold'] = readFloat(dataSec,
                                               'hysteresis/positionThreshold',
                                               0.0, 100.0, 7.0)
        bcfg['scrollSmoothingTime'] = readFloat(dataSec, 'scrollSmoothingTime',
                                                0.0, 1.0, 0.3)

    def _readUserCfg(self):
        ucfg = self._userCfg
        dataSec = Settings.g_instance.userPrefs[Settings.KEY_CONTROL_MODE]
        if dataSec is not None:
            dataSec = dataSec['artyMode/camera']
        ucfg['horzInvert'] = False
        ucfg['vertInvert'] = False
        ucfg['keySensitivity'] = readFloat(dataSec, 'keySensitivity', 0.0,
                                           10.0, 1.0)
        ucfg['sensitivity'] = readFloat(dataSec, 'sensitivity', 0.0, 10.0, 1.0)
        ucfg['scrollSensitivity'] = readFloat(dataSec, 'scrollSensitivity',
                                              0.0, 10.0, 1.0)
        ucfg['camDist'] = readFloat(dataSec, 'camDist', 0.0, 60.0, 0.0)
        return

    def _makeCfg(self):
        bcfg = self._baseCfg
        ucfg = self._userCfg
        cfg = self._cfg
        cfg['keySensitivity'] = bcfg['keySensitivity']
        cfg['sensitivity'] = bcfg['sensitivity']
        cfg['scrollSensitivity'] = bcfg['scrollSensitivity']
        cfg['distRange'] = bcfg['distRange']
        cfg['transitionDist'] = bcfg['transitionDist']
        cfg['angularSpeed'] = bcfg['angularSpeed']
        cfg['minimalPitch'] = bcfg['minimalPitch']
        cfg['maximalPitch'] = bcfg['maximalPitch']
        cfg['interpolationSpeed'] = bcfg['interpolationSpeed']
        cfg['distInterpolationSpeed'] = bcfg['distInterpolationSpeed']
        cfg['highPitchThresholdSq'] = bcfg['highPitchThreshold'] * bcfg[
            'highPitchThreshold']
        cfg['hTimeThreshold'] = bcfg['hTimeThreshold']
        cfg['hPositionThresholdSq'] = bcfg['hPositionThreshold'] * bcfg[
            'hPositionThreshold']
        cfg['scrollSmoothingTime'] = bcfg['scrollSmoothingTime']
        cfg['keySensitivity'] *= ucfg['keySensitivity']
        cfg['sensitivity'] *= ucfg['sensitivity']
        cfg['scrollSensitivity'] *= ucfg['scrollSensitivity']
        cfg['camDist'] = ucfg['camDist']
        cfg['horzInvert'] = ucfg['horzInvert']
        cfg['vertInvert'] = ucfg['vertInvert']

    def _handleSettingsChange(self, diff):
        super(ArtyCamera, self)._handleSettingsChange(diff)
        if SPGAim.AUTO_CHANGE_AIM_MODE in diff:
            self.__enableSwitchers()
        if GAME.SCROLL_SMOOTHING in diff:
            self.__scrollSmoother.setIsEnabled(
                self.settingsCore.getSetting(GAME.SCROLL_SMOOTHING))

    def _updateSettingsFromServer(self):
        super(ArtyCamera, self)._updateSettingsFromServer()
        if self.settingsCore.isReady:
            self.__enableSwitchers()
            self.__scrollSmoother.setIsEnabled(
                self.settingsCore.getSetting(GAME.SCROLL_SMOOTHING))

    def __enableSwitchers(self, updateTransitionEnabled=True):
        if updateTransitionEnabled and self.__desiredCamDist - TRANSITION_DIST_HYSTERESIS >= self._cfg[
                'transitionDist']:
            self.__transitionEnabled = False
        if self.settingsCore.isReady:
            self.__switchers.setIsEnabled(
                self.settingsCore.getSetting(SPGAim.AUTO_CHANGE_AIM_MODE)
                and self.__transitionEnabled)
 def new_showDamageFromShot(self, attackerID, points, effectsIndex,
                            damageFactor, *a, **k):
     if LOG_EVENTS and attackerID > 0:
         player = BigWorld.player()
         #Initial info
         points_count = len(points) if points else 0
         timeLeft, timeLeftSec = getTimeLeft()
         eventInfo = [
             '%s' % player.arenaUniqueID, timeLeft, timeLeftSec,
             '"Vehicle.showDamageFromShot"',
             '%s' % player.arena.vehicles[self.id].get('accountDBID', '-'),
             '%s' %
             player.arena.vehicles[attackerID].get('accountDBID', '-'),
             json.dumps({
                 'points': points_count,
                 'effectsIndex': effectsIndex,
                 'damageFactor': damageFactor
             })
         ]
         #Decode info
         shellInfo = {}
         for shot in player.arena.vehicles[attackerID][
                 'vehicleType'].gun.shots:
             if effectsIndex == shot.shell.effectsIndex:
                 shellInfo['name'] = shot.shell.name
                 shellInfo['kind'] = shellTypeAbb(shot.shell.kind)
                 shellInfo['damage'] = str(shot.shell.damage)
                 shellInfo['caliber'] = shot.shell.caliber
                 shellInfo['piercingPower'] = str(shot.piercingPower)
                 shellInfo['speed'] = round(shot.speed / 0.8, 3)
                 shellInfo['gravity'] = round(shot.gravity / 0.64, 3)
                 shellInfo['maxDistance'] = shot.maxDistance
                 if shot.shell.kind == 'HIGH_EXPLOSIVE':
                     shellInfo[
                         'explosionRadius'] = shot.shell.type.explosionRadius
                 break
         eventInfo.append(json.dumps(shellInfo) if shellInfo else '')
         maxHitEffectCode, decodedPoints, maxDamagedComponent = DamageFromShotDecoder.decodeHitPoints(
             points, self.appearance.collisions)
         hasPiercedHit = DamageFromShotDecoder.hasDamaged(maxHitEffectCode)
         attacker = BigWorld.entities.get(attackerID, None)
         attackerPos = attacker.position if isinstance(
             attacker, Vehicle
         ) and attacker.inWorld and attacker.isStarted else player.arena.positions.get(
             attackerID)
         eventInfo.append(
             json.dumps({
                 'maxHitEffectCode':
                 VEHICLE_HIT_EFFECT_NAMES.get(maxHitEffectCode),
                 'maxDamagedComponent':
                 maxDamagedComponent,
                 'hasPiercedHit':
                 hasPiercedHit,
                 'distance':
                 round(self.position.distTo(attackerPos), 3)
                 if attackerPos else None,
                 'hitPoints': [{
                     'componentName': point.componentName,
                     'hitEffectGroup': point.hitEffectGroup
                 } for point in decodedPoints] if decodedPoints else None
             }))
         for num, encodedPoint in enumerate(points, 1):
             hitsInfo = []  #[[Dir1-Layer1, ...], [Dir2-Layer1, ...], ...]
             hitsScheme = None
             compIdx, hitEffectCode, startPoint, endPoint = DamageFromShotDecoder.decodeSegment(
                 encodedPoint, self.appearance.collisions,
                 TankPartIndexes.ALL[-1])
             if compIdx >= 0 and startPoint != endPoint:
                 convertedCompIdx = DamageFromShotDecoder.convertComponentIndex(
                     compIdx)
                 bbox = self.appearance.collisions.getBoundingBox(
                     convertedCompIdx)
                 width, height, depth = (bbox[1] - bbox[0]) / 256.0
                 if COLLIDE_MULTI:
                     if COLLIDE_SCHEME == 'hexahedron':
                         hitsScheme = _CSHexahedron(width, height, depth,
                                                    COLLIDE_SCALE)
                     elif COLLIDE_SCHEME == 'cross':
                         hitsScheme = _CSCross(width, height, depth,
                                               COLLIDE_SCALE)
                     else:
                         hitsScheme = _CSCenter()
                 else:
                     hitsScheme = _CSCenter()
                 compMatrix = Matrix(
                     self.appearance.compoundModel.node(
                         TankPartIndexes.getName(convertedCompIdx)))
                 firstHitDir = endPoint - startPoint
                 firstHitDir.normalise()
                 firstHitDir = compMatrix.applyVector(firstHitDir)
                 firstHitPos = compMatrix.applyPoint(startPoint)
                 for direction in hitsScheme.directions:
                     hitInfo = []
                     collisions = self.appearance.collisions.collideAllWorld(
                         firstHitPos - firstHitDir.scale(COLLIDE_INDENT) +
                         direction, firstHitPos +
                         firstHitDir.scale(COLLIDE_LENGTH) + direction)
                     if collisions:
                         base = None
                         testPointAdded = collidePointAdded = False
                         for collision in collisions:
                             if collision[3] in TankPartIndexes.ALL:
                                 if base is None:
                                     base = collision[0]
                                 if not testPointAdded:
                                     if collision[0] > COLLIDE_INDENT:
                                         hitInfo.append(
                                             'TestPoint%s(distance=%s, tankPart=%s)'
                                             %
                                             (num
                                              if points_count > 1 else '',
                                              round(COLLIDE_INDENT - base,
                                                    4),
                                              TankPartIndexes.getName(
                                                  convertedCompIdx)))
                                         testPointAdded = True
                                 material = self.getMatinfo(
                                     collision[3], collision[2])
                                 hitInfo.append({
                                     'distance':
                                     round(collision[0] - base, 4),
                                     'angleCos':
                                     round(collision[1], 4),
                                     'tankPart':
                                     TankPartIndexes.getName(collision[3]),
                                     'armor':
                                     round(material.armor, 4)
                                     if material else None
                                 })
                                 if not collidePointAdded:
                                     collidePointAdded = True
                                 if material and material.vehicleDamageFactor > 0 and collision[
                                         3] in (TankPartIndexes.HULL,
                                                TankPartIndexes.TURRET):
                                     break
                         if collidePointAdded:
                             if not testPointAdded and base is not None:
                                 hitInfo.append(
                                     'TestPoint%s(distance=%s, tankPart=%s)'
                                     % (num if points_count > 1 else '',
                                        round(COLLIDE_INDENT - base, 4),
                                        TankPartIndexes.getName(
                                            convertedCompIdx)))
                     hitsInfo.append(hitInfo)
             eventInfo.append(json.dumps('%s: %s' % ('TestPoint%d' % num if points_count > 1 else 'layers' if hitsScheme.NAME == 'center' else 'TestPoint', \
                                                     hitsScheme.format(hitsInfo[0] if hitsScheme.NAME == 'center' else hitsInfo) if hitsScheme else '[]')))
         printStrings(LOG_EVENTS_FILENAME, eventInfo)