toontown-just-works/toontown/racing/DistributedRaceAI.py
2024-07-07 18:08:39 -05:00

501 lines
19 KiB
Python

from direct.directnotify import DirectNotifyGlobal
from direct.distributed.ClockDelta import *
from direct.distributed.DistributedObjectAI import DistributedObjectAI
from direct.fsm.FSM import FSM
from direct.task import Task
from toontown.uberdog import TopToonsGlobals
import random
from toontown.racing import RaceGlobals
from toontown.racing.DistributedGagAI import DistributedGagAI
from toontown.racing.DistributedVehicleAI import DistributedVehicleAI
from toontown.toonbase import TTLocalizer, ToontownGlobals
class DistributedRaceAI(DistributedObjectAI, FSM):
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedRaceAI")
def __init__(self, air, circuitPoints=[], circuitWinnings=[]):
DistributedObjectAI.__init__(self, air)
FSM.__init__(self, 'DistributedRaceAI')
self.air = air
self.zoneId = 0
self.trackId = 0
self.raceType = 0
self.circuitLoop = []
self.avatars = []
self.finishedAvatars = []
self.startingPlaces = []
self.avatarKarts = []
self.lapCount = 1
self.gags = {}
self.avatarGags = {}
self.livingGags = []
self.currentlyAffectedByAnvil = {}
self.avatarProgress = {}
self.circuitPoints = circuitPoints
self.circuitWinnings = circuitWinnings
self.quitAvatars = []
self.startTime = globalClockDelta.networkToLocalTime(globalClockDelta.getRealNetworkTime()) + 3
def generate(self):
for avatar in self.avatars:
self.acceptOnce(self.air.getAvatarExitEvent(avatar), self.playerLeave, [avatar])
self.demand('Join')
def delete(self):
for aK in self.avatarKarts:
kart = self.air.doId2do[aK[1]]
kart.requestDelete()
for gag in self.livingGags:
gag.requestDelete()
if not self.circuitLoop:
self.air.deallocateZone(self.zoneId)
for i in xrange(len(self.gags)):
taskMgr.remove('regenGag%i-%i' % (i, self.doId))
taskMgr.remove(self.uniqueName('next-race'))
DistributedObjectAI.delete(self)
def enterJoin(self):
self.beginBarrier('waitingForJoin', self.avatars, 60, self.joinBarrierCallback)
self.d_waitingForJoin()
def exitJoin(self):
pass
def enterPrep(self):
self.beginBarrier('waitingForReady', self.avatars, 60, self.readyBarrierCallback)
self.gagPoints = RaceGlobals.TrackDict[self.trackId][4]
if self.raceType != RaceGlobals.Practice:
for i in xrange(len(self.gagPoints)):
gagId = random.randint(0, 5)
self.b_genGag(i, 1, gagId)
self.d_prepForRace()
def exitPrep(self):
pass
def enterTutorial(self):
self.beginBarrier('readRules', self.avatars, 30, self.readRulesCallback)
self.d_startTutorial()
def exitTutorial(self):
pass
def enterStart(self):
self.startTime = globalClockDelta.networkToLocalTime(globalClockDelta.getRealNetworkTime()) + 3
self.b_startRace(3)
def exitStart(self):
pass
def readyBarrierCallback(self, avatars):
self.demand('Tutorial')
def readRulesCallback(self, avatars):
self.demand('Start')
def joinBarrierCallback(self, avatars):
for av in self.avatars:
if not av in avatars:
self.playerLeave(av)
for av in avatars:
kart = DistributedVehicleAI(self.air, av)
kart.generateWithRequired(self.zoneId)
self.avatarKarts.append([av, kart.getDoId()])
self.beginBarrier('waitingForPrep', self.avatars, 60, self.prepBarrierCallback)
self.sendUpdate('setEnteredRacers', [self.avatarKarts])
def prepBarrierCallback(self, avatars):
self.demand('Prep')
def setZoneId(self, zoneId):
self.zoneId = zoneId
def d_setZoneId(self, zoneId):
self.sendUpdate('setZoneId', [zoneId])
def b_setZoneId(self, zoneId):
self.setZoneId(zoneId)
self.d_setZoneId(zoneId)
def getZoneId(self):
return self.zoneId
def setTrackId(self, trackId):
self.trackId = trackId
def getTrackId(self):
return self.trackId
def setRaceType(self, raceType):
self.raceType = raceType
def getRaceType(self):
return self.raceType
def setCircuitLoop(self, circuitLoop):
self.circuitLoop = circuitLoop
if self.circuitLoop and not self.circuitPoints:
self.circuitPoints = [[0, 0]] * len(self.avatars)
self.circuitWinnings = [0] * len(self.avatars)
def getCircuitLoop(self):
return self.circuitLoop
def setAvatars(self, avatarList):
self.avatars = avatarList
def getAvatars(self):
return self.avatars
def setStartingPlaces(self, startingPlaces):
self.startingPlaces = startingPlaces
def getStartingPlaces(self):
return self.startingPlaces
def setLapCount(self, lapCount):
self.lapCount = lapCount
def getLapCount(self):
return self.lapCount
def waitingForJoin(self):
self.beginBarrier('waitingForJoin', self.avatars, 60, self.b_prepForRace)
def d_waitingForJoin(self):
self.sendUpdate('waitingForJoin', [])
def b_waitingForJoin(self):
self.waitingForJoin()
self.d_waitingForJoin()
def setEnteredRacers(self, todo0):
pass
def d_prepForRace(self):
self.sendUpdate('prepForRace', [])
def b_prepForRace(self, avatars):
self.prepForRace()
self.d_prepForRace()
def startTutorial(self):
self.beginBarrier('readRules', self.avatars, 60, self.raceStart)
def d_startTutorial(self):
self.sendUpdate('startTutorial', [])
def b_startTutorial(self, avatars):
self.startTutorial()
self.d_startTutorial()
def startRace(self, timeUntilStart):
taskMgr.doMethodLater(timeUntilStart, self.startKarts, 'startKarts%i' % self.doId, [])
def startKarts(self):
for avatarKart in self.avatarKarts:
if avatarKart[1] in self.air.doId2do:
kart = self.air.doId2do[avatarKart[1]]
kart.sendUpdate('setInput', [1])
self.avatarProgress[avatarKart[0]] = 0
self.avatarGags[avatarKart[0]] = 0
self.currentlyAffectedByAnvil[avatarKart[0]] = False
def b_startRace(self, timeUntilStart):
self.startRace(timeUntilStart)
self.d_startRace(timeUntilStart)
def d_startRace(self, timeUntilStart):
self.sendUpdate('startRace', [globalClockDelta.localToNetworkTime(globalClockDelta.globalClock.getRealTime() + timeUntilStart)])
def goToSpeedway(self, todo0, todo1):
pass
def genGag(self, slot, number, type):
self.gags[slot] = [number, type]
def d_genGag(self, slot, number, type):
self.sendUpdate('genGag', [slot, number, type])
def b_genGag(self, slot, number, type):
self.genGag(slot, number, type)
self.d_genGag(slot, number, type)
def dropAnvilOn(self, todo0, todo1, todo2):
pass
def shootPiejectile(self, todo0, todo1, todo2):
pass
def racerDisconnected(self, todo0):
pass
def setPlace(self, todo0, todo1, todo2, todo3, todo4, todo5, todo6, todo7, todo8, todo9):
pass
def setCircuitPlace(self, todo0, todo1, todo2, todo3, todo4, todo5):
pass
def endCircuitRace(self):
pass
def setRaceZone(self, todo0, todo1):
pass
def hasGag(self, slot, requestedGag, index):
avId = self.air.getAvatarIdFromSender()
if not avId in self.avatars:
self.air.writeServerEvent('suspicious', avId, 'Toon tried to get gag in a race they\'re not in!')
return
if self.raceType == RaceGlobals.Practice:
self.air.writeServerEvent('suspicious', avId, 'Toon tried to gain gag in a practice race!')
return
places = sorted(self.avatarProgress, key=self.avatarProgress.get)
avPlace = places.index(avId)
gag = self.gags[slot]
if not gag[0]:
self.air.writeServerEvent('suspicious', avId, 'Toon tried to pick up a gag that doesn\'t exist!')
return
gagIndex = gag[1]
realGag = RaceGlobals.GagFreq[avPlace][gagIndex]
if realGag != requestedGag:
self.air.writeServerEvent('suspicious', avId, 'Toon tried to get the wrong gag!')
return
self.gags[slot] = [0, 0]
self.avatarGags[avId] = requestedGag
taskMgr.doMethodLater(5, self.__regenGag, 'regenGag%i-%i' % (slot, self.doId), [slot])
def __regenGag(self, index):
gagId = random.randint(0, 5)
self.b_genGag(index, 1, gagId)
def racerLeft(self, avId):
realAvId = self.air.getAvatarIdFromSender()
if realAvId != avId:
self.air.writeServerEvent('suspicious', realAvId, 'Toon tried to make another quit race!')
return
if not avId in self.avatars:
self.air.writeServerEvent('suspicious', avId, 'Toon tried to leave race they\'re not in!')
return
if self.circuitLoop and self.finishedAvatars:
if avId in self.quitAvatars:
return
self.quitAvatars.append(avId)
self.checkForNextRace()
else:
self.avatars.remove(avId)
if avId in self.quitAvatars:
self.quitAvatars.remove(avId)
if set(self.finishedAvatars) == set(self.avatars) or len(self.avatars) == 0:
self.requestDelete()
def checkForNextRace(self):
if len(self.quitAvatars) >= len(self.avatars):
trackId = self.circuitLoop[0]
self.nextRace = DistributedRaceAI(self.air, self.circuitPoints, self.circuitWinnings)
self.nextRace.setZoneId(self.zoneId)
self.nextRace.setTrackId(trackId)
self.nextRace.setRaceType(self.raceType)
self.nextRace.setAvatars(self.avatars)
self.nextRace.setCircuitLoop(self.circuitLoop)
self.nextRace.setStartingPlaces(range(len(self.avatars)))
self.nextRace.setLapCount(3)
taskMgr.doMethodLater(3, self.startNewRace, self.uniqueName('next-race'), extraArgs=[trackId])
def startNewRace(self, trackId, task=None):
self.nextRace.generateWithRequired(self.zoneId)
self.sendUpdate('setRaceZone', [self.zoneId, trackId])
def heresMyT(self, avId, laps, currentLapT, timestamp):
realAvId = self.air.getAvatarIdFromSender()
if not avId == realAvId:
self.air.writeServerEvent('suspicious', realAvId, 'Toon tried to send a message as another toon!')
return
if not avId in self.avatars:
self.air.writeServerEvent('suspicious', avId, 'Toon not in race tried to send update to race!')
return
if laps == self.lapCount:
self.avatarFinished(avId)
self.avatarProgress[avId] = laps + currentLapT
def avatarFinished(self, avId):
if not avId in self.avatars:
self.air.writeServerEvent('suspicious', avId, 'Toon tried to finish in a race they\'re not in!')
return
if avId in self.finishedAvatars:
self.air.writeServerEvent('suspicious', avId, 'Toon tried to finish in a race twice!')
return
self.finishedAvatars.append(avId)
av = self.air.doId2do.get(avId)
place = len(self.finishedAvatars)
listPlace = place + (4 - len(self.avatarProgress)) - 1
entryFee = RaceGlobals.getEntryFee(self.trackId, self.raceType)
bonus = 0
totalTime = globalClockDelta.networkToLocalTime(globalClockDelta.getRealNetworkTime()) - self.startTime
qualify = False
if totalTime < RaceGlobals.getQualifyingTime(self.trackId):
qualify = True
self.air.leaderboardMgr.submitRace(self.trackId, av.getName(), totalTime)
if self.raceType == RaceGlobals.Practice:
winnings = RaceGlobals.PracticeWinnings
trophies = []
elif qualify:
winnings = entryFee * RaceGlobals.Winnings[listPlace]
trophies = self.calculateTrophies(avId, place == 1, qualify, totalTime)
else:
winnings = 0
trophies = []
av.b_setTickets(av.getTickets() + winnings)
if av.getTickets() > RaceGlobals.MaxTickets:
av.b_setTickets(RaceGlobals.MaxTickets)
av.addStat(ToontownGlobals.STAT_RACING)
points = []
if self.circuitPoints:
avIndex = self.avatars.index(avId)
points = self.circuitPoints[avIndex]
points[0] += points[1]
points[1] = RaceGlobals.CircuitPoints[place - 1]
self.sendUpdate('setPlace', [avId, totalTime, place, entryFee, qualify, max((winnings-entryFee), 0), bonus, trophies, points, 0])
if self.circuitPoints:
self.circuitWinnings[avIndex] += winnings
self.sendUpdate('setCircuitPlace', [avId, place, entryFee, self.circuitWinnings[avIndex], bonus, trophies])
if len(self.finishedAvatars) == len(self.avatars):
del self.circuitLoop[0]
self.sendUpdate('setCircuitLoop', [self.circuitLoop])
self.sendUpdate('endCircuitRace')
def calculateTrophies(self, avId, won, qualify, time):
if won:
messenger.send('topToonsManager-event', [avId, TopToonsGlobals.CAT_RACE_WON, 1])
av = self.air.doId2do[avId]
kartingHistory = av.getKartingHistory()
avTrophies = av.getKartingTrophies()
numTrophies = 0
for i in xrange(30):
if avTrophies[i] != 0:
numTrophies += 1
oldLaffBoost = int(numTrophies/10)
genre = RaceGlobals.getTrackGenre(self.trackId)
trophies = []
if won:
kartingHistory[genre] += 1
kartingHistory[3] += 1
if kartingHistory[3] > RaceGlobals.TotalWonRaces:
avTrophies[RaceGlobals.TotalWins] = 1
trophies.append(RaceGlobals.TotalWins)
for i in xrange(3):
if kartingHistory[genre] >= RaceGlobals.WonRaces[i] and avTrophies[RaceGlobals.AllWinsList[genre][i]] != 1:
avTrophies[RaceGlobals.AllWinsList[genre][i]] = 1
trophies.append(RaceGlobals.AllWinsList[genre][i])
if qualify:
kartingHistory[genre + 4] += 1
kartingHistory[7] += 1
if kartingHistory[7] >= RaceGlobals.TotalQualifiedRaces and avTrophies[RaceGlobals.TotalQuals] != 1:
avTrophies[RaceGlobals.TotalQuals] = 1
trophies.append(RaceGlobals.TotalQuals)
for i in xrange(3):
if kartingHistory[genre + 4] >= RaceGlobals.QualifiedRaces[i] and avTrophies[RaceGlobals.AllQualsList[genre][i]] != 1:
avTrophies[RaceGlobals.AllQualsList[genre][i]] = 1
trophies.append(RaceGlobals.AllQualsList[genre][i])
for i, history in enumerate(kartingHistory):
if history > 255:
kartingHistory[i] = 255
av.b_setKartingHistory(kartingHistory)
pKartingBest = av.getKartingPersonalBestAll()
trackIndex = TTLocalizer.KartRace_TrackNames.keys().index(self.trackId)
if pKartingBest[trackIndex] > time or not pKartingBest[trackIndex]:
pKartingBest[trackIndex] = time
av.b_setKartingPersonalBest(pKartingBest)
gTourTrophy = True
for bestTime in pKartingBest:
if not bestTime:
gTourTrophy = False
if gTourTrophy:
if avTrophies[RaceGlobals.GrandTouring] != 1:
avTrophies[RaceGlobals.GrandTouring] = 1
trophies.append(RaceGlobals.GrandTouring)
newLaffBoost = int((len(trophies) + numTrophies)/10)
if newLaffBoost - oldLaffBoost != 0:
for i in xrange(newLaffBoost):
if avTrophies[RaceGlobals.TrophyCups[i]] != 1:
avTrophies[RaceGlobals.TrophyCups[i]] = 1
trophies.append(RaceGlobals.TrophyCups[i])
av.b_setMaxHp(av.getMaxHp() + newLaffBoost - oldLaffBoost)
av.toonUp(av.getMaxHp())
av.b_setKartingTrophies(avTrophies)
return trophies
def requestThrow(self, x, y, z):
avId = self.air.getAvatarIdFromSender()
if not avId in self.avatars:
self.air.writeServerEvent('suspicious', avId, 'Toon tried to throw a gag in a race they\'re not in!')
if self.avatarGags[avId] == RaceGlobals.BANANA:
gag = DistributedGagAI(self.air)
gag.setRace(self.doId)
gag.setOwnerId(avId)
gag.setPos(x, y, z)
gag.setType(0)
gag.setInitTime(globalClockDelta.getRealNetworkTime())
gag.setActivateTime(globalClockDelta.getRealNetworkTime())
gag.generateWithRequired(self.zoneId)
self.livingGags.append(gag)
elif self.avatarGags[avId] == RaceGlobals.TURBO:
pass
elif self.avatarGags[avId] == RaceGlobals.ANVIL:
places = sorted(self.avatarProgress, key=self.avatarProgress.get, reverse=True)
for i in places:
if not i in self.finishedAvatars and not self.currentlyAffectedByAnvil[i]:
currAvatar = i
break
self.currentlyAffectedByAnvil[avId] = True
taskMgr.doMethodLater(RaceGlobals.AnvilSquishDuration, self.unsquish, 'unsquish-%i' % currAvatar, [currAvatar])
self.sendUpdate('dropAnvilOn', [avId, currAvatar, globalClockDelta.getRealNetworkTime()])
elif self.avatarGags[avId] == RaceGlobals.PIE:
places = sorted(self.avatarProgress, key=self.avatarProgress.get)
avPlace = places.index(avId)
if avPlace + 1 == len(places):
target = 0
else:
target = places[avPlace + 1]
self.sendUpdate('shootPiejectile', [avId, target, 0])
else:
self.air.writeServerEvent('suspicious', avId, 'Toon use race gag while not having one!')
self.avatarGags[avId] = 0
def unsquish(self, avId):
self.currentlyAffectedByAnvil[avId] = False
def playerLeave(self, avId):
self.sendUpdate('racerDisconnected', [avId])
if avId in self.avatars:
self.avatars.remove(avId)
count = 0
for aK in self.avatarKarts:
if aK[0] == avId and aK[1] in self.air.doId2do:
self.air.doId2do[aK[1]].handleUnexpectedExit()
del self.avatarKarts[count]
break
count += 1
if len(self.avatars) == 0:
self.requestDelete()
else:
self.checkForNextRace()
def requestKart(self):
pass
avId = self.air.getAvatarIdFromSender()
accId = self.air.getAccountIdFromSender()
if not avId in self.avatars:
self.air.writeServerEvent('suspicious', avId, 'Toon tried to request kart in race they\'re not in!')
return
for aK in self.avatarKarts:
if aK[0] == avId:
self.air.doId2do[aK[1]].request('Controlled', avId, accId)
self.air.doId2do[aK[1]].sendUpdate('setInput', [0])