Poodletooth-iLand/otp/avatar/Avatar.py

565 lines
20 KiB
Python
Raw Normal View History

2015-03-03 16:10:12 -06:00
from direct.actor.Actor import Actor
from direct.directnotify import DirectNotifyGlobal
from direct.distributed import ClockDelta
from direct.interval.IntervalGlobal import *
2015-03-03 16:10:12 -06:00
from direct.showbase.PythonUtil import recordCreationStack
from panda3d.core import *
2015-03-03 16:10:12 -06:00
import random
from otp.ai import MagicWordManager
from otp.ai.MagicWordGlobal import *
from otp.avatar.ShadowCaster import ShadowCaster
2015-05-30 14:47:29 -05:00
from otp.chat import ChatUtil
2015-03-03 16:10:12 -06:00
from otp.otpbase import OTPGlobals
from otp.otpbase import OTPLocalizer
from otp.otpbase import OTPRender
2015-06-24 11:32:30 -05:00
from otp.nametag.Nametag import Nametag
from otp.nametag.NametagGroup import NametagGroup
from otp.nametag.NametagConstants import *
2015-03-03 16:10:12 -06:00
teleportNotify = DirectNotifyGlobal.directNotify.newCategory('Teleport')
teleportNotify.showTime = True
if config.GetBool('want-teleport-debug', 1):
teleportNotify.setDebug(1)
def reconsiderAllUnderstandable():
for av in Avatar.ActiveAvatars:
av.considerUnderstandable()
class Avatar(Actor, ShadowCaster):
notify = directNotify.newCategory('Avatar')
ActiveAvatars = []
def __init__(self, other = None):
Actor.__init__(self, None, None, other, flattenable=0, setFinal=1)
ShadowCaster.__init__(self)
self.__font = OTPGlobals.getInterfaceFont()
2015-07-17 18:28:36 -05:00
self.name = ''
2015-03-03 16:10:12 -06:00
self.soundChatBubble = None
self.avatarType = ''
self.nametagNodePath = None
self.__nameVisible = 1
self.nametag = NametagGroup()
self.nametag.setAvatar(self)
2015-06-24 11:32:30 -05:00
self.nametag.setFont(OTPGlobals.getInterfaceFont())
self.nametag.setSpeechFont(OTPGlobals.getInterfaceFont())
self.nametag2dContents = Nametag.CName | Nametag.CSpeech
self.nametag2dDist = Nametag.CName | Nametag.CSpeech
self.nametag2dNormalContents = Nametag.CName | Nametag.CSpeech
2015-03-03 16:10:12 -06:00
self.nametag3d = self.attachNewNode('nametag3d')
self.nametag3d.setTag('cam', 'nametag')
self.nametag3d.setLightOff()
self.getGeomNode().showThrough(OTPRender.ShadowCameraBitmask)
self.nametag3d.hide(OTPRender.ShadowCameraBitmask)
self.collTube = None
self.scale = 1.0
self.height = 0.0
self.style = None
self.understandable = 1
2015-06-24 11:32:30 -05:00
self.setPlayerType(NametagGroup.CCNormal)
2015-03-03 16:10:12 -06:00
self.ghostMode = 0
self.__chatParagraph = None
self.__chatMessage = None
self.__chatFlags = 0
self.__chatPageNumber = None
self.__chatAddressee = None
self.__chatDialogueList = []
self.__chatSet = 0
self.__chatLocal = 0
self.__currentDialogue = None
def delete(self):
try:
self.Avatar_deleted
except:
self.deleteNametag3d()
Actor.cleanup(self)
self.Avatar_deleted = 1
del self.__font
del self.style
del self.soundChatBubble
self.nametag.destroy()
del self.nametag
self.nametag3d.removeNode()
ShadowCaster.delete(self)
Actor.delete(self)
def isLocal(self):
return 0
def isPet(self):
return False
def isProxy(self):
return False
def setPlayerType(self, playerType):
self.playerType = playerType
if not hasattr(self, 'nametag'):
self.notify.warning('no nametag attributed, but would have been used.')
return
if self.isUnderstandable():
2015-06-24 11:32:30 -05:00
self.nametag.setColorCode(self.playerType)
2015-03-03 16:10:12 -06:00
else:
2015-06-24 11:32:30 -05:00
self.nametag.setColorCode(NametagGroup.CCNoChat)
2015-07-01 05:15:05 -05:00
self.setNametagName()
2015-03-03 16:10:12 -06:00
def considerUnderstandable(self):
2015-07-03 09:46:21 -05:00
if self.playerType in (NametagGroup.CCNormal, NametagGroup.CCSpeedChat):
2015-06-24 11:32:30 -05:00
self.setPlayerType(NametagGroup.CCSpeedChat)
2015-07-03 09:46:21 -05:00
if hasattr(base, 'localAvatar') and (self == base.localAvatar):
2015-03-03 16:10:12 -06:00
self.understandable = 1
2015-07-03 09:46:21 -05:00
self.setPlayerType(NametagGroup.CCNormal)
elif hasattr(self, 'adminAccess') and self.isAdmin():
self.understandable = 2
self.setPlayerType(NametagGroup.CCAdmin)
2015-06-24 11:32:30 -05:00
elif self.playerType == NametagGroup.CCSuit:
2015-03-03 16:10:12 -06:00
self.understandable = 1
2015-06-24 11:32:30 -05:00
self.setPlayerType(NametagGroup.CCSuit)
2015-07-03 09:46:21 -05:00
elif self.playerType not in (NametagGroup.CCNormal, NametagGroup.CCSpeedChat):
2015-03-03 16:10:12 -06:00
self.understandable = 1
2015-07-03 09:46:21 -05:00
self.setPlayerType(NametagGroup.CCNonPlayer)
elif settings['trueFriends'] and base.localAvatar.isTrueFriends(self.doId):
self.understandable = 2
self.setPlayerType(NametagGroup.CCNormal)
elif settings['speedchatPlus']:
2015-03-03 16:10:12 -06:00
self.understandable = 1
2015-07-03 09:46:21 -05:00
self.setPlayerType(NametagGroup.CCSpeedChat)
2015-03-03 16:10:12 -06:00
else:
self.understandable = 0
2015-07-03 09:46:21 -05:00
self.setPlayerType(NametagGroup.CCSpeedChat)
2015-03-03 16:10:12 -06:00
if not hasattr(self, 'nametag'):
self.notify.warning('no nametag attributed, but would have been used')
else:
2015-06-24 11:32:30 -05:00
self.nametag.setColorCode(self.playerType)
2015-03-03 16:10:12 -06:00
def isUnderstandable(self):
return self.understandable
def setDNAString(self, dnaString):
pass
def setDNA(self, dna):
pass
def getAvatarScale(self):
return self.scale
def setAvatarScale(self, scale):
if self.scale != scale:
self.scale = scale
self.getGeomNode().setScale(scale)
self.setHeight(self.height)
def adjustNametag3d(self, parentScale = 1.0):
self.nametag3d.setPos(0, 0, self.height + 0.5)
def getHeight(self):
return self.height
def setHeight(self, height):
self.height = height
self.adjustNametag3d()
if self.collTube:
self.collTube.setPointB(0, 0, height - self.getRadius())
if self.collNodePath:
self.collNodePath.forceRecomputeBounds()
def getRadius(self):
return OTPGlobals.AvatarDefaultRadius
def getName(self):
return self.name
def getType(self):
return self.avatarType
def setName(self, name):
2015-07-01 05:15:05 -05:00
if hasattr(self, 'isDisguised') and self.isDisguised:
return
2015-03-03 16:10:12 -06:00
self.name = name
2015-07-01 05:15:05 -05:00
2015-03-03 16:10:12 -06:00
if hasattr(self, 'nametag'):
2015-07-01 05:15:05 -05:00
self.setNametagName()
2015-03-03 16:10:12 -06:00
def setDisplayName(self, str):
if hasattr(self, 'isDisguised'):
if self.isDisguised:
return
2015-07-01 05:15:05 -05:00
self.setNametagName(str)
2015-07-05 18:59:25 -05:00
2015-07-01 05:15:05 -05:00
def setNametagName(self, name=None):
if not name:
name = self.name
2015-07-05 18:59:25 -05:00
2015-07-03 10:00:25 -05:00
self.nametag.setName(name)
2015-07-01 05:15:05 -05:00
if hasattr(self, 'adminAccess') and self.isAdmin():
access = self.getAdminAccess()
if access in OTPLocalizer.AccessToString:
name += '\n\x01shadow\x01%s\x02' % OTPLocalizer.AccessToString[access]
2015-07-03 10:00:25 -05:00
self.nametag.setDisplayName(name)
2015-03-03 16:10:12 -06:00
def getFont(self):
return self.__font
def setFont(self, font):
self.__font = font
self.nametag.setFont(font)
2015-06-24 11:32:30 -05:00
2015-03-03 16:10:12 -06:00
def getStyle(self):
return self.style
def setStyle(self, style):
self.style = style
def getDialogueArray(self):
return None
def playCurrentDialogue(self, dialogue, chatFlags, interrupt = 1):
if interrupt and self.__currentDialogue is not None:
self.__currentDialogue.stop()
self.__currentDialogue = dialogue
if dialogue:
base.playSfx(dialogue, node=self)
elif chatFlags & CFSpeech != 0 and self.nametag.getNumChatPages() > 0:
2015-06-24 11:32:30 -05:00
self.playDialogueForString(self.nametag.getChat())
2015-03-03 16:10:12 -06:00
if self.soundChatBubble != None:
base.playSfx(self.soundChatBubble, node=self)
def playDialogueForString(self, chatString):
searchString = chatString.lower()
if searchString.find(OTPLocalizer.DialogSpecial) >= 0:
type = 'special'
elif searchString.find(OTPLocalizer.DialogExclamation) >= 0:
type = 'exclamation'
elif searchString.find(OTPLocalizer.DialogQuestion) >= 0:
type = 'question'
elif random.randint(0, 1):
type = 'statementA'
else:
type = 'statementB'
stringLength = len(chatString)
if stringLength <= OTPLocalizer.DialogLength1:
length = 1
elif stringLength <= OTPLocalizer.DialogLength2:
length = 2
elif stringLength <= OTPLocalizer.DialogLength3:
length = 3
else:
length = 4
self.playDialogue(type, length)
def playDialogue(self, type, length):
dialogueArray = self.getDialogueArray()
if dialogueArray == None:
return
sfxIndex = None
if type == 'statementA' or type == 'statementB':
if length == 1:
sfxIndex = 0
elif length == 2:
sfxIndex = 1
elif length >= 3:
sfxIndex = 2
elif type == 'question':
sfxIndex = 3
elif type == 'exclamation':
sfxIndex = 4
elif type == 'special':
sfxIndex = 5
else:
notify.error('unrecognized dialogue type: ', type)
if sfxIndex != None and sfxIndex < len(dialogueArray) and dialogueArray[sfxIndex] != None:
base.playSfx(dialogueArray[sfxIndex], node=self)
return
def getDialogueSfx(self, type, length):
retval = None
dialogueArray = self.getDialogueArray()
if dialogueArray == None:
return
sfxIndex = None
if type == 'statementA' or type == 'statementB':
if length == 1:
sfxIndex = 0
elif length == 2:
sfxIndex = 1
elif length >= 3:
sfxIndex = 2
elif type == 'question':
sfxIndex = 3
elif type == 'exclamation':
sfxIndex = 4
elif type == 'special':
sfxIndex = 5
else:
notify.error('unrecognized dialogue type: ', type)
if sfxIndex != None and sfxIndex < len(dialogueArray) and dialogueArray[sfxIndex] != None:
retval = dialogueArray[sfxIndex]
return retval
def setChatAbsolute(self, chatString, chatFlags, dialogue=None, interrupt=1):
self.clearChat()
2015-06-24 11:32:30 -05:00
self.nametag.setChat(chatString, chatFlags)
2015-03-03 16:10:12 -06:00
self.playCurrentDialogue(dialogue, chatFlags, interrupt)
def displayTalk(self, chatString):
if not base.localAvatar.isIgnored(self.doId):
self.clearChat()
if ChatUtil.isThought(chatString):
chatString = ChatUtil.removeThoughtPrefix(chatString)
self.nametag.setChat(chatString, CFThought)
2015-03-03 16:10:12 -06:00
else:
2015-06-24 11:32:30 -05:00
self.nametag.setChat(chatString, CFSpeech | CFTimeout)
2015-03-03 16:10:12 -06:00
def clearChat(self):
2015-06-24 11:32:30 -05:00
self.nametag.clearChat()
2015-03-03 16:10:12 -06:00
def getNameVisible(self):
return self.__nameVisible
def setNameVisible(self, bool):
self.__nameVisible = bool
if bool:
self.showName()
if not bool:
self.hideName()
def hideName(self):
nametag3d = self.nametag.getNametag3d()
nametag3d.setContents(Nametag.CSpeech | Nametag.CThought)
2015-03-03 16:10:12 -06:00
def showName(self):
if self.__nameVisible and (not self.ghostMode):
nametag3d = self.nametag.getNametag3d()
nametag3d.setContents(Nametag.CName | Nametag.CSpeech | Nametag.CThought)
2015-03-03 16:10:12 -06:00
def hideNametag2d(self):
nametag2d = self.nametag.getNametag2d()
2015-06-24 11:32:30 -05:00
self.nametag2dContents = 0
nametag2d.setContents(self.nametag2dContents & self.nametag2dDist)
2015-03-03 16:10:12 -06:00
def showNametag2d(self):
nametag2d = self.nametag.getNametag2d()
2015-06-24 11:32:30 -05:00
self.nametag2dContents = self.nametag2dNormalContents
if self.ghostMode:
self.nametag2dContents = Nametag.CSpeech
nametag2d.setContents(self.nametag2dContents & self.nametag2dDist)
2015-03-03 16:10:12 -06:00
def hideNametag3d(self):
nametag3d = self.nametag.getNametag3d()
nametag3d.setContents(0)
2015-03-03 16:10:12 -06:00
def showNametag3d(self):
nametag3d = self.nametag.getNametag3d()
if self.__nameVisible and (not self.ghostMode):
nametag3d.setContents(Nametag.CName | Nametag.CSpeech | Nametag.CThought)
2015-03-03 16:10:12 -06:00
else:
nametag3d.setContents(0)
2015-03-03 16:10:12 -06:00
def setPickable(self, flag):
self.nametag.setActive(flag)
def clickedNametag(self):
MagicWordManager.lastClickedNametag = self
2015-06-24 11:32:30 -05:00
if self.nametag.hasButton():
2015-03-03 16:10:12 -06:00
self.advancePageNumber()
2015-06-24 11:32:30 -05:00
elif self.nametag.isActive():
2015-03-03 16:10:12 -06:00
messenger.send('clickedNametag', [self])
def setPageChat(self, addressee, paragraph, message, quitButton,
extraChatFlags=None, dialogueList=[], pageButton=True):
2015-03-03 16:10:12 -06:00
self.__chatAddressee = addressee
self.__chatPageNumber = None
self.__chatParagraph = paragraph
self.__chatMessage = message
2015-06-24 11:32:30 -05:00
if extraChatFlags is None:
self.__chatFlags = CFSpeech
else:
self.__chatFlags = CFSpeech | extraChatFlags
2015-03-03 16:10:12 -06:00
self.__chatDialogueList = dialogueList
self.__chatSet = 0
self.__chatLocal = 0
self.__updatePageChat()
if addressee == base.localAvatar.doId:
if pageButton:
self.__chatFlags |= CFPageButton
2015-06-24 11:32:30 -05:00
if quitButton == None:
self.__chatFlags |= CFNoQuitButton
elif quitButton:
self.__chatFlags |= CFQuitButton
2015-03-03 16:10:12 -06:00
self.b_setPageNumber(self.__chatParagraph, 0)
def setLocalPageChat(self, message, quitButton, extraChatFlags=None,
dialogueList=[]):
2015-03-03 16:10:12 -06:00
self.__chatAddressee = base.localAvatar.doId
self.__chatPageNumber = None
self.__chatParagraph = None
self.__chatMessage = message
2015-06-24 11:32:30 -05:00
if extraChatFlags is None:
self.__chatFlags = CFSpeech
else:
self.__chatFlags = CFSpeech | extraChatFlags
2015-03-03 16:10:12 -06:00
self.__chatDialogueList = dialogueList
self.__chatSet = 1
self.__chatLocal = 1
self.__chatFlags |= CFPageButton
2015-06-24 11:32:30 -05:00
if quitButton == None:
self.__chatFlags |= CFNoQuitButton
elif quitButton:
self.__chatFlags |= CFQuitButton
2015-03-03 16:10:12 -06:00
if len(dialogueList) > 0:
dialogue = dialogueList[0]
else:
dialogue = None
self.clearChat()
self.setChatAbsolute(message, self.__chatFlags, dialogue)
self.setPageNumber(None, 0)
def setPageNumber(self, paragraph, pageNumber, timestamp=None):
if timestamp is None:
2015-03-03 16:10:12 -06:00
elapsed = 0.0
else:
elapsed = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
self.__chatPageNumber = [paragraph, pageNumber]
self.__updatePageChat()
if hasattr(self, 'uniqueName'):
if pageNumber >= 0:
messenger.send(self.uniqueName('nextChatPage'), [pageNumber, elapsed])
else:
messenger.send(self.uniqueName('doneChatPage'), [elapsed])
elif pageNumber >= 0:
messenger.send('nextChatPage', [pageNumber, elapsed])
else:
messenger.send('doneChatPage', [elapsed])
def advancePageNumber(self):
if (self.__chatAddressee == base.localAvatar.doId) and (
self.__chatPageNumber is not None) and (
self.__chatPageNumber[0] == self.__chatParagraph):
2015-03-03 16:10:12 -06:00
pageNumber = self.__chatPageNumber[1]
if pageNumber >= 0:
pageNumber += 1
if pageNumber >= self.nametag.getNumChatPages():
pageNumber = -1
if self.__chatLocal:
self.setPageNumber(self.__chatParagraph, pageNumber)
else:
self.b_setPageNumber(self.__chatParagraph, pageNumber)
def __updatePageChat(self):
if (self.__chatPageNumber is not None) and (
self.__chatPageNumber[0] == self.__chatParagraph):
2015-03-03 16:10:12 -06:00
pageNumber = self.__chatPageNumber[1]
if pageNumber >= 0:
if not self.__chatSet:
if len(self.__chatDialogueList) > 0:
dialogue = self.__chatDialogueList[0]
else:
dialogue = None
self.setChatAbsolute(self.__chatMessage, self.__chatFlags, dialogue)
self.__chatSet = 1
if pageNumber < self.nametag.getNumChatPages():
2015-06-24 11:32:30 -05:00
self.nametag.setPageNumber(pageNumber)
2015-03-03 16:10:12 -06:00
if pageNumber > 0:
if len(self.__chatDialogueList) > pageNumber:
dialogue = self.__chatDialogueList[pageNumber]
else:
dialogue = None
self.playCurrentDialogue(dialogue, self.__chatFlags)
else:
self.clearChat()
else:
self.clearChat()
def getAirborneHeight(self):
height = self.getPos(self.shadowPlacer.shadowNodePath)
return height.getZ() + 0.025
def initializeNametag3d(self):
self.deleteNametag3d()
nametagNode = self.nametag.getNametag3d()
self.nametagNodePath = self.nametag3d.attachNewNode(nametagNode)
2015-06-24 11:32:30 -05:00
iconNodePath = self.nametag.getNameIcon()
2015-03-03 16:10:12 -06:00
for cJoint in self.getNametagJoints():
cJoint.clearNetTransforms()
cJoint.addNetTransform(nametagNode)
def deleteNametag3d(self):
if self.nametagNodePath:
self.nametagNodePath.removeNode()
self.nametagNodePath = None
def initializeBodyCollisions(self, collIdStr):
self.collTube = CollisionTube(0, 0, 0.5, 0, 0, self.height - self.getRadius(), self.getRadius())
self.collNode = CollisionNode(collIdStr)
self.collNode.addSolid(self.collTube)
self.collNodePath = self.attachNewNode(self.collNode)
if self.ghostMode:
self.collNode.setCollideMask(OTPGlobals.GhostBitmask)
else:
self.collNode.setCollideMask(OTPGlobals.WallBitmask)
def stashBodyCollisions(self):
if hasattr(self, 'collNodePath'):
self.collNodePath.stash()
def unstashBodyCollisions(self):
if hasattr(self, 'collNodePath'):
self.collNodePath.unstash()
def disableBodyCollisions(self):
if hasattr(self, 'collNodePath'):
self.collNodePath.removeNode()
del self.collNodePath
self.collTube = None
return
def addActive(self):
if base.wantNametags:
try:
Avatar.ActiveAvatars.remove(self)
except ValueError:
pass
Avatar.ActiveAvatars.append(self)
self.nametag.manage(base.marginManager)
2015-06-24 11:32:30 -05:00
self.accept(self.nametag.getUniqueId(), self.clickedNametag)
2015-03-03 16:10:12 -06:00
def removeActive(self):
if base.wantNametags:
try:
Avatar.ActiveAvatars.remove(self)
except ValueError:
pass
self.nametag.unmanage(base.marginManager)
2015-06-24 11:32:30 -05:00
self.ignore(self.nametag.getUniqueId())
2015-03-03 16:10:12 -06:00
def loop(self, animName, restart = 1, partName = None, fromFrame = None, toFrame = None):
return Actor.loop(self, animName, restart, partName, fromFrame, toFrame)
def createTalkSequence(self, speech, waitTime, name='talkSequence'):
sequence = Sequence(name=name)
2015-03-03 16:10:12 -06:00
for text in speech:
sequence.append(Func(self.setChatAbsolute, text, CFSpeech))
sequence.append(Wait(len(text.split(' '))))
sequence.append(Func(self.clearChat))
sequence.append(Wait(waitTime))
return sequence
2015-03-03 16:10:12 -06:00
2015-05-24 23:49:39 -05:00
@magicWord(category=CATEGORY_COMMUNITY_MANAGER, types=[])
2015-03-03 16:10:12 -06:00
def target():
"""
Returns the current Spellbook target.
"""
target = spellbook.getTarget()
2015-07-17 18:28:36 -05:00
return 'Target: %s-%d [%d]' % (target.getName(), int(target.doId), int(target.getAdminAccess()))