oldschool-toontown/otp/avatar/LocalAvatar.py
2024-06-25 21:00:27 -05:00

1214 lines
46 KiB
Python

from panda3d.core import *
from panda3d.otp import Nametag, WhisperPopup
from direct.gui.DirectGui import *
from direct.showbase.PythonUtil import *
from direct.interval.IntervalGlobal import *
from direct.showbase.InputStateGlobal import inputState
from direct.controls import ControlManager
from . import DistributedAvatar
from direct.task import Task
from otp.otpbase import OTPGlobals
import math
import random
from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedSmoothNode
from otp.otpbase import OTPLocalizer
from direct.controls.GhostWalker import GhostWalker
from direct.controls.GravityWalker import GravityWalker
from direct.controls.ObserverWalker import ObserverWalker
from direct.controls.SwimWalker import SwimWalker
from direct.controls.TwoDWalker import TwoDWalker
class LocalAvatar(DistributedAvatar.DistributedAvatar, DistributedSmoothNode.DistributedSmoothNode):
notify = DirectNotifyGlobal.directNotify.newCategory('LocalAvatar')
wantDevCameraPositions = ConfigVariableBool('want-dev-camera-positions', 0).value
wantMouse = ConfigVariableBool('want-mouse', 0).value
sleepTimeout = ConfigVariableInt('sleep-timeout', 120).value
swimTimeout = ConfigVariableInt('afk-timeout', 600).value
__enableMarkerPlacement = ConfigVariableBool('place-markers', 0).value
acceptingNewFriends = ConfigVariableBool('accepting-new-friends', 1).value
acceptingNonFriendWhispers = ConfigVariableBool('accepting-non-friend-whispers', 0).value
def __init__(self, cr, chatMgr, talkAssistant = None, passMessagesThrough = False):
try:
self.LocalAvatar_initialized
return
except:
pass
self.LocalAvatar_initialized = 1
DistributedAvatar.DistributedAvatar.__init__(self, cr)
DistributedSmoothNode.DistributedSmoothNode.__init__(self, cr)
self.cTrav = CollisionTraverser('base.cTrav')
base.pushCTrav(self.cTrav)
self.cTrav.setRespectPrevTransform(1)
self.avatarControlsEnabled = 0
self.controlManager = ControlManager.ControlManager(True, passMessagesThrough)
self.initializeCollisions()
self.initializeSmartCamera()
self.cameraPositions = []
self.animMultiplier = 1.0
self.runTimeout = 2.5
self.customMessages = []
self.chatMgr = chatMgr
base.talkAssistant = talkAssistant
self.commonChatFlags = 0
self.garbleChat = 1
self.teleportAllowed = 1
self.lockedDown = 0
self.isPageUp = 0
self.isPageDown = 0
self.soundRun = None
self.soundWalk = None
self.sleepFlag = 0
self.isDisguised = 0
self.movingFlag = 0
self.swimmingFlag = 0
self.lastNeedH = None
self.accept('friendOnline', self.__friendOnline)
self.accept('friendOffline', self.__friendOffline)
self.accept('clickedWhisper', self.clickedWhisper)
self.accept('playerOnline', self.__playerOnline)
self.accept('playerOffline', self.__playerOffline)
self.sleepCallback = None
self.accept('wakeup', self.wakeUp)
self.jumpLandAnimFixTask = None
self.fov = OTPGlobals.DefaultCameraFov
self.accept('avatarMoving', self.clearPageUpDown)
self.nametag2dNormalContents = Nametag.CSpeech
self.showNametag2d()
self.setPickable(0)
self.posCameraSeq = None
return
def useSwimControls(self):
self.controlManager.use('swim', self)
def useGhostControls(self):
self.controlManager.use('ghost', self)
def useWalkControls(self):
self.controlManager.use('walk', self)
def useTwoDControls(self):
self.controlManager.use('twoD', self)
def isLockedDown(self):
return self.lockedDown
def lock(self):
if self.lockedDown == 1:
self.notify.debug('lock() - already locked!')
self.lockedDown = 1
def unlock(self):
if self.lockedDown == 0:
self.notify.debug('unlock() - already unlocked!')
self.lockedDown = 0
def isInWater(self):
return self.getZ(render) <= 0.0
def isTeleportAllowed(self):
return self.teleportAllowed and not self.isDisguised
def setTeleportAllowed(self, flag):
self.teleportAllowed = flag
self.refreshOnscreenButtons()
def sendFriendsListEvent(self):
self.wakeUp()
messenger.send('openFriendsList')
def delete(self):
try:
self.LocalAvatar_deleted
return
except:
self.LocalAvatar_deleted = 1
self.ignoreAll()
self.stopJumpLandTask()
taskMgr.remove('shadowReach')
base.popCTrav()
if self.posCameraSeq:
self.posCameraSeq.finish()
self.posCameraSeq = None
self.disableAvatarControls()
self.stopTrackAnimToSpeed()
self.stopUpdateSmartCamera()
self.shutdownSmartCamera()
self.deleteCollisions()
self.controlManager.delete()
self.physControls = None
del self.controlManager
self.positionExaminer.delete()
del self.positionExaminer
taskMgr.remove(self.uniqueName('walkReturnTask'))
self.chatMgr.delete()
del self.chatMgr
del self.soundRun
del self.soundWalk
if hasattr(self, 'soundWhisper'):
del self.soundWhisper
DistributedAvatar.DistributedAvatar.delete(self)
return
def shadowReach(self, state):
if base.localAvatar.shadowPlacer:
base.localAvatar.shadowPlacer.lifter.setReach(base.localAvatar.getAirborneHeight() + 4.0)
return Task.cont
def wantLegacyLifter(self):
return False
def setupControls(self, avatarRadius = 1.4, floorOffset = OTPGlobals.FloorOffset, reach = 4.0, wallBitmask = OTPGlobals.WallBitmask, floorBitmask = OTPGlobals.FloorBitmask, ghostBitmask = OTPGlobals.GhostBitmask):
walkControls = GravityWalker(legacyLifter=self.wantLegacyLifter())
walkControls.setWallBitMask(wallBitmask)
walkControls.setFloorBitMask(floorBitmask)
walkControls.initializeCollisions(self.cTrav, self, avatarRadius, floorOffset, reach)
walkControls.setAirborneHeightFunc(self.getAirborneHeight)
self.controlManager.add(walkControls, 'walk')
self.physControls = walkControls
twoDControls = TwoDWalker()
twoDControls.setWallBitMask(wallBitmask)
twoDControls.setFloorBitMask(floorBitmask)
twoDControls.initializeCollisions(self.cTrav, self, avatarRadius, floorOffset, reach)
twoDControls.setAirborneHeightFunc(self.getAirborneHeight)
self.controlManager.add(twoDControls, 'twoD')
swimControls = SwimWalker()
swimControls.setWallBitMask(wallBitmask)
swimControls.setFloorBitMask(floorBitmask)
swimControls.initializeCollisions(self.cTrav, self, avatarRadius, floorOffset, reach)
swimControls.setAirborneHeightFunc(self.getAirborneHeight)
self.controlManager.add(swimControls, 'swim')
ghostControls = GhostWalker()
ghostControls.setWallBitMask(ghostBitmask)
ghostControls.setFloorBitMask(floorBitmask)
ghostControls.initializeCollisions(self.cTrav, self, avatarRadius, floorOffset, reach)
ghostControls.setAirborneHeightFunc(self.getAirborneHeight)
self.controlManager.add(ghostControls, 'ghost')
observerControls = ObserverWalker()
observerControls.setWallBitMask(ghostBitmask)
observerControls.setFloorBitMask(floorBitmask)
observerControls.initializeCollisions(self.cTrav, self, avatarRadius, floorOffset, reach)
observerControls.setAirborneHeightFunc(self.getAirborneHeight)
self.controlManager.add(observerControls, 'observer')
self.controlManager.use('walk', self)
self.controlManager.disable()
def initializeCollisions(self):
self.setupControls()
def deleteCollisions(self):
self.controlManager.deleteCollisions()
self.ignore('entero157')
del self.cTrav
def initializeSmartCameraCollisions(self):
self.ccTrav = CollisionTraverser('LocalAvatar.ccTrav')
self.ccLine = CollisionSegment(0.0, 0.0, 0.0, 1.0, 0.0, 0.0)
self.ccLineNode = CollisionNode('ccLineNode')
self.ccLineNode.addSolid(self.ccLine)
self.ccLineNodePath = self.attachNewNode(self.ccLineNode)
self.ccLineBitMask = OTPGlobals.CameraBitmask
self.ccLineNode.setFromCollideMask(self.ccLineBitMask)
self.ccLineNode.setIntoCollideMask(BitMask32.allOff())
self.camCollisionQueue = CollisionHandlerQueue()
self.ccTrav.addCollider(self.ccLineNodePath, self.camCollisionQueue)
self.ccSphere = CollisionSphere(0, 0, 0, 1)
self.ccSphereNode = CollisionNode('ccSphereNode')
self.ccSphereNode.addSolid(self.ccSphere)
self.ccSphereNodePath = base.camera.attachNewNode(self.ccSphereNode)
self.ccSphereNode.setFromCollideMask(OTPGlobals.CameraBitmask)
self.ccSphereNode.setIntoCollideMask(BitMask32.allOff())
self.camPusher = CollisionHandlerPusher()
self.camPusher.addCollider(self.ccSphereNodePath, base.camera)
self.camPusher.setCenter(self)
self.ccPusherTrav = CollisionTraverser('LocalAvatar.ccPusherTrav')
self.ccSphere2 = self.ccSphere
self.ccSphereNode2 = CollisionNode('ccSphereNode2')
self.ccSphereNode2.addSolid(self.ccSphere2)
self.ccSphereNodePath2 = base.camera.attachNewNode(self.ccSphereNode2)
self.ccSphereNode2.setFromCollideMask(OTPGlobals.CameraBitmask)
self.ccSphereNode2.setIntoCollideMask(BitMask32.allOff())
self.camPusher2 = CollisionHandlerPusher()
self.ccPusherTrav.addCollider(self.ccSphereNodePath2, self.camPusher2)
self.camPusher2.addCollider(self.ccSphereNodePath2, base.camera)
self.camPusher2.setCenter(self)
self.camFloorRayNode = self.attachNewNode('camFloorRayNode')
self.ccRay = CollisionRay(0.0, 0.0, 0.0, 0.0, 0.0, -1.0)
self.ccRayNode = CollisionNode('ccRayNode')
self.ccRayNode.addSolid(self.ccRay)
self.ccRayNodePath = self.camFloorRayNode.attachNewNode(self.ccRayNode)
self.ccRayBitMask = OTPGlobals.FloorBitmask
self.ccRayNode.setFromCollideMask(self.ccRayBitMask)
self.ccRayNode.setIntoCollideMask(BitMask32.allOff())
self.ccTravFloor = CollisionTraverser('LocalAvatar.ccTravFloor')
self.camFloorCollisionQueue = CollisionHandlerQueue()
self.ccTravFloor.addCollider(self.ccRayNodePath, self.camFloorCollisionQueue)
self.ccTravOnFloor = CollisionTraverser('LocalAvatar.ccTravOnFloor')
self.ccRay2 = CollisionRay(0.0, 0.0, 0.0, 0.0, 0.0, -1.0)
self.ccRay2Node = CollisionNode('ccRay2Node')
self.ccRay2Node.addSolid(self.ccRay2)
self.ccRay2NodePath = self.camFloorRayNode.attachNewNode(self.ccRay2Node)
self.ccRay2BitMask = OTPGlobals.FloorBitmask
self.ccRay2Node.setFromCollideMask(self.ccRay2BitMask)
self.ccRay2Node.setIntoCollideMask(BitMask32.allOff())
self.ccRay2MoveNodePath = hidden.attachNewNode('ccRay2MoveNode')
self.camFloorCollisionBroadcaster = CollisionHandlerFloor()
self.camFloorCollisionBroadcaster.setInPattern('on-floor')
self.camFloorCollisionBroadcaster.setOutPattern('off-floor')
self.camFloorCollisionBroadcaster.addCollider(self.ccRay2NodePath, self.ccRay2MoveNodePath)
def deleteSmartCameraCollisions(self):
del self.ccTrav
del self.ccLine
del self.ccLineNode
self.ccLineNodePath.removeNode()
del self.ccLineNodePath
del self.camCollisionQueue
del self.ccRay
del self.ccRayNode
self.ccRayNodePath.removeNode()
del self.ccRayNodePath
del self.ccRay2
del self.ccRay2Node
self.ccRay2NodePath.removeNode()
del self.ccRay2NodePath
self.ccRay2MoveNodePath.removeNode()
del self.ccRay2MoveNodePath
del self.ccTravOnFloor
del self.ccTravFloor
del self.camFloorCollisionQueue
del self.camFloorCollisionBroadcaster
del self.ccSphere
del self.ccSphereNode
self.ccSphereNodePath.removeNode()
del self.ccSphereNodePath
del self.camPusher
del self.ccPusherTrav
del self.ccSphere2
del self.ccSphereNode2
self.ccSphereNodePath2.removeNode()
del self.ccSphereNodePath2
del self.camPusher2
def collisionsOff(self):
self.controlManager.collisionsOff()
def collisionsOn(self):
self.controlManager.collisionsOn()
def recalcCameraSphere(self):
nearPlaneDist = base.camLens.getNear()
hFov = base.camLens.getHfov()
vFov = base.camLens.getVfov()
hOff = nearPlaneDist * math.tan(deg2Rad(hFov / 2.0))
vOff = nearPlaneDist * math.tan(deg2Rad(vFov / 2.0))
camPnts = [Point3(hOff, nearPlaneDist, vOff),
Point3(-hOff, nearPlaneDist, vOff),
Point3(hOff, nearPlaneDist, -vOff),
Point3(-hOff, nearPlaneDist, -vOff),
Point3(0.0, 0.0, 0.0)]
avgPnt = Point3(0.0, 0.0, 0.0)
for camPnt in camPnts:
avgPnt = avgPnt + camPnt
avgPnt = avgPnt / len(camPnts)
sphereRadius = 0.0
for camPnt in camPnts:
dist = Vec3(camPnt - avgPnt).length()
if dist > sphereRadius:
sphereRadius = dist
avgPnt = Point3(avgPnt)
self.ccSphereNodePath.setPos(avgPnt)
self.ccSphereNodePath2.setPos(avgPnt)
self.ccSphere.setRadius(sphereRadius)
def putCameraFloorRayOnAvatar(self):
self.camFloorRayNode.setPos(self, 0, 0, 5)
def putCameraFloorRayOnCamera(self):
self.camFloorRayNode.setPos(self.ccSphereNodePath, 0, 0, 0)
def attachCamera(self):
camera.reparentTo(self)
base.enableMouse()
base.setMouseOnNode(self.node())
self.ignoreMouse = not self.wantMouse
self.setWalkSpeedNormal()
def detachCamera(self):
base.disableMouse()
def stopJumpLandTask(self):
if self.jumpLandAnimFixTask:
self.jumpLandAnimFixTask.remove()
self.jumpLandAnimFixTask = None
return
def jumpStart(self):
if not self.sleepFlag and self.hp > 0:
self.b_setAnimState('jumpAirborne', 1.0)
self.stopJumpLandTask()
def returnToWalk(self, task):
if self.sleepFlag:
state = 'Sleep'
elif self.hp > 0:
state = 'Happy'
else:
state = 'Sad'
self.b_setAnimState(state, 1.0)
return Task.done
if 1:
def jumpLandAnimFix(self, jumpTime):
if self.playingAnim != 'run' and self.playingAnim != 'walk':
return taskMgr.doMethodLater(jumpTime, self.returnToWalk, self.uniqueName('walkReturnTask'))
def jumpHardLand(self):
if self.allowHardLand():
self.b_setAnimState('jumpLand', 1.0)
self.stopJumpLandTask()
self.jumpLandAnimFixTask = self.jumpLandAnimFix(1.0)
if self.d_broadcastPosHpr:
self.d_broadcastPosHpr()
def jumpLand(self):
self.jumpLandAnimFixTask = self.jumpLandAnimFix(0.01)
if self.d_broadcastPosHpr:
self.d_broadcastPosHpr()
def setupAnimationEvents(self):
self.accept('jumpStart', self.jumpStart, [])
self.accept('jumpHardLand', self.jumpHardLand, [])
self.accept('jumpLand', self.jumpLand, [])
def ignoreAnimationEvents(self):
self.ignore('jumpStart')
self.ignore('jumpHardLand')
self.ignore('jumpLand')
def allowHardLand(self):
return not self.sleepFlag and self.hp > 0
def enableSmartCameraViews(self):
self.accept('tab', self.nextCameraPos, [1])
self.accept('shift-tab', self.nextCameraPos, [0])
self.accept('page_up', self.pageUp)
self.accept('page_down', self.pageDown)
def disableSmartCameraViews(self):
self.ignore('tab')
self.ignore('shift-tab')
self.ignore('page_up')
self.ignore('page_down')
self.ignore('page_down-up')
def enableAvatarControls(self):
if self.avatarControlsEnabled:
return
self.avatarControlsEnabled = 1
self.setupAnimationEvents()
self.controlManager.enable()
def disableAvatarControls(self):
if not self.avatarControlsEnabled:
return
self.avatarControlsEnabled = 0
self.ignoreAnimationEvents()
self.controlManager.disable()
self.clearPageUpDown()
def setWalkSpeedNormal(self):
self.controlManager.setSpeeds(OTPGlobals.ToonForwardSpeed, OTPGlobals.ToonJumpForce, OTPGlobals.ToonReverseSpeed, OTPGlobals.ToonRotateSpeed)
def setWalkSpeedSlow(self):
self.controlManager.setSpeeds(OTPGlobals.ToonForwardSlowSpeed, OTPGlobals.ToonJumpSlowForce, OTPGlobals.ToonReverseSlowSpeed, OTPGlobals.ToonRotateSlowSpeed)
def pageUp(self):
if not self.avatarControlsEnabled:
return
self.wakeUp()
if not self.isPageUp:
self.isPageDown = 0
self.isPageUp = 1
self.lerpCameraFov(70, 0.6)
self.setCameraPositionByIndex(self.cameraIndex)
else:
self.clearPageUpDown()
def pageDown(self):
if not self.avatarControlsEnabled:
return
self.wakeUp()
if not self.isPageDown:
self.isPageUp = 0
self.isPageDown = 1
self.lerpCameraFov(70, 0.6)
self.setCameraPositionByIndex(self.cameraIndex)
else:
self.clearPageUpDown()
def clearPageUpDown(self):
if self.isPageDown or self.isPageUp:
self.lerpCameraFov(self.fov, 0.6)
self.isPageDown = 0
self.isPageUp = 0
self.setCameraPositionByIndex(self.cameraIndex)
def nextCameraPos(self, forward):
if not self.avatarControlsEnabled:
return
self.wakeUp()
self.__cameraHasBeenMoved = 1
if forward:
self.cameraIndex += 1
if self.cameraIndex > len(self.cameraPositions) - 1:
self.cameraIndex = 0
else:
self.cameraIndex -= 1
if self.cameraIndex < 0:
self.cameraIndex = len(self.cameraPositions) - 1
self.setCameraPositionByIndex(self.cameraIndex)
def initCameraPositions(self):
camHeight = self.getClampedAvatarHeight()
heightScaleFactor = camHeight * 0.3333333333
defLookAt = Point3(0.0, 1.5, camHeight)
scXoffset = 3.0
scPosition = (Point3(scXoffset - 1, -10.0, camHeight + 5.0), Point3(scXoffset, 2.0, camHeight))
self.cameraPositions = [(Point3(0.0, -9.0 * heightScaleFactor, camHeight),
defLookAt,
Point3(0.0, camHeight, camHeight * 4.0),
Point3(0.0, camHeight, camHeight * -1.0),
0),
(Point3(0.0, 0.5, camHeight),
defLookAt,
Point3(0.0, camHeight, camHeight * 1.33),
Point3(0.0, camHeight, camHeight * 0.66),
1),
(Point3(5.7 * heightScaleFactor, 7.65 * heightScaleFactor, camHeight + 2.0),
Point3(0.0, 1.0, camHeight),
Point3(0.0, 1.0, camHeight * 4.0),
Point3(0.0, 1.0, camHeight * -1.0),
0),
(Point3(0.0, -24.0 * heightScaleFactor, camHeight + 4.0),
defLookAt,
Point3(0.0, 1.5, camHeight * 4.0),
Point3(0.0, 1.5, camHeight * -1.0),
0),
(Point3(0.0, -12.0 * heightScaleFactor, camHeight + 4.0),
defLookAt,
Point3(0.0, 1.5, camHeight * 4.0),
Point3(0.0, 1.5, camHeight * -1.0),
0)] + self.auxCameraPositions
if self.wantDevCameraPositions:
self.cameraPositions += [(Point3(0.0, 0.0, camHeight * 3),
Point3(0.0, 0.0, 0.0),
Point3(0.0, camHeight * 2, 0.0),
Point3(0.0, -camHeight * 2, 0.0),
1),
(Point3(camHeight * 3, 0.0, camHeight),
Point3(0.0, 0.0, camHeight),
Point3(0.0, camHeight, camHeight * 1.1),
Point3(0.0, camHeight, camHeight * 0.9),
1),
(Point3(camHeight * 3, 0.0, 0.0),
Point3(0.0, 0.0, camHeight),
Point3(0.0, camHeight, camHeight * 1.1),
Point3(0.0, camHeight, camHeight * 0.9),
1),
(Point3(-camHeight * 3, 0.0, camHeight),
Point3(0.0, 0.0, camHeight),
Point3(0.0, camHeight, camHeight * 1.1),
Point3(0.0, camHeight, camHeight * 0.9),
1),
(Point3(0.0, -60, 60),
defLookAt + Point3(0, 15, 0),
defLookAt + Point3(0, 15, 0),
defLookAt + Point3(0, 15, 0),
1),
(Point3(0.0, -20, 20),
defLookAt + Point3(0, 5, 0),
defLookAt + Point3(0, 5, 0),
defLookAt + Point3(0, 5, 0),
1)]
def addCameraPosition(self, camPos = None):
if camPos == None:
lookAtNP = self.attachNewNode('lookAt')
lookAtNP.setPos(base.cam, 0, 1, 0)
lookAtPos = lookAtNP.getPos()
camHeight = self.getClampedAvatarHeight()
camPos = (base.cam.getPos(self),
lookAtPos,
Point3(0.0, 1.5, camHeight * 4.0),
Point3(0.0, 1.5, camHeight * -1.0),
1)
lookAtNP.removeNode()
self.auxCameraPositions.append(camPos)
self.cameraPositions.append(camPos)
return
def resetCameraPosition(self):
self.cameraIndex = 0
self.setCameraPositionByIndex(self.cameraIndex)
def removeCameraPosition(self):
if len(self.cameraPositions) > 1:
camPos = self.cameraPositions[self.cameraIndex]
if camPos in self.auxCameraPositions:
self.auxCameraPositions.remove(camPos)
if camPos in self.cameraPositions:
self.cameraPositions.remove(camPos)
self.nextCameraPos(1)
def printCameraPositions(self):
print('[')
for i in range(len(self.cameraPositions)):
self.printCameraPosition(i)
print(',')
print(']')
def printCameraPosition(self, index):
cp = self.cameraPositions[index]
print('(Point3(%0.2f, %0.2f, %0.2f),' % (cp[0][0], cp[0][1], cp[0][2]))
print('Point3(%0.2f, %0.2f, %0.2f),' % (cp[1][0], cp[1][1], cp[1][2]))
print('Point3(%0.2f, %0.2f, %0.2f),' % (cp[2][0], cp[2][1], cp[2][2]))
print('Point3(%0.2f, %0.2f, %0.2f),' % (cp[3][0], cp[3][1], cp[3][2]))
print('%d,' % cp[4])
print(')', end=' ')
def posCamera(self, lerp, time):
if not lerp:
self.positionCameraWithPusher(self.getCompromiseCameraPos(), self.getLookAtPoint())
else:
camPos = self.getCompromiseCameraPos()
savePos = camera.getPos()
saveHpr = camera.getHpr()
self.positionCameraWithPusher(camPos, self.getLookAtPoint())
x = camPos[0]
y = camPos[1]
z = camPos[2]
destHpr = camera.getHpr()
h = destHpr[0]
p = destHpr[1]
r = destHpr[2]
camera.setPos(savePos)
camera.setHpr(saveHpr)
if self.posCameraSeq:
self.posCameraSeq.finish()
self.posCameraSeq = None
self.posCameraSeq = camera.posHprInterval(time, Point3(x, y, z), Point3(h, p, r), name='posCamera')
self.posCameraSeq.start()
def getClampedAvatarHeight(self):
return max(self.getHeight(), 3.0)
def getVisibilityPoint(self):
return Point3(0.0, 0.0, self.getHeight())
def setLookAtPoint(self, la):
self.__curLookAt = Point3(la)
def getLookAtPoint(self):
return Point3(self.__curLookAt)
def setIdealCameraPos(self, pos):
self.__idealCameraPos = Point3(pos)
self.updateSmartCameraCollisionLineSegment()
def getIdealCameraPos(self):
return Point3(self.__idealCameraPos)
def setCameraPositionByIndex(self, index):
self.notify.debug('switching to camera position %s' % index)
self.setCameraSettings(self.cameraPositions[index])
def setCameraPosForPetInteraction(self):
height = self.getClampedAvatarHeight()
point = Point3(height * (7 / 3.0), height * (-7 / 3.0), height)
self.prevIdealPos = self.getIdealCameraPos()
self.setIdealCameraPos(point)
self.posCamera(1, 0.7)
def unsetCameraPosForPetInteraction(self):
self.setIdealCameraPos(self.prevIdealPos)
del self.prevIdealPos
self.posCamera(1, 0.7)
def setCameraSettings(self, camSettings):
self.setIdealCameraPos(camSettings[0])
if self.isPageUp and self.isPageDown or not self.isPageUp and not self.isPageDown:
self.__cameraHasBeenMoved = 1
self.setLookAtPoint(camSettings[1])
elif self.isPageUp:
self.__cameraHasBeenMoved = 1
self.setLookAtPoint(camSettings[2])
elif self.isPageDown:
self.__cameraHasBeenMoved = 1
self.setLookAtPoint(camSettings[3])
else:
self.notify.error('This case should be impossible.')
self.__disableSmartCam = camSettings[4]
if self.__disableSmartCam:
self.putCameraFloorRayOnAvatar()
self.cameraZOffset = 0.0
def getCompromiseCameraPos(self):
if self.__idealCameraObstructed == 0:
compromisePos = self.getIdealCameraPos()
else:
visPnt = self.getVisibilityPoint()
idealPos = self.getIdealCameraPos()
distance = Vec3(idealPos - visPnt).length()
ratio = self.closestObstructionDistance / distance
compromisePos = idealPos * ratio + visPnt * (1 - ratio)
liftMult = 1.0 - ratio * ratio
compromisePos = Point3(compromisePos[0], compromisePos[1], compromisePos[2] + self.getHeight() * 0.4 * liftMult)
compromisePos.setZ(compromisePos[2] + self.cameraZOffset)
return compromisePos
def updateSmartCameraCollisionLineSegment(self):
pointB = self.getIdealCameraPos()
pointA = self.getVisibilityPoint()
vectorAB = Vec3(pointB - pointA)
lengthAB = vectorAB.length()
if lengthAB > 0.001:
self.ccLine.setPointA(pointA)
self.ccLine.setPointB(pointB)
def initializeSmartCamera(self):
self.__idealCameraObstructed = 0
self.closestObstructionDistance = 0.0
self.cameraIndex = 0
self.auxCameraPositions = []
self.cameraZOffset = 0.0
self.__onLevelGround = 0
self.__camCollCanMove = 0
self.__geom = render
self.__disableSmartCam = 0
self.initializeSmartCameraCollisions()
self._smartCamEnabled = False
def shutdownSmartCamera(self):
self.deleteSmartCameraCollisions()
def setOnLevelGround(self, flag):
self.__onLevelGround = flag
def setCameraCollisionsCanMove(self, flag):
self.__camCollCanMove = flag
def setGeom(self, geom):
self.__geom = geom
def startUpdateSmartCamera(self, push = 1):
if self._smartCamEnabled:
LocalAvatar.notify.warning('redundant call to startUpdateSmartCamera')
return
self._smartCamEnabled = True
self.__floorDetected = 0
self.__cameraHasBeenMoved = 0
self.recalcCameraSphere()
self.initCameraPositions()
self.setCameraPositionByIndex(self.cameraIndex)
self.posCamera(0, 0.0)
self.__instantaneousCamPos = camera.getPos()
if push:
self.cTrav.addCollider(self.ccSphereNodePath, self.camPusher)
self.ccTravOnFloor.addCollider(self.ccRay2NodePath, self.camFloorCollisionBroadcaster)
self.__disableSmartCam = 0
else:
self.__disableSmartCam = 1
self.__lastPosWrtRender = camera.getPos(render)
self.__lastHprWrtRender = camera.getHpr(render)
taskName = self.taskName('updateSmartCamera')
taskMgr.remove(taskName)
taskMgr.add(self.updateSmartCamera, taskName, priority=47)
self.enableSmartCameraViews()
def stopUpdateSmartCamera(self):
if not self._smartCamEnabled:
LocalAvatar.notify.warning('redundant call to stopUpdateSmartCamera')
return
self.disableSmartCameraViews()
self.cTrav.removeCollider(self.ccSphereNodePath)
self.ccTravOnFloor.removeCollider(self.ccRay2NodePath)
if not base.localAvatar.isEmpty():
self.putCameraFloorRayOnAvatar()
taskName = self.taskName('updateSmartCamera')
taskMgr.remove(taskName)
self._smartCamEnabled = False
def updateSmartCamera(self, task):
if not self.__camCollCanMove and not self.__cameraHasBeenMoved:
if self.__lastPosWrtRender == camera.getPos(render):
if self.__lastHprWrtRender == camera.getHpr(render):
return Task.cont
self.__cameraHasBeenMoved = 0
self.__lastPosWrtRender = camera.getPos(render)
self.__lastHprWrtRender = camera.getHpr(render)
self.__idealCameraObstructed = 0
if not self.__disableSmartCam:
self.ccTrav.traverse(self.__geom)
if self.camCollisionQueue.getNumEntries() > 0:
self.camCollisionQueue.sortEntries()
self.handleCameraObstruction(self.camCollisionQueue.getEntry(0))
if not self.__onLevelGround:
self.handleCameraFloorInteraction()
if not self.__idealCameraObstructed:
self.nudgeCamera()
if not self.__disableSmartCam:
self.ccPusherTrav.traverse(self.__geom)
self.putCameraFloorRayOnCamera()
self.ccTravOnFloor.traverse(self.__geom)
return Task.cont
def positionCameraWithPusher(self, pos, lookAt):
camera.setPos(pos)
self.ccPusherTrav.traverse(self.__geom)
camera.lookAt(lookAt)
def nudgeCamera(self):
CLOSE_ENOUGH = 0.1
curCamPos = self.__instantaneousCamPos
curCamHpr = camera.getHpr()
targetCamPos = self.getCompromiseCameraPos()
targetCamLookAt = self.getLookAtPoint()
posDone = 0
if Vec3(curCamPos - targetCamPos).length() <= CLOSE_ENOUGH:
camera.setPos(targetCamPos)
posDone = 1
camera.setPos(targetCamPos)
camera.lookAt(targetCamLookAt)
targetCamHpr = camera.getHpr()
hprDone = 0
if Vec3(curCamHpr - targetCamHpr).length() <= CLOSE_ENOUGH:
hprDone = 1
if posDone and hprDone:
return
lerpRatio = 0.15
lerpRatio = 1 - pow(1 - lerpRatio, globalClock.getDt() * 30.0)
self.__instantaneousCamPos = targetCamPos * lerpRatio + curCamPos * (1 - lerpRatio)
if self.__disableSmartCam or not self.__idealCameraObstructed:
newHpr = targetCamHpr * lerpRatio + curCamHpr * (1 - lerpRatio)
else:
newHpr = targetCamHpr
camera.setPos(self.__instantaneousCamPos)
camera.setHpr(newHpr)
def popCameraToDest(self):
newCamPos = self.getCompromiseCameraPos()
newCamLookAt = self.getLookAtPoint()
self.positionCameraWithPusher(newCamPos, newCamLookAt)
self.__instantaneousCamPos = camera.getPos()
def handleCameraObstruction(self, camObstrCollisionEntry):
collisionPoint = camObstrCollisionEntry.getSurfacePoint(self.ccLineNodePath)
collisionVec = Vec3(collisionPoint - self.ccLine.getPointA())
distance = collisionVec.length()
self.__idealCameraObstructed = 1
self.closestObstructionDistance = distance
self.popCameraToDest()
def handleCameraFloorInteraction(self):
self.putCameraFloorRayOnCamera()
self.ccTravFloor.traverse(self.__geom)
if self.__onLevelGround:
return
if self.camFloorCollisionQueue.getNumEntries() == 0:
return
self.camFloorCollisionQueue.sortEntries()
camObstrCollisionEntry = self.camFloorCollisionQueue.getEntry(0)
camHeightFromFloor = camObstrCollisionEntry.getSurfacePoint(self.ccRayNodePath)[2]
self.cameraZOffset = camera.getPos()[2] + camHeightFromFloor
if self.cameraZOffset < 0:
self.cameraZOffset = 0
if self.__floorDetected == 0:
self.__floorDetected = 1
self.popCameraToDest()
def lerpCameraFov(self, fov, time):
taskMgr.remove('cam-fov-lerp-play')
oldFov = base.camLens.getHfov()
if abs(fov - oldFov) > 0.1:
def setCamFov(fov):
base.camLens.setFov(fov)
self.camLerpInterval = LerpFunctionInterval(setCamFov, fromData=oldFov, toData=fov, duration=time, name='cam-fov-lerp')
self.camLerpInterval.start()
def setCameraFov(self, fov):
self.fov = fov
if not (self.isPageDown or self.isPageUp):
base.camLens.setFov(self.fov)
def gotoNode(self, node, eyeHeight = 3):
possiblePoints = (Point3(3, 6, 0),
Point3(-3, 6, 0),
Point3(6, 6, 0),
Point3(-6, 6, 0),
Point3(3, 9, 0),
Point3(-3, 9, 0),
Point3(6, 9, 0),
Point3(-6, 9, 0),
Point3(9, 9, 0),
Point3(-9, 9, 0),
Point3(6, 0, 0),
Point3(-6, 0, 0),
Point3(6, 3, 0),
Point3(-6, 3, 0),
Point3(9, 9, 0),
Point3(-9, 9, 0),
Point3(0, 12, 0),
Point3(3, 12, 0),
Point3(-3, 12, 0),
Point3(6, 12, 0),
Point3(-6, 12, 0),
Point3(9, 12, 0),
Point3(-9, 12, 0),
Point3(0, -6, 0),
Point3(-3, -6, 0),
Point3(0, -9, 0),
Point3(-6, -9, 0))
for point in possiblePoints:
pos = self.positionExaminer.consider(node, point, eyeHeight)
if pos:
self.setPos(node, pos)
self.lookAt(node)
self.setHpr(self.getH() + random.choice((-10, 10)), 0, 0)
return
self.setPos(node, 0, 0, 0)
def setCustomMessages(self, customMessages):
self.customMessages = customMessages
messenger.send('customMessagesChanged')
def displayWhisper(self, fromId, chatString, whisperType):
sender = None
sfx = self.soundWhisper
if whisperType == WhisperPopup.WTNormal or whisperType == WhisperPopup.WTQuickTalker:
if sender == None:
return
chatString = sender.getName() + ': ' + chatString
whisper = WhisperPopup(chatString, OTPGlobals.getInterfaceFont(), whisperType)
if sender != None:
whisper.setClickable(sender.getName(), fromId)
whisper.manage(base.marginManager)
base.playSfx(sfx)
return
def displayWhisperPlayer(self, fromId, chatString, whisperType):
sender = None
playerInfo = None
sfx = self.soundWhisper
playerInfo = base.cr.playerFriendsManager.playerId2Info.get(fromId, None)
if playerInfo == None:
return
senderName = playerInfo.playerName
if whisperType == WhisperPopup.WTNormal or whisperType == WhisperPopup.WTQuickTalker:
chatString = senderName + ': ' + chatString
whisper = WhisperPopup(chatString, OTPGlobals.getInterfaceFont(), whisperType)
if sender != None:
whisper.setClickable(senderName, fromId)
whisper.manage(base.marginManager)
base.playSfx(sfx)
return
def setAnimMultiplier(self, value):
self.animMultiplier = value
def getAnimMultiplier(self):
return self.animMultiplier
def enableRun(self):
self.accept('arrow_up', self.startRunWatch)
self.accept('arrow_up-up', self.stopRunWatch)
self.accept('control-arrow_up', self.startRunWatch)
self.accept('control-arrow_up-up', self.stopRunWatch)
self.accept('alt-arrow_up', self.startRunWatch)
self.accept('alt-arrow_up-up', self.stopRunWatch)
self.accept('shift-arrow_up', self.startRunWatch)
self.accept('shift-arrow_up-up', self.stopRunWatch)
def disableRun(self):
self.ignore('arrow_up')
self.ignore('arrow_up-up')
self.ignore('control-arrow_up')
self.ignore('control-arrow_up-up')
self.ignore('alt-arrow_up')
self.ignore('alt-arrow_up-up')
self.ignore('shift-arrow_up')
self.ignore('shift-arrow_up-up')
def startRunWatch(self):
def setRun(ignored):
messenger.send('running-on')
taskMgr.doMethodLater(self.runTimeout, setRun, self.uniqueName('runWatch'))
return Task.cont
def stopRunWatch(self):
taskMgr.remove(self.uniqueName('runWatch'))
messenger.send('running-off')
return Task.cont
def runSound(self):
self.soundWalk.stop()
base.playSfx(self.soundRun, looping=1)
def walkSound(self):
self.soundRun.stop()
base.playSfx(self.soundWalk, looping=1)
def stopSound(self):
self.soundRun.stop()
self.soundWalk.stop()
def wakeUp(self):
if self.sleepCallback != None:
taskMgr.remove(self.uniqueName('sleepwatch'))
self.startSleepWatch(self.sleepCallback)
self.lastMoved = globalClock.getFrameTime()
if self.sleepFlag:
self.sleepFlag = 0
return
def gotoSleep(self):
if not self.sleepFlag:
self.b_setAnimState('Sleep', self.animMultiplier)
self.sleepFlag = 1
def forceGotoSleep(self):
if self.hp > 0:
self.sleepFlag = 0
self.gotoSleep()
def startSleepWatch(self, callback):
self.sleepCallback = callback
taskMgr.doMethodLater(self.sleepTimeout, callback, self.uniqueName('sleepwatch'))
def stopSleepWatch(self):
taskMgr.remove(self.uniqueName('sleepwatch'))
self.sleepCallback = None
return
def startSleepSwimTest(self):
taskName = self.taskName('sleepSwimTest')
taskMgr.remove(taskName)
task = Task.Task(self.sleepSwimTest)
self.lastMoved = globalClock.getFrameTime()
self.lastState = None
self.lastAction = None
self.sleepSwimTest(task)
taskMgr.add(self.sleepSwimTest, taskName, 35)
return
def stopSleepSwimTest(self):
taskName = self.taskName('sleepSwimTest')
taskMgr.remove(taskName)
self.stopSound()
def sleepSwimTest(self, task):
now = globalClock.getFrameTime()
speed, rotSpeed, slideSpeed = self.controlManager.getSpeeds()
if speed != 0.0 or rotSpeed != 0.0 or inputState.isSet('jump'):
if not self.swimmingFlag:
self.swimmingFlag = 1
elif self.swimmingFlag:
self.swimmingFlag = 0
if self.swimmingFlag or self.hp <= 0:
self.wakeUp()
elif not self.sleepFlag:
now = globalClock.getFrameTime()
if now - self.lastMoved > self.swimTimeout:
self.swimTimeoutAction()
return Task.done
return Task.cont
def swimTimeoutAction(self):
pass
def trackAnimToSpeed(self, task):
speed, rotSpeed, slideSpeed = self.controlManager.getSpeeds()
if speed != 0.0 or rotSpeed != 0.0 or inputState.isSet('jump'):
if not self.movingFlag:
self.movingFlag = 1
self.stopLookAround()
elif self.movingFlag:
self.movingFlag = 0
self.startLookAround()
if self.movingFlag or self.hp <= 0:
self.wakeUp()
elif not self.sleepFlag:
now = globalClock.getFrameTime()
if now - self.lastMoved > self.sleepTimeout:
self.gotoSleep()
state = None
if self.sleepFlag:
state = 'Sleep'
elif self.hp > 0:
state = 'Happy'
else:
state = 'Sad'
if state != self.lastState:
self.lastState = state
self.b_setAnimState(state, self.animMultiplier)
if state == 'Sad':
self.setWalkSpeedSlow()
else:
self.setWalkSpeedNormal()
if self.cheesyEffect == OTPGlobals.CEFlatProfile or self.cheesyEffect == OTPGlobals.CEFlatPortrait:
needH = None
if rotSpeed > 0.0:
needH = -10
elif rotSpeed < 0.0:
needH = 10
elif speed != 0.0:
needH = 0
if needH != None and self.lastNeedH != needH:
node = self.getGeomNode().getChild(0)
lerp = Sequence(LerpHprInterval(node, 0.5, Vec3(needH, 0, 0), blendType='easeInOut'), name='cheesy-lerp-hpr', autoPause=1)
lerp.start()
self.lastNeedH = needH
else:
self.lastNeedH = None
action = self.setSpeed(speed, rotSpeed)
if action != self.lastAction:
self.lastAction = action
if self.emoteTrack:
self.emoteTrack.finish()
self.emoteTrack = None
if action == OTPGlobals.WALK_INDEX or action == OTPGlobals.REVERSE_INDEX:
self.walkSound()
elif action == OTPGlobals.RUN_INDEX:
self.runSound()
else:
self.stopSound()
return Task.cont
def hasTrackAnimToSpeed(self):
taskName = self.taskName('trackAnimToSpeed')
return taskMgr.hasTaskNamed(taskName)
def startTrackAnimToSpeed(self):
taskName = self.taskName('trackAnimToSpeed')
taskMgr.remove(taskName)
task = Task.Task(self.trackAnimToSpeed)
self.lastMoved = globalClock.getFrameTime()
self.lastState = None
self.lastAction = None
self.trackAnimToSpeed(task)
taskMgr.add(self.trackAnimToSpeed, taskName, 35)
return
def stopTrackAnimToSpeed(self):
taskName = self.taskName('trackAnimToSpeed')
taskMgr.remove(taskName)
self.stopSound()
def startChat(self):
self.chatMgr.start()
self.accept(OTPGlobals.WhisperIncomingEvent, self.handlePlayerFriendWhisper)
self.accept(OTPGlobals.ThinkPosHotkey, self.thinkPos)
self.accept(OTPGlobals.PrintCamPosHotkey, self.printCamPos)
if self.__enableMarkerPlacement:
self.accept(OTPGlobals.PlaceMarkerHotkey, self.__placeMarker)
def stopChat(self):
self.chatMgr.stop()
self.ignore(OTPGlobals.WhisperIncomingEvent)
self.ignore(OTPGlobals.ThinkPosHotkey)
self.ignore(OTPGlobals.PrintCamPosHotkey)
if self.__enableMarkerPlacement:
self.ignore(OTPGlobals.PlaceMarkerHotkey)
def printCamPos(self):
node = base.camera.getParent()
pos = base.cam.getPos(node)
hpr = base.cam.getHpr(node)
print('cam pos = ', repr(pos), ', cam hpr = ', repr(hpr))
def d_broadcastPositionNow(self):
self.d_clearSmoothing()
self.d_broadcastPosHpr()
def travCollisionsLOS(self, n = None):
if n == None:
n = self.__geom
self.ccTrav.traverse(n)
return
def travCollisionsFloor(self, n = None):
if n == None:
n = self.__geom
self.ccTravFloor.traverse(n)
return
def travCollisionsPusher(self, n = None):
if n == None:
n = self.__geom
self.ccPusherTrav.traverse(n)
return
def __friendOnline(self, doId, commonChatFlags = 0, whitelistChatFlags = 0):
friend = base.cr.identifyFriend(doId)
if friend != None and hasattr(friend, 'setCommonAndWhitelistChatFlags'):
friend.setCommonAndWhitelistChatFlags(commonChatFlags, whitelistChatFlags)
if self.oldFriendsList != None:
now = globalClock.getFrameTime()
elapsed = now - self.timeFriendsListChanged
if elapsed < 10.0 and self.oldFriendsList.count(doId) == 0:
self.oldFriendsList.append(doId)
return
if friend != None:
self.setSystemMessage(doId, OTPLocalizer.WhisperFriendComingOnline % friend.getName())
return
def __friendOffline(self, doId):
friend = base.cr.identifyFriend(doId)
if friend != None:
self.setSystemMessage(0, OTPLocalizer.WhisperFriendLoggedOut % friend.getName())
return
def __playerOnline(self, playerId):
playerInfo = base.cr.playerFriendsManager.playerId2Info[playerId]
if playerInfo:
self.setSystemMessage(playerId, OTPLocalizer.WhisperPlayerOnline % (playerInfo.playerName, playerInfo.location))
def __playerOffline(self, playerId):
playerInfo = base.cr.playerFriendsManager.playerId2Info[playerId]
if playerInfo:
self.setSystemMessage(playerId, OTPLocalizer.WhisperPlayerOffline % playerInfo.playerName)
def clickedWhisper(self, doId, isPlayer = None):
if not isPlayer:
friend = base.cr.identifyFriend(doId)
if friend != None:
messenger.send('clickedNametag', [friend])
self.chatMgr.whisperTo(friend.getName(), doId)
else:
friend = base.cr.playerFriendsManager.getFriendInfo(doId)
if friend:
messenger.send('clickedNametagPlayer', [None, doId])
self.chatMgr.whisperTo(friend.getName(), None, doId)
return
def d_setParent(self, parentToken):
DistributedSmoothNode.DistributedSmoothNode.d_setParent(self, parentToken)
def handlePlayerFriendWhisper(self, playerId, charMessage):
print('handlePlayerFriendWhisper')
self.displayWhisperPlayer(playerId, charMessage, WhisperPopup.WTNormal)
def canChat(self):
return 0