No one liked you anyways, Pairing Game

This commit is contained in:
DenialMC 2015-05-05 18:13:10 +03:00
parent c623f806cc
commit 2f528c1aa6
13 changed files with 18 additions and 1175 deletions

11
.gitignore vendored
View file

@ -1,16 +1,19 @@
# Python artifacts:
# Python artifacts
*.pyc
# PyCharm
.idea
# Mac directory info:
# Mac directory info
.DS_Store
# Shortcuts:
# Shortcuts
*.lnk
# Game-specific files and directories:
# Git
*.rej
# Game-specific files and directories
preferences.json
*.json
logs/

View file

@ -451,7 +451,6 @@ from toontown.estate import DistributedAnimatedStatuary/AI
from toontown.estate import DistributedPlantBase/AI
from toontown.estate import DistributedLawnDecor/AI
from toontown.minigame import DistributedTravelGame/AI
from toontown.minigame import DistributedPairingGame/AI
from toontown.minigame import DistributedVineGame/AI
from toontown.golf import DistributedPhysicsWorld/AI
from toontown.golf import DistributedGolfHole/AI
@ -2791,16 +2790,6 @@ dclass DistributedTravelGame : DistributedMinigame {
setBoardIndex(uint8) required broadcast ram;
};
dclass DistributedPairingGame : DistributedMinigame {
setDeckSeed(uint32) required broadcast ram;
setMaxOpenCards(uint8) broadcast ram;
openCardRequest(int16, int16) airecv clsend;
openCardResult(int16, uint32, int16, int8, int16[]) broadcast;
reportDone() airecv clsend;
setEveryoneDone() broadcast;
setSignaling(uint32) clsend broadcast;
};
struct golfData {
int16 frame;
int32/100000 x;

View file

@ -2,7 +2,7 @@
from pandac.PandaModules import *
hashVal = 526795320
hashVal = 1036327477
from toontown.coghq import DistributedCashbotBossSafe, DistributedCashbotBossCrane, DistributedBattleFactory, DistributedCashbotBossTreasure, DistributedCogHQDoor, DistributedSellbotHQDoor, DistributedFactoryElevatorExt, DistributedMintElevatorExt, DistributedLawOfficeElevatorExt, DistributedLawOfficeElevatorInt, LobbyManager, DistributedMegaCorp, DistributedFactory, DistributedLawOffice, DistributedLawOfficeFloor, DistributedLift, DistributedDoorEntity, DistributedSwitch, DistributedButton, DistributedTrigger, DistributedCrushableEntity, DistributedCrusherEntity, DistributedStomper, DistributedStomperPair, DistributedLaserField, DistributedGolfGreenGame, DistributedSecurityCamera, DistributedMover, DistributedElevatorMarker, DistributedBarrelBase, DistributedGagBarrel, DistributedBeanBarrel, DistributedHealBarrel, DistributedGrid, ActiveCell, DirectionalCell, CrusherCell, DistributedCrate, DistributedSinkingPlatform, BattleBlocker, DistributedMint, DistributedMintRoom, DistributedMintBattle, DistributedStage, DistributedStageRoom, DistributedStageBattle, DistributedLawbotBossGavel, DistributedLawbotCannon, DistributedLawbotChair, DistributedCogKart, DistributedCountryClub, DistributedCountryClubRoom, DistributedMoleField, DistributedCountryClubBattle, DistributedMaze, DistributedFoodBelt, DistributedBanquetTable, DistributedGolfSpot
@ -24,7 +24,7 @@ from toontown.distributed import ToontownDistrict, ToontownDistrictStats, Distri
from toontown.effects import DistributedFireworkShow
from toontown.safezone import DistributedTrolley, DistributedPartyGate, DistributedBoat, DistributedButterfly, DistributedMMPiano, DistributedDGFlower, DistributedFishingSpot, SafeZoneManager, DistributedTreasure, DistributedGolfKart, DistributedPicnicBasket, DistributedPicnicTable, DistributedChineseCheckers, DistributedCheckers, DistributedFindFour
from toontown.fishing import DistributedFishingPond, DistributedFishingTarget, DistributedPondBingoManager
from toontown.minigame import DistributedMinigame, DistributedMinigameTemplate, DistributedRaceGame, DistributedCannonGame, DistributedPhotoGame, DistributedPatternGame, DistributedRingGame, DistributedTagGame, DistributedMazeGame, DistributedTugOfWarGame, DistributedCatchGame, DistributedDivingGame, DistributedTargetGame, DistributedTravelGame, DistributedPairingGame, DistributedVineGame, DistributedIceGame, DistributedCogThiefGame, DistributedTwoDGame
from toontown.minigame import DistributedMinigame, DistributedMinigameTemplate, DistributedRaceGame, DistributedCannonGame, DistributedPhotoGame, DistributedPatternGame, DistributedRingGame, DistributedTagGame, DistributedMazeGame, DistributedTugOfWarGame, DistributedCatchGame, DistributedDivingGame, DistributedTargetGame, DistributedTravelGame, DistributedVineGame, DistributedIceGame, DistributedCogThiefGame, DistributedTwoDGame
from toontown.racing import DistributedVehicle, DistributedStartingBlock, DistributedRace, DistributedKartPad, DistributedRacePad, DistributedViewPad, DistributedStartingBlock, DistributedLeaderBoard, DistributedGag, DistributedProjectile
from toontown.catalog import CatalogManager, AccountDate
from toontown.rpc.AwardManager import AwardManager

View file

@ -1,532 +0,0 @@
from pandac.PandaModules import *
from toontown.toonbase.ToonBaseGlobal import *
from DistributedMinigame import *
from direct.fsm import ClassicFSM, State
from direct.fsm import State
from toontown.toonbase import TTLocalizer, ToontownTimer
from toontown.toonbase import ToontownBattleGlobals
from toontown.minigame import PlayingCardGlobals
from toontown.minigame import PairingGameCard
from toontown.minigame import PlayingCardDeck
from toontown.minigame import PairingGameGlobals
from OrthoWalk import OrthoWalk
from OrthoDrive import OrthoDrive
from direct.interval.IntervalGlobal import Sequence, Parallel, Func, LerpColorScaleInterval, LerpScaleInterval, LerpFunctionInterval, Wait, SoundInterval
from toontown.toonbase.ToontownGlobals import GlobalDialogColor
class DistributedPairingGame(DistributedMinigame):
TOON_SPEED = 11
MAX_FRAME_MOVE = 1
MAX_FACE_UP_CARDS = 2
notify = directNotify.newCategory('DistributedPairingGame')
bonusGlowTime = 0.5
EndGameTaskName = 'endPairingGame'
xCardInc = 4
cardsPerRow = 8
cardsPerCol = 5
def __init__(self, cr):
DistributedMinigame.__init__(self, cr)
self.gameFSM = ClassicFSM.ClassicFSM('DistributedPairingGame', [State.State('off', self.enterOff, self.exitOff, ['play']), State.State('play', self.enterPlay, self.exitPlay, ['cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, [])], 'off', 'cleanup')
self.addChildGameFSM(self.gameFSM)
self.cameraTopView = (17.6, 6.18756, 43.9956, 0, -89, 0)
self.cameraThreeQuarterView = (14.0, -8.93352, 33.4497, 0, -62.89, 0)
self.deckSeed = 0
self.faceUpList = []
self.localFaceUpList = []
self.inList = []
self.inactiveList = []
self.points = 0
self.flips = 0
self.matches = 0
self.yCardInc = 4
self.startingPositions = [(0, 0, 0, -45),
((self.cardsPerRow - 1) * self.xCardInc,
(self.cardsPerCol - 1) * self.yCardInc,
0,
135),
((self.cardsPerRow - 1) * self.xCardInc,
0,
0,
45),
(0,
(self.cardsPerCol - 1) * self.yCardInc,
0,
-135)]
self.stageMin = Point2(0, 0)
self.stageMax = Point2((self.cardsPerRow - 1) * self.xCardInc, (self.cardsPerCol - 1) * self.yCardInc)
self.gameDuration = PairingGameGlobals.EasiestGameDuration
def moveCameraToTop(self):
camera.reparentTo(render)
p = self.cameraThreeQuarterView
camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5])
def getTitle(self):
return TTLocalizer.PairingGameTitle
def getInstructions(self):
if self.numPlayers > 1:
return TTLocalizer.PairingGameInstructionsMulti
else:
return TTLocalizer.PairingGameInstructions
def getMaxDuration(self):
return 0
def load(self):
self.notify.debug('load')
DistributedMinigame.load(self)
self.gameDuration = PairingGameGlobals.calcGameDuration(self.getDifficulty())
self.gameBoard = loader.loadModel('phase_4/models/minigames/memory_room')
self.gameBoard.setPosHpr(0.5, 0, 0, 0, 0, 0)
self.gameBoard.setScale(1.0)
self.deck = PairingGameGlobals.createDeck(self.deckSeed, self.numPlayers)
self.notify.debug('%s' % self.deck.cards)
testCard = self.getDeckOrderIndex(self.cardsPerCol - 1, 0)
if not testCard > -1:
self.yCardInc *= 1.25
self.cards = []
for index in xrange(len(self.deck.cards)):
cardValue = self.deck.cards[index]
oneCard = PairingGameCard.PairingGameCard(cardValue)
oneCard.load()
xPos, yPos = self.getCardPos(index)
oneCard.setPos(xPos, yPos, 0)
oneCard.reparentTo(render)
self.notify.debug('%s' % oneCard.getPos())
self.notify.debug('suit %s rank %s value %s' % (oneCard.suit, oneCard.rank, oneCard.value))
self.accept('entercardCollision-%d' % oneCard.value, self.enterCard)
self.accept('exitcardCollision-%d' % oneCard.value, self.exitCard)
oneCard.turnDown(doInterval=False)
self.cards.append(oneCard)
self.bonusTraversal = range(len(self.cards))
self.bonusGlow = render.attachNewNode('bonusGlow')
sign = loader.loadModel('phase_4/models/minigames/garden_sign_memory')
sign.find('**/sign1').removeNode()
sign.find('**/sign2').removeNode()
sign.find('**/collision').removeNode()
sign.setPos(0, 0, 0.05)
sign.reparentTo(self.bonusGlow)
self.bonusGlow.setScale(2.5)
self.pointsFrame = DirectFrame(relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=GlobalDialogColor, geom_scale=(4, 1, 1), pos=(-0.33, 0, 0.9), scale=0.1, text=TTLocalizer.PairingGamePoints, text_align=TextNode.ALeft, text_scale=TTLocalizer.DPGpointsFrame, text_pos=(-1.94, -0.1, 0.0))
self.pointsLabel = DirectLabel(parent=self.pointsFrame, relief=None, text='0', text_fg=VBase4(0, 0.5, 0, 1), text_align=TextNode.ARight, text_scale=0.7, pos=(1.82, 0, -0.15))
self.flipsFrame = DirectFrame(relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=GlobalDialogColor, geom_scale=(4, 1, 1), pos=(0.33, 0, 0.9), scale=0.1, text=TTLocalizer.PairingGameFlips, text_align=TextNode.ALeft, text_scale=TTLocalizer.DPGflipsFrame, text_pos=(-1.94, -0.1, 0.0))
self.flipsLabel = DirectLabel(parent=self.flipsFrame, relief=None, text='0', text_fg=VBase4(0, 1.0, 0, 1), text_align=TextNode.ARight, text_scale=0.7, pos=(1.82, 0, -0.15))
self.__textGen = TextNode('ringGame')
self.__textGen.setFont(ToontownGlobals.getSignFont())
self.__textGen.setAlign(TextNode.ACenter)
self.sndPerfect = base.loadSfx('phase_4/audio/sfx/MG_pairing_all_matched.ogg')
self.calcBonusTraversal()
self.music = base.loadMusic('phase_4/audio/bgm/MG_Pairing.ogg')
self.matchSfx = base.loadSfx('phase_4/audio/sfx/MG_pairing_match.ogg')
self.matchWithBonusSfx = base.loadSfx('phase_4/audio/sfx/MG_pairing_match_bonus_both.ogg')
self.signalSfx = []
for i in xrange(4):
self.signalSfx.append(base.loadSfx('phase_4/audio/sfx/MG_pairing_jumping_signal.ogg'))
self.bonusMovesSfx = base.loadSfx('phase_4/audio/sfx/MG_pairing_bonus_moves.ogg')
return
def unload(self):
self.notify.debug('unload')
DistributedMinigame.unload(self)
self.removeChildGameFSM(self.gameFSM)
del self.gameFSM
self.gameBoard.removeNode()
del self.gameBoard
for card in self.cards:
card.unload()
del card
self.cards = []
self.pointsFrame.removeNode()
del self.pointsFrame
self.flipsFrame.removeNode()
del self.flipsFrame
del self.__textGen
del self.sndPerfect
self.bonusGlow.removeNode()
del self.bonusGlow
del self.music
del self.matchSfx
del self.matchWithBonusSfx
for i in xrange(4):
del self.signalSfx[0]
self.signalSfx = []
del self.bonusMovesSfx
def onstage(self):
self.notify.debug('onstage')
DistributedMinigame.onstage(self)
self.gameBoard.reparentTo(render)
for card in self.cards:
card.reparentTo(render)
lt = base.localAvatar
lt.reparentTo(render)
lt.hideName()
self.__placeToon(self.localAvId)
lt.setAnimState('Happy', 1.0)
lt.setSpeed(0, 0)
self.moveCameraToTop()
def offstage(self):
self.notify.debug('offstage')
self.gameBoard.hide()
for card in self.cards:
card.hide()
DistributedMinigame.offstage(self)
def handleDisabledAvatar(self, avId):
self.notify.debug('handleDisabledAvatar')
self.notify.debug('avatar ' + str(avId) + ' disabled')
DistributedMinigame.handleDisabledAvatar(self, avId)
def setGameReady(self):
if not self.hasLocalToon:
return
self.notify.debug('setGameReady')
if DistributedMinigame.setGameReady(self):
return
for index in xrange(self.numPlayers):
avId = self.avIdList[index]
toon = self.getAvatar(avId)
if toon:
toon.reparentTo(render)
self.__placeToon(avId)
toon.setAnimState('Happy', 1.0)
toon.startSmooth()
toon.startLookAround()
def setGameStart(self, timestamp):
if not self.hasLocalToon:
return
self.notify.debug('setGameStart')
DistributedMinigame.setGameStart(self, timestamp)
for avId in self.remoteAvIdList:
toon = self.getAvatar(avId)
if toon:
toon.stopLookAround()
self.gameFSM.request('play')
def isInPlayState(self):
if not self.gameFSM.getCurrentState():
return False
if not self.gameFSM.getCurrentState().getName() == 'play':
return False
return True
def enterOff(self):
self.notify.debug('enterOff')
def exitOff(self):
pass
def enterPlay(self):
self.notify.debug('enterPlay')
base.playMusic(self.music, looping=1, volume=0.9)
orthoDrive = OrthoDrive(self.TOON_SPEED, maxFrameMove=self.MAX_FRAME_MOVE, customCollisionCallback=self.__doPairingGameCollisions)
self.orthoWalk = OrthoWalk(orthoDrive, broadcast=not self.isSinglePlayer())
self.orthoWalk.start()
self.accept('insert', self.__flipKeyPressed)
self.accept('delete', self.__flipKeyPressed)
self.accept('time-control', self.__beginSignal)
self.accept('time-control-up', self.__endSignal)
self.bonusGlowIndex = 0
self.bonusGlowCard = self.bonusTraversal[self.bonusGlowIndex]
self.startBonusTask()
self.timer = ToontownTimer.ToontownTimer()
self.timer.posInTopRightCorner()
self.timer.setTime(self.gameDuration)
self.timer.countdown(self.gameDuration, self.timerExpired)
if base.localAvatar.laffMeter:
base.localAvatar.laffMeter.stop()
def exitPlay(self):
self.music.stop()
self.orthoWalk.stop()
self.orthoWalk.destroy()
del self.orthoWalk
self.bonusGlow.hide()
self.stopBonusTask()
self.timer.stop()
self.timer.destroy()
del self.timer
self.ignoreAll()
if base.localAvatar.laffMeter:
base.localAvatar.laffMeter.start()
if hasattr(self, 'perfectIval'):
self.perfectIval.pause()
del self.perfectIval
taskMgr.remove(self.EndGameTaskName)
taskMgr.remove('pairGameContinueSignal')
def enterCleanup(self):
self.notify.debug('enterCleanup')
def exitCleanup(self):
pass
def __placeToon(self, avId):
toon = self.getAvatar(avId)
if self.numPlayers == 1:
toon.setPos(0, 0, 0)
toon.setHpr(0, 0, 0)
else:
posIndex = self.avIdList.index(avId)
pos = self.startingPositions[posIndex]
toon.setPos(pos[0], pos[1], pos[2])
toon.setHpr(pos[3], 0, 0)
def __doPairingGameCollisions(self, oldPos, newPos):
x = bound(newPos[0], self.stageMin[0], self.stageMax[0])
y = bound(newPos[1], self.stageMin[1], self.stageMax[1])
newPos.setX(x)
newPos.setY(y)
if self.inList:
newPos.setZ(0.15)
else:
newPos.setZ(0.0)
if not oldPos == newPos:
taskMgr.remove('pairGameContinueSignal')
return newPos
def getDeckOrderFromValue(self, value):
for index in xrange(len(self.cards)):
if self.cards[index].value == value:
return index
return -1
def getDeckOrderFromPairingGameCard(self, into):
try:
index = self.cards.index(into)
except ValueError:
index = -1
return index
def enterCard(self, colEntry):
intoName = colEntry.getIntoNodePath().getName()
parts = intoName.split('-')
value = int(parts[1])
self.notify.debug('entered cardValue %d' % value)
deckOrder = self.getDeckOrderFromValue(value)
if deckOrder not in self.inList:
self.inList.append(deckOrder)
def exitCard(self, colEntry):
intoName = colEntry.getIntoNodePath().getName()
parts = intoName.split('-')
value = int(parts[1])
self.notify.debug('exited cardValue %d' % value)
deckOrder = self.getDeckOrderFromValue(value)
if deckOrder in self.inList:
self.inList.remove(deckOrder)
def handleMatch(self, cardA, cardB, withBonus):
self.notify.debug('we got a match %d %d' % (cardA, cardB))
self.matches += 1
if cardA in self.faceUpList:
self.faceUpList.remove(cardA)
if cardB in self.faceUpList:
self.faceUpList.remove(cardB)
self.inactiveList.append(cardA)
self.inactiveList.append(cardB)
matchIval = Parallel()
for card in [cardA, cardB]:
self.cards[card].setTransparency(1)
cardSeq = Sequence(LerpColorScaleInterval(self.cards[card], duration=1, colorScale=Vec4(1.0, 1.0, 1.0, 0.0)), Func(self.cards[card].hide))
matchIval.append(cardSeq)
if withBonus:
matchIval.append(SoundInterval(self.matchWithBonusSfx, node=self.cards[card], listenerNode=base.localAvatar, cutOff=240))
else:
matchIval.append(SoundInterval(self.matchSfx, node=self.cards[card], listenerNode=base.localAvatar, cutOff=240))
matchIval.start()
if len(self.inactiveList) == len(self.cards):
self.sendUpdate('reportDone')
def turnUpCard(self, deckOrder):
self.cards[deckOrder].turnUp()
self.faceUpList.append(deckOrder)
def turnDownCard(self, deckOrder):
self.cards[deckOrder].turnDown()
if deckOrder in self.faceUpList:
self.faceUpList.remove(deckOrder)
def __flipKeyPressed(self):
if self.inList:
shortestDistance = 10000
cardToFlip = -1
for deckOrder in self.inList:
dist = base.localAvatar.getDistance(self.cards[deckOrder])
if dist < shortestDistance:
shortestDistance = dist
cardToFlip = deckOrder
deckOrderIndex = cardToFlip
card = self.cards[deckOrderIndex]
if card.isFaceDown() and deckOrderIndex not in self.inactiveList:
self.sendUpdate('openCardRequest', [deckOrderIndex, self.bonusGlowCard])
elif card.isFaceUp() and deckOrderIndex in self.faceUpList:
pass
def moveBonusGlowTask(self, task):
if len(self.cards) == 0:
return Task.done
curT = self.getCurrentGameTime()
intTime = int(curT / self.bonusGlowTime)
newIndex = intTime % len(self.cards)
if not newIndex == self.bonusGlowIndex:
self.bonusGlowIndex = newIndex
self.bonusGlowCard = self.bonusTraversal[self.bonusGlowIndex]
card = self.cards[self.bonusGlowCard]
self.bonusGlow.setPos(card.getPos())
base.playSfx(self.bonusMovesSfx, node=card, volume=0.25)
return Task.cont
def timerExpired(self):
self.sendUpdate('reportDone')
def setDeckSeed(self, deckSeed):
if not self.hasLocalToon:
return
self.deckSeed = deckSeed
def updateFlipText(self):
self.flipsLabel['text'] = str(self.flips)
lowFlipModifier = PairingGameGlobals.calcLowFlipModifier(self.matches, self.flips)
red = 1.0 - lowFlipModifier
green = lowFlipModifier
self.flipsLabel['text_fg'] = Vec4(red, green, 0, 1.0)
def openCardResult(self, cardToTurnUp, avId, matchingCard, points, cardsToTurnDown):
if not self.hasLocalToon:
return
if not self.isInPlayState():
return
if avId == base.localAvatar.doId:
self.localFaceUpList.append(cardToTurnUp)
self.turnUpCard(cardToTurnUp)
gotBonus = False
if points - self.points > 1:
gotBonus = True
if matchingCard > -1:
self.handleMatch(cardToTurnUp, matchingCard, gotBonus)
self.flips += 1
self.updateFlipText()
self.points = points
self.pointsLabel['text'] = str(self.points)
for card in cardsToTurnDown:
self.turnDownCard(card)
def startBonusTask(self):
taskMgr.add(self.moveBonusGlowTask, self.taskName('moveBonusGlowTask'))
def stopBonusTask(self):
taskMgr.remove(self.taskName('moveBonusGlowTask'))
def setEveryoneDone(self):
if not self.hasLocalToon:
return
if self.gameFSM.getCurrentState().getName() != 'play':
self.notify.warning('ignoring setEveryoneDone msg')
return
self.notify.debug('setEveryoneDone')
def endGame(task, self = self):
if not PairingGameGlobals.EndlessGame:
self.gameOver()
return Task.done
self.timer.hide()
self.bonusGlow.hide()
if len(self.inactiveList) == len(self.cards):
self.notify.debug('perfect game!')
perfectTextSubnode = hidden.attachNewNode(self.__genText(TTLocalizer.PairingGamePerfect))
perfectText = hidden.attachNewNode('perfectText')
perfectTextSubnode.reparentTo(perfectText)
frame = self.__textGen.getCardActual()
offsetY = -abs(frame[2] + frame[3]) / 2.0
perfectTextSubnode.setPos(0, 0, offsetY)
perfectText.setColor(1, 0.1, 0.1, 1)
def fadeFunc(t, text = perfectText):
text.setColorScale(1, 1, 1, t)
def destroyText(text = perfectText):
text.removeNode()
textTrack = Sequence(Func(perfectText.reparentTo, aspect2d), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=0.3, startScale=0.0), LerpFunctionInterval(fadeFunc, fromData=0.0, toData=1.0, duration=0.5)), Wait(2.0), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=1.0), LerpFunctionInterval(fadeFunc, fromData=1.0, toData=0.0, duration=0.5, blendType='easeIn')), Func(destroyText), WaitInterval(0.5), Func(endGame, None))
soundTrack = SoundInterval(self.sndPerfect)
self.perfectIval = Parallel(textTrack, soundTrack)
self.perfectIval.start()
else:
taskMgr.doMethodLater(1, endGame, self.EndGameTaskName)
return
def __genText(self, text):
self.__textGen.setText(text)
return self.__textGen.generate()
def b_setSignaling(self, avId):
self.setSignaling(avId)
self.sendUpdate('setSignaling', [self.localAvId])
def setSignaling(self, avId):
if not self.hasLocalToon:
return
avIndex = self.avIdList.index(avId)
av = base.cr.doId2do.get(avId)
if av and avIndex >= 0 and hasattr(self, 'signalSfx') and self.signalSfx:
base.playSfx(self.signalSfx[avIndex], node=av)
def __beginSignal(self, mouseParam):
self.notify.debug('beginSignal')
base.localAvatar.b_setEmoteState(1, 1.0)
self.b_setSignaling(self.localAvId)
taskMgr.doMethodLater(1.67, self.__continueSignal, 'pairGameContinueSignal')
def __endSignal(self, mouseParam):
self.notify.debug('endSignal')
base.localAvatar.b_setEmoteState(-1, 1.0)
taskMgr.remove('pairGameContinueSignal')
def __continueSignal(self, task):
base.localAvatar.b_setEmoteState(1, 1.0)
self.b_setSignaling(self.localAvId)
taskMgr.doMethodLater(1.67, self.__continueSignal, 'pairGameContinueSignal')
def getCardPos(self, deckOrderIndex):
col = deckOrderIndex % self.cardsPerRow
row = deckOrderIndex / self.cardsPerRow
x = col * self.xCardInc
y = row * self.yCardInc
return (x, y)
def getDeckOrderIndex(self, row, col):
retval = row * self.cardsPerRow
retval += col
if retval >= len(self.deck.cards):
retval = -1
return retval
def calcBonusTraversal(self):
self.bonusTraversal = []
halfRow = self.cardsPerRow / 2
if self.cardsPerRow % 2:
halfRow += 1
for i in xrange(halfRow):
for j in xrange(2):
col = i + j * halfRow
for row in xrange(self.cardsPerCol):
card = self.getDeckOrderIndex(row, col)
if card > -1:
self.bonusTraversal.append(card)

