toontown-just-works/toontown/minigame/DistributedTugOfWarGameAI.py
2024-07-07 18:08:39 -05:00

333 lines
13 KiB
Python

from DistributedMinigameAI import *
from direct.fsm import ClassicFSM, State
from direct.fsm import State
import random
from direct.task.Task import Task
import copy
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 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', [self.offsetDict.keys(), 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 xrange(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 xrange(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 xrange(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 xrange(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 xrange(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