toontown-just-works/toontown/golf/DistributedGolfCourseAI.py
2024-07-07 18:08:39 -05:00

998 lines
37 KiB
Python

from direct.distributed import DistributedObjectAI
from direct.directnotify import DirectNotifyGlobal
from toontown.toonbase import ToontownGlobals
from toontown.golf import DistributedGolfHoleAI
from panda3d.core import *
from direct.fsm.FSM import FSM
from toontown.ai.ToonBarrier import *
from toontown.golf import GolfGlobals
from toontown.uberdog import TopToonsGlobals
INITIAL = 0
EXITED = 1
EXPECTED = 2
JOINED = 3
READY = 4
ONHOLE = 5
BALLIN = 6
JOIN_TIMEOUT = 30
READY_TIMEOUT = 30
EXIT_TIMEOUT = 30
REWARD_TIMEOUT = 30
class DistributedGolfCourseAI(DistributedObjectAI.DistributedObjectAI, FSM):
notify = directNotify.newCategory('DistributedGolfCourseAI')
defaultTransitions = {'Off': ['WaitJoin'],
'WaitJoin': ['WaitReadyCourse', 'Cleanup'],
'WaitReadyCourse': ['WaitReadyHole', 'Cleanup'],
'WaitReadyHole': ['PlayHole',
'Cleanup',
'WaitLeaveHole',
'WaitReward'],
'PlayHole': ['PlayHole',
'WaitLeaveHole',
'Cleanup',
'WaitReward'],
'WaitLeaveHole': ['WaitReadyHole',
'WaitLeaveCourse',
'Cleanup',
'WaitReward'],
'WaitReward': ['WaitLeaveCourse', 'Cleanup', 'WaitLeaveHole'],
'WaitLeaveCourse': ['Cleanup'],
'Cleanup': ['Off']}
def __init__(self, zoneId, avIds, courseId, preferredHoleId = None):
FSM.__init__(self, 'GolfCourse_%s_FSM' % zoneId)
DistributedObjectAI.DistributedObjectAI.__init__(self, simbase.air)
self.notify.debug('GOLF COURSE: init')
self.zoneId = zoneId
self.currentHole = None
self.avIdList = []
self.avStateDict = {}
self.addExpectedGolfers(avIds)
self.courseId = courseId
self.preferredHoleId = preferredHoleId
self.courseInfo = GolfGlobals.CourseInfo[self.courseId]
self.numHoles = self.courseInfo['numHoles']
self.holeIds = self.calcHolesToUse()
self.notify.debug('self.holeIds = %s' % self.holeIds)
self.numHolesPlayed = 0
self.curHoleIndex = 0
self.trophyListLen = 0
self.courseBestListLen = 0
self.holeBestListLen = 0
self.cupListLen = 0
self.scores = {}
self.aimTimes = {}
self.startingHistory = {}
self.endingHistory = {}
self.startingHoleBest = {}
self.endingHoleBest = {}
self.startingCourseBest = {}
self.endingCourseBest = {}
self.startingCups = {}
self.endingCups = {}
self.initHistory()
self.newTrophies = {}
self.newHoleBest = {}
self.newCourseBest = {}
self.newCups = {}
self.drivingToons = []
self.__barrier = None
self.winnerByTieBreak = 0
return
def initHistory(self):
for avId in self.avIdList:
av = simbase.air.doId2do.get(avId)
if av:
history = av.getGolfHistory()
self.startingHistory[avId] = history[:]
self.endingHistory[avId] = history[:]
holeBest = av.getGolfHoleBest()
self.startingHoleBest[avId] = holeBest[:]
self.endingHoleBest[avId] = holeBest[:]
courseBest = av.getGolfCourseBest()
self.startingCourseBest[avId] = courseBest[:]
self.endingCourseBest[avId] = courseBest[:]
def generate(self):
DistributedObjectAI.DistributedObjectAI.generate(self)
self.grabGolfers()
def delete(self):
self.notify.debug('GOLF COURSE: delete: deleting AI GolfCourse object')
if hasattr(self, 'rewardBarrier'):
self.rewardBarrier.cleanup()
del self.rewardBarrier
if self.currentHole:
self.notify.debug('calling requestDelete on hole %d' % self.currentHole.doId)
self.currentHole.requestDelete()
self.currentHole = None
self.ignoreAll()
from toontown.golf import GolfManagerAI
GolfManagerAI.GolfManagerAI().removeCourse(self)
if self.__barrier:
self.__barrier.cleanup()
self.__barrier = None
DistributedObjectAI.DistributedObjectAI.delete(self)
return
def load(self):
self.b_setCourseReady()
self.request('WaitReadyCourse')
def getZoneId(self):
return self.zoneId
def addExpectedGolfers(self, avIdList):
self.notify.debug('Sending %s to course %s' % (avIdList, self.zoneId))
for avId in avIdList:
golfer = simbase.air.doId2do.get(avId)
if golfer:
if avId not in self.avIdList:
self.avIdList.append(avId)
self.avStateDict[avId] = INITIAL
elif self.avStateDict[avId] == EXITED:
if self.isGenerated():
pass
else:
self.notify.warning('GOLF COURSE: trying to grab golfer %s that is already on the course' % avId)
def grabGolfers(self):
for avId in self.avIdList:
golfer = simbase.air.doId2do.get(avId)
if golfer:
if self.avStateDict[avId] == INITIAL:
self.avStateDict[avId] = EXPECTED
self.request('WaitJoin')
def getGolferIds(self):
return self.avIdList
def checkGolferPlaying(self, avId):
if self.avStateDict[avId] == ONHOLE:
return 1
else:
return 0
def b_setCourseReady(self):
self.setCourseReady()
self.d_setCourseReady()
def d_setCourseReady(self):
self.notify.debug('GOLF COURSE: Sending setCourseReady')
self.sendUpdate('setCourseReady', [self.numHoles, self.holeIds, self.calcCoursePar()])
def setCourseReady(self):
self.notify.debug('GOLF COURSE: setCourseReady: golf course ready with avatars: %s' % self.avIdList)
self.trophyListLen = 0
self.courseBestListLen = 0
self.holeBestListLen = 0
self.cupListLen = 0
self.normalExit = 1
def d_setPlayHole(self):
self.notify.debug('GOLF COURSE: setPlayHole: play on golf hole about to start')
self.sendUpdate('setPlayHole', [])
def b_setCourseExit(self):
self.d_setCourseExit()
self.setCourseExit()
def d_setCourseExit(self):
self.notify.debug('GOLF COURSE: Sending setGameExit')
self.sendUpdate('setCourseExit', [])
def setCourseExit(self):
self.notify.debug('GOLF COURSE: setGameExit')
def handleExitedAvatar(self, avId):
self.notify.warning('GOLF COURSE: handleExitedAvatar: avatar id exited: ' + str(avId))
self.avStateDict[avId] = EXITED
self.sendUpdate('avExited', [avId])
if self.currentHole and not self.haveAllGolfersExited():
self.currentHole.avatarDropped(avId)
if self.haveAllGolfersExited():
self.setCourseAbort()
elif self.isCurHoleDone():
if self.isPlayingLastHole():
if self.state not in ['WaitReward', 'WaitReadyHole']:
self.safeDemand('WaitReward')
else:
self.notify.debug('allBalls are in holes, calling holeOver')
self.holeOver()
if hasattr(self, 'rewardBarrier'):
if self.rewardBarrier:
self.rewardBarrier.clear(avId)
if hasattr(self, '__barrier'):
if self.__barrier:
self.__.clear(avId)
def startNextHole(self):
self.notify.debugStateCall(self)
holeId = self.holeIds[self.numHolesPlayed]
self.currentHole = DistributedGolfHoleAI.DistributedGolfHoleAI(self.zoneId, golfCourse=self, holeId=holeId)
self.currentHole.generateWithRequired(self.zoneId)
self.d_setCurHoleDoId(self.currentHole.doId)
self.safeDemand('WaitReadyHole')
def holeOver(self):
self.notify.debug('GOLF COURSE: holeOver')
self.numHolesPlayed += 1
if self.numHolesPlayed < self.numHoles:
self.b_setCurHoleIndex(self.numHolesPlayed)
self.safeDemand('WaitLeaveHole')
def setCourseAbort(self):
self.notify.debug('GOLF COURSE: setGameAbort')
self.normalExit = 0
self.sendUpdate('setCourseAbort', [0])
self.safeDemand('Cleanup')
def enterOff(self):
self.notify.debug('GOLF COURSE: enterOff')
def exitOff(self):
self.notify.debug('GOLF COURSE: exitOff')
def enterWaitJoin(self):
self.notify.debug('GOLF COURSE: enterWaitJoin')
for avId in self.avIdList:
self.avStateDict[avId] = EXPECTED
self.acceptOnce(self.air.getAvatarExitEvent(avId), self.handleExitedAvatar, extraArgs=[avId])
def allAvatarsJoined(self = self):
self.notify.debug('GOLF COURSE: all avatars joined')
self.load()
def handleTimeout(avIds, self = self):
self.notify.debug('GOLF COURSE: timed out waiting for clients %s to join' % avIds)
for avId in self.avStateDict:
if not self.avStateDict[avId] == JOINED:
self.handleExitedAvatar(avId)
if self.haveAllGolfersExited():
self.setCourseAbort()
else:
self.load()
self.__barrier = ToonBarrier('waitClientsJoin', self.uniqueName('waitClientsJoin'), self.avIdList, JOIN_TIMEOUT, allAvatarsJoined, handleTimeout)
def exitWaitJoin(self):
self.notify.debugStateCall(self)
self.__barrier.cleanup()
self.__barrier = None
return
def setAvatarJoined(self):
avId = self.air.getAvatarIdFromSender()
self.notify.debug('GOLF COURSE: setAvatarJoined: avatar id joined: ' + str(avId))
self.avStateDict[avId] = JOINED
self.notify.debug('GOLF COURSE: setAvatarJoined: new states: ' + str(self.avStateDict))
if hasattr(self, '_DistributedGolfCourseAI__barrier') and self.__barrier:
self.__barrier.clear(avId)
else:
self.notify.warning('setAvatarJoined avId=%d but barrier is invalid' % avId)
def exitFrameworkWaitClientsJoin(self):
self.__barrier.cleanup()
del self.__barrier
def enterWaitReadyCourse(self):
self.notify.debug('GOLF COURSE: enterWaitReadyCourse')
def allAvatarsInCourse(self = self):
self.notify.debug('GOLF COURSE: all avatars ready course')
for avId in self.avIdList:
blankScoreList = [0] * self.numHoles
self.scores[avId] = blankScoreList
self.aimTimes[avId] = 0
self.notify.debug('self.scores = %s' % self.scores)
self.startNextHole()
def handleTimeout(avIds, self = self):
self.notify.debug("GOLF COURSE: Course timed out waiting for clients %s to report 'ready'" % avIds)
if self.haveAllGolfersExited():
self.setCourseAbort()
else:
allAvatarsInCourse()
self.__barrier = ToonBarrier('WaitReadyCourse', self.uniqueName('WaitReadyCourse'), self.avIdList, READY_TIMEOUT, allAvatarsInCourse, handleTimeout)
for avId in self.avStateDict.keys():
if self.avStateDict[avId] == READY:
self.__barrier.clear(avId)
def setAvatarReadyCourse(self):
avId = self.air.getAvatarIdFromSender()
self.notify.debug('GOLF COURSE: setAvatarReadyCourse: avatar id ready: ' + str(avId))
self.avStateDict[avId] = READY
self.notify.debug('GOLF COURSE: setAvatarReadyCourse: new avId states: ' + str(self.avStateDict))
if self.state == 'WaitReadyCourse':
self.__barrier.clear(avId)
def exitWaitReadyCourse(self):
self.notify.debugStateCall(self)
self.__barrier.cleanup()
self.__barrier = None
return
def enterWaitReadyHole(self):
self.notify.debug('GOLF COURSE: enterWaitReadyHole')
def allAvatarsInHole(self = self):
self.notify.debug('GOLF COURSE: all avatars ready hole')
if self.safeDemand('PlayHole'):
self.d_setPlayHole()
def handleTimeout(avIds, self = self):
self.notify.debug("GOLF COURSE: Hole timed out waiting for clients %s to report 'ready'" % avIds)
if self.haveAllGolfersExited():
self.setCourseAbort()
elif self.safeDemand('PlayHole'):
self.d_setPlayHole()
stillPlaying = self.getStillPlayingAvIds()
self.__barrier = ToonBarrier('WaitReadyHole', self.uniqueName('WaitReadyHole'), stillPlaying, READY_TIMEOUT, allAvatarsInHole, handleTimeout)
for avId in self.avStateDict.keys():
if self.avStateDict[avId] == ONHOLE:
self.__barrier.clear(avId)
def exitWaitReadyHole(self):
self.notify.debugStateCall(self)
if hasattr(self, '__barrier'):
self.__barrier.cleanup()
self.__barrier = None
return
def getStillPlayingAvIds(self):
retval = []
for avId in self.avIdList:
av = simbase.air.doId2do.get(avId)
if av:
if avId in self.avStateDict and not self.avStateDict[avId] == EXITED:
retval.append(avId)
return retval
def avatarReadyHole(self, avId):
if self.state not in ['WaitJoin', 'WaitReadyCourse', 'WaitReadyHole']:
self.notify.debug('GOLF COURSE: Ignoring setAvatarReadyHole message')
return
self.notify.debug('GOLF COURSE: setAvatarReadyHole: avatar id ready: ' + str(avId))
self.avStateDict[avId] = ONHOLE
self.notify.debug('GOLF COURSE: setAvatarReadyHole: new avId states: ' + str(self.avStateDict))
if self.state == 'WaitReadyHole':
self.__barrier.clear(avId)
def enterPlayHole(self):
self.notify.debug('GOLF COURSE: enterPlayHole')
if self.currentHole and not self.currentHole.playStarted:
self.currentHole.startPlay()
def exitPlayHole(self):
self.notify.debug('GOLF COURSE: exitPlayHole')
def enterWaitLeaveHole(self):
self.notify.debugStateCall(self)
self.notify.debug('calling requestDelete on hole %d' % self.currentHole.doId)
self.currentHole.requestDelete()
self.currentHole = None
if self.numHolesPlayed >= self.numHoles:
pass
else:
self.startNextHole()
return
def exitWaitLeaveHole(self):
pass
def enterWaitReward(self):
self.updateHistoryForCourseComplete()
self.awardTrophies()
self.awardCups()
self.awardHoleBest()
self.awardCourseBest()
self.recordHoleInOne()
self.recordCourseUnderPar()
trophiesList = []
for index in xrange(len(self.avIdList)):
avId = self.avIdList[index]
if avId in self.newTrophies:
oneTrophyList = self.newTrophies[avId]
trophiesList.append(oneTrophyList)
else:
trophiesList.append([])
while len(trophiesList) < GolfGlobals.MAX_PLAYERS_PER_HOLE:
trophiesList.append([])
holeBestList = []
for index in xrange(len(self.avIdList)):
avId = self.avIdList[index]
if avId in self.newHoleBest:
oneTrophyList = self.newHoleBest[avId]
holeBestList.append(oneTrophyList)
else:
holeBestList.append([])
while len(holeBestList) < GolfGlobals.MAX_PLAYERS_PER_HOLE:
holeBestList.append([])
courseBestList = []
for index in xrange(len(self.avIdList)):
avId = self.avIdList[index]
if avId in self.newCourseBest:
oneTrophyList = self.newCourseBest[avId]
courseBestList.append(oneTrophyList)
else:
courseBestList.append([])
while len(courseBestList) < GolfGlobals.MAX_PLAYERS_PER_HOLE:
courseBestList.append([])
cupList = []
for index in xrange(len(self.avIdList)):
avId = self.avIdList[index]
if avId in self.newCups:
oneCupList = self.newCups[avId]
cupList.append(oneCupList)
self.cupListLen = self.cupListLen + 1
else:
cupList.append([])
while len(cupList) < GolfGlobals.MAX_PLAYERS_PER_HOLE:
cupList.append([])
REWARD_TIMEOUT = (self.trophyListLen + self.holeBestListLen + self.courseBestListLen + self.cupListLen) * 5 + 19
aimTimesList = [0] * 4
aimIndex = 0
stillPlaying = self.getStillPlayingAvIds()
for avId in self.avIdList:
if avId in stillPlaying:
aimTime = 0
if avId in self.aimTimes:
aimTime = self.aimTimes[avId]
aimTimesList[aimIndex] = aimTime
aimIndex += 1
self.sendUpdate('setReward', [trophiesList,
self.rankings,
holeBestList,
courseBestList,
cupList,
self.winnerByTieBreak,
aimTimesList[0],
aimTimesList[1],
aimTimesList[2],
aimTimesList[3]])
def allAvatarsRewarded(self = self):
self.notify.debug('GOLF COURSE: all avatars rewarded')
self.rewardDone()
def handleRewardTimeout(avIds, self = self):
self.notify.debug('GOLF COURSE: timed out waiting for clients %s to finish reward' % avIds)
self.rewardDone()
stillPlaying = self.getStillPlayingAvIds()
self.rewardBarrier = ToonBarrier('waitReward', self.uniqueName('waitReward'), stillPlaying, REWARD_TIMEOUT, allAvatarsRewarded, handleRewardTimeout)
def exitWaitReward(self):
pass
def enterWaitLeaveCourse(self):
self.notify.debugStateCall(self)
self.setCourseAbort()
def exitWaitLeaveCourse(self):
pass
def enterCleanup(self):
self.notify.debug('GOLF COURSE: enterCleanup')
self.requestDelete()
def exitCleanup(self):
self.notify.debug('GOLF COURSE: exitCleanup')
def isCurHoleDone(self):
retval = False
if self.areAllBallsInHole():
retval = True
else:
retval = True
for state in self.avStateDict.values():
if not (state == BALLIN or state == EXITED):
retval = False
break
return retval
def areAllBallsInHole(self):
self.notify.debug('areAllBallsInHole, self.avStateDict=%s' % self.avStateDict)
allBallsInHole = True
for state in self.avStateDict.values():
if state != BALLIN:
allBallsInHole = False
return allBallsInHole
def isPlayingLastHole(self):
retval = self.numHoles - self.numHolesPlayed == 1
return retval
def setBallIn(self, avId):
self.notify.debug('setBallIn %d' % avId)
if self.avStateDict[avId] == BALLIN:
self.notify.debug('setBallIn already in BALLIN state, just returning')
return
self.avStateDict[avId] = BALLIN
self.updateHistoryForBallIn(avId)
if self.isCurHoleDone():
if self.isPlayingLastHole():
if self.state != 'WaitReward':
self.safeDemand('WaitReward')
else:
self.notify.debug('allBalls are in holes, calling holeOver')
self.holeOver()
def updateHistoryForBallIn(self, avId):
if self.currentHole == None:
return
holeId = self.currentHole.holeId
holeInfo = GolfGlobals.HoleInfo[holeId]
par = holeInfo['par']
holeIndex = self.numHolesPlayed
if holeIndex >= self.numHoles:
self.notify.warning('updateHistoryForBallIn invalid holeIndex %d' % holeIndex)
holeIndex = self.numHoles - 1
elif holeIndex < 0:
self.notify.warning('updateHistoryForBallIn invalid holeIndex %d' % holeIndex)
holeIndex = 0
strokes = self.scores[avId][holeIndex]
self.notify.debug('self.scores = %s' % self.scores)
diff = strokes - par
if strokes == 1:
self.incrementEndingHistory(avId, GolfGlobals.HoleInOneShots)
if diff <= -2:
self.incrementEndingHistory(avId, GolfGlobals.EagleOrBetterShots)
if diff <= -1:
self.incrementEndingHistory(avId, GolfGlobals.BirdieOrBetterShots)
if diff <= 0:
self.endingHistory[avId][GolfGlobals.ParOrBetterShots] += 1
if strokes < self.endingHoleBest[avId][holeId] or self.endingHoleBest[avId][holeId] == 0:
self.endingHoleBest[avId][holeId] = strokes
return
def incrementEndingHistory(self, avId, historyIndex):
if avId in self.endingHistory and historyIndex in GolfGlobals.TrophyRequirements:
maximumAmount = GolfGlobals.TrophyRequirements[historyIndex][-1]
if self.endingHistory[avId][historyIndex] < maximumAmount:
self.endingHistory[avId][historyIndex] += 1
def getCourseId(self):
return self.courseId
def abortCurrentHole(self):
holeId = self.currentHole.holeId
holeDoId = self.currentHole.doId
self.currentHole.finishHole()
return (holeId, holeDoId)
def calcHolesToUse(self):
retval = []
if simbase.air.config.GetBool('golf-course-randomized', 1):
retval = self.calcHolesToUseRandomized(self.courseId)
self.notify.debug('randomized courses!')
for x in xrange(len(retval)):
self.notify.debug('Hole is: %s' % retval[x])
else:
validHoles = self.calcUniqueHoles(self.courseId)
if self.preferredHoleId in validHoles:
retval.append(self.preferredHoleId)
while len(retval) < self.numHoles:
for holeId in GolfGlobals.CourseInfo[self.courseId]['holeIds']:
if type(holeId) == type(0):
retval.append(holeId)
elif type(holeId) == type(()):
retval.append(holeId[0])
else:
self.notify.warning('cant handle %s' % self.holeId)
if len(retval) >= self.numHoles:
break
return retval
def incrementScore(self, avId):
self.notify.debug('incrementScore self.scores=%s avId=%s' % (self.scores, avId))
self.scores[avId][self.numHolesPlayed] += 1
self.notify.debug('after increment self.score=%s' % self.scores)
self.sendScores()
def sendScores(self):
self.notify.debug('sendScores self.scores = %s' % self.scores)
scorelist = []
for avId in self.avIdList:
for score in self.scores[avId]:
scorelist.append(score)
self.sendUpdate('setScores', [scorelist])
self.notify.debug('sendScores end self.scores = %s' % self.scores)
def getCurHoleIndex(self):
return self.curHoleIndex
def b_setCurHoleIndex(self, holeIndex):
self.setCurHoleIndex(holeIndex)
self.d_setCurHoleIndex(holeIndex)
def d_setCurHoleIndex(self, holeIndex):
self.sendUpdate('setCurHoleIndex', [holeIndex])
def setCurHoleIndex(self, holeIndex):
self.curHoleIndex = holeIndex
def setDoneReward(self):
avId = self.air.getAvatarIdFromSender()
self.notify.debug('got rewardDone from %d' % avId)
if hasattr(self, 'rewardBarrier'):
self.rewardBarrier.clear(avId)
self.sendUpdate('setCourseAbort', [avId])
def rewardDone(self):
self.notify.debug('rewardDone')
self.holeOver()
self.safeDemand('WaitLeaveCourse')
def updateHistoryForCourseComplete(self):
self.calcRankings()
stillPlaying = self.getStillPlayingAvIds()
for avId in stillPlaying:
self.incrementEndingHistory(avId, GolfGlobals.CoursesCompleted)
coursePar = self.calcCoursePar()
totalScore = self.getTotalScore(avId)
if totalScore < coursePar:
self.incrementEndingHistory(avId, GolfGlobals.CoursesUnderPar)
if len(stillPlaying) > 1:
self.incrementEndingHistory(avId, GolfGlobals.MultiPlayerCoursesCompleted)
if self.rankingsById[avId] == 1:
if self.courseId == 0:
self.incrementEndingHistory(avId, GolfGlobals.CourseZeroWins)
elif self.courseId == 1:
self.incrementEndingHistory(avId, GolfGlobals.CourseOneWins)
elif self.courseId == 2:
self.incrementEndingHistory(avId, GolfGlobals.CourseTwoWins)
else:
self.notify.warning('unhandled case, self.courseId=%s' % self.courseId)
if totalScore < self.endingCourseBest[avId][self.courseId] or self.endingCourseBest[avId][self.courseId] == 0:
self.endingCourseBest[avId][self.courseId] = totalScore
def calcRankings(self):
stillPlaying = self.getStillPlayingAvIds()
self.rankings = []
totalScores = []
for avId in self.avIdList:
aimTime = 0
if avId in self.aimTimes:
aimTime = self.aimTimes[avId]
if avId in stillPlaying:
totalScores.append((avId, self.getTotalScore(avId), aimTime))
else:
totalScores.append((avId, 255, aimTime))
def scoreCompareNoTime(tupleA, tupleB):
if tupleA[1] > tupleB[1]:
return 1
elif tupleA[1] == tupleB[1]:
return 0
else:
return -1
def scoreCompareWithTime(tupleA, tupleB):
if tupleA[1] > tupleB[1]:
return 1
elif tupleA[1] == tupleB[1]:
if tupleA[2] > tupleB[2]:
return 1
elif tupleA[2] == tupleB[2]:
return 0
else:
return -1
else:
return -1
if GolfGlobals.TIME_TIE_BREAKER:
totalScores.sort(scoreCompareWithTime)
else:
totalScores.sort(scoreCompareNoTime)
curRank = 0
oldScore = 0
oldTime = 0
self.rankingsById = {}
for scoreTuple in totalScores:
time = scoreTuple[2]
score = scoreTuple[1]
avId = scoreTuple[0]
if score > oldScore or GolfGlobals.TIME_TIE_BREAKER and score == oldScore and time > oldTime:
curRank += 1
oldScore = score
oldTime = time
self.rankingsById[avId] = curRank
tiedForFirst = []
tempRank = 0
oldScore = 0
oldTime = 0
for scoreTuple in totalScores:
time = scoreTuple[2]
score = scoreTuple[1]
avId = scoreTuple[0]
if score > oldScore:
tempRank += 1
oldScore = score
oldTime = time
if tempRank == 1:
tiedForFirst.append(avId)
for avId in self.avIdList:
if avId in stillPlaying:
self.rankings.append(self.rankingsById[avId])
else:
self.rankings.append(-1)
if len(tiedForFirst) >= 2 and not GolfGlobals.TIME_TIE_BREAKER:
winnerAvId = random.choice(tiedForFirst)
winnerIndex = self.avIdList.index(winnerAvId)
self.winnerByTieBreak = winnerAvId
for index in xrange(len(self.rankings)):
if self.rankings[index] > 0 and index != winnerIndex:
self.rankings[index] += 1
for avId in self.rankingsById:
if self.rankingsById[avId] > 0 and avId != winnerAvId:
self.rankingsById[avId] += 1
elif len(tiedForFirst) >= 2:
winnerAvId = totalScores[0][0]
self.winnerByTieBreak = winnerAvId
def awardTrophies(self):
stillPlaying = self.getStillPlayingAvIds()
for avId in stillPlaying:
av = simbase.air.doId2do.get(avId)
if av:
oldHistory = self.startingHistory[avId]
endingHistory = self.endingHistory[avId]
oldTrophies = GolfGlobals.calcTrophyListFromHistory(oldHistory)
endingTrophies = GolfGlobals.calcTrophyListFromHistory(endingHistory)
av.b_setGolfHistory(endingHistory)
av.addStat(ToontownGlobals.STAT_GOLF)
newTrophies = []
for index in xrange(len(oldTrophies)):
if not oldTrophies[index] and endingTrophies[index]:
self.notify.debug('New Trophy %d' % index)
self.air.writeServerEvent('golf_trophy', avId, '%s' % index)
newTrophies.append(True)
self.trophyListLen = self.trophyListLen + 1
else:
newTrophies.append(False)
self.newTrophies[avId] = newTrophies
def awardCups(self):
stillPlaying = self.getStillPlayingAvIds()
for avId in stillPlaying:
av = simbase.air.doId2do.get(avId)
if av:
oldHistory = self.startingHistory[avId]
endingHistory = self.endingHistory[avId]
oldCups = GolfGlobals.calcCupListFromHistory(oldHistory)
endingCups = GolfGlobals.calcCupListFromHistory(endingHistory)
newCups = []
for index in xrange(len(oldCups)):
if not oldCups[index] and endingCups[index]:
self.notify.debug('New Trophy %d' % index)
newCups.append(True)
self.air.writeServerEvent('golf_cup', avId, '%s' % index)
newMaxHp = av.getMaxHp() + 1
av.b_setMaxHp(newMaxHp)
av.toonUp(newMaxHp)
else:
newCups.append(False)
self.newCups[avId] = newCups
def awardHoleBest(self):
stillPlaying = self.getStillPlayingAvIds()
for avId in stillPlaying:
av = simbase.air.doId2do.get(avId)
if av:
oldHoleBest = self.startingHoleBest[avId]
endingHoleBest = self.endingHoleBest[avId]
av.b_setGolfHoleBest(endingHoleBest)
newHoleBest = []
longestHoleBestList = 0
for index in xrange(len(oldHoleBest)):
if endingHoleBest[index] < oldHoleBest[index]:
self.notify.debug('New HoleBest %d' % index)
newHoleBest.append(True)
longestHoleBestList = longestHoleBestList + 1
else:
newHoleBest.append(False)
if longestHoleBestList > self.holeBestListLen:
self.holeBestListLen = longestHoleBestList
self.newHoleBest[avId] = newHoleBest
def awardCourseBest(self):
stillPlaying = self.getStillPlayingAvIds()
for avId in stillPlaying:
av = simbase.air.doId2do.get(avId)
if av:
oldCourseBest = self.startingCourseBest[avId]
endingCourseBest = self.endingCourseBest[avId]
av.b_setGolfCourseBest(endingCourseBest)
newCourseBest = []
longestCourseBestList = 0
for index in xrange(len(oldCourseBest)):
if endingCourseBest[index] < oldCourseBest[index]:
self.notify.debug('New CourseBest %d' % index)
newCourseBest.append(True)
longestCourseBestList = longestCourseBestList + 1
else:
newCourseBest.append(False)
if longestCourseBestList > self.courseBestListLen:
self.courseBestListLen = longestCourseBestList
self.newCourseBest[avId] = newCourseBest
def haveAllGolfersExited(self):
retval = True
for avId in self.avStateDict:
if not self.avStateDict[avId] == EXITED:
retval = False
break
return retval
def getCurHoleDoId(self):
retval = 0
if self.currentHole:
retval = self.currentHole.doId
return retval
def d_setCurHoleDoId(self, curHoleDoId):
self.sendUpdate('setCurHoleDoId', [curHoleDoId])
def calcCoursePar(self):
retval = 0
for holeId in self.holeIds:
holeInfo = GolfGlobals.HoleInfo[holeId]
retval += holeInfo['par']
return retval
def getTotalScore(self, avId):
retval = 0
if avId in self.scores:
for holeScore in self.scores[avId]:
retval += holeScore
return retval
def getCurHoleScore(self, avId):
retval = 0
if avId in self.scores and self.numHolesPlayed < len(self.scores[avId]):
retval = self.scores[avId][self.numHolesPlayed]
return retval
def toggleDrivePermission(self, avId):
if avId in self.drivingToons:
self.drivingToons.remove(avId)
self.sendUpdate('changeDrivePermission', [avId, 0])
retval = False
else:
self.drivingToons.append(avId)
self.sendUpdate('changeDrivePermission', [avId, 1])
retval = True
return retval
def safeDemand(self, newState):
doingDemand = False
if self.state == 'Cleanup':
pass
else:
if self.state in self.defaultTransitions:
if newState in self.defaultTransitions[self.state]:
self.demand(newState)
doingDemand = True
elif self.state == None:
self.demand(newState)
doingDemand = True
if not doingDemand:
self.notify.warning('doId=%d ignoring demand from %s to %s' % (self.doId, self.state, newState))
return doingDemand
def setAvatarExited(self):
avId = self.air.getAvatarIdFromSender()
self.handleExitedAvatar(avId)
def createChoicesList(self, courseId, possibleHoles):
retval = []
holeIds = GolfGlobals.CourseInfo[courseId]['holeIds']
for holeOrTuple in holeIds:
if type(holeOrTuple) == type(()):
holeId = holeOrTuple[0]
weight = holeOrTuple[1]
elif type(holeOrTuple) == type(0):
holeId = holeOrTuple
weight = 1
else:
self.notify.warning('cant handle %s' % holeOrTuple)
continue
if holeId in possibleHoles:
retval += [holeId] * weight
return retval
def calcUniqueHoles(self, courseId):
uniqueHoles = set()
for holeOrTuple in GolfGlobals.CourseInfo[courseId]['holeIds']:
if type(holeOrTuple) == type(()):
uniqueHoles.add(holeOrTuple[0])
elif type(holeOrTuple) == type(0):
uniqueHoles.add(holeOrTuple)
else:
self.notify.warning('cant handle %s' % holeOrTuple)
return uniqueHoles
def calcHolesToUseRandomized(self, courseId):
retval = []
numHoles = GolfGlobals.CourseInfo[courseId]['numHoles']
uniqueHoles = self.calcUniqueHoles(courseId)
curHolesChosen = set()
while len(retval) < numHoles:
if uniqueHoles == curHolesChosen:
curHolesChosen = set()
possibleHoles = uniqueHoles - curHolesChosen
choicesList = self.createChoicesList(courseId, possibleHoles)
if not self.preferredHoleId == None and self.preferredHoleId in choicesList and self.preferredHoleId not in curHolesChosen:
holeChosen = self.preferredHoleId
else:
holeChosen = random.choice(choicesList)
retval.append(holeChosen)
curHolesChosen.add(holeChosen)
return retval
def recordHoleInOne(self):
stillPlaying = self.getStillPlayingAvIds()
for avId in stillPlaying:
scoreList = self.scores[avId]
ns = 0
for holeIndex in xrange(len(scoreList)):
strokes = scoreList[holeIndex]
if strokes == 1:
ns +=1
holeId = self.holeIds[holeIndex]
self.air.writeServerEvent('golf_ace', avId, '%d|%d|%s' % (self.courseId, holeId, stillPlaying))
if ns:
messenger.send('topToonsManager-event', [avId, TopToonsGlobals.CAT_HOLE_IN_ONE, ns])
def recordCourseUnderPar(self):
coursePar = self.calcCoursePar()
stillPlaying = self.getStillPlayingAvIds()
for avId in stillPlaying:
totalScore = self.getTotalScore(avId)
netScore = totalScore - coursePar
if netScore < 0:
self.air.writeServerEvent('golf_underPar', avId, '%d|%d|%s' % (self.courseId, netScore, stillPlaying))
messenger.send('topToonsManager-event', [avId, TopToonsGlobals.CAT_COURSE_UNDER_PAR, 1])
def addAimTime(self, avId, aimTime):
if avId in self.aimTimes:
self.aimTimes[avId] += aimTime