View file

@ -1,229 +0,0 @@
from DistributedMinigameAI import *
from direct.fsm import ClassicFSM, State
from direct.fsm import State
from toontown.minigame import PlayingCardGlobals
from toontown.minigame import PlayingCard
from toontown.minigame.PlayingCard import PlayingCardBase
from toontown.minigame import PlayingCardDeck
from toontown.minigame import PairingGameGlobals
from toontown.ai.ToonBarrier import ToonBarrier
class DistributedPairingGameAI(DistributedMinigameAI):
notify = directNotify.newCategory('DistributedPairingGameAI')
OneCardInMultiplayer = True
TurnDownTwoAtATime = True
def __init__(self, air, minigameId):
try:
self.DistributedPairingGameAI_initialized
except:
self.DistributedPairingGameAI_initialized = 1
DistributedMinigameAI.__init__(self, air, minigameId)
self.gameFSM = ClassicFSM.ClassicFSM('DistributedPairingGameAI', [State.State('inactive', self.enterInactive, self.exitInactive, ['play']), State.State('play', self.enterPlay, self.exitPlay, ['cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, ['inactive'])], 'inactive', 'inactive')
self.addChildGameFSM(self.gameFSM)
self.gameFSM.enterInitialState()
self.deckSeed = random.randint(0, 4000000)
self.faceUpDict = {}
self.inactiveList = []
self.maxOpenCards = 2
self.points = 0
self.flips = 0
self.matches = 0
self.cards = []
self.gameDuration = 90
def generate(self):
self.notify.debug('generate')
DistributedMinigameAI.generate(self)
def delete(self):
self.notify.debug('delete')
del self.gameFSM
DistributedMinigameAI.delete(self)
def setGameReady(self):
self.notify.debug('setGameReady')
if self.OneCardInMultiplayer and len(self.avIdList) > 1:
self.maxOpenCards = 1
self.sendUpdate('setMaxOpenCards', [self.maxOpenCards])
DistributedMinigameAI.setGameReady(self)
for avId in self.avIdList:
self.faceUpDict[avId] = []
self.deck = PairingGameGlobals.createDeck(self.deckSeed, self.numPlayers)
for index in xrange(len(self.deck.cards)):
cardValue = self.deck.cards[index]
oneCard = PlayingCardBase(cardValue)
self.cards.append(oneCard)
def setGameStart(self, timestamp):
self.notify.debug('setGameStart')
DistributedMinigameAI.setGameStart(self, timestamp)
self.gameFSM.request('play')
def setGameAbort(self):
self.notify.debug('setGameAbort')
if self.gameFSM.getCurrentState():
self.gameFSM.request('cleanup')
DistributedMinigameAI.setGameAbort(self)
def calcLowFlipBonus(self):
lowFlipModifier = PairingGameGlobals.calcLowFlipModifier(self.matches, self.flips)
bonus = lowFlipModifier * self.matches
self.notify.debug('low flip bonus = %d' % bonus)
return bonus
def gameOver(self):
self.notify.debug('gameOver')
lowFlipBonus = 0
for avId in self.avIdList:
self.scoreDict[avId] = max(1, self.points)
lowFlipBonus = self.calcLowFlipBonus()
self.scoreDict[avId] += lowFlipBonus
if self.matches == len(self.cards) / 2:
self.scoreDict[avId] += round(len(self.cards) / 4.0)
self.logAllPerfect()
logAvId = self.avIdList[0]
self.air.writeServerEvent('minigame_pairing', self.doId, '%s|%s|%s|%s|%s|%s|%s|%s' % (ToontownGlobals.PairingGameId,
self.getSafezoneId(),
self.avIdList,
self.scoreDict[logAvId],
self.gameDuration,
self.matches,
self.flips,
lowFlipBonus))
self.gameFSM.request('cleanup')
DistributedMinigameAI.gameOver(self)
def enterInactive(self):
self.notify.debug('enterInactive')
def exitInactive(self):
pass
def enterPlay(self):
self.notify.debug('enterPlay')
def allToonsDone(self = self):
self.notify.debug('allToonsDone')
self.sendUpdate('setEveryoneDone')
if not PairingGameGlobals.EndlessGame:
self.gameOver()
def handleTimeout(avIds, self = self):
self.notify.debug('handleTimeout: avatars %s did not report "done"' % avIds)
self.setGameAbort()
self.gameDuration = PairingGameGlobals.calcGameDuration(self.getDifficulty())
self.doneBarrier = ToonBarrier('waitClientsDone', self.uniqueName('waitClientsDone'), self.avIdList, self.gameDuration + MinigameGlobals.latencyTolerance, allToonsDone, handleTimeout)
def exitPlay(self):
self.doneBarrier.cleanup()
del self.doneBarrier
def enterCleanup(self):
self.notify.debug('enterCleanup')
self.gameFSM.request('inactive')
def exitCleanup(self):
pass
def getDeckSeed(self):
return self.deckSeed
def isCardFaceUp(self, deckOrderIndex):
retval = False
for key in self.faceUpDict.keys():
if deckOrderIndex in self.faceUpDict[key]:
retval = True
break
return retval
def isCardFaceDown(self, deckOrderIndex):
return not self.isCardFaceUp(deckOrderIndex)
def checkForMatch(self):
faceUpList = []
for oneToonFaceUpList in self.faceUpDict.values():
faceUpList += oneToonFaceUpList
for i in xrange(len(faceUpList)):
cardA = faceUpList[i]
for j in xrange(i + 1, len(faceUpList)):
cardB = faceUpList[j]
if self.cards[cardA].rank == self.cards[cardB].rank:
return (cardA, cardB)
return (-1, -1)
def handleMatch(self, cardA, cardB):
self.notify.debug('we got a match %d %d' % (cardA, cardB))
for key in self.faceUpDict.keys():
if cardA in self.faceUpDict[key]:
self.faceUpDict[key].remove(cardA)
if cardB in self.faceUpDict[key]:
self.faceUpDict[key].remove(cardB)
self.inactiveList.append(cardA)
self.inactiveList.append(cardB)
def turnDownCard(self, cardA):
self.notify.debug('turning down card %d' % cardA)
for key in self.faceUpDict.keys():
if cardA in self.faceUpDict[key]:
self.faceUpDict[key].remove(cardA)
def openCardRequest(self, deckOrderIndex, bonusGlowCard):
if self.isCardFaceUp(deckOrderIndex):
return
if self.gameFSM.getCurrentState().getName() != 'play':
return
avId = self.air.getAvatarIdFromSender()
if avId not in self.avIdList:
self.air.writeServerEvent('suspicious', avId, 'openCardRequest from non-player av %s' % avId)
return
if deckOrderIndex < 0 or deckOrderIndex >= len(self.cards):
self.air.writeServerEvent('suspicious', avId, 'openCardRequest: invalid deckOrderIndex: %s' % deckOrderIndex)
return
if bonusGlowCard < 0 or bonusGlowCard >= len(self.cards):
self.air.writeServerEvent('suspicious', avId, 'openCardRequest: invalid bonusGlowCard: %s' % bonusGlowCard)
return
cardsToTurnDown = []
faceUpList = self.faceUpDict[avId]
numCardsFaceUpAtStart = len(faceUpList)
if len(faceUpList) >= self.maxOpenCards:
oldestCard = faceUpList.pop(0)
cardsToTurnDown.append(oldestCard)
if self.TurnDownTwoAtATime and numCardsFaceUpAtStart == 2:
secondOldestCard = faceUpList.pop(0)
cardsToTurnDown.append(secondOldestCard)
cardToTurnUp = deckOrderIndex
self.faceUpDict[avId].append(cardToTurnUp)
cardA, cardB = self.checkForMatch()
matchingCard = -1
if cardA > -1:
self.handleMatch(cardA, cardB)
if cardA == deckOrderIndex:
matchingCard = cardB
else:
matchingCard = cardA
pointsToGive = 1
if bonusGlowCard in [cardA, cardB]:
pointsToGive += 1
self.points += pointsToGive
self.matches += 1
self.flips += 1
self.sendUpdate('openCardResult', [cardToTurnUp,
avId,
matchingCard,
self.points,
cardsToTurnDown])
def reportDone(self):
if self.gameFSM.getCurrentState().getName() != 'play':
return
avId = self.air.getAvatarIdFromSender()
self.notify.debug('reportDone: avatar %s is done' % avId)
self.doneBarrier.clear(avId)

View file

@ -1,94 +0,0 @@
from PlayingCard import PlayingCardNodePath
import PlayingCardGlobals
from pandac.PandaModules import NodePath, Vec3
from direct.interval.IntervalGlobal import LerpHprInterval, Parallel, SoundInterval
class PairingGameCard(PlayingCardNodePath):
DoIntervalDefault = True
FlipTime = 0.25
UseDifferentCardColors = True
CardColors = [(0.933594, 0.265625, 0.28125, 1.0),
(0.550781, 0.824219, 0.324219, 1.0),
(0.347656, 0.820312, 0.953125, 1.0),
(0.460938, 0.378906, 0.824219, 1.0),
(0.710938, 0.234375, 0.4375, 1.0),
(0.285156, 0.328125, 0.726562, 1.0),
(0.242188, 0.742188, 0.515625, 1.0),
(0.96875, 0.691406, 0.699219, 1.0),
(0.996094, 0.957031, 0.597656, 1.0),
(0.992188, 0.480469, 0.167969, 1.0)]
def __init__(self, value):
style = PlayingCardGlobals.Styles[0]
PlayingCardNodePath.__init__(self, style, value)
self.enterCallback = None
self.exitCallback = None
return
def load(self):
oneCard = loader.loadModel('phase_4/models/minigames/garden_sign_memory')
prop = self.attachNewNode('prop')
PlayingCardGlobals.getImage(self.style, self.suit, self.rank).copyTo(prop)
prop.setScale(7)
oneCard.find('**/glow').removeNode()
cs = oneCard.find('**/collision')
for solidIndex in xrange(cs.node().getNumSolids()):
cs.node().modifySolid(solidIndex).setTangible(False)
cs.node().setName('cardCollision-%d' % self.value)
sign = oneCard.find('**/sign1')
if self.UseDifferentCardColors:
index = self.rank % len(self.CardColors)
color = self.CardColors[index]
sign.setColorScale(*color)
prop.setPos(0.0, 0.0, 0.08)
prop.setP(-90)
prop.reparentTo(oneCard)
oneCard.reparentTo(self)
cardBack = oneCard.find('**/sign2')
cardBack.setColorScale(0.12, 0.35, 0.5, 1.0)
cardModel = loader.loadModel('phase_3.5/models/gui/playingCard')
logo = cardModel.find('**/logo')
logo.reparentTo(self)
logo.setScale(0.45)
logo.setP(90)
logo.setZ(0.025)
logo.setX(-0.05)
logo.setH(180)
cardModel.removeNode()
self.setR(0)
self.setScale(2.5)
self.flipIval = None
self.turnUpSound = base.loadSfx('phase_4/audio/sfx/MG_pairing_card_flip_face_up.ogg')
self.turnDownSound = base.loadSfx('phase_4/audio/sfx/MG_pairing_card_flip_face_down.ogg')
return
def unload(self):
self.clearFlipIval()
self.removeNode()
del self.turnUpSound
del self.turnDownSound
def turnUp(self, doInterval = DoIntervalDefault):
self.faceUp = 1
if doInterval:
self.clearFlipIval()
self.flipIval = Parallel(LerpHprInterval(self, self.FlipTime, Vec3(0, 0, 0)), SoundInterval(self.turnUpSound, node=self, listenerNode=base.localAvatar, cutOff=240))
self.flipIval.start()
else:
self.setR(0)
def clearFlipIval(self):
if self.flipIval:
self.flipIval.finish()
self.flipIval = None
return
def turnDown(self, doInterval = DoIntervalDefault):
self.faceUp = 0
if doInterval:
self.clearFlipIval()
self.flipIval = Parallel(LerpHprInterval(self, self.FlipTime, Vec3(0, 0, 180)), SoundInterval(self.turnDownSound, node=self, listenerNode=base.localAvatar, cutOff=240))
self.flipIval.start()
else:
self.setR(180)

View file

@ -1,39 +0,0 @@
import PlayingCardDeck
EasiestGameDuration = 120
HardestGameDuration = 90
EndlessGame = config.GetBool('endless-pairing-game', 0)
MaxRankIndexUsed = [7,
7,
7,
8,
9]
def createDeck(deckSeed, numPlayers):
deck = PlayingCardDeck.PlayingCardDeck()
deck.shuffleWithSeed(deckSeed)
deck.removeRanksAbove(MaxRankIndexUsed[numPlayers])
return deck
def calcGameDuration(difficulty):
difference = EasiestGameDuration - HardestGameDuration
adjust = difference * difficulty
retval = EasiestGameDuration - adjust
return retval
def calcLowFlipModifier(matches, flips):
idealFlips = round(matches * 2 * 1.6)
if idealFlips < 2:
idealFlips = 2
maxFlipsForBonus = idealFlips * 2
retval = 0
if flips < idealFlips:
retval = 1
elif maxFlipsForBonus < flips:
retval = 0
else:
divisor = maxFlipsForBonus - idealFlips
difference = maxFlipsForBonus - flips
retval = float(difference) / divisor
return retval

View file

@ -1,114 +0,0 @@
from direct.gui.DirectGui import *
from pandac.PandaModules import *
from direct.task import Task
from toontown.toonbase import TTLocalizer
import PlayingCardGlobals
class PlayingCardBase:
def __init__(self, value):
self.faceUp = 1
self.setValue(value)
def getCardName(self):
PlayingCardGlobals.getCardName(self.value)
def getRank(self):
return self.rank
def getSuit(self):
return self.suit
def getValue(self):
return self.value
def setImage(self):
pass
def setValue(self, value):
self.value = value
if self.value == PlayingCardGlobals.Unknown:
self.suit = None
self.rank = None
self.turnDown()
else:
self.suit = value / PlayingCardGlobals.MaxRank
self.rank = value % PlayingCardGlobals.MaxRank
self.setImage()
return
def isFaceUp(self):
return self.faceUp
def isFaceDown(self):
return not self.faceUp
def turnUp(self):
self.faceUp = 1
self.setImage()
def turnDown(self):
self.faceUp = 0
self.setImage()
class PlayingCardNodePath(NodePath, PlayingCardBase):
def __init__(self, style, value):
self.image = None
self.style = style
NodePath.__init__(self, 'PlayingCard')
PlayingCardBase.__init__(self, value)
return
def setImage(self):
if self.faceUp:
image = PlayingCardGlobals.getImage(self.style, self.suit, self.rank)
else:
image = PlayingCardGlobals.getBack(self.style)
if self.image:
self.image.removeNode()
self.image = image.copyTo(self)
class PlayingCardButton(PlayingCardBase, DirectButton):
def __init__(self, style, value):
PlayingCardBase.__init__(self, value)
self.style = style
DirectButton.__init__(self, relief=None)
self.initialiseoptions(PlayingCardButton)
self.bind(DGG.B1PRESS, self.dragStart)
self.bind(DGG.B1RELEASE, self.dragStop)
return
def setImage(self):
if self.faceUp:
image = PlayingCardGlobals.getImage(self.style, self.suit, self.rank)
else:
image = PlayingCardGlobals.getBack(self.style)
self['image'] = image
def dragStart(self, event):
taskMgr.remove(self.taskName('dragTask'))
vWidget2render2d = self.getPos(render2d)
vMouse2render2d = Point3(event.getMouse()[0], 0, event.getMouse()[1])
editVec = Vec3(vWidget2render2d - vMouse2render2d)
task = taskMgr.add(self.dragTask, self.taskName('dragTask'))
task.editVec = editVec
def dragTask(self, task):
mwn = base.mouseWatcherNode
if mwn.hasMouse():
vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1])
newPos = vMouse2render2d + task.editVec
self.setPos(render2d, newPos)
return Task.cont
def dragStop(self, event):
taskMgr.remove(self.taskName('dragTask'))
messenger.send('PlayingCardDrop', sentArgs=[self])
def destroy(self):
taskMgr.remove(self.taskName('dragTask'))
DirectButton.destroy(self)

View file

@ -1,44 +0,0 @@
import random
import PlayingCardGlobals
from toontown.minigame.PlayingCard import PlayingCardBase
class PlayingCardDeck:
def __init__(self):
self.shuffle()
def shuffle(self):
self.cards = range(0, PlayingCardGlobals.MaxSuit * PlayingCardGlobals.MaxRank)
random.shuffle(self.cards)
def shuffleWithSeed(self, seed):
generator = random.Random()
generator.seed(seed)
self.cards = range(0, PlayingCardGlobals.MaxSuit * PlayingCardGlobals.MaxRank)
generator.shuffle(self.cards)
def dealCard(self):
return self.cards.pop(0)
def dealCards(self, num):
cardList = []
for i in xrange(num):
cardList.append(self.cards.pop(0))
return cardList
def count(self):
return len(self.cards)
def removeRanksAbove(self, maxRankInDeck):
done = False
while not done:
removedOne = False
for cardValue in self.cards:
tempCard = PlayingCardBase(cardValue)
if tempCard.rank > maxRankInDeck:
self.cards.remove(cardValue)
removedOne = True
if not removedOne:
done = True

View file

@ -1,85 +0,0 @@
from toontown.toonbase import TTLocalizer
from toontown.toonbase import ToontownBattleGlobals
from pandac.PandaModules import Vec4
Up = 1
Down = 0
MaxRank = 13
MaxSuit = 4
Hearts = 0
Diamonds = 1
Clubs = 2
Spades = 3
Suits = [Hearts,
Diamonds,
Clubs,
Spades]
Unknown = 255
UpColor = Vec4(1, 1, 1, 1)
RolloverColor = Vec4(1, 1, 0.5, 1)
DownColor = Vec4(1, 0.9, 0.9, 1)
DisabledColor = Vec4(1, 1, 1, 0.5)
CardColors = (UpColor,
DownColor,
RolloverColor,
DisabledColor)
def getCardName(value):
if value == Unknown:
return TTLocalizer.PlayingCardUnknown
else:
rank = value % MaxRank
suit = value / MaxRank
return TTLocalizer.getPlayingCardName(suit, rank)
Styles = ['standard']
CardImages = {}
_cardImagesInitialized = 0
_modelPathBase = 'phase_3.5/models/gui/inventory_icons'
def convertValueToGagTrackAndLevel(value):
imageNum = int(rank / MaxSuit)
track = imageNum % (ToontownBattleGlobals.MAX_TRACK_INDEX + 1)
level = imageNum / (ToontownBattleGlobals.MAX_TRACK_INDEX + 1)
return (track, level)
def convertRankToGagTrackAndLevel(rank):
track = rank % (ToontownBattleGlobals.MAX_TRACK_INDEX + 1)
level = rank / (ToontownBattleGlobals.MAX_TRACK_INDEX + 1)
return (track, level)
def initCardImages():
global _cardImagesInitialized
suitCodes = ('h', 'd', 'c', 's')
rankCodes = ('02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '01')
for style in Styles:
modelPath = _modelPathBase
cardModel = loader.loadModel(modelPath)
cardModel.hide()
CardImages[style] = {}
for suitIndex in xrange(MaxSuit):
CardImages[style][suitIndex] = {}
for rankIndex in xrange(MaxRank):
track, level = convertRankToGagTrackAndLevel(rankIndex)
propName = ToontownBattleGlobals.AvPropsNew[track][level]
cardNode = cardModel.find('**/%s' % propName)
CardImages[style][suitIndex][rankIndex] = cardNode
propName = ToontownBattleGlobals.AvPropsNew[ToontownBattleGlobals.MAX_TRACK_INDEX][ToontownBattleGlobals.MAX_LEVEL_INDEX]
CardImages[style]['back'] = cardModel.find(propName)
_cardImagesInitialized = 1
def getImage(style, suit, rank):
if _cardImagesInitialized == 0:
initCardImages()
return CardImages[style][suit][rank]
def getBack(style):
if _cardImagesInitialized == 0:
initCardImages()
return CardImages[style]['back']

View file

@ -8301,12 +8301,6 @@ TravelGameGotBonus = '%(name)s got a bonus of %(numBeans)s Jellybeans!'
TravelGameNoOneGotBonus = 'No one reached their secret goal. Everyone gets 1 Jellybean.'
TravelGameConvertingVotesToBeans = 'Converting some votes to Jellybeans...'
TravelGameGoingBackToShop = "Only 1 toon left. Going to Goofy's Gag Shop."
PairingGameTitle = 'Toon Memory Game'
PairingGameInstructions = 'Press Delete to open a card. Match 2 cards to score a point. Make a match with the bonus glow and earn an extra point. Earn more points by keeping the flips low.'
PairingGameInstructionsMulti = 'Press Delete to open a card. Press Control to signal another toon to open a card. Match 2 cards to score a point. Make a match with the bonus glow and earn an extra point. Earn more points by keeping the flips low.'
PairingGamePerfect = 'PERFECT!!'
PairingGameFlips = 'Flips:'
PairingGamePoints = 'Points:'
TrolleyHolidayStart = 'Trolley Tracks is about to begin! Board any trolley with 2 or more toons to play.'
TrolleyHolidayOngoing = 'Welcome! Trolley Tracks is currently in progress.'
TrolleyHolidayEnd = "That's all for today's Trolley Tracks. See you next week!"
@ -8861,7 +8855,6 @@ InteractivePropTrackBonusTerms = {0: 'Super Toon-Up!',
4: 'Super Throw!',
5: 'Super Squirt!',
6: ''}
PlayingCardUnknown = 'Card Name is unknown'
GloveSameColorMessage = 'You already have those gloves!'
GloveNoMoneyMessage = "You don't have enough jellybeans!"
GloveSuccessMessage = 'Have fun with your new gloves!'

View file

@ -99,8 +99,6 @@ MPMgaugeTargetTop = 0.35
MPMgaugeTargetBot = 0.35
PstatusLabel = 0.08
PBstatusLabel = 0.08
DPGpointsFrame = 0.7
DPGflipsFrame = 0.7
DTGvoteButton = 0.07
DTGuseLabel = 0.1
DTGvotesPeriodLabel = 0.1

View file

@ -342,12 +342,11 @@ TugOfWarGameId = 7
CatchGameId = 8
DivingGameId = 9
TargetGameId = 10
PairingGameId = 11
VineGameId = 12
IceGameId = 13
CogThiefGameId = 14
TwoDGameId = 15
PhotoGameId = 16
VineGameId = 11
IceGameId = 12
CogThiefGameId = 13
TwoDGameId = 14
PhotoGameId = 15
TravelGameId = 100
MinigameNames = {'race': RaceGameId,
'cannon': CannonGameId,
@ -362,7 +361,6 @@ MinigameNames = {'race': RaceGameId,
'catch': CatchGameId,
'diving': DivingGameId,
'target': TargetGameId,
'pairing': PairingGameId,
'vine': VineGameId,
'ice': IceGameId,
'thief': CogThiefGameId,
@ -380,7 +378,6 @@ MinigameIDs = (RaceGameId,
CatchGameId,
DivingGameId,
TargetGameId,
PairingGameId,
VineGameId,
IceGameId,
CogThiefGameId,
@ -388,10 +385,10 @@ MinigameIDs = (RaceGameId,
PhotoGameId,
TravelGameId)
MinigamePlayerMatrix = {
1: (CannonGameId, MazeGameId, TugOfWarGameId, RingGameId, VineGameId, CogThiefGameId, TwoDGameId, DivingGameId, PairingGameId, CatchGameId, TargetGameId, PhotoGameId),
2: (CannonGameId, MazeGameId, TugOfWarGameId, PatternGameId, TagGameId, RingGameId, VineGameId, IceGameId, CogThiefGameId, TwoDGameId, DivingGameId, PairingGameId, CatchGameId, TargetGameId, PhotoGameId),
3: (CannonGameId, MazeGameId, TugOfWarGameId, PatternGameId, RaceGameId, TagGameId, VineGameId, RingGameId, IceGameId, CogThiefGameId, TwoDGameId, DivingGameId, PairingGameId, CatchGameId, TargetGameId, PhotoGameId),
4: (CannonGameId, MazeGameId, TugOfWarGameId, PatternGameId, RaceGameId, TagGameId, VineGameId, RingGameId, IceGameId, CogThiefGameId, TwoDGameId, DivingGameId, PairingGameId, CatchGameId, TargetGameId, PhotoGameId),
1: (CannonGameId, MazeGameId, TugOfWarGameId, RingGameId, VineGameId, CogThiefGameId, TwoDGameId, DivingGameId, CatchGameId, TargetGameId, PhotoGameId),
2: (CannonGameId, MazeGameId, TugOfWarGameId, PatternGameId, TagGameId, RingGameId, VineGameId, IceGameId, CogThiefGameId, TwoDGameId, DivingGameId, CatchGameId, TargetGameId, PhotoGameId),
3: (CannonGameId, MazeGameId, TugOfWarGameId, PatternGameId, RaceGameId, TagGameId, VineGameId, RingGameId, IceGameId, CogThiefGameId, TwoDGameId, DivingGameId, CatchGameId, TargetGameId, PhotoGameId),
4: (CannonGameId, MazeGameId, TugOfWarGameId, PatternGameId, RaceGameId, TagGameId, VineGameId, RingGameId, IceGameId, CogThiefGameId, TwoDGameId, DivingGameId, CatchGameId, TargetGameId, PhotoGameId),
}
KeyboardTimeout = 300
phaseMap = {Tutorial: 4,