229 lines
8.5 KiB
Python
229 lines
8.5 KiB
Python
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 range(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 list(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 list(self.faceUpDict.values()):
|
|
faceUpList += oneToonFaceUpList
|
|
|
|
for i in range(len(faceUpList)):
|
|
cardA = faceUpList[i]
|
|
for j in range(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 list(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 list(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.logSuspicious(avId, 'openCardRequest: invalid deckOrderIndex: %s' % deckOrderIndex)
|
|
return
|
|
if bonusGlowCard < 0 or bonusGlowCard >= len(self.cards):
|
|
self.logSuspicious(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)
|