from .DistributedMinigameAI import * from direct.fsm import ClassicFSM, State from direct.fsm import State import random from direct.task.Task import Task import copy from . import TugOfWarGameGlobals import math class DistributedTugOfWarGameAI(DistributedMinigameAI): def __init__(self, air, minigameId): try: self.DistributedTugOfWarGameAI_initialized except: self.DistributedTugOfWarGameAI_initialized = 1 DistributedMinigameAI.__init__(self, air, minigameId) self.gameFSM = ClassicFSM.ClassicFSM('DistributedTugOfWarGameAI', [State.State('off', self.enterInactive, self.exitInactive, ['waitClientsReady', 'cleanup']), State.State('waitClientsReady', self.enterWaitClientsReady, self.exitWaitClientsReady, ['sendGoSignal', 'cleanup']), State.State('sendGoSignal', self.enterSendGoSignal, self.exitSendGoSignal, ['waitForResults', 'cleanup']), State.State('waitForResults', self.enterWaitForResults, self.exitWaitForResults, ['waitClientsReady', 'contestOver', 'cleanup']), State.State('contestOver', self.enterContestOver, self.exitContestOver, ['cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, ['off'])], 'off', 'off') self.addChildGameFSM(self.gameFSM) self.switched = 0 self.side = {} self.forceDict = [{}, {}] self.keyRateDict = {} self.howManyReported = 0 self.offsetDict = {} self.kMovement = 0.02 self.suitId = 666 self.suitForces = [(6, 4), (2, 5), (2, 6.5), (3, 8.0), (5, 6), (8, 8), (9, 8.5), (4, 9)] self.suitForceMultiplier = 0.75 self.curSuitForce = 0 self.suitOffset = 0 self.contestEnded = 0 self.losingSide = -1 self.winners = [] self.losers = [] self.tieers = [] self.timeBonus = float(TugOfWarGameGlobals.TIME_BONUS_RANGE) def delete(self): self.notify.debug('delete') del self.gameFSM del self.side del self.forceDict del self.keyRateDict del self.offsetDict del self.suitForces del self.winners del self.tieers del self.losers DistributedMinigameAI.delete(self) def setGameReady(self): self.notify.debug('setGameReady') self.suitType = random.randrange(1, 5) self.suitJellybeanReward = math.pow(2, self.suitType - 1) if self.isSinglePlayer(): self.gameType = TugOfWarGameGlobals.TOON_VS_COG self.suitForceMultiplier = 0.58 + float(self.suitType) / 10.0 else: randInt = random.randrange(0, 10) if randInt < 8: self.gameType = TugOfWarGameGlobals.TOON_VS_COG self.suitForceMultiplier = 0.65 + float(self.suitType) / 16.0 self.kMovement = 0.02 else: self.gameType = TugOfWarGameGlobals.TOON_VS_TOON self.kMovement = 0.04 self.sendUpdate('sendGameType', [self.gameType, self.suitType]) DistributedMinigameAI.setGameReady(self) self.__initGameVars() def setGameStart(self, timestamp): self.notify.debug('setGameStart') DistributedMinigameAI.setGameStart(self, timestamp) self.gameFSM.request('waitClientsReady') 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 enterInactive(self): self.notify.debug('enterInactive') def exitInactive(self): pass def __initGameVars(self): self.currentButtons = [0, 0] self.readyClients = [] def enterWaitClientsReady(self): self.notify.debug('enterWaitClientsReady') taskMgr.doMethodLater(TugOfWarGameGlobals.WAIT_FOR_CLIENTS_TIMEOUT, self.waitForClientsTimeout, self.taskName('clients-timeout')) def exitWaitClientsReady(self): taskMgr.remove(self.taskName('clients-timeout')) def waitForClientsTimeout(self, task): self.notify.debug('Done waiting for clients') self.sendUpdate('sendStopSignal', [self.winners, self.losers, self.tieers]) self.gameOver() return Task.done def reportPlayerReady(self, side): avId = self.air.getAvatarIdFromSender() if avId in self.readyClients: self.notify.warning('Got reportPlayerReady from an avId more than once: %s' % avId) return if avId not in self.avIdList or side not in [0, 1]: self.notify.warning('Got reportPlayerReady from an avId: %s not in our list: %s' % (avId, self.avIdList)) else: self.readyClients.append(avId) self.side[avId] = side self.forceDict[side][avId] = 0 self.offsetDict[avId] = 0 if len(self.readyClients) == self.numPlayers: self.readyClients = [] self.gameFSM.request('sendGoSignal') def sendNewAvIdList(self, newAvIdList): for avId in newAvIdList: if avId not in self.scoreDict: self.notify.debug('invalid avId in new list from %s' % self.air.getAvatarIdFromSender()) return if not self.switched: self.switched = 1 self.avIdList = newAvIdList elif self.avIdList != newAvIdList: self.notify.debug('Big trouble in little TugOWar Town') def enterSendGoSignal(self): self.notify.debug('enterSendGoSignal') taskMgr.doMethodLater(TugOfWarGameGlobals.GAME_DURATION, self.timerExpired, self.taskName('gameTimer')) if self.gameType == TugOfWarGameGlobals.TOON_VS_COG: self.curSuitForceInd = 0 taskMgr.add(self.timeForNewSuitForce, self.taskName('suitForceTimer')) taskMgr.doMethodLater(1, self.calcTimeBonus, self.taskName('timeBonusTimer')) self.sendUpdate('sendGoSignal', [[0, 1]]) self.gameFSM.request('waitForResults') def timerExpired(self, task): self.notify.debug('timer expired') self.gameFSM.request('contestOver') return Task.done def timeForNewSuitForce(self, task): self.notify.debug('timeForNewSuitForce') if self.curSuitForceInd < len(self.suitForces): randForce = random.random() - 0.5 self.curSuitForce = self.suitForceMultiplier * self.numPlayers * (self.suitForces[self.curSuitForceInd][1] + randForce) taskMgr.doMethodLater(self.suitForces[self.curSuitForceInd][0], self.timeForNewSuitForce, self.taskName('suitForceTimer')) self.curSuitForceInd += 1 return Task.done def calcTimeBonus(self, task): delta = float(TugOfWarGameGlobals.TIME_BONUS_RANGE) / float(TugOfWarGameGlobals.GAME_DURATION) self.timeBonus = self.timeBonus - delta taskMgr.doMethodLater(1, self.calcTimeBonus, self.taskName('timeBonusTimer')) return Task.done def exitSendGoSignal(self): pass def enterWaitForResults(self): self.notify.debug('enterWaitForResults') def calculateOffsets(self): f = [0, 0] for i in [0, 1]: for x in list(self.forceDict[i].values()): f[i] += x if self.gameType == TugOfWarGameGlobals.TOON_VS_COG: f[1] += self.curSuitForce deltaF = f[1] - f[0] deltaX = deltaF * self.kMovement for avId in self.avIdList: offset = deltaX if self.side[avId] == 0: if deltaX < 0: offset = deltaX / 2.0 elif deltaX > 0: offset = deltaX / 2.0 self.offsetDict[avId] += offset if deltaX < 0: self.suitOffset += deltaX else: self.suitOffset += deltaX / 2.0 def reportCurrentKeyRate(self, keyRate, force): avId = self.air.getAvatarIdFromSender() if avId not in self.side: self.notify.warning('Avatar %s sent reportCurrentKeyRate too early %s' % (avId, self.side)) return self.keyRateDict[avId] = keyRate self.forceDict[self.side[avId]][avId] = force self.sendUpdate('remoteKeyRateUpdate', [avId, self.keyRateDict[avId]]) self.howManyReported += 1 if self.howManyReported == self.numPlayers: self.howManyReported = 0 self.calculateOffsets() self.sendUpdate('sendCurrentPosition', [list(self.offsetDict.keys()), list(self.offsetDict.values())]) if self.gameType == TugOfWarGameGlobals.TOON_VS_COG: self.sendUpdate('sendSuitPosition', [self.suitOffset]) def reportEndOfContest(self, index): if index not in [0, 1]: self.notify.warning('Got a bad index %s ' % index) return self.losingSide = index self.notify.debug('losing side = %d' % self.losingSide) if self.contestEnded == 0: self.contestEnded = 1 self.gameFSM.request('contestOver') def __processResults(self): if self.contestEnded: self.timeBonus = TugOfWarGameGlobals.TIME_BONUS_MIN + int(self.timeBonus + 0.5) if self.gameType == TugOfWarGameGlobals.TOON_VS_COG: if self.losingSide == 1: self.losers.append(self.suitId) else: self.winners.append(self.suitId) for i in range(0, self.numPlayers): avId = self.avIdList[i] if self.side[avId] != self.losingSide: self.scoreDict[avId] = self.suitJellybeanReward + TugOfWarGameGlobals.WIN_JELLYBEANS self.winners.append(avId) else: self.scoreDict[avId] = TugOfWarGameGlobals.LOSS_JELLYBEANS self.losers.append(avId) else: for i in range(0, self.numPlayers): avId = self.avIdList[i] if self.side[avId] != self.losingSide: self.scoreDict[avId] = TugOfWarGameGlobals.WIN_JELLYBEANS self.winners.append(avId) else: self.scoreDict[avId] = TugOfWarGameGlobals.LOSS_JELLYBEANS self.losers.append(avId) elif self.gameType == TugOfWarGameGlobals.TOON_VS_COG: for i in range(0, self.numPlayers): avId = self.avIdList[i] if -self.offsetDict[avId] > self.suitOffset: self.scoreDict[avId] = self.suitJellybeanReward / 2 + TugOfWarGameGlobals.TIE_WIN_JELLYBEANS self.winners.append(avId) else: self.scoreDict[avId] = self.suitJellybeanReward / 2 + TugOfWarGameGlobals.TIE_LOSS_JELLYBEANS self.losers.append(avId) self.winners.append(self.suitId) else: maxOffset = -100 minOffset = 100 for i in range(0, self.numPlayers): avId = self.avIdList[i] if self.side[avId] == 0: if -self.offsetDict[avId] > maxOffset: maxOffset = -self.offsetDict[avId] elif -self.offsetDict[avId] < minOffset: minOffset = -self.offsetDict[avId] elif self.side[avId] == 1: if self.offsetDict[avId] > maxOffset: maxOffset = self.offsetDict[avId] elif self.offsetDict[avId] < minOffset: minOffset = self.offsetDict[avId] for i in range(0, self.numPlayers): avId = self.avIdList[i] if maxOffset != minOffset: if self.side[avId] == 0: if -self.offsetDict[avId] == maxOffset: self.scoreDict[avId] = TugOfWarGameGlobals.TIE_WIN_JELLYBEANS self.winners.append(avId) else: self.scoreDict[avId] = TugOfWarGameGlobals.TIE_LOSS_JELLYBEANS self.losers.append(avId) elif self.side[avId] == 1: if self.offsetDict[avId] == maxOffset: self.scoreDict[avId] = TugOfWarGameGlobals.TIE_WIN_JELLYBEANS self.winners.append(avId) else: self.scoreDict[avId] = TugOfWarGameGlobals.TIE_LOSS_JELLYBEANS self.losers.append(avId) else: self.scoreDict[avId] += TugOfWarGameGlobals.TIE_JELLYBEANS self.tieers.append(avId) self.gameOver() def exitWaitForResults(self): pass def enterContestOver(self): self.__processResults() self.sendUpdate('sendStopSignal', [self.winners, self.losers, self.tieers]) def exitContestOver(self): pass def enterCleanup(self): self.notify.debug('enterCleanup') taskMgr.remove(self.taskName('gameTimer')) taskMgr.remove(self.taskName('timeBonusTimer')) taskMgr.remove(self.taskName('suitForceTimer')) self.gameFSM.request('off') def exitCleanup(self): pass