2019-11-02 17:27:54 -05:00
|
|
|
from pandac.PandaModules import *
|
|
|
|
from toontown.toonbase.ToonBaseGlobal import *
|
|
|
|
from direct.interval.IntervalGlobal import *
|
2019-12-30 00:07:56 -06:00
|
|
|
from .DistributedMinigame import *
|
2019-11-02 17:27:54 -05:00
|
|
|
from direct.gui.DirectGui import *
|
|
|
|
from pandac.PandaModules import *
|
|
|
|
from direct.fsm import ClassicFSM, State
|
|
|
|
from direct.fsm import State
|
|
|
|
from toontown.toonbase import ToontownTimer
|
2019-12-30 00:07:56 -06:00
|
|
|
from . import PatternGameGlobals
|
2019-11-02 17:27:54 -05:00
|
|
|
from toontown.toon import ToonHead
|
|
|
|
from toontown.char import CharDNA
|
|
|
|
from toontown.char import Char
|
2019-12-30 00:07:56 -06:00
|
|
|
from . import ArrowKeys
|
2019-11-02 17:27:54 -05:00
|
|
|
import random
|
|
|
|
from toontown.toonbase import ToontownGlobals
|
|
|
|
from toontown.toonbase import TTLocalizer
|
|
|
|
|
|
|
|
class DistributedPatternGame(DistributedMinigame):
|
|
|
|
phase4snd = 'phase_4/audio/sfx/'
|
2020-01-14 13:28:52 -06:00
|
|
|
ButtonSoundNames = (phase4snd + 'm_match_trumpet.ogg',
|
|
|
|
phase4snd + 'm_match_guitar.ogg',
|
|
|
|
phase4snd + 'm_match_drums.ogg',
|
|
|
|
phase4snd + 'm_match_piano.ogg')
|
|
|
|
bgm = 'phase_4/audio/bgm/m_match_bg1.ogg'
|
2019-11-02 17:27:54 -05:00
|
|
|
strWatch = TTLocalizer.PatternGameWatch
|
|
|
|
strGo = TTLocalizer.PatternGameGo
|
|
|
|
strRight = TTLocalizer.PatternGameRight
|
|
|
|
strWrong = TTLocalizer.PatternGameWrong
|
|
|
|
strPerfect = TTLocalizer.PatternGamePerfect
|
|
|
|
strBye = TTLocalizer.PatternGameBye
|
|
|
|
strWaitingOtherPlayers = TTLocalizer.PatternGameWaitingOtherPlayers
|
|
|
|
strPleaseWait = TTLocalizer.PatternGamePleaseWait
|
|
|
|
strRound = TTLocalizer.PatternGameRound
|
|
|
|
minnieAnimNames = ['up',
|
|
|
|
'left',
|
|
|
|
'down',
|
|
|
|
'right']
|
|
|
|
toonAnimNames = ['up',
|
|
|
|
'left',
|
|
|
|
'down',
|
|
|
|
'right',
|
|
|
|
'slip-forward',
|
|
|
|
'slip-backward',
|
|
|
|
'victory']
|
|
|
|
|
|
|
|
def __init__(self, cr):
|
|
|
|
DistributedMinigame.__init__(self, cr)
|
|
|
|
self.gameFSM = ClassicFSM.ClassicFSM('DistributedPatternGame', [State.State('off', self.enterOff, self.exitOff, ['waitForServerPattern']),
|
|
|
|
State.State('waitForServerPattern', self.enterWaitForServerPattern, self.exitWaitForServerPattern, ['showServerPattern', 'cleanup']),
|
|
|
|
State.State('showServerPattern', self.enterShowServerPattern, self.exitShowServerPattern, ['getUserInput', 'playBackPatterns', 'cleanup']),
|
|
|
|
State.State('getUserInput', self.enterGetUserInput, self.exitGetUserInput, ['waitForPlayerPatterns', 'playBackPatterns', 'cleanup']),
|
|
|
|
State.State('waitForPlayerPatterns', self.enterWaitForPlayerPatterns, self.exitWaitForPlayerPatterns, ['playBackPatterns', 'cleanup', 'checkGameOver']),
|
|
|
|
State.State('playBackPatterns', self.enterPlayBackPatterns, self.exitPlayBackPatterns, ['checkGameOver', 'cleanup']),
|
|
|
|
State.State('checkGameOver', self.enterCheckGameOver, self.exitCheckGameOver, ['waitForServerPattern', 'cleanup']),
|
|
|
|
State.State('cleanup', self.enterCleanup, self.exitCleanup, [])], 'off', 'cleanup')
|
|
|
|
self.addChildGameFSM(self.gameFSM)
|
|
|
|
self.arrowColor = VBase4(1, 0, 0, 1)
|
|
|
|
self.xColor = VBase4(1, 0, 0, 1)
|
|
|
|
self.celebrate = 0
|
|
|
|
self.oldBgColor = None
|
|
|
|
self.trans = VBase4(1, 0, 0, 0)
|
|
|
|
self.opaq = VBase4(1, 0, 0, 1)
|
|
|
|
self.normalTextColor = VBase4(0.537, 0.84, 0.33, 1.0)
|
|
|
|
self.__otherToonIndex = {}
|
|
|
|
return
|
|
|
|
|
|
|
|
def getTitle(self):
|
|
|
|
return TTLocalizer.PatternGameTitle
|
|
|
|
|
|
|
|
def getInstructions(self):
|
|
|
|
return TTLocalizer.PatternGameInstructions
|
|
|
|
|
|
|
|
def getMaxDuration(self):
|
|
|
|
inputDur = PatternGameGlobals.NUM_ROUNDS * PatternGameGlobals.InputTime
|
|
|
|
return inputDur * 1.3
|
|
|
|
|
|
|
|
def load(self):
|
|
|
|
self.notify.debug('load')
|
|
|
|
DistributedMinigame.load(self)
|
|
|
|
self.timer = ToontownTimer.ToontownTimer()
|
|
|
|
self.timer.posInTopRightCorner()
|
|
|
|
self.timer.hide()
|
|
|
|
self.room = loader.loadModel('phase_4/models/minigames/matching_room')
|
|
|
|
self.buttonSounds = []
|
|
|
|
for soundName in self.ButtonSoundNames:
|
2019-11-23 16:07:27 -06:00
|
|
|
self.buttonSounds.append(base.loader.loadSfx(soundName))
|
2019-11-02 17:27:54 -05:00
|
|
|
|
2020-01-14 13:28:52 -06:00
|
|
|
self.correctSound = base.loader.loadSfx('phase_4/audio/sfx/MG_pos_buzzer.ogg')
|
|
|
|
self.incorrectSound = base.loader.loadSfx('phase_4/audio/sfx/MG_neg_buzzer.ogg')
|
|
|
|
self.perfectSound = base.loader.loadSfx('phase_4/audio/sfx/MG_win.ogg')
|
|
|
|
self.fallSound = base.loader.loadSfx('phase_4/audio/sfx/MG_Tag_A.ogg')
|
2019-11-23 16:18:49 -06:00
|
|
|
self.music = base.loader.loadMusic(self.bgm)
|
2019-11-02 17:27:54 -05:00
|
|
|
self.waitingText = DirectLabel(text=self.strPleaseWait, text_fg=(0.9, 0.9, 0.9, 1.0), frameColor=(1, 1, 1, 0), text_font=ToontownGlobals.getSignFont(), pos=(0, 0, -.78), scale=0.12)
|
|
|
|
self.roundText = DirectLabel(text=self.strRound % 1, text_fg=self.normalTextColor, frameColor=(1, 1, 1, 0), text_font=ToontownGlobals.getSignFont(), pos=(0.014, 0, -.84), scale=0.12)
|
|
|
|
self.roundText.hide()
|
|
|
|
self.waitingText.hide()
|
|
|
|
matchingGameGui = loader.loadModel('phase_3.5/models/gui/matching_game_gui')
|
|
|
|
minnieArrow = matchingGameGui.find('**/minnieArrow')
|
|
|
|
minnieX = matchingGameGui.find('**/minnieX')
|
|
|
|
minnieCircle = matchingGameGui.find('**/minnieCircle')
|
|
|
|
self.arrows = [None] * 5
|
|
|
|
for x in range(0, 5):
|
|
|
|
self.arrows[x] = minnieArrow.copyTo(hidden)
|
|
|
|
self.arrows[x].hide()
|
|
|
|
|
|
|
|
self.xs = [None] * 5
|
|
|
|
for x in range(0, 5):
|
|
|
|
self.xs[x] = minnieX.copyTo(hidden)
|
|
|
|
self.xs[x].hide()
|
|
|
|
|
|
|
|
self.statusBalls = []
|
|
|
|
self.totalMoves = PatternGameGlobals.INITIAL_ROUND_LENGTH + PatternGameGlobals.ROUND_LENGTH_INCREMENT * (PatternGameGlobals.NUM_ROUNDS - 1)
|
|
|
|
for x in range(0, 4):
|
|
|
|
self.statusBalls.append([None] * self.totalMoves)
|
|
|
|
|
|
|
|
for x in range(0, 4):
|
|
|
|
for y in range(0, self.totalMoves):
|
|
|
|
self.statusBalls[x][y] = minnieCircle.copyTo(hidden)
|
|
|
|
self.statusBalls[x][y].hide()
|
|
|
|
|
|
|
|
minnieArrow.removeNode()
|
|
|
|
minnieX.removeNode()
|
|
|
|
minnieCircle.removeNode()
|
|
|
|
matchingGameGui.removeNode()
|
|
|
|
self.minnie = Char.Char()
|
|
|
|
m = self.minnie
|
|
|
|
dna = CharDNA.CharDNA()
|
|
|
|
dna.newChar('mn')
|
|
|
|
m.setDNA(dna)
|
|
|
|
m.setName(TTLocalizer.Minnie)
|
|
|
|
m.reparentTo(hidden)
|
|
|
|
self.backRowHome = Point3(3, 11, 0)
|
|
|
|
self.backRowXSpacing = 1.8
|
|
|
|
self.frontRowHome = Point3(0, 18, 0)
|
|
|
|
self.frontRowXSpacing = 3.0
|
|
|
|
self.stdNumDanceStepPingFrames = self.minnie.getNumFrames(self.minnieAnimNames[0])
|
|
|
|
self.stdNumDanceStepPingPongFrames = self.__numPingPongFrames(self.stdNumDanceStepPingFrames)
|
|
|
|
self.buttonPressDelayPercent = (self.stdNumDanceStepPingFrames - 1.0) / self.stdNumDanceStepPingPongFrames
|
|
|
|
self.animPlayRates = []
|
|
|
|
animPlayRate = 1.4
|
|
|
|
animPlayRateMult = 1.06
|
|
|
|
for i in range(PatternGameGlobals.NUM_ROUNDS):
|
|
|
|
self.animPlayRates.append(animPlayRate)
|
|
|
|
animPlayRate *= animPlayRateMult
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
def unload(self):
|
|
|
|
self.notify.debug('unload')
|
|
|
|
DistributedMinigame.unload(self)
|
|
|
|
self.timer.destroy()
|
|
|
|
del self.timer
|
|
|
|
del self.lt
|
|
|
|
del self.buttonSounds
|
|
|
|
del self.music
|
|
|
|
del self.__otherToonIndex
|
|
|
|
del self.correctSound
|
|
|
|
del self.incorrectSound
|
|
|
|
del self.perfectSound
|
|
|
|
del self.fallSound
|
|
|
|
self.waitingText.destroy()
|
|
|
|
del self.waitingText
|
|
|
|
self.roundText.destroy()
|
|
|
|
del self.roundText
|
2019-12-30 00:07:56 -06:00
|
|
|
for x in list(self.arrowDict.values()):
|
2019-11-02 17:27:54 -05:00
|
|
|
x[0].removeNode()
|
|
|
|
x[1].removeNode()
|
|
|
|
if len(x) == 3:
|
|
|
|
for y in x[2]:
|
|
|
|
y.removeNode()
|
|
|
|
|
|
|
|
del self.arrowDict
|
|
|
|
for x in self.arrows:
|
|
|
|
if x:
|
|
|
|
x.removeNode()
|
|
|
|
|
|
|
|
del self.arrows
|
|
|
|
for x in self.xs:
|
|
|
|
if x:
|
|
|
|
x.removeNode()
|
|
|
|
|
|
|
|
del self.xs
|
|
|
|
for x in self.statusBalls:
|
|
|
|
if x:
|
|
|
|
for y in x:
|
|
|
|
if y:
|
|
|
|
y.removeNode()
|
|
|
|
del y
|
|
|
|
|
|
|
|
del self.statusBalls
|
|
|
|
self.room.removeNode()
|
|
|
|
del self.room
|
|
|
|
self.minnie.delete()
|
|
|
|
del self.minnie
|
|
|
|
self.removeChildGameFSM(self.gameFSM)
|
|
|
|
del self.gameFSM
|
|
|
|
|
|
|
|
def onstage(self):
|
|
|
|
self.notify.debug('onstage')
|
|
|
|
DistributedMinigame.onstage(self)
|
|
|
|
self.arrowDict = {}
|
|
|
|
self.lt = base.localAvatar
|
|
|
|
camera.reparentTo(render)
|
|
|
|
camera.setPosHpr(0.0, -14.59, 10.56, 0.0, -16.39, 0.0)
|
|
|
|
base.camLens.setFov(24.66)
|
|
|
|
NametagGlobals.setGlobalNametagScale(0.6)
|
|
|
|
self.arrowKeys = ArrowKeys.ArrowKeys()
|
|
|
|
self.room.reparentTo(render)
|
|
|
|
self.room.setPosHpr(0.0, 18.39, -ToontownGlobals.FloorOffset, 0.0, 0.0, 0.0)
|
|
|
|
self.room.setScale(1)
|
|
|
|
for anim in self.minnieAnimNames:
|
|
|
|
self.minnie.pose(anim, 0)
|
|
|
|
|
|
|
|
for anim in self.toonAnimNames:
|
|
|
|
self.lt.pose(anim, 0)
|
|
|
|
|
|
|
|
self.minnieAnimSpeedMult = {}
|
|
|
|
self.toonAnimSpeedMult = {}
|
|
|
|
for anim in self.minnieAnimNames:
|
|
|
|
numFrames = self.minnie.getNumFrames(anim)
|
|
|
|
self.minnieAnimSpeedMult[anim] = float(self.__numPingPongFrames(numFrames)) / float(self.stdNumDanceStepPingPongFrames)
|
|
|
|
|
|
|
|
for anim in self.toonAnimNames:
|
|
|
|
numFrames = self.lt.getNumFrames(anim)
|
|
|
|
self.toonAnimSpeedMult[anim] = float(self.__numPingPongFrames(numFrames)) / float(self.stdNumDanceStepPingPongFrames)
|
|
|
|
|
|
|
|
lt = self.lt
|
|
|
|
lt.reparentTo(render)
|
|
|
|
lt.useLOD(1000)
|
|
|
|
lt.setPos(-3.5, 11, 0.0)
|
|
|
|
lt.setScale(1)
|
|
|
|
self.makeToonLookatCamera(lt)
|
|
|
|
lt.loop('neutral')
|
|
|
|
lt.startBlink()
|
|
|
|
lt.startLookAround()
|
|
|
|
self.arrowDict['lt'] = [self.arrows.pop(), self.xs.pop(), self.statusBalls.pop()]
|
|
|
|
jj = self.lt.nametag3d
|
|
|
|
for k in range(0, 2):
|
|
|
|
self.arrowDict['lt'][k].setBillboardAxis()
|
|
|
|
self.arrowDict['lt'][k].setBin('fixed', 100)
|
|
|
|
self.arrowDict['lt'][k].reparentTo(jj)
|
|
|
|
if k == 0:
|
|
|
|
self.arrowDict['lt'][k].setScale(2.5)
|
|
|
|
self.arrowDict['lt'][k].setColor(self.arrowColor)
|
|
|
|
else:
|
|
|
|
self.arrowDict['lt'][k].setScale(4, 4, 4)
|
|
|
|
self.arrowDict['lt'][k].setColor(self.xColor)
|
|
|
|
self.arrowDict['lt'][k].setPos(0, 0, 1)
|
|
|
|
|
|
|
|
self.formatStatusBalls(self.arrowDict['lt'][2], jj)
|
|
|
|
m = self.minnie
|
|
|
|
m.reparentTo(render)
|
|
|
|
m.setPos(-1.6, 20, 0)
|
|
|
|
m.setScale(1)
|
|
|
|
self.makeToonLookatCamera(m)
|
|
|
|
m.loop('neutral')
|
|
|
|
m.startBlink()
|
|
|
|
self.minnie.nametag.manage(base.marginManager)
|
|
|
|
self.minnie.startEarTask()
|
|
|
|
self.minnie.setPickable(0)
|
|
|
|
self.minnie.nametag.getNametag3d().setChatWordwrap(8)
|
|
|
|
self.arrowDict['m'] = [self.arrows.pop(), self.xs.pop()]
|
|
|
|
jj = self.minnie.nametag3d
|
|
|
|
for k in range(0, 2):
|
|
|
|
self.arrowDict['m'][k].setBillboardAxis()
|
|
|
|
self.arrowDict['m'][k].setBin('fixed', 100)
|
|
|
|
self.arrowDict['m'][k].setColor(self.arrowColor)
|
|
|
|
self.arrowDict['m'][k].reparentTo(jj)
|
|
|
|
self.arrowDict['m'][k].setScale(4)
|
|
|
|
self.arrowDict['m'][k].setPos(0, 0, 1.7)
|
|
|
|
|
|
|
|
base.playMusic(self.music, looping=1, volume=1)
|
|
|
|
|
|
|
|
def offstage(self):
|
|
|
|
self.notify.debug('offstage')
|
|
|
|
DistributedMinigame.offstage(self)
|
|
|
|
self.music.stop()
|
|
|
|
base.camLens.setFov(ToontownGlobals.DefaultCameraFov)
|
|
|
|
NametagGlobals.setGlobalNametagScale(1.0)
|
|
|
|
self.arrowKeys.destroy()
|
|
|
|
del self.arrowKeys
|
|
|
|
self.room.reparentTo(hidden)
|
|
|
|
self.roundText.hide()
|
|
|
|
self.minnie.nametag.unmanage(base.marginManager)
|
|
|
|
self.minnie.stopEarTask()
|
|
|
|
self.minnie.stop()
|
|
|
|
self.minnie.stopBlink()
|
|
|
|
self.minnie.reparentTo(hidden)
|
|
|
|
self.lt.setScale(1)
|
|
|
|
for avId in self.remoteAvIdList:
|
|
|
|
toon = self.getAvatar(avId)
|
|
|
|
if toon:
|
|
|
|
toon.setScale(1)
|
|
|
|
|
|
|
|
for avId in self.avIdList:
|
|
|
|
av = self.getAvatar(avId)
|
|
|
|
if av:
|
|
|
|
av.resetLOD()
|
|
|
|
for anim in self.toonAnimNames:
|
|
|
|
av.setPlayRate(1.0, anim)
|
|
|
|
|
|
|
|
def setGameReady(self):
|
|
|
|
if not self.hasLocalToon:
|
|
|
|
return
|
|
|
|
self.notify.debug('setGameReady')
|
|
|
|
if DistributedMinigame.setGameReady(self):
|
|
|
|
return
|
|
|
|
for avId in self.remoteAvIdList:
|
|
|
|
toon = self.getAvatar(avId)
|
|
|
|
if toon:
|
|
|
|
self.arrowDict[avId] = [self.arrows.pop(), self.xs.pop(), self.statusBalls.pop()]
|
|
|
|
jj = toon.nametag3d
|
|
|
|
for k in range(0, 2):
|
|
|
|
self.arrowDict[avId][k].setBillboardAxis()
|
|
|
|
self.arrowDict[avId][k].setBin('fixed', 100)
|
|
|
|
self.arrowDict[avId][k].reparentTo(jj)
|
|
|
|
if k == 0:
|
|
|
|
self.arrowDict[avId][k].setScale(2.5)
|
|
|
|
self.arrowDict[avId][k].setColor(self.arrowColor)
|
|
|
|
else:
|
|
|
|
self.arrowDict[avId][k].setScale(4, 4, 4)
|
|
|
|
self.arrowDict[avId][k].setColor(self.xColor)
|
|
|
|
self.arrowDict[avId][k].setPos(0, 0, 1)
|
|
|
|
|
|
|
|
self.formatStatusBalls(self.arrowDict[avId][2], jj)
|
|
|
|
toon.reparentTo(render)
|
|
|
|
toon.useLOD(1000)
|
|
|
|
toon.setPos(self.getBackRowPos(avId))
|
|
|
|
toon.setScale(0.9)
|
|
|
|
self.makeToonLookatCamera(toon)
|
|
|
|
for anim in self.toonAnimNames:
|
|
|
|
toon.pose(anim, 0)
|
|
|
|
|
|
|
|
toon.loop('neutral')
|
|
|
|
|
|
|
|
if self.isSinglePlayer():
|
|
|
|
self.waitingText['text'] = self.strPleaseWait
|
|
|
|
else:
|
|
|
|
self.waitingText['text'] = self.strWaitingOtherPlayers
|
|
|
|
self.animTracks = {}
|
|
|
|
for avId in self.avIdList:
|
|
|
|
self.animTracks[avId] = None
|
|
|
|
|
|
|
|
self.__initGameVars()
|
|
|
|
return
|
|
|
|
|
|
|
|
def setGameStart(self, timestamp):
|
|
|
|
if not self.hasLocalToon:
|
|
|
|
return
|
|
|
|
self.notify.debug('setGameStart')
|
|
|
|
DistributedMinigame.setGameStart(self, timestamp)
|
|
|
|
self.gameFSM.request('waitForServerPattern')
|
|
|
|
|
|
|
|
def __initGameVars(self):
|
|
|
|
self.round = 0
|
|
|
|
self.perfectGame = 1
|
|
|
|
|
|
|
|
def __numPingPongFrames(self, numFrames):
|
|
|
|
return numFrames * 2 - 1
|
|
|
|
|
|
|
|
def makeToonLookatCamera(self, toon):
|
|
|
|
toon.headsUp(camera)
|
|
|
|
|
|
|
|
def setText(self, t, newtext):
|
|
|
|
t['text'] = newtext
|
|
|
|
|
|
|
|
def setTextFG(self, t, fg):
|
|
|
|
t['text_fg'] = fg
|
|
|
|
|
|
|
|
def getWalkTrack(self, toon, posList, startPos = None, lookAtCam = 1, endHeading = 180):
|
|
|
|
walkSpeed = 7
|
|
|
|
origPos = toon.getPos()
|
|
|
|
origHpr = toon.getHpr()
|
|
|
|
track = Sequence(Func(toon.loop, 'run'))
|
|
|
|
if startPos:
|
|
|
|
toon.setPos(startPos)
|
|
|
|
track.append(Func(toon.setPos, startPos))
|
|
|
|
for endPos in posList:
|
|
|
|
toon.headsUp(Point3(endPos))
|
|
|
|
track.append(Func(toon.setHpr, Point3(toon.getH(), 0, 0)))
|
|
|
|
lastPos = toon.getPos()
|
|
|
|
distance = Vec3(endPos - lastPos).length()
|
|
|
|
duration = distance / walkSpeed
|
|
|
|
toon.setPos(endPos)
|
|
|
|
track.append(LerpPosInterval(toon, duration=duration, pos=Point3(endPos), startPos=Point3(lastPos)))
|
|
|
|
|
|
|
|
if lookAtCam:
|
|
|
|
saveHpr = toon.getHpr()
|
|
|
|
toon.headsUp(camera)
|
|
|
|
endHeading = toon.getHpr()[0]
|
|
|
|
toon.setHpr(saveHpr)
|
|
|
|
curHeading = toon.getH()
|
|
|
|
if endHeading - curHeading > 180.0:
|
|
|
|
endHeading -= 360
|
|
|
|
elif endHeading - curHeading < -180.0:
|
|
|
|
endHeading += 360
|
|
|
|
endHpr = Point3(endHeading, 0, 0)
|
|
|
|
duration = abs(endHeading - curHeading) / 180.0 * 0.3
|
|
|
|
track.extend([Func(toon.loop, 'walk'), LerpHprInterval(toon, duration, endHpr), Func(toon.loop, 'neutral')])
|
|
|
|
toon.setPos(origPos)
|
|
|
|
toon.setHpr(origHpr)
|
|
|
|
return track
|
|
|
|
|
|
|
|
def getDanceStepDuration(self):
|
|
|
|
numFrames = self.stdNumDanceStepPingPongFrames
|
|
|
|
return numFrames / abs(self.animPlayRate * self.minnieAnimSpeedMult[self.minnieAnimNames[0]] * self.minnie.getFrameRate(self.minnieAnimNames[0]))
|
|
|
|
|
|
|
|
def __getDanceStepAnimTrack(self, toon, anim, speedScale):
|
|
|
|
numFrames = toon.getNumFrames(anim)
|
|
|
|
return Sequence(Func(toon.pingpong, anim, fromFrame=0, toFrame=numFrames - 1), Wait(self.getDanceStepDuration()))
|
|
|
|
|
|
|
|
def __getMinnieDanceStepAnimTrack(self, minnie, direction):
|
|
|
|
animName = self.minnieAnimNames[direction]
|
|
|
|
return self.__getDanceStepAnimTrack(minnie, animName, self.minnieAnimSpeedMult[animName])
|
|
|
|
|
|
|
|
def __getToonDanceStepAnimTrack(self, toon, direction):
|
|
|
|
animName = self.toonAnimNames[direction]
|
|
|
|
return self.__getDanceStepAnimTrack(toon, animName, self.toonAnimSpeedMult[animName])
|
|
|
|
|
|
|
|
def getDanceStepButtonSoundTrack(self, index):
|
|
|
|
duration = self.getDanceStepDuration()
|
|
|
|
wait = duration * self.buttonPressDelayPercent
|
|
|
|
return Sequence(Wait(wait), Func(base.playSfx, self.__getButtonSound(index)), Wait(duration - wait))
|
|
|
|
|
|
|
|
def getDanceArrowAnimTrack(self, toonID, pattern, speedy):
|
|
|
|
track = Sequence()
|
|
|
|
track.append(Func(self.showArrow, toonID))
|
|
|
|
for buttonIndex in pattern:
|
|
|
|
track.append(self.getDanceArrowSingleTrack(toonID, buttonIndex, speedy))
|
|
|
|
|
|
|
|
track.append(Func(self.hideArrow, toonID))
|
|
|
|
return track
|
|
|
|
|
|
|
|
def changeArrow(self, toonID, index):
|
|
|
|
self.arrowDict[toonID][0].setR(-(90 - 90 * index))
|
|
|
|
|
|
|
|
def showArrow(self, toonID):
|
|
|
|
self.arrowDict[toonID][0].show()
|
|
|
|
|
|
|
|
def hideArrow(self, toonID):
|
|
|
|
self.arrowDict[toonID][0].hide()
|
|
|
|
|
|
|
|
def showX(self, toonID):
|
|
|
|
self.arrowDict[toonID][1].show()
|
|
|
|
|
|
|
|
def hideX(self, toonID):
|
|
|
|
self.arrowDict[toonID][1].hide()
|
|
|
|
|
|
|
|
def celebrated(self):
|
|
|
|
self.celebrate = 1
|
|
|
|
|
|
|
|
def returnCelebrationIntervals(self, turnOn):
|
|
|
|
ri = []
|
|
|
|
if turnOn:
|
|
|
|
ri.append(ActorInterval(actor=self.lt, animName='victory', duration=5.5))
|
|
|
|
else:
|
|
|
|
ri.append(Func(self.lt.loop, 'neutral'))
|
|
|
|
for avId in self.remoteAvIdList:
|
|
|
|
toon = self.getAvatar(avId)
|
|
|
|
if toon:
|
|
|
|
if turnOn:
|
|
|
|
ri.append(ActorInterval(actor=toon, animName='victory', duration=5.5))
|
|
|
|
else:
|
|
|
|
ri.append(Func(toon.loop, 'neutral'))
|
|
|
|
|
|
|
|
if len(self.remoteAvIdList) == 0:
|
|
|
|
return ri
|
|
|
|
else:
|
|
|
|
return Parallel(ri)
|
|
|
|
|
|
|
|
def formatStatusBalls(self, sb, jj):
|
|
|
|
for x in range(0, self.totalMoves):
|
|
|
|
sb[x].setBillboardAxis()
|
|
|
|
sb[x].setBin('fixed', 100)
|
|
|
|
sb[x].reparentTo(jj)
|
|
|
|
sb[x].setScale(1)
|
|
|
|
xpos = +(int(self.totalMoves / 2) * 0.25) - 0.25 * x
|
|
|
|
sb[x].setPos(xpos, 0, 0.3)
|
|
|
|
|
|
|
|
def showStatusBalls(self, toonID):
|
|
|
|
sb = self.arrowDict[toonID][2]
|
|
|
|
for x in range(0, len(self.__serverPattern)):
|
|
|
|
sb[x].setColor(1, 1, 1, 1)
|
|
|
|
sb[x].show()
|
|
|
|
|
|
|
|
def hideStatusBalls(self, toonID):
|
|
|
|
sb = self.arrowDict[toonID][2]
|
|
|
|
for x in range(0, len(sb)):
|
|
|
|
sb[x].hide()
|
|
|
|
|
|
|
|
def colorStatusBall(self, toonID, which, good):
|
|
|
|
if good:
|
|
|
|
self.arrowDict[toonID][2][which].setColor(0, 1, 0, 1)
|
|
|
|
else:
|
|
|
|
self.arrowDict[toonID][2][which].setColor(1, 0, 0, 1)
|
|
|
|
|
|
|
|
def getDanceArrowSingleTrack(self, toonID, index, speedy):
|
|
|
|
duration = self.getDanceStepDuration()
|
|
|
|
wait = duration * self.buttonPressDelayPercent
|
|
|
|
d = duration - wait
|
|
|
|
if speedy:
|
|
|
|
track = Sequence(Func(self.changeArrow, toonID, index), Wait(wait))
|
|
|
|
else:
|
|
|
|
track = Sequence(Func(self.changeArrow, toonID, index), Wait(wait), LerpColorInterval(self.arrowDict[toonID][0], d, self.trans, self.opaq))
|
|
|
|
return track
|
|
|
|
|
|
|
|
def getDanceSequenceAnimTrack(self, toon, pattern):
|
|
|
|
getDanceStepTrack = self.__getToonDanceStepAnimTrack
|
|
|
|
if toon == self.minnie:
|
|
|
|
getDanceStepTrack = self.__getMinnieDanceStepAnimTrack
|
|
|
|
tracks = Sequence()
|
|
|
|
for direction in pattern:
|
|
|
|
tracks.append(getDanceStepTrack(toon, direction))
|
|
|
|
|
|
|
|
if len(pattern):
|
|
|
|
tracks.append(Func(toon.loop, 'neutral'))
|
|
|
|
return tracks
|
|
|
|
|
|
|
|
def getDanceSequenceButtonSoundTrack(self, pattern):
|
|
|
|
track = Sequence()
|
|
|
|
for buttonIndex in pattern:
|
|
|
|
track.append(self.getDanceStepButtonSoundTrack(buttonIndex))
|
|
|
|
|
|
|
|
return track
|
|
|
|
|
|
|
|
def __getRowPos(self, rowHome, xSpacing, index, numSpots):
|
|
|
|
xOffset = xSpacing * index - xSpacing * (numSpots - 1) / 2.0
|
|
|
|
return rowHome + Point3(xOffset, 0, 0)
|
|
|
|
|
|
|
|
def getBackRowPos(self, avId):
|
|
|
|
index = self.remoteAvIdList.index(avId)
|
|
|
|
return self.__getRowPos(self.backRowHome, self.backRowXSpacing, index, len(self.remoteAvIdList))
|
|
|
|
|
|
|
|
def getFrontRowPos(self, avId):
|
|
|
|
index = self.avIdList.index(avId)
|
|
|
|
return self.__getRowPos(self.frontRowHome, self.frontRowXSpacing, index, len(self.avIdList))
|
|
|
|
|
|
|
|
def __setMinnieChat(self, str, giggle):
|
2020-01-07 15:44:33 -06:00
|
|
|
str = str.replace('%s', self.getAvatar(self.localAvId).getName())
|
2019-11-02 17:27:54 -05:00
|
|
|
self.minnie.setChatAbsolute(str, CFSpeech)
|
|
|
|
if giggle:
|
|
|
|
self.minnie.playDialogue('statementA', 1)
|
|
|
|
|
|
|
|
def __clearMinnieChat(self):
|
|
|
|
self.minnie.clearChat()
|
|
|
|
|
|
|
|
def enterOff(self):
|
|
|
|
self.notify.debug('enterOff')
|
|
|
|
|
|
|
|
def exitOff(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def enterWaitForServerPattern(self):
|
|
|
|
self.notify.debug('enterWaitForServerPattern')
|
|
|
|
self.sendUpdate('reportPlayerReady', [])
|
|
|
|
|
|
|
|
def setPattern(self, pattern):
|
|
|
|
if not self.hasLocalToon:
|
|
|
|
return
|
|
|
|
self.notify.debug('setPattern: ' + str(pattern))
|
|
|
|
self.__serverPattern = pattern
|
|
|
|
self.gameFSM.request('showServerPattern')
|
|
|
|
|
|
|
|
def exitWaitForServerPattern(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def enterShowServerPattern(self):
|
|
|
|
self.notify.debug('enterShowServerPattern')
|
|
|
|
self.round += 1
|
|
|
|
self.roundText.show()
|
|
|
|
self.roundText.setScale(0.12)
|
|
|
|
self.roundText['text'] = self.strRound % self.round
|
|
|
|
self.animPlayRate = self.animPlayRates[self.round - 1]
|
|
|
|
for avId in self.avIdList:
|
|
|
|
toon = self.getAvatar(avId)
|
|
|
|
if toon:
|
|
|
|
for anim in self.toonAnimNames:
|
|
|
|
toon.setPlayRate(self.animPlayRate * self.toonAnimSpeedMult[anim], anim)
|
|
|
|
|
|
|
|
for anim in self.minnieAnimNames:
|
|
|
|
self.minnie.setPlayRate(self.animPlayRate * self.minnieAnimSpeedMult[anim], anim)
|
|
|
|
|
|
|
|
text = self.strWatch
|
|
|
|
danceTrack = self.getDanceSequenceAnimTrack(self.minnie, self.__serverPattern)
|
|
|
|
arrowTrack = self.getDanceArrowAnimTrack('m', self.__serverPattern, 0)
|
|
|
|
soundTrack = self.getDanceSequenceButtonSoundTrack(self.__serverPattern)
|
|
|
|
self.showTrack = Sequence(Func(self.__setMinnieChat, text, 1), Wait(0.5), Parallel(danceTrack, soundTrack, arrowTrack), Wait(0.2), Func(self.__clearMinnieChat), Func(self.gameFSM.request, 'getUserInput'))
|
|
|
|
self.showTrack.start()
|
|
|
|
|
|
|
|
def exitShowServerPattern(self):
|
|
|
|
if self.showTrack.isPlaying():
|
|
|
|
self.showTrack.pause()
|
|
|
|
del self.showTrack
|
|
|
|
|
|
|
|
def enterGetUserInput(self):
|
|
|
|
self.notify.debug('enterGetUserInput')
|
|
|
|
self.setupTrack = None
|
|
|
|
self.proceedTrack = None
|
|
|
|
|
|
|
|
def startTimer(self = self):
|
|
|
|
self.currentStartTime = globalClock.getFrameTime()
|
|
|
|
self.timer.show()
|
|
|
|
self.timer.countdown(PatternGameGlobals.InputTime, self.__handleInputTimeout)
|
|
|
|
|
|
|
|
def enableKeys(self = self):
|
|
|
|
|
|
|
|
def keyPress(self, index):
|
|
|
|
self.__pressHandler(index)
|
|
|
|
|
|
|
|
def keyRelease(self, index):
|
|
|
|
self.__releaseHandler(index)
|
|
|
|
|
|
|
|
self.arrowKeys.setPressHandlers([lambda self = self, keyPress = keyPress: keyPress(self, 0),
|
|
|
|
lambda self = self, keyPress = keyPress: keyPress(self, 2),
|
|
|
|
lambda self = self, keyPress = keyPress: keyPress(self, 3),
|
|
|
|
lambda self = self, keyPress = keyPress: keyPress(self, 1)])
|
|
|
|
self.arrowKeys.setReleaseHandlers([lambda self = self, keyRelease = keyRelease: keyRelease(self, 0),
|
|
|
|
lambda self = self, keyRelease = keyRelease: keyRelease(self, 2),
|
|
|
|
lambda self = self, keyRelease = keyRelease: keyRelease(self, 3),
|
|
|
|
lambda self = self, keyRelease = keyRelease: keyRelease(self, 1)])
|
|
|
|
|
|
|
|
self.__localPattern = []
|
|
|
|
self.__otherToonIndex.clear()
|
|
|
|
self.showStatusBalls('lt')
|
|
|
|
for avId in self.remoteAvIdList:
|
|
|
|
self.showStatusBalls(avId)
|
|
|
|
self.__otherToonIndex[avId] = 0
|
|
|
|
|
|
|
|
self.setupTrack = Sequence(Func(self.__setMinnieChat, self.strGo, 0), Func(self.setText, self.roundText, TTLocalizer.PatternGameGo), Func(self.roundText.setScale, 0.3), Func(enableKeys), Func(startTimer), Wait(0.8), Func(self.__clearMinnieChat), Func(self.setText, self.roundText, ' '), Func(self.roundText.setScale, 0.12), Func(self.setTextFG, self.roundText, self.normalTextColor))
|
|
|
|
self.setupTrack.start()
|
|
|
|
return
|
|
|
|
|
|
|
|
def __handleInputTimeout(self):
|
|
|
|
self.__doneGettingInput(self.__localPattern)
|
|
|
|
|
|
|
|
def __pressHandler(self, index):
|
|
|
|
self.__buttonPressed(index)
|
|
|
|
|
|
|
|
def __releaseHandler(self, index):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def remoteButtonPressed(self, avId, index, wrong):
|
|
|
|
if not self.hasLocalToon:
|
|
|
|
return
|
|
|
|
if self.gameFSM.getCurrentState().getName() not in ['getUserInput', 'waitForPlayerPatterns']:
|
|
|
|
return
|
|
|
|
if avId != self.localAvId:
|
|
|
|
if self.animTracks[avId]:
|
|
|
|
self.animTracks[avId].finish()
|
|
|
|
av = self.getAvatar(avId)
|
|
|
|
if wrong:
|
|
|
|
acts = ['slip-forward', 'slip-backward']
|
|
|
|
ag = random.choice(acts)
|
|
|
|
self.arrowDict[avId][0].hide()
|
|
|
|
self.animTracks[avId] = Sequence(Func(self.showX, avId), Func(self.colorStatusBall, avId, self.__otherToonIndex[avId], 0), ActorInterval(actor=av, animName=ag, duration=2.35), Func(av.loop, 'neutral'), Func(self.hideX, avId))
|
|
|
|
else:
|
|
|
|
self.colorStatusBall(avId, self.__otherToonIndex[avId], 1)
|
|
|
|
arrowTrack = self.getDanceArrowAnimTrack(avId, [index], 1)
|
|
|
|
potTrack = self.getDanceSequenceAnimTrack(av, [index])
|
|
|
|
self.animTracks[avId] = Parallel(potTrack, arrowTrack)
|
|
|
|
self.__otherToonIndex[avId] += 1
|
|
|
|
self.animTracks[avId].start()
|
|
|
|
|
|
|
|
def __getButtonSound(self, index):
|
|
|
|
return self.buttonSounds[index]
|
|
|
|
|
|
|
|
def __buttonPressed(self, index):
|
|
|
|
if len(self.__localPattern) >= len(self.__serverPattern):
|
|
|
|
return
|
|
|
|
if self.animTracks[self.localAvId]:
|
|
|
|
self.animTracks[self.localAvId].finish()
|
|
|
|
badd = 0
|
|
|
|
if index != self.__serverPattern[len(self.__localPattern)]:
|
|
|
|
badd = 1
|
|
|
|
acts = ['slip-forward', 'slip-backward']
|
|
|
|
ag = random.choice(acts)
|
|
|
|
self.animTracks[self.localAvId] = Sequence(Func(self.showX, 'lt'), Func(self.colorStatusBall, 'lt', len(self.__localPattern), 0), ActorInterval(actor=self.lt, animName=ag, duration=2.35), Func(self.lt.loop, 'neutral'), Func(self.hideX, 'lt'))
|
|
|
|
self.arrowDict['lt'][0].hide()
|
|
|
|
base.playSfx(self.fallSound)
|
|
|
|
else:
|
|
|
|
self.colorStatusBall('lt', len(self.__localPattern), 1)
|
|
|
|
base.playSfx(self.__getButtonSound(index))
|
|
|
|
arrowTrack = self.getDanceArrowAnimTrack('lt', [index], 1)
|
|
|
|
potTrack = self.getDanceSequenceAnimTrack(self.lt, [index])
|
|
|
|
self.animTracks[self.localAvId] = Parallel(potTrack, arrowTrack)
|
|
|
|
self.sendUpdate('reportButtonPress', [index, badd])
|
|
|
|
self.animTracks[self.localAvId].start()
|
|
|
|
self.__localPattern.append(index)
|
|
|
|
if len(self.__localPattern) == len(self.__serverPattern) or badd:
|
|
|
|
self.__doneGettingInput(self.__localPattern)
|
|
|
|
|
|
|
|
def __doneGettingInput(self, pattern):
|
|
|
|
self.arrowKeys.setPressHandlers(self.arrowKeys.NULL_HANDLERS)
|
|
|
|
self.currentTotalTime = globalClock.getFrameTime() - self.currentStartTime
|
|
|
|
self.proceedTrack = Sequence(Wait(self.getDanceStepDuration()), Func(self.sendUpdate, 'reportPlayerPattern', [pattern, self.currentTotalTime]), Func(self.gameFSM.request, 'waitForPlayerPatterns'))
|
|
|
|
self.proceedTrack.start()
|
|
|
|
|
|
|
|
def exitGetUserInput(self):
|
|
|
|
self.timer.stop()
|
|
|
|
self.timer.hide()
|
|
|
|
self.arrowKeys.setPressHandlers(self.arrowKeys.NULL_HANDLERS)
|
|
|
|
self.arrowKeys.setReleaseHandlers(self.arrowKeys.NULL_HANDLERS)
|
|
|
|
if self.setupTrack and self.setupTrack.isPlaying():
|
|
|
|
self.setupTrack.pause()
|
|
|
|
if self.proceedTrack and self.proceedTrack.isPlaying():
|
|
|
|
self.proceedTrack.pause()
|
|
|
|
del self.setupTrack
|
|
|
|
del self.proceedTrack
|
|
|
|
self.__clearMinnieChat()
|
|
|
|
|
|
|
|
def enterWaitForPlayerPatterns(self):
|
|
|
|
self.notify.debug('enterWaitForPlayerPatterns')
|
|
|
|
|
|
|
|
def setPlayerPatterns(self, pattern1, pattern2, pattern3, pattern4, fastestAvId):
|
|
|
|
if not self.hasLocalToon:
|
|
|
|
return
|
|
|
|
self.fastestAvId = fastestAvId
|
|
|
|
self.notify.debug('setPlayerPatterns:' + ' pattern1:' + str(pattern1) + ' pattern2:' + str(pattern2) + ' pattern3:' + str(pattern3) + ' pattern4:' + str(pattern4))
|
|
|
|
self.playerPatterns = {}
|
|
|
|
patterns = [pattern1,
|
|
|
|
pattern2,
|
|
|
|
pattern3,
|
|
|
|
pattern4]
|
|
|
|
for i in range(len(self.avIdList)):
|
|
|
|
self.playerPatterns[self.avIdList[i]] = patterns[i]
|
|
|
|
|
|
|
|
self.gameFSM.request('playBackPatterns')
|
|
|
|
|
|
|
|
def exitWaitForPlayerPatterns(self):
|
|
|
|
self.waitingText.hide()
|
|
|
|
|
|
|
|
def enterPlayBackPatterns(self):
|
|
|
|
self.notify.debug('enterPlayBackPatterns')
|
|
|
|
if self.fastestAvId == self.localAvId:
|
|
|
|
self.roundText.setScale(0.1)
|
|
|
|
if self.numPlayers != 2:
|
|
|
|
self.roundText['text'] = TTLocalizer.PatternGameFastest
|
|
|
|
else:
|
|
|
|
self.roundText['text'] = TTLocalizer.PatternGameFaster
|
|
|
|
jumpTrack = Sequence(ActorInterval(actor=self.lt, animName='jump', duration=1.7), Func(self.lt.loop, 'neutral'))
|
|
|
|
elif self.fastestAvId == 0:
|
|
|
|
if self.round == PatternGameGlobals.NUM_ROUNDS:
|
|
|
|
self.roundText['text'] = ' '
|
|
|
|
else:
|
|
|
|
self.roundText.setScale(0.1)
|
|
|
|
self.roundText['text'] = TTLocalizer.PatternGameYouCanDoIt
|
|
|
|
jumpTrack = Sequence(Wait(0.5), Wait(0.5))
|
|
|
|
elif self.fastestAvId == 1:
|
|
|
|
self.roundText.setScale(0.1)
|
|
|
|
self.roundText['text'] = TTLocalizer.PatternGameGreatJob
|
|
|
|
jumpTrack = Sequence(Wait(0.5), Wait(0.5))
|
|
|
|
else:
|
|
|
|
self.roundText.setScale(0.08)
|
|
|
|
av = self.getAvatar(self.fastestAvId)
|
|
|
|
jumpTrack = Sequence(ActorInterval(actor=av, animName='jump', duration=1.7), Func(av.loop, 'neutral'))
|
|
|
|
if self.numPlayers != 2:
|
|
|
|
rewardStr = TTLocalizer.PatternGameOtherFastest
|
|
|
|
else:
|
|
|
|
rewardStr = TTLocalizer.PatternGameOtherFaster
|
|
|
|
self.roundText['text'] = av.getName() + rewardStr
|
|
|
|
success = self.playerPatterns[self.localAvId] == self.__serverPattern
|
|
|
|
self.hideStatusBalls('lt')
|
|
|
|
for avId in self.remoteAvIdList:
|
|
|
|
self.hideStatusBalls(avId)
|
|
|
|
|
|
|
|
if success:
|
|
|
|
sound = self.correctSound
|
|
|
|
text = self.strRight
|
|
|
|
else:
|
|
|
|
self.perfectGame = 0
|
|
|
|
sound = self.incorrectSound
|
|
|
|
text = self.strWrong
|
|
|
|
soundTrack = Sequence(Func(base.playSfx, sound), Wait(1.6))
|
|
|
|
textTrack = Sequence(Wait(0.2), Func(self.__setMinnieChat, text, 0), Wait(1.3), Func(self.__clearMinnieChat))
|
|
|
|
self.playBackPatternsTrack = Sequence(Parallel(soundTrack, textTrack, jumpTrack), Func(self.gameFSM.request, 'checkGameOver'))
|
|
|
|
self.playBackPatternsTrack.start()
|
|
|
|
|
|
|
|
def exitPlayBackPatterns(self):
|
|
|
|
if self.playBackPatternsTrack.isPlaying():
|
|
|
|
self.playBackPatternsTrack.pause()
|
|
|
|
del self.playBackPatternsTrack
|
|
|
|
|
|
|
|
def enterCheckGameOver(self):
|
|
|
|
self.notify.debug('enterCheckGameOver')
|
|
|
|
self.__winTrack = None
|
|
|
|
if self.round < PatternGameGlobals.NUM_ROUNDS:
|
|
|
|
self.gameFSM.request('waitForServerPattern')
|
|
|
|
else:
|
|
|
|
text = self.strBye
|
|
|
|
sound = None
|
|
|
|
delay = 2.0
|
|
|
|
if self.perfectGame:
|
|
|
|
text = self.strPerfect
|
|
|
|
sound = self.perfectSound
|
|
|
|
delay = 2.2
|
|
|
|
if self.celebrate:
|
|
|
|
text = TTLocalizer.PatternGameImprov
|
|
|
|
self.__winTrack = Sequence(Func(self.__setMinnieChat, text, 1), Func(base.playSfx, self.perfectSound), Sequence(self.returnCelebrationIntervals(1)), Sequence(self.returnCelebrationIntervals(0)), Func(self.__clearMinnieChat), Func(self.gameOver))
|
|
|
|
else:
|
|
|
|
self.__winTrack = Sequence(Func(self.__setMinnieChat, text, 1), Func(base.playSfx, sound), Wait(delay), Func(self.__clearMinnieChat), Func(self.gameOver))
|
|
|
|
self.__winTrack.start()
|
|
|
|
return
|
|
|
|
|
|
|
|
def exitCheckGameOver(self):
|
|
|
|
if self.__winTrack and self.__winTrack.isPlaying():
|
|
|
|
self.__winTrack.pause()
|
|
|
|
del self.__winTrack
|
|
|
|
|
|
|
|
def enterCleanup(self):
|
|
|
|
self.notify.debug('enterCleanup')
|
2019-12-30 00:07:56 -06:00
|
|
|
for track in list(self.animTracks.values()):
|
2019-11-02 17:27:54 -05:00
|
|
|
if track and track.isPlaying():
|
|
|
|
track.pause()
|
|
|
|
|
|
|
|
del self.animTracks
|
|
|
|
|
|
|
|
def exitCleanup(self):
|
|
|
|
pass
|