diff --git a/toontown/hood/GenericAnimatedProp.py b/toontown/hood/GenericAnimatedProp.py index d439b675..5672470f 100755 --- a/toontown/hood/GenericAnimatedProp.py +++ b/toontown/hood/GenericAnimatedProp.py @@ -8,12 +8,12 @@ from toontown.hood import HoodUtil class GenericAnimatedProp(AnimatedProp.AnimatedProp): notify = DirectNotifyGlobal.directNotify.newCategory('GenericAnimatedProp') - AnimsUsingWav = [] def __init__(self, node): AnimatedProp.AnimatedProp.__init__(self, node) self.origAnimNameToSound = {} code = node.getTag('DNACode') + if code.startswith('interactive_prop_'): pathStr = code[len('interactive_prop_'):].split('__')[0] elif code.startswith('animated_prop_generic_'): @@ -23,10 +23,12 @@ class GenericAnimatedProp(AnimatedProp.AnimatedProp): nextUnderscore = tempStr.find('_') finalStr = tempStr[nextUnderscore + 1:] pathStr = finalStr.split('__')[0] + phaseDelimeter = len('phase_') + pathStr[len('phase_'):].find('_') phaseStr = pathStr[:phaseDelimeter] pathTokens = pathStr[phaseDelimeter + 1:].split('_') self.path = phaseStr + for path in pathTokens: self.path += '/' self.path += path @@ -39,6 +41,11 @@ class GenericAnimatedProp(AnimatedProp.AnimatedProp): def delete(self): AnimatedProp.AnimatedProp.delete(self) + + if hasattr(self, 'soundNode'): + self.soundNode.cleanup() + del self.soundNode + self.node.cleanup() del self.node del self.trashcan @@ -67,6 +74,7 @@ class GenericAnimatedProp(AnimatedProp.AnimatedProp): self.hoodId = ToontownGlobals.ToontownCentral fullString = str(node) splits = fullString.split('/') + if len(splits) >= 5: visId = int(splits[4]) self.visId = visId @@ -80,28 +88,22 @@ class GenericAnimatedProp(AnimatedProp.AnimatedProp): def createSoundInterval(self, origAnimNameWithPath, maximumDuration): if not hasattr(base, 'localAvatar'): return Sequence() - sfxVolume = 1.0 - cutoff = 45 + if not hasattr(self, 'soundPath'): self.soundPath = self.path.replace('/models/char', '/audio/sfx') + origAnimName = origAnimNameWithPath.split('/')[-1] - theSound = self.origAnimNameToSound.get(origAnimName) - if not theSound: - soundfile = origAnimName.replace('tt_a_ara', 'tt_s_ara') - fullPath = self.soundPath + '/' + soundfile - if origAnimName in self.AnimsUsingWav: - theSound = loader.loadSfx(fullPath + '.ogg') - else: - theSound = loader.loadSfx(fullPath + '.ogg') - self.origAnimNameToSound[origAnimName] = theSound - if theSound: - soundDur = theSound.length() - if maximumDuration < soundDur: - if base.config.GetBool('interactive-prop-info', False): - if self.visId == localAvatar.zoneId and origAnimName != 'tt_a_ara_dga_hydrant_idleIntoFight': - self.notify.warning('anim %s had duration of %s while sound has duration of %s' % (origAnimName, maximumDuration, soundDur)) - soundDur = maximumDuration - result = SoundInterval(theSound, node=self.node, listenerNode=base.localAvatar, volume=sfxVolume, cutOff=cutoff, startTime=0, duration=soundDur) - else: - result = Sequence() - return result + sound = self.origAnimNameToSound.get(origAnimName) + + if not sound: + sound = loader.loadSfx('%s/%s.ogg' % (self.soundPath, origAnimName.replace('tt_a_ara', 'tt_s_ara'))) + self.origAnimNameToSound[origAnimName] = sound + + if sound: + if not hasattr(self, 'soundNode'): + self.soundNode = render.attachNewNode('Sound Node') + self.soundNode.setPos(self.trashcan.getBounds().getCenter()) + + return SoundInterval(sound, node=self.soundNode, listenerNode=base.localAvatar, volume=1.0, cutOff=45, startTime=0, duration=min(sound.length(), maximumDuration)) + + return Sequence() \ No newline at end of file diff --git a/toontown/hood/HydrantInteractiveProp.py b/toontown/hood/HydrantInteractiveProp.py index 15463bce..b279a33a 100755 --- a/toontown/hood/HydrantInteractiveProp.py +++ b/toontown/hood/HydrantInteractiveProp.py @@ -111,8 +111,8 @@ class HydrantInteractiveProp(InteractiveAnimatedProp.InteractiveAnimatedProp): if self.hasOverrideIval(origAnimName): result.append(Func(self.showWater)) - anim = self.createAnimIval('fight0' if 'fightBoost' in origAnimName else 'fight1') - result.append(anim) + animAndSound = self.createAnimAndSoundIval('fight0' if 'fightBoost' in origAnimName else 'fight1') + result.append(animAndSound) result.append(Func(self.hideWater)) - return result + return result \ No newline at end of file diff --git a/toontown/hood/InteractiveAnimatedProp.py b/toontown/hood/InteractiveAnimatedProp.py index 18123b11..84d57f88 100755 --- a/toontown/hood/InteractiveAnimatedProp.py +++ b/toontown/hood/InteractiveAnimatedProp.py @@ -1,13 +1,11 @@ -import math -import random -import GenericAnimatedProp -from direct.actor import Actor -from direct.interval.IntervalGlobal import Sequence, ActorInterval, Wait, Func, Parallel -from direct.fsm import FSM -from direct.showbase.PythonUtil import weightedChoice from pandac.PandaModules import TextNode, Vec3 +from direct.actor import Actor +from direct.fsm import FSM +from direct.interval.IntervalGlobal import Sequence, ActorInterval, Wait, Func, SoundInterval, Parallel +from direct.showbase.PythonUtil import weightedChoice from toontown.toonbase import ToontownGlobals -from toontown.hood import ZoneUtil +import GenericAnimatedProp +import math, random def clearPythonIvals(ival): if hasattr(ival, 'function'): @@ -17,8 +15,6 @@ def clearPythonIvals(ival): clearPythonIvals(oneIval) ival.pythonIvals = [] - return - class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): ZoneToIdles = {} @@ -44,6 +40,7 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): self.okToStartNextAnim = False cellIndexStr = node.getTag('DNACellIndex') self.cellIndex = ord(cellIndexStr) + self.origAnimNameToSound = {} self.lastPlayingAnimPhase = 0 self.buildingsMakingMeSad = set() GenericAnimatedProp.GenericAnimatedProp.__init__(self, node) @@ -67,20 +64,25 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): 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 @@ -95,14 +97,17 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): 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 @@ -113,6 +118,7 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): def createIdleInterval(self): result = Sequence() + if self.numIdles >= 3: numberOfAnimsAbove2 = self.numIdles - 2 for rareIdle in xrange(2, self.numIdles): @@ -152,26 +158,28 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): def createBattleCheerInterval(self): result = Sequence() + for i in xrange(self.numFightAnims): animKey = 'fight%d' % i - animIval = self.createAnimIval(animKey) + animAndSoundIval = self.createAnimAndSoundIval(animKey) origAnimName = self.node.getAnimFilename(animKey).split('/')[-1] if self.hasOverrideIval(origAnimName): result.append(self.getOverrideIval(origAnimName)) elif self.hasSpecialIval(origAnimName): - result.append(Parallel(animIval, self.getSpecialIval(origAnimName))) + result.append(Parallel(animAndSoundIval, self.getSpecialIval(origAnimName))) else: - result.append(animIval) + result.append(animAndSoundIval) 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: - result = self.createAnimIval('sad') + result = self.createAnimAndSoundIval('sad') return result def hasSpecialIval(self, origAnimName): @@ -188,18 +196,21 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): def createVictoryInterval(self): result = Sequence() + if self.hoodId in self.ZoneToVictoryAnims: - animIval = self.createAnimIval('victory') - result.append(animIval) + animAndSoundIval = self.createAnimAndSoundIval('victory') + result.append(animAndSoundIval) + 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') self.node.stop() self.node.pose('idle0', 0) - self.idleInterval.loop() + self.requestIdleOrSad() else: self.notify.debug('props do not buff battles') self.node.stop() @@ -215,6 +226,7 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): 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: @@ -248,6 +260,7 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): def chooseIdleAnimToRun(self): result = self.numIdles - 1 + if base.config.GetBool('randomize-interactive-idles', True): pairs = [] for i in xrange(self.numIdles): @@ -261,47 +274,54 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): 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.curIval = Wait(3) self.notify.debug('false self.okToStartNextAnim=%s' % self.okToStartNextAnim) - return - def createIdleAnimInterval(self, whichIdleAnim, startingTime = 0): + def createIdleAnimAndSoundInterval(self, whichIdleAnim, startingTime = 0): 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] + + soundIval = self.createSoundInterval(origAnimName, animIvalDuration) + soundIvalDuration = soundIval.getDuration() + if self.hasSpecialIval(origAnimName): specialIval = self.getSpecialIval(origAnimName) - return Parallel(animIval, specialIval) + return Parallel(animIval, soundIval, specialIval) else: - return animIval + return Parallel(animIval, soundIval) 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 - idleAnim = self.createIdleAnimInterval(whichIdleAnim) - result = Sequence(idleAnim, Wait(self.IdlePauseTime), Func(self.startNextIdleAnim)) + + idleAnimAndSound = self.createIdleAnimAndSoundInterval(whichIdleAnim) + result = Sequence(idleAnimAndSound, Wait(self.IdlePauseTime), Func(self.startNextIdleAnim)) + 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] @@ -314,17 +334,14 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): pauseTime = random.randrange(minPauseTime, maxPauseTime + 1) result = Sequence() for i in xrange(numberOfLoops): - result.append(idleAnim) + result.append(idleAnimAndSound) 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) - self.request('Faceoff') + return result def gotoBattleCheer(self): self.notify.debugStateCall(self) @@ -345,22 +362,14 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): 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: @@ -373,82 +382,74 @@ class InteractiveAnimatedProp(GenericAnimatedProp.GenericAnimatedProp, FSM.FSM): return result - def createFaceoffInterval(self): - result = Sequence() - if self.lastIdleAnimName: - whichIdleAnim = self.calcWhichIdleAnim(self.lastIdleAnimName) - anim = self.createIdleAnimInterval(whichIdleAnim, self.lastIdleTime) - result.append(anim) - idleIntoFightIval = self.createAnimIval('idleIntoFight') - 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 + return self.ZoneToIdles[self.hoodId][whichIdleAnim][3] + return None 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 + anim = self.ZoneToIdles[self.hoodId][whichIdleAnim] - def createAnimIval(self, animKey): + return anim[0] if isinstance(anim, tuple) else anim + + def createAnimAndSoundIval(self, animKey): animIval = self.node.actorInterval(animKey) animIvalDuration = animIval.getDuration() origAnimName = self.node.getAnimFilename(animKey) + soundIval = self.createSoundInterval(origAnimName, animIvalDuration) + soundIvalDuration = soundIval.getDuration() + if self.hasSpecialIval(origAnimName): specialIval = self.getSpecialIval(origAnimName) - return Parallel(animIval, specialIval) + return Parallel(animIval, soundIval, specialIval) else: - return animIval + return Parallel(animIval, soundIval) def clearCurIval(self): if self.curIval: self.curIval.finish() + clearPythonIvals(self.curIval) - self.curIval = None + self.curIval = None \ No newline at end of file diff --git a/toontown/hood/MailboxInteractiveProp.py b/toontown/hood/MailboxInteractiveProp.py index fa2a315f..e9db742c 100755 --- a/toontown/hood/MailboxInteractiveProp.py +++ b/toontown/hood/MailboxInteractiveProp.py @@ -69,9 +69,6 @@ class MailboxInteractiveProp(InteractiveAnimatedProp.InteractiveAnimatedProp): IdlePauseTime = base.config.GetFloat('prop-idle-pause-time', 0.0) - def __init__(self, node): - InteractiveAnimatedProp.InteractiveAnimatedProp.__init__(self, node) - def setupActor(self, node): self.pieActor = Actor.Actor('phase_5/models/char/tt_r_prp_ext_piePackage', {'fightBoost': 'phase_5/models/char/tt_a_prp_ext_piePackage_fightBoost'}) self.pieActor.reparentTo(self.node) diff --git a/toontown/hood/TrashcanInteractiveProp.py b/toontown/hood/TrashcanInteractiveProp.py index 1ac6c658..25689e74 100755 --- a/toontown/hood/TrashcanInteractiveProp.py +++ b/toontown/hood/TrashcanInteractiveProp.py @@ -66,7 +66,4 @@ class TrashcanInteractiveProp(InteractiveAnimatedProp.InteractiveAnimatedProp): ToontownGlobals.TheBrrrgh: ('tt_a_ara_tbr_trashcan_fightBoost', 'tt_a_ara_tbr_trashcan_fightCheer', 'tt_a_ara_tbr_trashcan_fightIdle'), ToontownGlobals.DonaldsDreamland: ('tt_a_ara_ddl_trashcan_fightBoost', 'tt_a_ara_ddl_trashcan_fightCheer', 'tt_a_ara_ddl_trashcan_fightIdle')} - IdlePauseTime = base.config.GetFloat('prop-idle-pause-time', 0.0) - - def __init__(self, node): - InteractiveAnimatedProp.InteractiveAnimatedProp.__init__(self, node) \ No newline at end of file + IdlePauseTime = base.config.GetFloat('prop-idle-pause-time', 0.0) \ No newline at end of file