from math import * from DistributedMinigameAI import * from direct.distributed.ClockDelta import * from direct.fsm import ClassicFSM, State from direct.fsm import State import random from direct.task.Task import Task import RaceGameGlobals class DistributedRaceGameAI(DistributedMinigameAI): def __init__(self, air, minigameId): try: self.DistributedRaceGameAI_initialized except: self.DistributedRaceGameAI_initialized = 1 DistributedMinigameAI.__init__(self, air, minigameId) self.gameFSM = ClassicFSM.ClassicFSM('DistributedRaceGameAI', [State.State('inactive', self.enterInactive, self.exitInactive, ['waitClientsChoices']), State.State('waitClientsChoices', self.enterWaitClientsChoices, self.exitWaitClientsChoices, ['processChoices', 'cleanup']), State.State('processChoices', self.enterProcessChoices, self.exitProcessChoices, ['waitClientsChoices', 'cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, ['inactive'])], 'inactive', 'inactive') self.addChildGameFSM(self.gameFSM) self.avatarChoices = {} self.avatarPositions = {} self.chancePositions = {} self.rewardDict = {} def delete(self): self.notify.debug('delete') del self.gameFSM DistributedMinigameAI.delete(self) def setGameReady(self): self.notify.debug('setGameReady') DistributedMinigameAI.setGameReady(self) self.resetChancePositions() self.resetPositions() def setGameStart(self, timestamp): self.notify.debug('setGameStart') DistributedMinigameAI.setGameStart(self, timestamp) self.gameFSM.request('waitClientsChoices') def setGameAbort(self): self.notify.debug('setGameAbort') if self.gameFSM.getCurrentState(): self.gameFSM.request('cleanup') DistributedMinigameAI.setGameAbort(self) def gameOver(self): self.notify.debug('gameOver') self.gameFSM.request('cleanup') DistributedMinigameAI.gameOver(self) def anyAvatarWon(self, positionDict): for avId, position in positionDict.items(): if position >= RaceGameGlobals.NumberToWin: self.notify.debug('anyAvatarWon: Somebody won') return 1 self.notify.debug('anyAvatarWon: Nobody won') return 0 def allAvatarsChosen(self): for choice in self.avatarChoices.values(): if choice == -1: return 0 return 1 def checkChoice(self, choice): if choice not in RaceGameGlobals.ValidChoices: self.notify.warning('checkChoice: invalid choice: ' + str(choice)) return RaceGameGlobals.ValidChoices[0] else: return choice def resetChoices(self): for avId in self.avIdList: self.avatarChoices[avId] = -1 def resetPositions(self): for avId in self.avIdList: self.avatarPositions[avId] = 0 def resetChancePositions(self): chancePositions = [] for avId in self.avIdList: pos = random.randint(5, RaceGameGlobals.NumberToWin - 1) self.chancePositions[avId] = pos self.rewardDict[avId] = random.randint(0, len(RaceGameGlobals.ChanceRewards) - 1) chancePositions.append(pos) self.sendUpdate('setChancePositions', [chancePositions]) def setAvatarChoice(self, choice): avatarId = self.air.getAvatarIdFromSender() self.notify.debug('setAvatarChoice: avatar: ' + str(avatarId) + ' chose: ' + str(choice)) self.avatarChoices[avatarId] = self.checkChoice(choice) self.sendUpdate('setAvatarChose', [avatarId]) if self.allAvatarsChosen(): self.notify.debug('setAvatarChoice: all avatars have chosen') self.gameFSM.request('processChoices') else: self.notify.debug('setAvatarChoice: still waiting for more choices') def enterInactive(self): self.notify.debug('enterInactive') def exitInactive(self): pass def enterWaitClientsChoices(self): self.notify.debug('enterWaitClientsChoices') self.resetChoices() taskMgr.doMethodLater(RaceGameGlobals.InputTimeout, self.waitClientsChoicesTimeout, self.taskName('input-timeout')) self.sendUpdate('setTimerStartTime', [globalClockDelta.getFrameNetworkTime()]) def exitWaitClientsChoices(self): taskMgr.remove(self.taskName('input-timeout')) def waitClientsChoicesTimeout(self, task): self.notify.debug('waitClientsChoicesTimeout: did not hear from all clients') for avId in self.avatarChoices.keys(): if self.avatarChoices[avId] == -1: self.avatarChoices[avId] = 0 self.gameFSM.request('processChoices') return Task.done def enterProcessChoices(self): self.notify.debug('enterProcessChoices: ') self.choiceArray = [] self.positionArray = [] self.rewardArray = [] for avId in self.avIdList: choice = self.avatarChoices[avId] freq = self.avatarChoices.values().count(choice) self.processChoice(avId, choice, freq) masterList = [] for avId in self.avIdList: masterList.append(-1) done = 0 rewarded = 0 while not done: self.notify.debug('enterProcessChoice: notDone') rewardList = masterList[:] for avId in self.avIdList: reward = self.processReward(avId) if reward != -1: rewarded = 1 rewardList[self.avIdList.index(avId)] = reward self.rewardArray += rewardList for av in self.avIdList: if av == avId: self.processChoice(av, RaceGameGlobals.ChanceRewards[reward][0][0]) else: self.processChoice(av, RaceGameGlobals.ChanceRewards[reward][0][1]) break if not rewarded: self.rewardArray += rewardList self.notify.debug(' rewardList: ' + str(rewardList)) self.notify.debug(' rewardArray: ' + str(self.rewardArray)) done = rewardList.count(-1) == len(rewardList) self.checkForWinners() def processChoice(self, avId, choice, freq = 1): self.notify.debug('processChoice: av = ' + str(avId) + ' choice = ' + str(choice)) if freq == 1: if choice != 0: if self.avatarPositions[avId] < RaceGameGlobals.NumberToWin: self.avatarPositions[avId] += choice if self.avatarPositions[avId] < 0: self.avatarPositions[avId] = 0 self.choiceArray.append(choice) self.positionArray.append(self.avatarPositions[avId]) self.notify.debug('Process choice (' + str(choice) + ') for av: ' + str(avId)) self.notify.debug(' choiceArray: ' + str(self.choiceArray)) self.notify.debug(' positionArray: ' + str(self.positionArray)) def processReward(self, rewardee): self.notify.debug('processReward: ' + str(rewardee)) reward = -1 if self.avatarPositions[rewardee] == self.chancePositions[rewardee]: reward = self.rewardDict[rewardee] bonus = RaceGameGlobals.ChanceRewards[reward][2] self.scoreDict[rewardee] = self.scoreDict[rewardee] + bonus self.chancePositions[rewardee] = -1 return reward def checkForWinners(self): self.notify.debug('checkForWinners: ') self.sendUpdate('setServerChoices', [self.choiceArray, self.positionArray, self.rewardArray]) delay = 0.0 for reward in self.rewardArray: if reward != -1: delay += 7.0 if self.anyAvatarWon(self.avatarPositions): numWinners = 0 for avId in self.avIdList: if self.avatarPositions[avId] >= RaceGameGlobals.NumberToWin: numWinners = numWinners + 1 for avId in self.avIdList: newJellybeans = ceil(self.avatarPositions[avId] * 0.5) if self.avatarPositions[avId] >= RaceGameGlobals.NumberToWin: newJellybeans = RaceGameGlobals.NumberToWin if numWinners > 1: newJellybeans = newJellybeans - 3 self.scoreDict[avId] = self.scoreDict[avId] + newJellybeans taskMgr.doMethodLater(delay, self.rewardTimeoutTaskGameOver, self.taskName('reward-timeout')) else: taskMgr.doMethodLater(delay, self.rewardTimeoutTask, self.taskName('reward-timeout')) def oldEnterProcessChoices(self, recurse = 0): self.notify.debug('enterProcessChoices') if not recurse: self.choiceArray = [] self.positionArray = [] self.rewardArray = [] for avId in self.avIdList: choice = self.avatarChoices[avId] reward = -1 if choice != 0: freq = self.avatarChoices.values().count(choice) if recurse or freq == 1: self.avatarPositions[avId] += choice if self.avatarPositions[avId] < 0: self.avatarPositions[avId] = 0 if self.avatarPositions[avId] == self.chancePositions[avId]: reward = self.rewardDict[avId] self.scoreDict[avId] = self.scoreDict[avId] + RaceGameGlobals.ChanceRewards[reward][2] self.chancePositions[avId] = -1 self.choiceArray.append(choice) self.positionArray.append(self.avatarPositions[avId]) self.rewardArray.append(reward) self.notify.debug(' choiceArray: ' + str(self.choiceArray)) self.notify.debug(' positionArray: ' + str(self.positionArray)) self.notify.debug(' rewardArray: ' + str(self.rewardArray)) thisTurnRewards = self.rewardArray[-len(self.avatarPositions):] rewardIndex = 0 for reward in thisTurnRewards: if reward != -1: for avId in self.avIdList: if self.avIdList.index(avId) == rewardIndex: self.avatarChoices[avId] = RaceGameGlobals.ChanceRewards[reward][0][0] else: self.avatarChoices[avId] = RaceGameGlobals.ChanceRewards[reward][0][1] self.enterProcessChoices(1) rewardIndex += 1 if not recurse: self.sendUpdate('setServerChoices', [self.choiceArray, self.positionArray, self.rewardArray]) delay = 0.0 for reward in self.rewardArray: if reward != -1: delay += 7.0 if self.anyAvatarWon(self.avatarPositions): numWinners = 0 for avId in self.avIdList: if self.avatarPositions[avId] >= RaceGameGlobals.NumberToWin: numWinners = numWinners + 1 for avId in self.avIdList: newJellybeans = ceil(self.avatarPositions[avId] * 0.5) if self.avatarPositions[avId] >= RaceGameGlobals.NumberToWin: newJellybeans = RaceGameGlobals.NumberToWin if numWinners > 1: newJellybeans = newJellybeans - 3 self.scoreDict[avId] = self.scoreDict[avId] + newJellybeans taskMgr.doMethodLater(delay, self.rewardTimeoutTaskGameOver, self.taskName('reward-timeout')) else: taskMgr.doMethodLater(delay, self.rewardTimeoutTask, self.taskName('reward-timeout')) return None def rewardTimeoutTaskGameOver(self, task): self.notify.debug('Done waiting for rewards, game over') self.gameOver() return Task.done def rewardTimeoutTask(self, task): self.notify.debug('Done waiting for rewards') self.gameFSM.request('waitClientsChoices') return Task.done def exitProcessChoices(self): taskMgr.remove(self.taskName('reward-timeout')) def enterCleanup(self): self.notify.debug('enterCleanup') self.gameFSM.request('inactive') def exitCleanup(self): pass