historical/toontown-classic.git/toontown/minigame/DistributedCogThiefGameAI.py
2024-01-16 11:20:27 -06:00

409 lines
17 KiB
Python

import random
from panda3d.core import Point3
from direct.fsm import ClassicFSM
from direct.fsm import State
from direct.distributed.ClockDelta import globalClockDelta
from direct.task import Task
from toontown.minigame import DistributedMinigameAI
from toontown.minigame import MinigameGlobals
from toontown.minigame import CogThiefGameGlobals
CTGG = CogThiefGameGlobals
class DistributedCogThiefGameAI(DistributedMinigameAI.DistributedMinigameAI):
notify = directNotify.newCategory('DistributedCogThiefGameAI')
ExplodeWaitTime = 6.0 + CTGG.LyingDownDuration
def __init__(self, air, minigameId):
try:
self.DistributedCogThiefGameAI_initialized
except:
self.DistributedCogThiefGameAI_initialized = 1
DistributedMinigameAI.DistributedMinigameAI.__init__(self, air, minigameId)
self.gameFSM = ClassicFSM.ClassicFSM('DistributedCogThiefGameAI', [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.cogInfo = {}
self.barrelInfo = {}
self.initBarrelInfo()
def generate(self):
self.notify.debug('generate')
DistributedMinigameAI.DistributedMinigameAI.generate(self)
def delete(self):
self.notify.debug('delete')
del self.gameFSM
self.removeAllTasks()
DistributedMinigameAI.DistributedMinigameAI.delete(self)
def setGameReady(self):
self.notify.debug('setGameReady')
self.initCogInfo()
DistributedMinigameAI.DistributedMinigameAI.setGameReady(self)
def setGameStart(self, timestamp):
self.notify.debug('setGameStart')
DistributedMinigameAI.DistributedMinigameAI.setGameStart(self, timestamp)
self.gameFSM.request('play')
def setGameAbort(self):
self.notify.debug('setGameAbort')
if self.gameFSM.getCurrentState():
self.gameFSM.request('cleanup')
DistributedMinigameAI.DistributedMinigameAI.setGameAbort(self)
def gameOver(self):
self.notify.debug('gameOver')
score = int(CTGG.calcScore(self.getCurrentGameTime()))
for avId in self.avIdList:
self.scoreDict[avId] = score
if self.getNumBarrelsStolen() == 0:
for avId in self.avIdList:
self.scoreDict[avId] += CTGG.PerfectBonus[len(self.avIdList) - 1]
self.logPerfectGame(avId)
self.gameFSM.request('cleanup')
DistributedMinigameAI.DistributedMinigameAI.gameOver(self)
def enterInactive(self):
self.notify.debug('enterInactive')
def exitInactive(self):
pass
def enterPlay(self):
self.notify.debug('enterPlay')
self.startSuitGoals()
if not config.GetBool('cog-thief-endless', 0):
taskMgr.doMethodLater(CTGG.GameTime, self.timerExpired, self.taskName('gameTimer'))
def exitPlay(self):
pass
def enterCleanup(self):
self.notify.debug('enterCleanup')
taskMgr.remove(self.taskName('gameTimer'))
self.gameFSM.request('inactive')
def exitCleanup(self):
pass
def initCogInfo(self):
for cogIndex in xrange(self.getNumCogs()):
self.cogInfo[cogIndex] = {'pos': Point3(CogThiefGameGlobals.CogStartingPositions[cogIndex]),
'goal': CTGG.NoGoal,
'goalId': CTGG.InvalidGoalId,
'barrel': CTGG.NoBarrelCarried}
def initBarrelInfo(self):
for barrelIndex in xrange(CogThiefGameGlobals.NumBarrels):
self.barrelInfo[barrelIndex] = {'pos': Point3(CogThiefGameGlobals.BarrelStartingPositions[barrelIndex]),
'carriedBy': CTGG.BarrelOnGround,
'stolen': False}
def makeCogCarryBarrel(self, timestamp, clientStamp, cogIndex, barrelIndex):
if cogIndex in self.cogInfo and barrelIndex in self.barrelInfo:
self.barrelInfo[barrelIndex]['carriedBy'] = cogIndex
self.cogInfo[cogIndex]['barrel'] = barrelIndex
else:
self.notify.warning('makeCogCarryBarrel invalid cogIndex=%s barrelIndex=%s' % (cogIndex, barrelIndex))
def b_makeCogCarryBarrel(self, clientStamp, cogIndex, barrelIndex):
timestamp = globalClockDelta.localToNetworkTime(globalClock.getFrameTime(), bits=32)
self.notify.debug('b_makeCogCarryBarrel timeStamp=%s clientStamp=%s cog=%s barrel=%s' % (timestamp,
clientStamp,
cogIndex,
barrelIndex))
self.makeCogCarryBarrel(timestamp, clientStamp, cogIndex, barrelIndex)
self.d_makeCogCarryBarrel(timestamp, clientStamp, cogIndex, barrelIndex)
def d_makeCogCarryBarrel(self, timestamp, clientStamp, cogIndex, barrelIndex):
pos = self.cogInfo[cogIndex]['pos']
gameTime = self.getCurrentGameTime()
self.sendUpdate('makeCogCarryBarrel', [timestamp,
clientStamp,
cogIndex,
barrelIndex,
pos[0],
pos[1],
pos[2]])
def makeCogDropBarrel(self, timestamp, clientStamp, cogIndex, barrelIndex, barrelPos):
if cogIndex in self.cogInfo and barrelIndex in self.barrelInfo:
self.barrelInfo[barrelIndex]['carriedBy'] = CTGG.BarrelOnGround
self.cogInfo[cogIndex]['barrel'] = CTGG.NoBarrelCarried
else:
self.notify.warning('makeCogDropBarrel invalid cogIndex=%s barrelIndex=%s' % (cogIndex, barrelIndex))
def b_makeCogDropBarrel(self, clientStamp, cogIndex, barrelIndex, barrelPos):
if self.barrelInfo[barrelIndex]['carriedBy'] != cogIndex:
self.notify.error("self.barrelInfo[%s]['carriedBy'] != %s" % (barrelIndex, cogIndex))
timestamp = globalClockDelta.localToNetworkTime(globalClock.getFrameTime(), bits=32)
self.makeCogDropBarrel(timestamp, clientStamp, cogIndex, barrelIndex, barrelPos)
self.d_makeCogDropBarrel(timestamp, clientStamp, cogIndex, barrelIndex, barrelPos)
def d_makeCogDropBarrel(self, timestamp, clientStamp, cogIndex, barrelIndex, barrelPos):
pos = barrelPos
gameTime = self.getCurrentGameTime()
self.sendUpdate('makeCogDropBarrel', [timestamp,
clientStamp,
cogIndex,
barrelIndex,
pos[0],
pos[1],
pos[2]])
def isCogCarryingABarrel(self, cogIndex):
result = self.cogInfo[cogIndex]['barrel'] > CTGG.NoBarrelCarried
return result
def isCogCarryingThisBarrel(self, cogIndex, barrelIndex):
result = self.cogInfo[cogIndex]['barrel'] == barrelIndex
return result
def startSuitGoals(self):
delayTimes = []
for cogIndex in xrange(self.getNumCogs()):
delayTimes.append(cogIndex * 1.0)
random.shuffle(delayTimes)
for cogIndex in xrange(self.getNumCogs()):
self.doMethodLater(delayTimes[cogIndex], self.chooseSuitGoal, self.uniqueName('choseSuitGoal-%d-' % cogIndex), extraArgs=[cogIndex])
def chaseToon(self, suitNum, avId):
goalType = CTGG.ToonGoal
goalId = avId
self.cogInfo[suitNum]['goal'] = goalType
self.cogInfo[suitNum]['goalId'] = goalId
pos = self.cogInfo[suitNum]['pos']
timestamp = globalClockDelta.localToNetworkTime(globalClock.getFrameTime(), bits=32)
self.notify.debug('chaseToon time=%s suitNum=%s, avId=%s' % (timestamp, suitNum, avId))
gameTime = self.getCurrentGameTime()
self.sendUpdate('updateSuitGoal', [timestamp,
timestamp,
suitNum,
goalType,
goalId,
pos[0],
pos[1],
pos[2]])
def hitBySuit(self, avId, timestamp, suitNum, x, y, z):
if suitNum >= self.getNumCogs():
self.notify.warning('hitBySuit, possible hacker avId=%s' % avId)
return
barrelIndex = self.cogInfo[suitNum]['barrel']
if barrelIndex >= 0:
barrelPos = Point3(x, y, z)
self.b_makeCogDropBarrel(timestamp, suitNum, barrelIndex, barrelPos)
startPos = CTGG.CogStartingPositions[suitNum]
self.cogInfo[suitNum]['pos'] = startPos
self.cogInfo[suitNum]['goal'] = CTGG.NoGoal
self.cogInfo[suitNum]['goalId'] = CTGG.InvalidGoalId
self.sendSuitSync(timestamp, suitNum)
self.doMethodLater(self.ExplodeWaitTime, self.chooseSuitGoal, self.uniqueName('choseSuitGoal-%d-' % suitNum), extraArgs=[suitNum])
def sendSuitSync(self, clientstamp, suitNum):
pos = self.cogInfo[suitNum]['pos']
timestamp = globalClockDelta.localToNetworkTime(globalClock.getFrameTime(), bits=32)
goalType = self.cogInfo[suitNum]['goal']
goalId = self.cogInfo[suitNum]['goalId']
gameTime = self.getCurrentGameTime()
self.sendUpdate('updateSuitGoal', [timestamp,
clientstamp,
suitNum,
goalType,
goalId,
pos[0],
pos[1],
pos[2]])
def chooseSuitGoal(self, suitNum):
barrelIndex = self.findClosestUnassignedBarrel(suitNum)
if barrelIndex >= 0:
self.chaseBarrel(suitNum, barrelIndex)
else:
noOneChasing = self.avIdList[:]
for key in self.cogInfo:
if self.cogInfo[key]['goal'] == CTGG.ToonGoal:
toonId = self.cogInfo[key]['goalId']
if toonId in noOneChasing:
noOneChasing.remove(toonId)
chaseToonId = self.avIdList[0]
if noOneChasing:
chaseToonId = random.choice(noOneChasing)
else:
chaseToonId = random.choice(self.avIdList)
self.chaseToon(suitNum, chaseToonId)
def chaseBarrel(self, suitNum, barrelIndex):
goalType = CTGG.BarrelGoal
goalId = barrelIndex
self.cogInfo[suitNum]['goal'] = goalType
self.cogInfo[suitNum]['goalId'] = goalId
pos = self.cogInfo[suitNum]['pos']
timestamp = globalClockDelta.localToNetworkTime(globalClock.getFrameTime(), bits=32)
self.notify.debug('chaseBarrel time=%s suitNum=%s, barrelIndex=%s' % (timestamp, suitNum, barrelIndex))
gameTime = self.getCurrentGameTime()
self.sendUpdate('updateSuitGoal', [timestamp,
timestamp,
suitNum,
goalType,
goalId,
pos[0],
pos[1],
pos[2]])
def getCogCarryingBarrel(self, barrelIndex):
return self.barrelInfo[barrelIndex]['carriedBy']
def cogHitBarrel(self, clientStamp, cogIndex, barrelIndex, x, y, z):
if cogIndex >= self.getNumCogs():
self.notify.warning('cogHitBarrel, possible hacker cogIndex=%s' % cogIndex)
return
if barrelIndex >= CTGG.NumBarrels:
self.notify.warning('cogHitBarrel, possible hacker barrelIndex=%s' % barrelIndex)
return
if self.isCogCarryingABarrel(cogIndex):
self.notify.debug('cog is already carrying a barrel ignore')
return
if self.cogInfo[cogIndex]['goal'] == CTGG.NoGoal:
self.notify.debug('ignoring barrel hit as cog %d has no goal' % cogIndex)
return
if self.getCogCarryingBarrel(barrelIndex) == CTGG.BarrelOnGround:
pos = Point3(x, y, z)
returnPosIndex = self.chooseReturnPos(cogIndex, pos)
self.runAway(clientStamp, cogIndex, pos, barrelIndex, returnPosIndex)
def chooseReturnPos(self, cogIndex, cogPos):
shortestDistance = 10000
shortestReturnIndex = -1
for retIndex in xrange(len(CTGG.CogReturnPositions)):
retPos = CTGG.CogReturnPositions[retIndex]
distance = (cogPos - retPos).length()
if distance < shortestDistance:
shortestDistance = distance
shortestReturnIndex = retIndex
self.notify.debug('shortest distance=%s index=%s' % (shortestDistance, shortestReturnIndex))
self.notify.debug('chooseReturnpos returning %s' % shortestReturnIndex)
return shortestReturnIndex
def runAway(self, clientStamp, cogIndex, cogPos, barrelIndex, returnPosIndex):
self.cogInfo[cogIndex]['pos'] = cogPos
self.b_makeCogCarryBarrel(clientStamp, cogIndex, barrelIndex)
goalType = CTGG.RunAwayGoal
goalId = returnPosIndex
self.cogInfo[cogIndex]['goal'] = goalType
self.cogInfo[cogIndex]['goalId'] = 0
timestamp = globalClockDelta.localToNetworkTime(globalClock.getFrameTime(), bits=32)
gameTime = self.getCurrentGameTime()
self.sendUpdate('updateSuitGoal', [timestamp,
clientStamp,
cogIndex,
goalType,
goalId,
cogPos[0],
cogPos[1],
cogPos[2]])
def pieHitSuit(self, avId, timestamp, suitNum, x, y, z):
if suitNum >= self.getNumCogs():
self.notify.warning('hitBySuit, possible hacker avId=%s' % avId)
return
barrelIndex = self.cogInfo[suitNum]['barrel']
if barrelIndex >= 0:
barrelPos = Point3(x, y, z)
self.b_makeCogDropBarrel(timestamp, suitNum, barrelIndex, barrelPos)
startPos = CTGG.CogStartingPositions[suitNum]
self.cogInfo[suitNum]['pos'] = startPos
self.cogInfo[suitNum]['goal'] = CTGG.NoGoal
self.cogInfo[suitNum]['goalId'] = CTGG.InvalidGoalId
self.sendSuitSync(timestamp, suitNum)
self.doMethodLater(self.ExplodeWaitTime, self.chooseSuitGoal, self.uniqueName('choseSuitGoal-%d-' % suitNum), extraArgs=[suitNum])
def findClosestUnassignedBarrel(self, suitNum):
possibleBarrels = []
for key in self.barrelInfo:
info = self.barrelInfo[key]
if info['carriedBy'] == CTGG.BarrelOnGround and not info['stolen']:
if not self.isCogGoingForBarrel(key):
possibleBarrels.append(key)
shortestDistance = 10000
shortestBarrelIndex = -1
cogPos = self.cogInfo[suitNum]['pos']
for possibleIndex in possibleBarrels:
barrelPos = self.barrelInfo[possibleIndex]['pos']
distance = (cogPos - barrelPos).length()
if distance < shortestDistance:
shortestDistance = distance
shortestBarrelIndex = possibleIndex
return shortestBarrelIndex
def isCogGoingForBarrel(self, barrelIndex):
result = False
for suitNum in self.cogInfo:
cogInfo = self.cogInfo[suitNum]
if cogInfo['goal'] == CTGG.BarrelGoal and cogInfo['goalId'] == barrelIndex:
result = True
break
return result
def markBarrelStolen(self, clientStamp, barrelIndex):
timestamp = globalClockDelta.localToNetworkTime(globalClock.getFrameTime(), bits=32)
self.sendUpdate('markBarrelStolen', [timestamp, clientStamp, barrelIndex])
self.barrelInfo[barrelIndex]['stolen'] = True
def getNumBarrelsStolen(self):
numStolen = 0
for barrel in self.barrelInfo.values():
if barrel['stolen']:
numStolen += 1
return numStolen
def cogAtReturnPos(self, clientstamp, cogIndex, barrelIndex):
if cogIndex not in self.cogInfo or barrelIndex not in self.barrelInfo:
avId = self.air.getAvatarIdFromSender()
self.air.writeServerEvent('suspicious cogAtReturnPos avId=%s, cogIndex=%s, barrelIndex=%s' % (avId, cogIndex, barrelIndex))
return
if self.cogInfo[cogIndex]['goal'] == CTGG.RunAwayGoal:
if self.isCogCarryingThisBarrel(cogIndex, barrelIndex):
self.markBarrelStolen(clientstamp, barrelIndex)
returnPosIndex = self.cogInfo[cogIndex]['goalId']
retPos = CTGG.CogReturnPositions[returnPosIndex]
self.b_makeCogDropBarrel(clientstamp, cogIndex, barrelIndex, retPos)
startPos = CTGG.CogStartingPositions[cogIndex]
self.cogInfo[cogIndex]['pos'] = startPos
self.cogInfo[cogIndex]['goal'] = CTGG.NoGoal
self.cogInfo[cogIndex]['goalId'] = CTGG.InvalidGoalId
self.doMethodLater(0.5, self.chooseSuitGoal, self.uniqueName('choseSuitGoal-%d-' % cogIndex), extraArgs=[cogIndex])
self.checkForGameOver()
def checkForGameOver(self):
numStolen = 0
for key in self.barrelInfo:
if self.barrelInfo[key]['stolen']:
numStolen += 1
self.notify.debug('numStolen = %s' % numStolen)
if simbase.config.GetBool('cog-thief-check-barrels', 1):
if not simbase.config.GetBool('cog-thief-endless', 0):
if numStolen == len(self.barrelInfo):
self.gameOver()
def timerExpired(self, task):
self.notify.debug('timer expired')
self.gameOver()
return Task.done
def getNumCogs(self):
result = simbase.config.GetInt('cog-thief-num-cogs', 0)
if not result:
safezone = self.getSafezoneId()
result = CTGG.calculateCogs(self.numPlayers, safezone)
return result