Poodletooth-iLand/toontown/hood/InteractiveAnimatedProp.py

455 lines
17 KiB
Python
Raw Normal View History

2015-03-03 22:10:12 +00:00
import math
import random
import GenericAnimatedProp
from direct.actor import Actor
2015-04-10 13:34:44 +00:00
from direct.interval.IntervalGlobal import Sequence, ActorInterval, Wait, Func, Parallel
2015-03-03 22:10:12 +00:00
from direct.fsm import FSM
from direct.showbase.PythonUtil import weightedChoice
from pandac.PandaModules import TextNode, Vec3
from toontown.toonbase import ToontownGlobals
from toontown.hood import ZoneUtil
def clearPythonIvals(ival):
if hasattr(ival, 'function'):
ival.function = None
if hasattr(ival, 'pythonIvals'):
for oneIval in ival.pythonIvals:
clearPythonIvals(oneIval)
ival.pythonIvals = []
return
class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM):
ZoneToIdles = {}
ZoneToIdleIntoFightAnims = {}
ZoneToFightAnims = {}
ZoneToVictoryAnims = {}
ZoneToSadAnims = {}
IdlePauseTime = base.config.GetFloat('prop-idle-pause-time', 0.0)
HpTextGenerator = TextNode('HpTextGenerator')
BattleCheerText = '+'
2015-04-09 17:17:24 +00:00
def __init__(self, node):
2015-03-03 22:10:12 +00:00
FSM.FSM.__init__(self, 'InteractiveProp-%s' % str(node))
self.numIdles = 0
self.numFightAnims = 0
self.idleInterval = None
self.battleCheerInterval = None
self.sadInterval = None
self.victoryInterval = None
self.lastIdleAnimName = ''
self.lastIdleTime = 0
self.curIval = None
self.okToStartNextAnim = False
cellIndexStr = node.getTag('DNACellIndex')
self.cellIndex = ord(cellIndexStr)
self.lastPlayingAnimPhase = 0
self.buildingsMakingMeSad = set()
GenericAnimatedProp.GenericAnimatedProp.__init__(self, node)
def delete(self):
self.exit()
GenericAnimatedProp.GenericAnimatedProp.delete(self)
self.idleInterval = None
self.battleCheerInterval = None
self.sadInterval = None
self.victoryInterval = None
def getCellIndex(self):
return self.cellIndex
def playBattleCheerAnim(self):
self.node.loop('battleCheer')
def setupActor(self, node):
if self.hoodId in self.ZoneToIdles:
self.numIdles = len(self.ZoneToIdles[self.hoodId])
if self.hoodId in self.ZoneToFightAnims:
self.numFightAnims = len(self.ZoneToFightAnims[self.hoodId])
self.idleInterval = None
anim = node.getTag('DNAAnim')
self.trashcan = Actor.Actor(node, copy=0)
self.trashcan.reparentTo(node)
animDict = {}
animDict['anim'] = '%s/%s' % (self.path, anim)
for i in xrange(self.numIdles):
baseAnim = self.ZoneToIdles[self.hoodId][i]
if isinstance(baseAnim, tuple):
baseAnim = baseAnim[0]
animStr = self.path + '/' + baseAnim
animKey = 'idle%d' % i
animDict[animKey] = animStr
settleName = self.getSettleName(i)
if settleName:
settleStr = self.path + '/' + settleName
settleKey = 'settle%d' % i
animDict[settleKey] = settleStr
for i in xrange(self.numFightAnims):
animStr = self.path + '/' + self.ZoneToFightAnims[self.hoodId][i]
animKey = 'fight%d' % i
animDict[animKey] = animStr
if self.hoodId in self.ZoneToIdleIntoFightAnims:
animStr = self.path + '/' + self.ZoneToIdleIntoFightAnims[self.hoodId]
animKey = 'idleIntoFight'
animDict[animKey] = animStr
if self.hoodId in self.ZoneToIdleIntoFightAnims:
animStr = self.path + '/' + self.ZoneToVictoryAnims[self.hoodId]
animKey = 'victory'
animDict[animKey] = animStr
if self.hoodId in self.ZoneToSadAnims:
animStr = self.path + '/' + self.ZoneToSadAnims[self.hoodId]
animKey = 'sad'
animDict[animKey] = animStr
self.trashcan.loadAnims(animDict)
self.trashcan.pose('anim', 0)
self.node = self.trashcan
self.idleInterval = self.createIdleInterval()
self.battleCheerInterval = self.createBattleCheerInterval()
self.victoryInterval = self.createVictoryInterval()
self.sadInterval = self.createSadInterval()
def createIdleInterval(self):
result = Sequence()
if self.numIdles >= 3:
numberOfAnimsAbove2 = self.numIdles - 2
for rareIdle in xrange(2, self.numIdles):
for i in xrange(2):
result.append(ActorInterval(self.node, 'idle0'))
result.append(Wait(self.IdlePauseTime))
result.append(ActorInterval(self.node, 'idle1'))
result.append(Wait(self.IdlePauseTime))
result.append(ActorInterval(self.node, 'idle%d' % rareIdle))
result.append(Wait(self.IdlePauseTime))
else:
for i in xrange(self.numIdles):
result.append(ActorInterval(self.node, 'idle%d' % i))
self.notify.debug('idle interval=%s' % result)
return result
def createBattleCheerText(self):
self.HpTextGenerator.setFont(ToontownGlobals.getSignFont())
self.HpTextGenerator.setText(self.BattleCheerText)
self.HpTextGenerator.clearShadow()
self.HpTextGenerator.setAlign(TextNode.ACenter)
r = 0
g = 0
b = 1
a = 1
self.HpTextGenerator.setTextColor(r, g, b, a)
self.hpTextNode = self.HpTextGenerator.generate()
self.hpText = self.node.attachNewNode(self.hpTextNode)
self.hpText.setScale(1)
self.hpText.setBillboardPointEye()
self.hpText.setBin('fixed', 100)
self.hpText.setPos(0, 0, 4)
self.hpText.hide()
def createBattleCheerInterval(self):
result = Sequence()
for i in xrange(self.numFightAnims):
animKey = 'fight%d' % i
2015-04-10 13:34:44 +00:00
animIval = self.createAnimIval(animKey)
2015-03-03 22:10:12 +00:00
origAnimName = self.node.getAnimFilename(animKey).split('/')[-1]
if self.hasOverrideIval(origAnimName):
result.append(self.getOverrideIval(origAnimName))
elif self.hasSpecialIval(origAnimName):
2015-04-10 13:34:44 +00:00
result.append(Parallel(animIval, self.getSpecialIval(origAnimName)))
2015-03-03 22:10:12 +00:00
else:
2015-04-10 13:34:44 +00:00
result.append(animIval)
2015-03-03 22:10:12 +00:00
self.createBattleCheerText()
battleCheerTextIval = Sequence(Func(self.hpText.show), self.hpText.posInterval(duration=4.0, pos=Vec3(0, 0, 7), startPos=(0, 0, 3)), Func(self.hpText.hide))
ivalWithText = Parallel(battleCheerTextIval, result)
return ivalWithText
def createSadInterval(self):
result = Sequence()
if self.hoodId in self.ZoneToSadAnims:
2015-04-10 13:34:44 +00:00
result = self.createAnimIval('sad')
2015-03-03 22:10:12 +00:00
return result
def hasSpecialIval(self, origAnimName):
return False
def getSpecialIval(self, origAnimName):
return Sequence()
def hasOverrideIval(self, origAnimName):
return False
def getOverrideIval(self, origAnimName):
return Sequence()
def createVictoryInterval(self):
result = Sequence()
if self.hoodId in self.ZoneToVictoryAnims:
2015-04-10 13:34:44 +00:00
animIval = self.createAnimIval('victory')
result.append(animIval)
2015-03-03 22:10:12 +00:00
return result
def enter(self):
GenericAnimatedProp.GenericAnimatedProp.enter(self)
if base.config.GetBool('props-buff-battles', True):
self.notify.debug('props buff battles is true')
2015-04-09 17:17:24 +00:00
self.node.stop()
self.node.pose('idle0', 0)
self.idleInterval.loop()
2015-03-03 22:10:12 +00:00
else:
self.notify.debug('props do not buff battles')
self.node.stop()
self.node.pose('idle0', 0)
def exit(self):
self.okToStartNextAnim = False
self.notify.debug('%s %d okToStartNextAnim=%s' % (self, self.visId, self.okToStartNextAnim))
GenericAnimatedProp.GenericAnimatedProp.exit(self)
self.request('Off')
def requestIdleOrSad(self):
if not hasattr(self, 'node') or not self.node:
self.notify.warning("requestIdleOrSad returning hasattr(self,'node')=%s" % hasattr(self, 'node'))
return
if self.buildingsMakingMeSad:
self.request('Sad')
else:
self.request('DoIdleAnim')
def enterDoIdleAnim(self):
self.notify.debug('enterDoIdleAnim numIdels=%d' % self.numIdles)
self.okToStartNextAnim = True
self.notify.debug('%s %d okToStartNextAnim=%s' % (self, self.visId, self.okToStartNextAnim))
self.startNextIdleAnim()
def exitDoIdleAnim(self):
self.notify.debug('exitDoIdlesAnim numIdles=%d' % self.numIdles)
self.okToStartNextAnim = False
self.notify.debug('%s %d okToStartNextAnim=%s' % (self, self.visId, self.okToStartNextAnim))
self.calcLastIdleFrame()
self.clearCurIval()
def calcLastIdleFrame(self):
if self.curIval and self.curIval.ivals:
firstIval = self.curIval.ivals[0]
if isinstance(firstIval, ActorInterval):
self.lastIdleFrame = firstIval.getCurrentFrame()
self.lastIdleAnimName = firstIval.animName
elif isinstance(firstIval, Parallel):
for testIval in firstIval.ivals:
if isinstance(firstIval, ActorInterval):
self.lastIdleTime = testIval.getT()
self.lastIdleAnimName = testIval.animName
break
def chooseIdleAnimToRun(self):
result = self.numIdles - 1
if base.config.GetBool('randomize-interactive-idles', True):
pairs = []
for i in xrange(self.numIdles):
reversedChance = self.numIdles - i - 1
pairs.append((math.pow(2, reversedChance), i))
sum = math.pow(2, self.numIdles) - 1
result = weightedChoice(pairs, sum=sum)
self.notify.debug('chooseAnimToRun numIdles=%s pairs=%s result=%s' % (self.numIdles, pairs, result))
else:
result = self.lastPlayingAnimPhase + 1
if result >= len(self.ZoneToIdles[self.hoodId]):
result = 0
return result
def startNextIdleAnim(self):
self.notify.debug('startNextAnim self.okToStartNextAnim=%s' % self.okToStartNextAnim)
if not hasattr(self, 'node') or not self.node:
self.notify.warning("startNextIdleAnim returning hasattr(self,'node')=%s" % hasattr(self, 'node'))
return
self.curIval = None
if self.okToStartNextAnim:
self.notify.debug('got pass okToStartNextAnim')
whichAnim = self.chooseIdleAnimToRun()
if self.visId == localAvatar.zoneId:
self.notify.debug('whichAnim=%s' % whichAnim)
self.lastPlayingAnimPhase = whichAnim
self.curIval = self.createIdleAnimSequence(whichAnim)
self.notify.debug('starting curIval of length %s' % self.curIval.getDuration())
self.curIval.start()
else:
self.curIval = Wait(10)
self.notify.debug('false self.okToStartNextAnim=%s' % self.okToStartNextAnim)
return
2015-04-10 13:34:44 +00:00
def createIdleAnimInterval(self, whichIdleAnim, startingTime = 0):
2015-03-03 22:10:12 +00:00
animIval = self.node.actorInterval('idle%d' % whichIdleAnim, startTime=startingTime)
animIvalDuration = animIval.getDuration()
origAnimName = self.ZoneToIdles[self.hoodId][whichIdleAnim]
if isinstance(origAnimName, tuple):
origAnimName = origAnimName[0]
if self.hasSpecialIval(origAnimName):
specialIval = self.getSpecialIval(origAnimName)
2015-04-10 13:34:44 +00:00
return Parallel(animIval, specialIval)
2015-03-03 22:10:12 +00:00
else:
2015-04-10 13:34:44 +00:00
return animIval
2015-03-03 22:10:12 +00:00
def createIdleAnimSequence(self, whichIdleAnim):
dummyResult = Sequence(Wait(self.IdlePauseTime))
if not hasattr(self, 'node') or not self.node:
self.notify.warning("createIdleAnimSequence returning dummyResult hasattr(self,'node')=%s" % hasattr(self, 'node'))
return dummyResult
2015-04-10 13:34:44 +00:00
idleAnim = self.createIdleAnimInterval(whichIdleAnim)
result = Sequence(idleAnim, Wait(self.IdlePauseTime), Func(self.startNextIdleAnim))
2015-03-03 22:10:12 +00:00
if isinstance(self.ZoneToIdles[self.hoodId][whichIdleAnim], tuple) and len(self.ZoneToIdles[self.hoodId][whichIdleAnim]) > 2:
info = self.ZoneToIdles[self.hoodId][whichIdleAnim]
origAnimName = info[0]
minLoop = info[1]
maxLoop = info[2]
settleAnim = info[3]
minPauseTime = info[4]
maxPauseTime = info[5]
numberOfLoops = random.randrange(minLoop, maxLoop + 1)
pauseTime = random.randrange(minPauseTime, maxPauseTime + 1)
result = Sequence()
for i in xrange(numberOfLoops):
2015-04-10 13:34:44 +00:00
result.append(idleAnim)
2015-03-03 22:10:12 +00:00
if self.getSettleName(whichIdleAnim):
result.append(self.node.actorInterval('settle%d' % whichIdleAnim))
result.append(Wait(pauseTime))
result.append(Func(self.startNextIdleAnim))
return result
def gotoFaceoff(self):
self.notify.debugStateCall(self)
2015-04-09 17:17:24 +00:00
self.request('Faceoff')
2015-03-03 22:10:12 +00:00
def gotoBattleCheer(self):
self.notify.debugStateCall(self)
2015-04-09 17:17:24 +00:00
self.request('BattleCheer')
2015-03-03 22:10:12 +00:00
def gotoIdle(self):
self.notify.debugStateCall(self)
2015-04-09 17:17:24 +00:00
self.request('DoIdleAnim')
2015-03-03 22:10:12 +00:00
def gotoVictory(self):
self.notify.debugStateCall(self)
2015-04-09 17:17:24 +00:00
self.request('Victory')
2015-03-03 22:10:12 +00:00
def gotoSad(self, buildingDoId):
self.notify.debugStateCall(self)
self.buildingsMakingMeSad.add(buildingDoId)
2015-04-09 17:17:24 +00:00
self.request('Sad')
2015-03-03 22:10:12 +00:00
def buildingLiberated(self, buildingDoId):
self.buildingsMakingMeSad.discard(buildingDoId)
if not self.buildingsMakingMeSad:
self.gotoIdle()
def enterFaceoff(self):
self.notify.debugStateCall(self)
self.curIval = self.createFaceoffInterval()
self.curIval.start()
def exitFaceoff(self):
self.notify.debugStateCall(self)
self.curIval.pause()
self.curIval = None
def calcWhichIdleAnim(self, animName):
result = 0
info = self.ZoneToIdles[self.hoodId]
for index, curInfo in enumerate(info):
if isinstance(curInfo, tuple):
if curInfo[0] == animName:
result = index
break
elif isinstance(curInfo, str):
if curInfo == animName:
result = index
breal
return result
def createFaceoffInterval(self):
result = Sequence()
if self.lastIdleAnimName:
whichIdleAnim = self.calcWhichIdleAnim(self.lastIdleAnimName)
2015-04-10 13:34:44 +00:00
anim = self.createIdleAnimInterval(whichIdleAnim, self.lastIdleTime)
result.append(anim)
idleIntoFightIval = self.createAnimIval('idleIntoFight')
2015-03-03 22:10:12 +00:00
result.append(idleIntoFightIval)
result.append(Func(self.gotoBattleCheer))
return result
def enterBattleCheer(self):
self.notify.debugStateCall(self)
self.curIval = self.battleCheerInterval
if self.curIval:
self.curIval.loop()
def exitBattleCheer(self):
self.notify.debugStateCall(self)
if self.curIval:
self.curIval.finish()
self.curIval = None
return
def enterVictory(self):
self.notify.debugStateCall(self)
self.curIval = self.victoryInterval
if self.curIval:
self.curIval.loop()
def exitVictory(self):
self.notify.debugStateCall(self)
if self.curIval:
self.curIval.finish()
self.curIval = None
return
def enterSad(self):
self.notify.debugStateCall(self)
self.curIval = self.sadInterval
if self.curIval:
self.curIval.loop()
def exitSad(self):
self.notify.debugStateCall(self)
if self.curIval:
self.curIval.finish()
self.curIval = None
return
def getSettleName(self, whichIdleAnim):
result = None
if isinstance(self.ZoneToIdles[self.hoodId][whichIdleAnim], tuple) and len(self.ZoneToIdles[self.hoodId][whichIdleAnim]) > 3:
result = self.ZoneToIdles[self.hoodId][whichIdleAnim][3]
return result
def getOrigIdleAnimName(self, whichIdleAnim):
result = None
if isinstance(self.ZoneToIdles[self.hoodId][whichIdleAnim], tuple):
result = self.ZoneToIdles[self.hoodId][whichIdleAnim][0]
else:
result = self.ZoneToIdles[self.hoodId][whichIdleAnim]
return result
2015-04-10 13:34:44 +00:00
def createAnimIval(self, animKey):
2015-03-03 22:10:12 +00:00
animIval = self.node.actorInterval(animKey)
animIvalDuration = animIval.getDuration()
origAnimName = self.node.getAnimFilename(animKey)
if self.hasSpecialIval(origAnimName):
specialIval = self.getSpecialIval(origAnimName)
2015-04-10 13:34:44 +00:00
return Parallel(animIval, specialIval)
2015-03-03 22:10:12 +00:00
else:
2015-04-10 13:34:44 +00:00
return animIval
2015-03-03 22:10:12 +00:00
def clearCurIval(self):
if self.curIval:
self.curIval.finish()
clearPythonIvals(self.curIval)
2015-05-09 17:27:08 +00:00
self.curIval = None