def enterWaitPlayback(self):
     self.notify.debug('enterWaitPlayback')
     stillPlayingList = self.golfCourse.getStillPlayingAvIds()
     self.barrierPlayback = ToonBarrier(
         'waitClientsPlayback', self.uniqueName('waitClientsPlayback'),
         stillPlayingList, 120, self.handleWaitPlaybackDone,
         self.handlePlaybackTimeout)
 def enterWaitClientsReady(self):
     self.notify.debug('enterWaitClientsReady')
     self.nextRoundBarrier = ToonBarrier(
         'nextRoundReady', self.uniqueName('nextRoundReady'), self.avIdList,
         PatternGameGlobals.ClientsReadyTimeout, self.__allPlayersReady,
         self.__clientsReadyTimeout)
     for avId in self.readyClients:
         self.nextRoundBarrier.clear(avId)
 def enterWaitForResults(self):
     self.notify.debug('enterWaitForResults')
     self.results = [None] * self.numPlayers
     self.fastestTime = PatternGameGlobals.InputTime * 2
     self.fastestAvId = 0
     self.resultsBarrier = ToonBarrier(
         'results', self.uniqueName('results'), self.avIdList,
         PatternGameGlobals.InputTimeout + 1.0 * self.round,
         self.__gotAllPatterns, self.__resultsTimeout)
     return
    def enterFrameworkWaitClientsReady(self):
        self.notify.debug("BASE: enterFrameworkWaitClientsReady")

        def allAvatarsReady(self=self):
            self.notify.debug("BASE: all avatars ready")
            self.frameworkFSM.request("frameworkGame")

        def handleTimeout(avIds, self=self):
            self.notify.debug("BASE: timed out waiting for clients %s to report 'ready'" % avIds)
            self.setGameAbort()

        self.__barrier = ToonBarrier(
            "waitClientsReady",
            self.uniqueName("waitClientsReady"),
            self.avIdList,
            READY_TIMEOUT,
            allAvatarsReady,
            handleTimeout,
        )
        for avId in self.stateDict.keys():
            if self.stateDict[avId] == READY:
                self.__barrier.clear(avId)

        self.notify.debug("  safezone: %s" % self.getSafezoneId())
        self.notify.debug("difficulty: %s" % self.getDifficulty())
 def enterWaitForResults(self):
     self.notify.debug('enterWaitForResults')
     self.results = [None] * self.numPlayers
     self.fastestTime = PatternGameGlobals.InputTime * 2
     self.fastestAvId = 0
     self.resultsBarrier = ToonBarrier('results', self.uniqueName('results'), self.avIdList, PatternGameGlobals.InputTimeout + 1.0 * self.round, self.__gotAllPatterns, self.__resultsTimeout)
     return
Exemplo n.º 6
0
    def enterPlay(self):
        self.notify.debug('enterPlay')
        self.caughtList = [0] * 100
        table = CatchGameGlobals.NumFruits[self.numPlayers - 1]
        self.numFruits = table[self.getSafezoneId()]
        self.notify.debug('numFruits: %s' % self.numFruits)
        self.fruitsCaught = 0

        def allToonsDone(self = self):
            self.notify.debug('allToonsDone')
            self.sendUpdate('setEveryoneDone')
            if not CatchGameGlobals.EndlessGame:
                self.gameOver()

        def handleTimeout(avIds, self = self):
            self.notify.debug('handleTimeout: avatars %s did not report "done"' % avIds)
            self.setGameAbort()

        self.doneBarrier = ToonBarrier('waitClientsDone', self.uniqueName('waitClientsDone'), self.avIdList, CatchGameGlobals.GameDuration + MinigameGlobals.latencyTolerance, allToonsDone, handleTimeout)
Exemplo n.º 7
0
    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 enterPlay(self):
        self.notify.debug('enterPlay')

        def allToonsDone(self=self):
            self.notify.debug('allToonsDone')
            self.sendUpdate('setEveryoneDone')
            if not ToonBlitzGlobals.EndlessGame:
                self.gameOver()

        def handleTimeout(avIds, self=self):
            self.notify.debug(
                'handleTimeout: avatars %s did not report "done"' % avIds)
            self.setGameAbort()

        self.doneBarrier = ToonBarrier(
            'waitClientsDone', self.uniqueName('waitClientsDone'),
            self.avIdList,
            ToonBlitzGlobals.GameDuration[self.getSafezoneId()] +
            ToonBlitzGlobals.ShowScoresDuration +
            MinigameGlobals.latencyTolerance, allToonsDone, handleTimeout)
Exemplo n.º 9
0
    def enterFrameworkWaitClientsExit(self):
        self.notify.debug('BASE: enterFrameworkWaitClientsExit')
        self.b_setGameExit()

        def allAvatarsExited(self=self):
            self.notify.debug('BASE: all avatars exited')
            self.frameworkFSM.request('frameworkCleanup')

        def handleTimeout(avIds, self=self):
            self.notify.debug(
                'BASE: timed out waiting for clients %s to exit' % avIds)
            self.frameworkFSM.request('frameworkCleanup')

        self.__barrier = ToonBarrier('waitClientsExit',
                                     self.uniqueName('waitClientsExit'),
                                     self.avIdList, EXIT_TIMEOUT,
                                     allAvatarsExited, handleTimeout)
        for avId in self.stateDict.keys():
            if self.stateDict[avId] == EXITED:
                self.__barrier.clear(avId)
Exemplo n.º 10
0
    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 enterPlay(self):
        self.notify.debug('enterPlay')

        def allToonsDone(self = self):
            self.notify.debug('allToonsDone')
            self.sendUpdate('setEveryoneDone')
            if not ToonBlitzGlobals.EndlessGame:
                self.gameOver()

        def handleTimeout(avIds, self = self):
            self.notify.debug('handleTimeout: avatars %s did not report "done"' % avIds)
            self.setGameAbort()

        self.doneBarrier = ToonBarrier('waitClientsDone', self.uniqueName('waitClientsDone'), self.avIdList, ToonBlitzGlobals.GameDuration[self.getSafezoneId()] + ToonBlitzGlobals.ShowScoresDuration + MinigameGlobals.latencyTolerance, allToonsDone, handleTimeout)
Exemplo n.º 12
0
    def enterFrameworkWaitClientsReady(self):
        self.notify.debug('BASE: enterFrameworkWaitClientsReady')

        def allAvatarsReady(self=self):
            self.notify.debug('BASE: all avatars ready')
            self.frameworkFSM.request('frameworkGame')

        def handleTimeout(avIds, self=self):
            self.notify.debug(
                "BASE: timed out waiting for clients %s to report 'ready'" %
                avIds)
            self.setGameAbort()

        self.__barrier = ToonBarrier('waitClientsReady',
                                     self.uniqueName('waitClientsReady'),
                                     self.avIdList, READY_TIMEOUT,
                                     allAvatarsReady, handleTimeout)
        for avId in self.stateDict.keys():
            if self.stateDict[avId] == READY:
                self.__barrier.clear(avId)

        self.notify.debug('  safezone: %s' % self.getSafezoneId())
        self.notify.debug('difficulty: %s' % self.getDifficulty())
Exemplo n.º 13
0
    def enterFrameworkWaitClientsJoin(self):
        self.notify.debug('BASE: enterFrameworkWaitClientsJoin')
        for avId in self.avIdList:
            self.stateDict[avId] = EXPECTED
            self.scoreDict[avId] = DEFAULT_POINTS
            self.acceptOnce(self.air.getAvatarExitEvent(avId),
                            self.handleExitedAvatar,
                            extraArgs=[avId])

        def allAvatarsJoined(self=self):
            self.notify.debug('BASE: all avatars joined')
            self.b_setGameReady()
            self.frameworkFSM.request('frameworkWaitClientsReady')

        def handleTimeout(avIds, self=self):
            self.notify.debug(
                'BASE: timed out waiting for clients %s to join' % avIds)
            self.setGameAbort()

        self.__barrier = ToonBarrier('waitClientsJoin',
                                     self.uniqueName('waitClientsJoin'),
                                     self.avIdList, JOIN_TIMEOUT,
                                     allAvatarsJoined, handleTimeout)
Exemplo n.º 14
0
    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 enterFrameworkWaitClientsExit(self):
        self.notify.debug("BASE: enterFrameworkWaitClientsExit")
        self.b_setGameExit()

        def allAvatarsExited(self=self):
            self.notify.debug("BASE: all avatars exited")
            self.frameworkFSM.request("frameworkCleanup")

        def handleTimeout(avIds, self=self):
            self.notify.debug("BASE: timed out waiting for clients %s to exit" % avIds)
            self.frameworkFSM.request("frameworkCleanup")

        self.__barrier = ToonBarrier(
            "waitClientsExit",
            self.uniqueName("waitClientsExit"),
            self.avIdList,
            EXIT_TIMEOUT,
            allAvatarsExited,
            handleTimeout,
        )
        for avId in self.stateDict.keys():
            if self.stateDict[avId] == EXITED:
                self.__barrier.clear(avId)
    def enterFrameworkWaitClientsJoin(self):
        self.notify.debug("BASE: enterFrameworkWaitClientsJoin")
        for avId in self.avIdList:
            self.stateDict[avId] = EXPECTED
            self.scoreDict[avId] = DEFAULT_POINTS
            self.acceptOnce(self.air.getAvatarExitEvent(avId), self.handleExitedAvatar, extraArgs=[avId])

        def allAvatarsJoined(self=self):
            self.notify.debug("BASE: all avatars joined")
            self.b_setGameReady()
            self.frameworkFSM.request("frameworkWaitClientsReady")

        def handleTimeout(avIds, self=self):
            self.notify.debug("BASE: timed out waiting for clients %s to join" % avIds)
            self.setGameAbort()

        self.__barrier = ToonBarrier(
            "waitClientsJoin",
            self.uniqueName("waitClientsJoin"),
            self.avIdList,
            JOIN_TIMEOUT,
            allAvatarsJoined,
            handleTimeout,
        )
class DistributedMinigameAI(DistributedObjectAI.DistributedObjectAI):
    notify = directNotify.newCategory("DistributedMinigameAI")

    def __init__(self, air, minigameId):
        try:
            self.DistributedMinigameAI_initialized
        except:
            self.DistributedMinigameAI_initialized = 1
            DistributedObjectAI.DistributedObjectAI.__init__(self, air)
            self.minigameId = minigameId
            self.frameworkFSM = ClassicFSM.ClassicFSM(
                "DistributedMinigameAI",
                [
                    State.State(
                        "frameworkOff", self.enterFrameworkOff, self.exitFrameworkOff, ["frameworkWaitClientsJoin"]
                    ),
                    State.State(
                        "frameworkWaitClientsJoin",
                        self.enterFrameworkWaitClientsJoin,
                        self.exitFrameworkWaitClientsJoin,
                        ["frameworkWaitClientsReady", "frameworkWaitClientsExit", "frameworkCleanup"],
                    ),
                    State.State(
                        "frameworkWaitClientsReady",
                        self.enterFrameworkWaitClientsReady,
                        self.exitFrameworkWaitClientsReady,
                        ["frameworkGame", "frameworkWaitClientsExit", "frameworkCleanup"],
                    ),
                    State.State(
                        "frameworkGame",
                        self.enterFrameworkGame,
                        self.exitFrameworkGame,
                        ["frameworkWaitClientsExit", "frameworkCleanup"],
                    ),
                    State.State(
                        "frameworkWaitClientsExit",
                        self.enterFrameworkWaitClientsExit,
                        self.exitFrameworkWaitClientsExit,
                        ["frameworkCleanup"],
                    ),
                    State.State(
                        "frameworkCleanup", self.enterFrameworkCleanup, self.exitFrameworkCleanup, ["frameworkOff"]
                    ),
                ],
                "frameworkOff",
                "frameworkOff",
            )
            self.frameworkFSM.enterInitialState()
            self.avIdList = []
            self.stateDict = {}
            self.scoreDict = {}
            self.difficultyOverride = None
            self.trolleyZoneOverride = None
            self.skippable = True
            self.skipAvIds = []

    def addChildGameFSM(self, gameFSM):
        self.frameworkFSM.getStateNamed("frameworkGame").addChild(gameFSM)

    def removeChildGameFSM(self, gameFSM):
        self.frameworkFSM.getStateNamed("frameworkGame").removeChild(gameFSM)

    def setExpectedAvatars(self, avIds):
        self.avIdList = avIds
        self.numPlayers = len(self.avIdList)
        self.notify.debug("BASE: setExpectedAvatars: expecting avatars: " + str(self.avIdList))

    def setNewbieIds(self, newbieIds):
        self.newbieIdList = newbieIds
        if len(self.newbieIdList) > 0:
            self.notify.debug("BASE: setNewbieIds: %s" % self.newbieIdList)

    def setTrolleyZone(self, trolleyZone):
        self.trolleyZone = trolleyZone

    def setDifficultyOverrides(self, difficultyOverride, trolleyZoneOverride):
        self.difficultyOverride = difficultyOverride
        if self.difficultyOverride is not None:
            self.difficultyOverride = MinigameGlobals.QuantizeDifficultyOverride(difficultyOverride)
        self.trolleyZoneOverride = trolleyZoneOverride
        return

    def _playing(self):
        if not hasattr(self, "gameFSM"):
            return False
        if self.gameFSM.getCurrentState() == None:
            return False
        return self.gameFSM.getCurrentState().getName() == "play"

    def _inState(self, states):
        if not hasattr(self, "gameFSM"):
            return False
        if self.gameFSM.getCurrentState() == None:
            return False
        return self.gameFSM.getCurrentState().getName() in makeList(states)

    def generate(self):
        DistributedObjectAI.DistributedObjectAI.generate(self)
        self.frameworkFSM.request("frameworkWaitClientsJoin")

    def delete(self):
        self.notify.debug("BASE: delete: deleting AI minigame object")
        del self.frameworkFSM
        self.ignoreAll()
        DistributedObjectAI.DistributedObjectAI.delete(self)

    def isSinglePlayer(self):
        if self.numPlayers == 1:
            return 1
        else:
            return 0

    def getParticipants(self):
        return self.avIdList

    def getTrolleyZone(self):
        return self.trolleyZone

    def getDifficultyOverrides(self):
        response = [self.difficultyOverride, self.trolleyZoneOverride]
        if response[0] is None:
            response[0] = MinigameGlobals.NoDifficultyOverride
        else:
            response[0] *= MinigameGlobals.DifficultyOverrideMult
            response[0] = int(response[0])
        if response[1] is None:
            response[1] = MinigameGlobals.NoTrolleyZoneOverride
        return response

    def b_setGameReady(self):
        self.setGameReady()
        self.d_setGameReady()

    def d_setGameReady(self):
        self.notify.debug("BASE: Sending setGameReady")
        self.sendUpdate("setGameReady", [])

    def setGameReady(self):
        self.notify.debug("BASE: setGameReady: game ready with avatars: %s" % self.avIdList)
        self.normalExit = 1

    def b_setGameStart(self, timestamp):
        self.d_setGameStart(timestamp)
        self.setGameStart(timestamp)

    def d_setGameStart(self, timestamp):
        self.notify.debug("BASE: Sending setGameStart")
        self.sendUpdate("setGameStart", [timestamp])

    def setGameStart(self, timestamp):
        self.notify.debug("BASE: setGameStart")

    def b_setGameExit(self):
        self.d_setGameExit()
        self.setGameExit()

    def d_setGameExit(self):
        self.notify.debug("BASE: Sending setGameExit")
        self.sendUpdate("setGameExit", [])

    def setGameExit(self):
        self.notify.debug("BASE: setGameExit")

    def setGameAbort(self):
        self.notify.debug("BASE: setGameAbort")
        self.normalExit = 0
        self.sendUpdate("setGameAbort", [])
        self.frameworkFSM.request("frameworkCleanup")

    def handleExitedAvatar(self, avId):
        self.notify.warning("BASE: handleExitedAvatar: avatar id exited: " + str(avId))
        self.stateDict[avId] = EXITED
        self.setGameAbort()

    def gameOver(self):
        self.frameworkFSM.request("frameworkWaitClientsExit")

    def enterFrameworkOff(self):
        self.notify.debug("BASE: enterFrameworkOff")

    def exitFrameworkOff(self):
        pass

    def enterFrameworkWaitClientsJoin(self):
        self.notify.debug("BASE: enterFrameworkWaitClientsJoin")
        for avId in self.avIdList:
            self.stateDict[avId] = EXPECTED
            self.scoreDict[avId] = DEFAULT_POINTS
            self.acceptOnce(self.air.getAvatarExitEvent(avId), self.handleExitedAvatar, extraArgs=[avId])

        def allAvatarsJoined(self=self):
            self.notify.debug("BASE: all avatars joined")
            self.b_setGameReady()
            self.frameworkFSM.request("frameworkWaitClientsReady")

        def handleTimeout(avIds, self=self):
            self.notify.debug("BASE: timed out waiting for clients %s to join" % avIds)
            self.setGameAbort()

        self.__barrier = ToonBarrier(
            "waitClientsJoin",
            self.uniqueName("waitClientsJoin"),
            self.avIdList,
            JOIN_TIMEOUT,
            allAvatarsJoined,
            handleTimeout,
        )

    def setAvatarJoined(self):
        if self.frameworkFSM.getCurrentState().getName() != "frameworkWaitClientsJoin":
            self.notify.debug("BASE: Ignoring setAvatarJoined message")
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug("BASE: setAvatarJoined: avatar id joined: " + str(avId))
        self.air.writeServerEvent("minigame_joined", avId, "%s|%s" % (self.minigameId, self.trolleyZone))
        self.stateDict[avId] = JOINED
        self.notify.debug("BASE: setAvatarJoined: new states: " + str(self.stateDict))
        self.__barrier.clear(avId)

    def exitFrameworkWaitClientsJoin(self):
        self.__barrier.cleanup()
        del self.__barrier

    def enterFrameworkWaitClientsReady(self):
        self.notify.debug("BASE: enterFrameworkWaitClientsReady")

        def allAvatarsReady(self=self):
            self.notify.debug("BASE: all avatars ready")
            self.frameworkFSM.request("frameworkGame")

        def handleTimeout(avIds, self=self):
            self.notify.debug("BASE: timed out waiting for clients %s to report 'ready'" % avIds)
            self.setGameAbort()

        self.__barrier = ToonBarrier(
            "waitClientsReady",
            self.uniqueName("waitClientsReady"),
            self.avIdList,
            READY_TIMEOUT,
            allAvatarsReady,
            handleTimeout,
        )
        for avId in self.stateDict.keys():
            if self.stateDict[avId] == READY:
                self.__barrier.clear(avId)

        self.notify.debug("  safezone: %s" % self.getSafezoneId())
        self.notify.debug("difficulty: %s" % self.getDifficulty())

    def setAvatarReady(self):
        if self.frameworkFSM.getCurrentState().getName() not in [
            "frameworkWaitClientsReady",
            "frameworkWaitClientsJoin",
        ]:
            self.notify.debug("BASE: Ignoring setAvatarReady message")
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug("BASE: setAvatarReady: avatar id ready: " + str(avId))
        self.stateDict[avId] = READY
        self.notify.debug("BASE: setAvatarReady: new avId states: " + str(self.stateDict))
        if self.frameworkFSM.getCurrentState().getName() == "frameworkWaitClientsReady":
            self.__barrier.clear(avId)
        self.skippable = False

    def exitFrameworkWaitClientsReady(self):
        self.__barrier.cleanup()
        del self.__barrier

    def enterFrameworkGame(self):
        self.notify.debug("BASE: enterFrameworkGame")
        self.gameStartTime = globalClock.getRealTime()
        self.b_setGameStart(globalClockDelta.localToNetworkTime(self.gameStartTime))

    def exitFrameworkGame(self):
        pass

    def enterFrameworkWaitClientsExit(self):
        self.notify.debug("BASE: enterFrameworkWaitClientsExit")
        self.b_setGameExit()

        def allAvatarsExited(self=self):
            self.notify.debug("BASE: all avatars exited")
            self.frameworkFSM.request("frameworkCleanup")

        def handleTimeout(avIds, self=self):
            self.notify.debug("BASE: timed out waiting for clients %s to exit" % avIds)
            self.frameworkFSM.request("frameworkCleanup")

        self.__barrier = ToonBarrier(
            "waitClientsExit",
            self.uniqueName("waitClientsExit"),
            self.avIdList,
            EXIT_TIMEOUT,
            allAvatarsExited,
            handleTimeout,
        )
        for avId in self.stateDict.keys():
            if self.stateDict[avId] == EXITED:
                self.__barrier.clear(avId)

    def setAvatarExited(self):
        if self.frameworkFSM.getCurrentState().getName() != "frameworkWaitClientsExit":
            self.notify.debug("BASE: Ignoring setAvatarExit message")
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug("BASE: setAvatarExited: avatar id exited: " + str(avId))
        self.stateDict[avId] = EXITED
        self.notify.debug("BASE: setAvatarExited: new avId states: " + str(self.stateDict))
        self.__barrier.clear(avId)
        self.checkForSkip()

    def exitFrameworkWaitClientsExit(self):
        self.__barrier.cleanup()
        del self.__barrier

    def hasScoreMult(self):
        return 1

    def enterFrameworkCleanup(self):
        self.notify.debug("BASE: enterFrameworkCleanup: normalExit=%s" % self.normalExit)
        scoreMult = MinigameGlobals.getScoreMult(self.getSafezoneId())
        if not self.hasScoreMult():
            scoreMult = 1.0
        self.notify.debug("score multiplier: %s" % scoreMult)
        for avId in self.avIdList:
            self.scoreDict[avId] *= scoreMult

        scoreList = []
        for avId in self.avIdList:
            if self.normalExit:
                score = int(self.scoreDict[avId] + 0.5)
            else:
                score = 0
            if simbase.air.newsManager.isHolidayRunning(
                ToontownGlobals.JELLYBEAN_TROLLEY_HOLIDAY
            ) or simbase.air.newsManager.isHolidayRunning(ToontownGlobals.JELLYBEAN_TROLLEY_HOLIDAY_MONTH):
                score *= MinigameGlobals.JellybeanTrolleyHolidayScoreMultiplier
            logEvent = False
            if score > 255:
                score = 255
                logEvent = True
            elif score < 0:
                score = 0
                logEvent = True
            if logEvent:
                self.air.writeServerEvent(
                    "suspicious",
                    avId,
                    "got %s jellybeans playing minigame %s in zone %s" % (score, self.minigameId, self.getSafezoneId()),
                )
            scoreList.append(score)

        self.requestDelete()
        self.handleRegularPurchaseManager(scoreList)
        self.frameworkFSM.request("frameworkOff")

    def handleRegularPurchaseManager(self, scoreList):
        for id in self.newbieIdList:
            pm = NewbiePurchaseManagerAI.NewbiePurchaseManagerAI(
                self.air, id, self.avIdList, scoreList, self.minigameId, self.trolleyZone
            )
            MinigameCreatorAI.acquireMinigameZone(self.zoneId)
            pm.generateWithRequired(self.zoneId)

        if len(self.avIdList) > len(self.newbieIdList):
            pm = PurchaseManagerAI.PurchaseManagerAI(
                self.air, self.avIdList, scoreList, self.minigameId, self.trolleyZone, self.newbieIdList
            )
            pm.generateWithRequired(self.zoneId)

    def exitFrameworkCleanup(self):
        pass

    def requestExit(self):
        self.notify.debug("BASE: requestExit: client has requested the game to end")
        self.setGameAbort()

    def local2GameTime(self, timestamp):
        return timestamp - self.gameStartTime

    def game2LocalTime(self, timestamp):
        return timestamp + self.gameStartTime

    def getCurrentGameTime(self):
        return self.local2GameTime(globalClock.getFrameTime())

    def getDifficulty(self):
        if self.difficultyOverride is not None:
            return self.difficultyOverride
        if hasattr(self.air, "minigameDifficulty"):
            return float(self.air.minigameDifficulty)
        return MinigameGlobals.getDifficulty(self.getSafezoneId())

    def getSafezoneId(self):
        if self.trolleyZoneOverride is not None:
            return self.trolleyZoneOverride
        if hasattr(self.air, "minigameSafezoneId"):
            return MinigameGlobals.getSafezoneId(self.air.minigameSafezoneId)
        return MinigameGlobals.getSafezoneId(self.trolleyZone)

    def logPerfectGame(self, avId):
        self.air.writeServerEvent(
            "perfectMinigame", avId, "%s|%s|%s" % (self.minigameId, self.trolleyZone, self.avIdList)
        )

    def logAllPerfect(self):
        for avId in self.avIdList:
            self.logPerfectGame(avId)

    def requestSkip(self):
        avId = self.air.getAvatarIdFromSender()

        if (not self.skippable) or (avId not in self.avIdList) or (avId in self.skipAvIds):
            return

        self.skipAvIds.append(avId)
        self.checkForSkip()

    def checkForSkip(self):
        if len(self.skipAvIds) >= len(self.avIdList):
            self.skippable = False
            self.setGameAbort()
        else:
            self.sendUpdate("setSkipCount", [len(self.skipAvIds)])
class DistributedGolfHoleAI(
        DistributedPhysicsWorldAI.DistributedPhysicsWorldAI, FSM,
        GolfHoleBase.GolfHoleBase):
    defaultTransitions = {
        'Off': ['Cleanup', 'WaitTee'],
        'WaitTee': ['WaitSwing', 'Cleanup', 'WaitTee', 'WaitPlayback'],
        'WaitSwing': ['WaitPlayback', 'Cleanup', 'WaitSwing', 'WaitTee'],
        'WaitPlayback': ['WaitSwing', 'Cleanup', 'WaitTee', 'WaitPlayback'],
        'Cleanup': ['Off']
    }
    id = 0
    notify = directNotify.newCategory('DistributedGolfHoleAI')

    def __init__(self, zoneId, golfCourse, holeId):
        FSM.__init__(self, 'Golf_%s_FSM' % self.id)
        DistributedPhysicsWorldAI.DistributedPhysicsWorldAI.__init__(
            self, simbase.air)
        GolfHoleBase.GolfHoleBase.__init__(self)
        self.zoneId = zoneId
        self.golfCourse = golfCourse
        self.holeId = holeId
        self.avIdList = golfCourse.avIdList[:]
        self.watched = [0, 0, 0, 0]
        self.barrierPlayback = None
        self.trustedAvId = None
        self.activeGolferIndex = None
        self.activeGolferId = None
        self.holeInfo = GolfGlobals.HoleInfo[self.holeId]
        self.teeChosen = {}
        for avId in self.avIdList:
            self.teeChosen[avId] = -1

        self.ballPos = {}
        for avId in self.avIdList:
            self.ballPos[avId] = Vec3(0, 0, 0)

        self.playStarted = False
        return

    def curGolfBall(self):
        return self.ball

    def generate(self):
        DistributedPhysicsWorldAI.DistributedPhysicsWorldAI.generate(self)
        self.ball = self.createBall()
        self.createRays()
        if len(self.teePositions) > 1:
            startPos = self.teePositions[1]
        else:
            startPos = self.teePositions[0]
        startPos += Vec3(0, 0, GolfGlobals.GOLF_BALL_RADIUS)
        self.ball.setPosition(startPos)

    def delete(self):
        self.notify.debug('__delete__')
        DistributedPhysicsWorldAI.DistributedPhysicsWorldAI.delete(self)
        self.notify.debug('calling self.terrainModel.removeNode')
        self.terrainModel.removeNode()
        self.notify.debug('self.barrierPlayback is %s' % self.barrierPlayback)
        if self.barrierPlayback:
            self.notify.debug('calling self.barrierPlayback.cleanup')
            self.barrierPlayback.cleanup()
            self.notify.debug('calling self.barrierPlayback = None')
            self.barrierPlayback = None
        self.activeGolferId = None
        return

    def setZoneId(self, zoneId):
        self.zoneId = zoneId

    def setAvatarReadyHole(self):
        self.notify.debugStateCall(self)
        avId = self.air.getAvatarIdFromSender()
        self.golfCourse.avatarReadyHole(avId)

    def startPlay(self):
        self.notify.debug('startPlay')
        self.playStarted = True
        self.numGolfers = len(self.golfCourse.getGolferIds())
        self.selectNextGolfer()

    def selectNextGolfer(self):
        self.notify.debug(
            'selectNextGolfer, old golferIndex=%s old golferId=%s' %
            (self.activeGolferIndex, self.activeGolferId))
        if self.golfCourse.isCurHoleDone():
            return
        if self.activeGolferIndex == None:
            self.activeGolferIndex = 0
            self.activeGolferId = self.golfCourse.getGolferIds()[
                self.activeGolferIndex]
        else:
            self.activeGolferIndex += 1
            if self.activeGolferIndex >= len(self.golfCourse.getGolferIds()):
                self.activeGolferIndex = 0
            self.activeGolferId = self.golfCourse.getGolferIds()[
                self.activeGolferIndex]
        safety = 0
        while safety < 50 and not self.golfCourse.checkGolferPlaying(
                self.golfCourse.getGolferIds()[self.activeGolferIndex]):
            self.activeGolferIndex += 1
            self.notify.debug('Index %s' % self.activeGolferIndex)
            if self.activeGolferIndex >= len(self.golfCourse.getGolferIds()):
                self.activeGolferIndex = 0
            self.activeGolferId = self.golfCourse.getGolferIds()[
                self.activeGolferIndex]
            safety += 1

        if safety != 50:
            golferId = self.golfCourse.getGolferIds()[self.activeGolferIndex]
            if self.teeChosen[golferId] == -1:
                self.sendUpdate('golferChooseTee', [golferId])
                self.request('WaitTee')
            else:
                self.sendUpdate('golfersTurn', [golferId])
                self.request('WaitSwing')
        else:
            self.notify.debug('safety')
        self.notify.debug(
            'selectNextGolfer, new golferIndex=%s new golferId=%s' %
            (self.activeGolferIndex, self.activeGolferId))
        return

    def clearWatched(self):
        self.watched = [1, 1, 1, 1]
        for index in xrange(len(self.golfCourse.getGolferIds())):
            self.watched[index] = 0

    def setWatched(self, avId):
        for index in xrange(len(self.golfCourse.getGolferIds())):
            if self.golfCourse.getGolferIds()[index] == avId:
                self.watched[index] = 1

    def checkWatched(self):
        if 0 not in self.watched:
            return True
        else:
            return False

    def turnDone(self):
        self.notify.debug('Turn Done')
        avId = self.air.getAvatarIdFromSender()
        if self.barrierPlayback:
            self.barrierPlayback.clear(avId)

    def ballInHole(self, golferId=None):
        self.notify.debug('ballInHole')
        if golferId:
            avId = golferId
        else:
            avId = self.air.getAvatarIdFromSender()
        self.golfCourse.setBallIn(avId)
        if self.golfCourse.isCurHoleDone():
            self.notify.debug('ballInHole doing nothing')
        else:
            self.notify.debug('ballInHole calling self.selectNextGolfer')
            self.selectNextGolfer()

    def getHoleId(self):
        return self.holeId

    def finishHole(self):
        self.notify.debug('finishHole')
        self.golfCourse.holeOver()

    def getGolferIds(self):
        return self.avIdList

    def loadLevel(self):
        GolfHoleBase.GolfHoleBase.loadLevel(self)
        optionalObjects = self.terrainModel.findAllMatches('**/optional*')
        requiredObjects = self.terrainModel.findAllMatches('**/required*')
        self.parseLocators(optionalObjects, 1)
        self.parseLocators(requiredObjects, 0)
        self.teeNodePath = self.terrainModel.find('**/tee0')
        if self.teeNodePath.isEmpty():
            teePos = Vec3(0, 0, 10)
        else:
            teePos = self.teeNodePath.getPos()
            teePos.setZ(teePos.getZ() + GolfGlobals.GOLF_BALL_RADIUS)
            self.notify.debug('teeNodePath heading = %s' %
                              self.teeNodePath.getH())
        self.teePositions = [teePos]
        teeIndex = 1
        teeNode = self.terrainModel.find('**/tee%d' % teeIndex)
        while not teeNode.isEmpty():
            teePos = teeNode.getPos()
            teePos.setZ(teePos.getZ() + GolfGlobals.GOLF_BALL_RADIUS)
            self.teePositions.append(teePos)
            self.notify.debug('teeNodeP heading = %s' % teeNode.getH())
            teeIndex += 1
            teeNode = self.terrainModel.find('**/tee%d' % teeIndex)

    def createLocatorDict(self):
        self.locDict = {}
        locatorNum = 1
        curNodePath = self.hardSurfaceNodePath.find('**/locator%d' %
                                                    locatorNum)
        while not curNodePath.isEmpty():
            self.locDict[locatorNum] = curNodePath
            locatorNum += 1
            curNodePath = self.hardSurfaceNodePath.find('**/locator%d' %
                                                        locatorNum)

    def loadBlockers(self):
        loadAll = simbase.config.GetBool('golf-all-blockers', 0)
        self.createLocatorDict()
        self.blockerNums = self.holeInfo['blockers']
        for locatorNum in self.locDict:
            if locatorNum in self.blockerNums or loadAll:
                locator = self.locDict[locatorNum]
                locatorParent = locator.getParent()
                locator.getChildren().wrtReparentTo(locatorParent)
            else:
                self.locDict[locatorNum].removeNode()

        self.hardSurfaceNodePath.flattenStrong()

    def createBall(self):
        golfBallGeom = self.createSphere(self.world, self.space,
                                         GolfGlobals.GOLF_BALL_DENSITY,
                                         GolfGlobals.GOLF_BALL_RADIUS, 1)[1]
        return golfBallGeom

    def preStep(self):
        GolfHoleBase.GolfHoleBase.preStep(self)

    def postStep(self):
        GolfHoleBase.GolfHoleBase.postStep(self)

    def postSwing(self, cycleTime, power, x, y, z, dirX, dirY):
        avId = self.air.getAvatarIdFromSender()
        self.storeAction = [avId, cycleTime, power, x, y, z, dirX, dirY]
        if self.commonHoldData:
            self.doAction()

    def postSwingState(self, cycleTime, power, x, y, z, dirX, dirY, curAimTime,
                       commonObjectData):
        self.notify.debug('postSwingState')
        if not self.golfCourse.getStillPlayingAvIds():
            return
        avId = self.air.getAvatarIdFromSender()
        self.storeAction = [avId, cycleTime, power, x, y, z, dirX, dirY]
        self.commonHoldData = commonObjectData
        self.trustedAvId = self.chooseAvatarToSimulate()
        self.sendUpdateToAvatarId(
            self.trustedAvId, 'assignRecordSwing',
            [avId, cycleTime, power, x, y, z, dirX, dirY, commonObjectData])
        self.golfCourse.addAimTime(avId, curAimTime)

    def chooseAvatarToSimulate(self):
        stillPlaying = self.golfCourse.getStillPlayingAvIds()

        return stillPlaying[0] if stillPlaying else 0

    def ballMovie2AI(self, cycleTime, avId, movie, spinMovie, ballInFrame,
                     ballTouchedHoleFrame, ballFirstTouchedHoleFrame,
                     commonObjectData):
        sentFromId = self.air.getAvatarIdFromSender()
        if sentFromId == self.trustedAvId:
            lastFrameNum = len(movie) - 2
            if lastFrameNum < 0:
                lastFrameNum = 0
            lastFrame = movie[lastFrameNum]
            lastPos = Vec3(lastFrame[1], lastFrame[2], lastFrame[3])
            self.ballPos[avId] = lastPos
            self.golfCourse.incrementScore(avId)
            for id in self.golfCourse.getStillPlayingAvIds():
                if not id == sentFromId:
                    self.sendUpdateToAvatarId(id, 'ballMovie2Client', [
                        cycleTime, avId, movie, spinMovie, ballInFrame,
                        ballTouchedHoleFrame, ballFirstTouchedHoleFrame,
                        commonObjectData
                    ])

            if self.state == 'WaitPlayback' or self.state == 'WaitTee':
                self.notify.warning(
                    'ballMovie2AI requesting from %s to WaitPlayback' %
                    self.state)
            self.request('WaitPlayback')
        elif self.trustedAvId == None:
            return
        else:
            self.doAction()
        self.trustedAvId = None
        return

    def performReadyAction(self):
        avId = self.storeAction[0]
        if self.state == 'WaitPlayback':
            self.notify.debugStateCall(self)
            self.notify.debug(
                'ignoring the postSwing for avId=%d since we are in WaitPlayback'
                % avId)
            return
        if avId == self.activeGolferId:
            self.golfCourse.incrementScore(self.activeGolferId)
        else:
            self.notify.warning(
                'activGolferId %d not equal to sender avId %d' %
                (self.activeGolferId, avId))
        if avId not in self.golfCourse.drivingToons:
            position = self.ballPos[avId]
        else:
            position = Vec3(self.storeAction[3], self.storeAction[4],
                            self.storeAction[5])
        self.useCommonObjectData(self.commonHoldData)
        newPos = self.trackRecordBodyFlight(self.ball, self.storeAction[1],
                                            self.storeAction[2], position,
                                            self.storeAction[6],
                                            self.storeAction[7])
        if self.state == 'WaitPlayback' or self.state == 'WaitTee':
            self.notify.warning(
                'performReadyAction requesting from %s to WaitPlayback' %
                self.state)
        self.request('WaitPlayback')
        self.sendUpdate('ballMovie2Client', [
            self.storeAction[1], avId, self.recording, self.aVRecording,
            self.ballInHoleFrame, self.ballTouchedHoleFrame,
            self.ballFirstTouchedHoleFrame, self.commonHoldData
        ])
        self.ballPos[avId] = newPos
        self.trustedAvId = None
        return

    def postResult(self, cycleTime, avId, recording, aVRecording,
                   ballInHoleFrame, ballTouchedHoleFrame,
                   ballFirstTouchedHoleFrame):
        pass

    def enterWaitSwing(self):
        pass

    def exitWaitSwing(self):
        pass

    def enterWaitTee(self):
        pass

    def exitWaitTee(self):
        pass

    def enterWaitPlayback(self):
        self.notify.debug('enterWaitPlayback')
        stillPlayingList = self.golfCourse.getStillPlayingAvIds()
        self.barrierPlayback = ToonBarrier(
            'waitClientsPlayback', self.uniqueName('waitClientsPlayback'),
            stillPlayingList, 120, self.handleWaitPlaybackDone,
            self.handlePlaybackTimeout)

    def hasCurGolferReachedMaxSwing(self):
        strokes = self.golfCourse.getCurHoleScore(self.activeGolferId)
        maxSwing = self.holeInfo['maxSwing']
        retval = strokes >= maxSwing
        if retval:
            av = simbase.air.doId2do.get(self.activeGolferId)
            if av:
                if av.getUnlimitedSwing():
                    retval = False
        return retval

    def handleWaitPlaybackDone(self):
        if self.isCurBallInHole(
                self.activeGolferId) or self.hasCurGolferReachedMaxSwing():
            if self.activeGolferId:
                self.ballInHole(self.activeGolferId)
        else:
            self.selectNextGolfer()

    def isCurBallInHole(self, golferId):
        retval = False
        for holePos in self.holePositions:
            displacement = self.ballPos[golferId] - holePos
            length = displacement.length()
            self.notify.debug('hole %s length=%s' % (holePos, length))
            if length <= GolfGlobals.DistanceToBeInHole:
                retval = True
                break

        return retval

    def exitWaitPlayback(self):
        self.notify.debug('exitWaitPlayback')
        if hasattr(self, 'barrierPlayback') and self.barrierPlayback:
            self.barrierPlayback.cleanup()
            self.barrierPlayback = None
        return

    def enterCleanup(self):
        pass

    def exitCleanup(self):
        pass

    def handlePlaybackTimeout(self, task=None):
        self.notify.debug('handlePlaybackTimeout')
        self.handleWaitPlaybackDone()

    def getGolfCourseDoId(self):
        return self.golfCourse.doId

    def avatarDropped(self, avId):
        self.notify.warning('avId %d dropped, self.state=%s' %
                            (avId, self.state))
        if self.barrierPlayback:
            self.barrierPlayback.clear(avId)
        else:
            if avId == self.trustedAvId:
                self.doAction()
            if avId == self.activeGolferId and not self.golfCourse.haveAllGolfersExited(
            ):
                self.selectNextGolfer()

    def setAvatarTee(self, chosenTee):
        golferId = self.air.getAvatarIdFromSender()
        self.teeChosen[golferId] = chosenTee
        self.ballPos[golferId] = self.teePositions[chosenTee]
        self.sendUpdate('setAvatarFinalTee', [golferId, chosenTee])
        self.sendUpdate('golfersTurn', [golferId])
        self.request('WaitSwing')

    def setBox(self, pos0, pos1, pos2, quat0, quat1, quat2, quat3, anV0, anV1,
               anV2, lnV0, lnV1, lnV2):
        self.sendUpdate('sendBox', [
            pos0, pos1, pos2, quat0, quat1, quat2, quat3, anV0, anV1, anV2,
            lnV0, lnV1, lnV2
        ])

    def parseLocators(self, objectCollection, optional=0):
        if optional and objectCollection.getNumPaths():
            if 'optionalMovers' in self.holeInfo:
                for optionalMoverId in self.holeInfo['optionalMovers']:
                    searchStr = 'optional_mover_' + str(optionalMoverId)
                    for objIndex in xrange(objectCollection.getNumPaths()):
                        object = objectCollection.getPath(objIndex)
                        if searchStr in object.getName():
                            self.fillLocator(objectCollection, objIndex)
                            break

        else:
            for index in xrange(objectCollection.getNumPaths()):
                self.fillLocator(objectCollection, index)

    def fillLocator(self, objectCollection, index):
        path = objectCollection[index]
        pathName = path.getName()
        pathArray = pathName.split('_')
        sizeX = None
        sizeY = None
        move = None
        type = None
        for subString in pathArray:
            if subString[:1] == 'X':
                dataString = subString[1:]
                dataString = dataString.replace('p', '.')
                sizeX = float(dataString)
            elif subString[:1] == 'Y':
                dataString = subString[1:]
                dataString = dataString.replace('p', '.')
                sizeY = float(dataString)
            elif subString[:1] == 'd':
                dataString = subString[1:]
                dataString = dataString.replace('p', '.')
                move = float(dataString)
            elif subString == 'mover':
                type = 4
            elif subString == 'windmillLocator':
                type = 3

        if type == 4 and move and sizeX and sizeY:
            self.createCommonObject(4, path.getPos(), path.getHpr(), sizeX,
                                    sizeY, move)
        elif type == 3:
            self.createCommonObject(3, path.getPos(), path.getHpr())
        return
Exemplo n.º 19
0
class DistributedMinigameAI(DistributedObjectAI.DistributedObjectAI):
    notify = directNotify.newCategory('DistributedMinigameAI')

    def __init__(self, air, minigameId):
        try:
            self.DistributedMinigameAI_initialized
        except:
            self.DistributedMinigameAI_initialized = 1
            DistributedObjectAI.DistributedObjectAI.__init__(self, air)
            self.minigameId = minigameId
            self.frameworkFSM = ClassicFSM.ClassicFSM(
                'DistributedMinigameAI', [
                    State.State('frameworkOff', self.enterFrameworkOff,
                                self.exitFrameworkOff,
                                ['frameworkWaitClientsJoin']),
                    State.State(
                        'frameworkWaitClientsJoin',
                        self.enterFrameworkWaitClientsJoin,
                        self.exitFrameworkWaitClientsJoin, [
                            'frameworkWaitClientsReady',
                            'frameworkWaitClientsExit', 'frameworkCleanup'
                        ]),
                    State.State(
                        'frameworkWaitClientsReady',
                        self.enterFrameworkWaitClientsReady,
                        self.exitFrameworkWaitClientsReady, [
                            'frameworkGame', 'frameworkWaitClientsExit',
                            'frameworkCleanup'
                        ]),
                    State.State(
                        'frameworkGame', self.enterFrameworkGame,
                        self.exitFrameworkGame,
                        ['frameworkWaitClientsExit', 'frameworkCleanup']),
                    State.State('frameworkWaitClientsExit',
                                self.enterFrameworkWaitClientsExit,
                                self.exitFrameworkWaitClientsExit,
                                ['frameworkCleanup']),
                    State.State('frameworkCleanup', self.enterFrameworkCleanup,
                                self.exitFrameworkCleanup, ['frameworkOff'])
                ], 'frameworkOff', 'frameworkOff')
            self.frameworkFSM.enterInitialState()
            self.avIdList = []
            self.stateDict = {}
            self.scoreDict = {}
            self.difficultyOverride = None
            self.trolleyZoneOverride = None
            self.skippable = True
            self.skipAvIds = []

    def addChildGameFSM(self, gameFSM):
        self.frameworkFSM.getStateNamed('frameworkGame').addChild(gameFSM)

    def removeChildGameFSM(self, gameFSM):
        self.frameworkFSM.getStateNamed('frameworkGame').removeChild(gameFSM)

    def setExpectedAvatars(self, avIds):
        self.avIdList = avIds
        self.numPlayers = len(self.avIdList)
        self.notify.debug('BASE: setExpectedAvatars: expecting avatars: ' +
                          str(self.avIdList))

    def setNewbieIds(self, newbieIds):
        self.newbieIdList = newbieIds
        if len(self.newbieIdList) > 0:
            self.notify.debug('BASE: setNewbieIds: %s' % self.newbieIdList)

    def setTrolleyZone(self, trolleyZone):
        self.trolleyZone = trolleyZone

    def setDifficultyOverrides(self, difficultyOverride, trolleyZoneOverride):
        self.difficultyOverride = difficultyOverride
        if self.difficultyOverride is not None:
            self.difficultyOverride = MinigameGlobals.QuantizeDifficultyOverride(
                difficultyOverride)
        self.trolleyZoneOverride = trolleyZoneOverride
        return

    def _playing(self):
        if not hasattr(self, 'gameFSM'):
            return False
        if self.gameFSM.getCurrentState() == None:
            return False
        return self.gameFSM.getCurrentState().getName() == 'play'

    def _inState(self, states):
        if not hasattr(self, 'gameFSM'):
            return False
        if self.gameFSM.getCurrentState() == None:
            return False
        return self.gameFSM.getCurrentState().getName() in makeList(states)

    def generate(self):
        DistributedObjectAI.DistributedObjectAI.generate(self)
        self.frameworkFSM.request('frameworkWaitClientsJoin')

    def delete(self):
        self.notify.debug('BASE: delete: deleting AI minigame object')
        del self.frameworkFSM
        self.ignoreAll()
        DistributedObjectAI.DistributedObjectAI.delete(self)

    def isSinglePlayer(self):
        if self.numPlayers == 1:
            return 1
        else:
            return 0

    def getParticipants(self):
        return self.avIdList

    def getTrolleyZone(self):
        return self.trolleyZone

    def getDifficultyOverrides(self):
        response = [self.difficultyOverride, self.trolleyZoneOverride]
        if response[0] is None:
            response[0] = MinigameGlobals.NoDifficultyOverride
        else:
            response[0] *= MinigameGlobals.DifficultyOverrideMult
            response[0] = int(response[0])
        if response[1] is None:
            response[1] = MinigameGlobals.NoTrolleyZoneOverride
        return response

    def b_setGameReady(self):
        self.setGameReady()
        self.d_setGameReady()

    def d_setGameReady(self):
        self.notify.debug('BASE: Sending setGameReady')
        self.sendUpdate('setGameReady', [])

    def setGameReady(self):
        self.notify.debug('BASE: setGameReady: game ready with avatars: %s' %
                          self.avIdList)
        self.normalExit = 1

    def b_setGameStart(self, timestamp):
        self.d_setGameStart(timestamp)
        self.setGameStart(timestamp)

    def d_setGameStart(self, timestamp):
        self.notify.debug('BASE: Sending setGameStart')
        self.sendUpdate('setGameStart', [timestamp])

    def setGameStart(self, timestamp):
        self.notify.debug('BASE: setGameStart')

    def b_setGameExit(self):
        self.d_setGameExit()
        self.setGameExit()

    def d_setGameExit(self):
        self.notify.debug('BASE: Sending setGameExit')
        self.sendUpdate('setGameExit', [])

    def setGameExit(self):
        self.notify.debug('BASE: setGameExit')

    def setGameAbort(self):
        self.notify.debug('BASE: setGameAbort')
        self.normalExit = 0
        self.sendUpdate('setGameAbort', [])
        self.frameworkFSM.request('frameworkCleanup')

    def handleExitedAvatar(self, avId):
        self.notify.warning('BASE: handleExitedAvatar: avatar id exited: ' +
                            str(avId))
        self.stateDict[avId] = EXITED
        self.setGameAbort()

    def gameOver(self):
        self.frameworkFSM.request('frameworkWaitClientsExit')

    def enterFrameworkOff(self):
        self.notify.debug('BASE: enterFrameworkOff')

    def exitFrameworkOff(self):
        pass

    def enterFrameworkWaitClientsJoin(self):
        self.notify.debug('BASE: enterFrameworkWaitClientsJoin')
        for avId in self.avIdList:
            self.stateDict[avId] = EXPECTED
            self.scoreDict[avId] = DEFAULT_POINTS
            self.acceptOnce(self.air.getAvatarExitEvent(avId),
                            self.handleExitedAvatar,
                            extraArgs=[avId])

        def allAvatarsJoined(self=self):
            self.notify.debug('BASE: all avatars joined')
            self.b_setGameReady()
            self.frameworkFSM.request('frameworkWaitClientsReady')

        def handleTimeout(avIds, self=self):
            self.notify.debug(
                'BASE: timed out waiting for clients %s to join' % avIds)
            self.setGameAbort()

        self.__barrier = ToonBarrier('waitClientsJoin',
                                     self.uniqueName('waitClientsJoin'),
                                     self.avIdList, JOIN_TIMEOUT,
                                     allAvatarsJoined, handleTimeout)

    def setAvatarJoined(self):
        if self.frameworkFSM.getCurrentState().getName(
        ) != 'frameworkWaitClientsJoin':
            self.notify.debug('BASE: Ignoring setAvatarJoined message')
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('BASE: setAvatarJoined: avatar id joined: ' +
                          str(avId))
        self.air.writeServerEvent(
            'minigame_joined', avId,
            '%s|%s' % (self.minigameId, self.trolleyZone))
        self.stateDict[avId] = JOINED
        self.notify.debug('BASE: setAvatarJoined: new states: ' +
                          str(self.stateDict))
        self.__barrier.clear(avId)

    def exitFrameworkWaitClientsJoin(self):
        self.__barrier.cleanup()
        del self.__barrier

    def enterFrameworkWaitClientsReady(self):
        self.notify.debug('BASE: enterFrameworkWaitClientsReady')

        def allAvatarsReady(self=self):
            self.notify.debug('BASE: all avatars ready')
            self.frameworkFSM.request('frameworkGame')

        def handleTimeout(avIds, self=self):
            self.notify.debug(
                "BASE: timed out waiting for clients %s to report 'ready'" %
                avIds)
            self.setGameAbort()

        self.__barrier = ToonBarrier('waitClientsReady',
                                     self.uniqueName('waitClientsReady'),
                                     self.avIdList, READY_TIMEOUT,
                                     allAvatarsReady, handleTimeout)
        for avId in self.stateDict.keys():
            if self.stateDict[avId] == READY:
                self.__barrier.clear(avId)

        self.notify.debug('  safezone: %s' % self.getSafezoneId())
        self.notify.debug('difficulty: %s' % self.getDifficulty())

    def setAvatarReady(self):
        if self.frameworkFSM.getCurrentState().getName() not in [
                'frameworkWaitClientsReady', 'frameworkWaitClientsJoin'
        ]:
            self.notify.debug('BASE: Ignoring setAvatarReady message')
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('BASE: setAvatarReady: avatar id ready: ' +
                          str(avId))
        self.stateDict[avId] = READY
        self.notify.debug('BASE: setAvatarReady: new avId states: ' +
                          str(self.stateDict))
        if self.frameworkFSM.getCurrentState().getName(
        ) == 'frameworkWaitClientsReady':
            self.__barrier.clear(avId)
        self.skippable = False

    def exitFrameworkWaitClientsReady(self):
        self.__barrier.cleanup()
        del self.__barrier

    def enterFrameworkGame(self):
        self.notify.debug('BASE: enterFrameworkGame')
        self.gameStartTime = globalClock.getRealTime()
        self.b_setGameStart(
            globalClockDelta.localToNetworkTime(self.gameStartTime))

    def exitFrameworkGame(self):
        pass

    def enterFrameworkWaitClientsExit(self):
        self.notify.debug('BASE: enterFrameworkWaitClientsExit')
        self.b_setGameExit()

        def allAvatarsExited(self=self):
            self.notify.debug('BASE: all avatars exited')
            self.frameworkFSM.request('frameworkCleanup')

        def handleTimeout(avIds, self=self):
            self.notify.debug(
                'BASE: timed out waiting for clients %s to exit' % avIds)
            self.frameworkFSM.request('frameworkCleanup')

        self.__barrier = ToonBarrier('waitClientsExit',
                                     self.uniqueName('waitClientsExit'),
                                     self.avIdList, EXIT_TIMEOUT,
                                     allAvatarsExited, handleTimeout)
        for avId in self.stateDict.keys():
            if self.stateDict[avId] == EXITED:
                self.__barrier.clear(avId)

    def setAvatarExited(self):
        if self.frameworkFSM.getCurrentState().getName(
        ) != 'frameworkWaitClientsExit':
            self.notify.debug('BASE: Ignoring setAvatarExit message')
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('BASE: setAvatarExited: avatar id exited: ' +
                          str(avId))
        self.stateDict[avId] = EXITED
        self.notify.debug('BASE: setAvatarExited: new avId states: ' +
                          str(self.stateDict))
        self.__barrier.clear(avId)
        self.checkForSkip()

    def exitFrameworkWaitClientsExit(self):
        self.__barrier.cleanup()
        del self.__barrier

    def hasScoreMult(self):
        return 1

    def enterFrameworkCleanup(self):
        self.notify.debug('BASE: enterFrameworkCleanup: normalExit=%s' %
                          self.normalExit)
        scoreMult = MinigameGlobals.getScoreMult(self.getSafezoneId())
        if not self.hasScoreMult():
            scoreMult = 1.0
        self.notify.debug('score multiplier: %s' % scoreMult)
        for avId in self.avIdList:
            self.scoreDict[avId] *= scoreMult

        scoreList = []
        for avId in self.avIdList:
            if self.normalExit:
                score = int(self.scoreDict[avId] + 0.5)
            else:
                score = 0
            if simbase.air.newsManager.isHolidayRunning(
                    ToontownGlobals.JELLYBEAN_TROLLEY_HOLIDAY
            ) or simbase.air.newsManager.isHolidayRunning(
                    ToontownGlobals.JELLYBEAN_TROLLEY_HOLIDAY_MONTH):
                score *= MinigameGlobals.JellybeanTrolleyHolidayScoreMultiplier
            logEvent = False
            if score > 255:
                score = 255
                logEvent = True
            elif score < 0:
                score = 0
                logEvent = True
            if logEvent:
                self.air.writeServerEvent(
                    'suspicious', avId,
                    'got %s jellybeans playing minigame %s in zone %s' %
                    (score, self.minigameId, self.getSafezoneId()))
            scoreList.append(score)

        self.requestDelete()
        self.handleRegularPurchaseManager(scoreList)
        self.frameworkFSM.request('frameworkOff')

    def handleRegularPurchaseManager(self, scoreList):
        for id in self.newbieIdList:
            pm = NewbiePurchaseManagerAI.NewbiePurchaseManagerAI(
                self.air, id, self.avIdList, scoreList, self.minigameId,
                self.trolleyZone)
            MinigameCreatorAI.acquireMinigameZone(self.zoneId)
            pm.generateWithRequired(self.zoneId)

        if len(self.avIdList) > len(self.newbieIdList):
            pm = PurchaseManagerAI.PurchaseManagerAI(self.air, self.avIdList,
                                                     scoreList,
                                                     self.minigameId,
                                                     self.trolleyZone,
                                                     self.newbieIdList)
            pm.generateWithRequired(self.zoneId)

    def exitFrameworkCleanup(self):
        pass

    def requestExit(self):
        self.notify.debug(
            'BASE: requestExit: client has requested the game to end')
        self.setGameAbort()

    def local2GameTime(self, timestamp):
        return timestamp - self.gameStartTime

    def game2LocalTime(self, timestamp):
        return timestamp + self.gameStartTime

    def getCurrentGameTime(self):
        return self.local2GameTime(globalClock.getFrameTime())

    def getDifficulty(self):
        if self.difficultyOverride is not None:
            return self.difficultyOverride
        if hasattr(self.air, 'minigameDifficulty'):
            return float(self.air.minigameDifficulty)
        return MinigameGlobals.getDifficulty(self.getSafezoneId())

    def getSafezoneId(self):
        if self.trolleyZoneOverride is not None:
            return self.trolleyZoneOverride
        if hasattr(self.air, 'minigameSafezoneId'):
            return MinigameGlobals.getSafezoneId(self.air.minigameSafezoneId)
        return MinigameGlobals.getSafezoneId(self.trolleyZone)

    def logPerfectGame(self, avId):
        self.air.writeServerEvent(
            'perfectMinigame', avId,
            '%s|%s|%s' % (self.minigameId, self.trolleyZone, self.avIdList))

    def logAllPerfect(self):
        for avId in self.avIdList:
            self.logPerfectGame(avId)

    def requestSkip(self):
        avId = self.air.getAvatarIdFromSender()

        if (not self.skippable) or (avId not in self.avIdList) or (
                avId in self.skipAvIds):
            return

        self.skipAvIds.append(avId)
        self.checkForSkip()

    def checkForSkip(self):
        if len(self.skipAvIds) >= len(self.avIdList):
            self.skippable = False
            self.setGameAbort()
        else:
            self.sendUpdate('setSkipCount', [len(self.skipAvIds)])
 def enterWaitPlayback(self):
     self.notify.debug('enterWaitPlayback')
     stillPlayingList = self.golfCourse.getStillPlayingAvIds()
     self.barrierPlayback = ToonBarrier('waitClientsPlayback', self.uniqueName('waitClientsPlayback'), stillPlayingList, 120, self.handleWaitPlaybackDone, self.handlePlaybackTimeout)
class DistributedGolfHoleAI(DistributedPhysicsWorldAI.DistributedPhysicsWorldAI, FSM, GolfHoleBase.GolfHoleBase):
    defaultTransitions = {'Off': ['Cleanup', 'WaitTee'],
     'WaitTee': ['WaitSwing',
                 'Cleanup',
                 'WaitTee',
                 'WaitPlayback'],
     'WaitSwing': ['WaitPlayback',
                   'Cleanup',
                   'WaitSwing',
                   'WaitTee'],
     'WaitPlayback': ['WaitSwing',
                      'Cleanup',
                      'WaitTee',
                      'WaitPlayback'],
     'Cleanup': ['Off']}
    id = 0
    notify = directNotify.newCategory('DistributedGolfHoleAI')

    def __init__(self, zoneId, golfCourse, holeId):
        FSM.__init__(self, 'Golf_%s_FSM' % self.id)
        DistributedPhysicsWorldAI.DistributedPhysicsWorldAI.__init__(self, simbase.air)
        GolfHoleBase.GolfHoleBase.__init__(self)
        self.zoneId = zoneId
        self.golfCourse = golfCourse
        self.holeId = holeId
        self.avIdList = golfCourse.avIdList[:]
        self.watched = [0,
         0,
         0,
         0]
        self.barrierPlayback = None
        self.trustedAvId = None
        self.activeGolferIndex = None
        self.activeGolferId = None
        self.holeInfo = GolfGlobals.HoleInfo[self.holeId]
        self.teeChosen = {}
        for avId in self.avIdList:
            self.teeChosen[avId] = -1

        self.ballPos = {}
        for avId in self.avIdList:
            self.ballPos[avId] = Vec3(0, 0, 0)

        self.playStarted = False
        return

    def curGolfBall(self):
        return self.ball

    def generate(self):
        DistributedPhysicsWorldAI.DistributedPhysicsWorldAI.generate(self)
        self.ball = self.createBall()
        self.createRays()
        if len(self.teePositions) > 1:
            startPos = self.teePositions[1]
        else:
            startPos = self.teePositions[0]
        startPos += Vec3(0, 0, GolfGlobals.GOLF_BALL_RADIUS)
        self.ball.setPosition(startPos)

    def delete(self):
        self.notify.debug('__delete__')
        DistributedPhysicsWorldAI.DistributedPhysicsWorldAI.delete(self)
        self.notify.debug('calling self.terrainModel.removeNode')
        self.terrainModel.removeNode()
        self.notify.debug('self.barrierPlayback is %s' % self.barrierPlayback)
        if self.barrierPlayback:
            self.notify.debug('calling self.barrierPlayback.cleanup')
            self.barrierPlayback.cleanup()
            self.notify.debug('calling self.barrierPlayback = None')
            self.barrierPlayback = None
        self.activeGolferId = None
        return

    def setZoneId(self, zoneId):
        self.zoneId = zoneId

    def setAvatarReadyHole(self):
        self.notify.debugStateCall(self)
        avId = self.air.getAvatarIdFromSender()
        self.golfCourse.avatarReadyHole(avId)

    def startPlay(self):
        self.notify.debug('startPlay')
        self.playStarted = True
        self.numGolfers = len(self.golfCourse.getGolferIds())
        self.selectNextGolfer()

    def selectNextGolfer(self):
        self.notify.debug('selectNextGolfer, old golferIndex=%s old golferId=%s' % (self.activeGolferIndex, self.activeGolferId))
        if self.golfCourse.isCurHoleDone():
            return
        if self.activeGolferIndex == None:
            self.activeGolferIndex = 0
            self.activeGolferId = self.golfCourse.getGolferIds()[self.activeGolferIndex]
        else:
            self.activeGolferIndex += 1
            if self.activeGolferIndex >= len(self.golfCourse.getGolferIds()):
                self.activeGolferIndex = 0
            self.activeGolferId = self.golfCourse.getGolferIds()[self.activeGolferIndex]
        safety = 0
        while safety < 50 and not self.golfCourse.checkGolferPlaying(self.golfCourse.getGolferIds()[self.activeGolferIndex]):
            self.activeGolferIndex += 1
            self.notify.debug('Index %s' % self.activeGolferIndex)
            if self.activeGolferIndex >= len(self.golfCourse.getGolferIds()):
                self.activeGolferIndex = 0
            self.activeGolferId = self.golfCourse.getGolferIds()[self.activeGolferIndex]
            safety += 1

        if safety != 50:
            golferId = self.golfCourse.getGolferIds()[self.activeGolferIndex]
            if self.teeChosen[golferId] == -1:
                self.sendUpdate('golferChooseTee', [golferId])
                self.request('WaitTee')
            else:
                self.sendUpdate('golfersTurn', [golferId])
                self.request('WaitSwing')
        else:
            self.notify.debug('safety')
        self.notify.debug('selectNextGolfer, new golferIndex=%s new golferId=%s' % (self.activeGolferIndex, self.activeGolferId))
        return

    def clearWatched(self):
        self.watched = [1,
         1,
         1,
         1]
        for index in xrange(len(self.golfCourse.getGolferIds())):
            self.watched[index] = 0

    def setWatched(self, avId):
        for index in xrange(len(self.golfCourse.getGolferIds())):
            if self.golfCourse.getGolferIds()[index] == avId:
                self.watched[index] = 1

    def checkWatched(self):
        if 0 not in self.watched:
            return True
        else:
            return False

    def turnDone(self):
        self.notify.debug('Turn Done')
        avId = self.air.getAvatarIdFromSender()
        if self.barrierPlayback:
            self.barrierPlayback.clear(avId)

    def ballInHole(self, golferId = None):
        self.notify.debug('ballInHole')
        if golferId:
            avId = golferId
        else:
            avId = self.air.getAvatarIdFromSender()
        self.golfCourse.setBallIn(avId)
        if self.golfCourse.isCurHoleDone():
            self.notify.debug('ballInHole doing nothing')
        else:
            self.notify.debug('ballInHole calling self.selectNextGolfer')
            self.selectNextGolfer()

    def getHoleId(self):
        return self.holeId

    def finishHole(self):
        self.notify.debug('finishHole')
        self.golfCourse.holeOver()

    def getGolferIds(self):
        return self.avIdList

    def loadLevel(self):
        GolfHoleBase.GolfHoleBase.loadLevel(self)
        optionalObjects = self.terrainModel.findAllMatches('**/optional*')
        requiredObjects = self.terrainModel.findAllMatches('**/required*')
        self.parseLocators(optionalObjects, 1)
        self.parseLocators(requiredObjects, 0)
        self.teeNodePath = self.terrainModel.find('**/tee0')
        if self.teeNodePath.isEmpty():
            teePos = Vec3(0, 0, 10)
        else:
            teePos = self.teeNodePath.getPos()
            teePos.setZ(teePos.getZ() + GolfGlobals.GOLF_BALL_RADIUS)
            self.notify.debug('teeNodePath heading = %s' % self.teeNodePath.getH())
        self.teePositions = [teePos]
        teeIndex = 1
        teeNode = self.terrainModel.find('**/tee%d' % teeIndex)
        while not teeNode.isEmpty():
            teePos = teeNode.getPos()
            teePos.setZ(teePos.getZ() + GolfGlobals.GOLF_BALL_RADIUS)
            self.teePositions.append(teePos)
            self.notify.debug('teeNodeP heading = %s' % teeNode.getH())
            teeIndex += 1
            teeNode = self.terrainModel.find('**/tee%d' % teeIndex)

    def createLocatorDict(self):
        self.locDict = {}
        locatorNum = 1
        curNodePath = self.hardSurfaceNodePath.find('**/locator%d' % locatorNum)
        while not curNodePath.isEmpty():
            self.locDict[locatorNum] = curNodePath
            locatorNum += 1
            curNodePath = self.hardSurfaceNodePath.find('**/locator%d' % locatorNum)

    def loadBlockers(self):
        loadAll = simbase.config.GetBool('golf-all-blockers', 0)
        self.createLocatorDict()
        self.blockerNums = self.holeInfo['blockers']
        for locatorNum in self.locDict:
            if locatorNum in self.blockerNums or loadAll:
                locator = self.locDict[locatorNum]
                locatorParent = locator.getParent()
                locator.getChildren().wrtReparentTo(locatorParent)
            else:
                self.locDict[locatorNum].removeNode()

        self.hardSurfaceNodePath.flattenStrong()

    def createBall(self):
        golfBallGeom = self.createSphere(self.world, self.space, GolfGlobals.GOLF_BALL_DENSITY, GolfGlobals.GOLF_BALL_RADIUS, 1)[1]
        return golfBallGeom

    def preStep(self):
        GolfHoleBase.GolfHoleBase.preStep(self)

    def postStep(self):
        GolfHoleBase.GolfHoleBase.postStep(self)

    def postSwing(self, cycleTime, power, x, y, z, dirX, dirY):
        avId = self.air.getAvatarIdFromSender()
        self.storeAction = [avId,
         cycleTime,
         power,
         x,
         y,
         z,
         dirX,
         dirY]
        if self.commonHoldData:
            self.doAction()

    def postSwingState(self, cycleTime, power, x, y, z, dirX, dirY, curAimTime, commonObjectData):
        self.notify.debug('postSwingState')
        if not self.golfCourse.getStillPlayingAvIds():
            return
        avId = self.air.getAvatarIdFromSender()
        self.storeAction = [avId,
         cycleTime,
         power,
         x,
         y,
         z,
         dirX,
         dirY]
        self.commonHoldData = commonObjectData
        self.trustedAvId = self.chooseAvatarToSimulate()
        self.sendUpdateToAvatarId(self.trustedAvId, 'assignRecordSwing', [avId,
         cycleTime,
         power,
         x,
         y,
         z,
         dirX,
         dirY,
         commonObjectData])
        self.golfCourse.addAimTime(avId, curAimTime)

    def chooseAvatarToSimulate(self):
        stillPlaying = self.golfCourse.getStillPlayingAvIds()

        return stillPlaying[0] if stillPlaying else 0

    def ballMovie2AI(self, cycleTime, avId, movie, spinMovie, ballInFrame, ballTouchedHoleFrame, ballFirstTouchedHoleFrame, commonObjectData):
        sentFromId = self.air.getAvatarIdFromSender()
        if sentFromId == self.trustedAvId:
            lastFrameNum = len(movie) - 2
            if lastFrameNum < 0:
                lastFrameNum = 0
            lastFrame = movie[lastFrameNum]
            lastPos = Vec3(lastFrame[1], lastFrame[2], lastFrame[3])
            self.ballPos[avId] = lastPos
            self.golfCourse.incrementScore(avId)
            for id in self.golfCourse.getStillPlayingAvIds():
                if not id == sentFromId:
                    self.sendUpdateToAvatarId(id, 'ballMovie2Client', [cycleTime,
                     avId,
                     movie,
                     spinMovie,
                     ballInFrame,
                     ballTouchedHoleFrame,
                     ballFirstTouchedHoleFrame,
                     commonObjectData])

            if self.state == 'WaitPlayback' or self.state == 'WaitTee':
                self.notify.warning('ballMovie2AI requesting from %s to WaitPlayback' % self.state)
            self.request('WaitPlayback')
        elif self.trustedAvId == None:
            return
        else:
            self.doAction()
        self.trustedAvId = None
        return

    def performReadyAction(self):
        avId = self.storeAction[0]
        if self.state == 'WaitPlayback':
            self.notify.debugStateCall(self)
            self.notify.debug('ignoring the postSwing for avId=%d since we are in WaitPlayback' % avId)
            return
        if avId == self.activeGolferId:
            self.golfCourse.incrementScore(self.activeGolferId)
        else:
            self.notify.warning('activGolferId %d not equal to sender avId %d' % (self.activeGolferId, avId))
        if avId not in self.golfCourse.drivingToons:
            position = self.ballPos[avId]
        else:
            position = Vec3(self.storeAction[3], self.storeAction[4], self.storeAction[5])
        self.useCommonObjectData(self.commonHoldData)
        newPos = self.trackRecordBodyFlight(self.ball, self.storeAction[1], self.storeAction[2], position, self.storeAction[6], self.storeAction[7])
        if self.state == 'WaitPlayback' or self.state == 'WaitTee':
            self.notify.warning('performReadyAction requesting from %s to WaitPlayback' % self.state)
        self.request('WaitPlayback')
        self.sendUpdate('ballMovie2Client', [self.storeAction[1],
         avId,
         self.recording,
         self.aVRecording,
         self.ballInHoleFrame,
         self.ballTouchedHoleFrame,
         self.ballFirstTouchedHoleFrame,
         self.commonHoldData])
        self.ballPos[avId] = newPos
        self.trustedAvId = None
        return

    def postResult(self, cycleTime, avId, recording, aVRecording, ballInHoleFrame, ballTouchedHoleFrame, ballFirstTouchedHoleFrame):
        pass

    def enterWaitSwing(self):
        pass

    def exitWaitSwing(self):
        pass

    def enterWaitTee(self):
        pass

    def exitWaitTee(self):
        pass

    def enterWaitPlayback(self):
        self.notify.debug('enterWaitPlayback')
        stillPlayingList = self.golfCourse.getStillPlayingAvIds()
        self.barrierPlayback = ToonBarrier('waitClientsPlayback', self.uniqueName('waitClientsPlayback'), stillPlayingList, 120, self.handleWaitPlaybackDone, self.handlePlaybackTimeout)

    def hasCurGolferReachedMaxSwing(self):
        strokes = self.golfCourse.getCurHoleScore(self.activeGolferId)
        maxSwing = self.holeInfo['maxSwing']
        retval = strokes >= maxSwing
        if retval:
            av = simbase.air.doId2do.get(self.activeGolferId)
            if av:
                if av.getUnlimitedSwing():
                    retval = False
        return retval

    def handleWaitPlaybackDone(self):
        if self.isCurBallInHole(self.activeGolferId) or self.hasCurGolferReachedMaxSwing():
            if self.activeGolferId:
                self.ballInHole(self.activeGolferId)
        else:
            self.selectNextGolfer()

    def isCurBallInHole(self, golferId):
        retval = False
        for holePos in self.holePositions:
            displacement = self.ballPos[golferId] - holePos
            length = displacement.length()
            self.notify.debug('hole %s length=%s' % (holePos, length))
            if length <= GolfGlobals.DistanceToBeInHole:
                retval = True
                break

        return retval

    def exitWaitPlayback(self):
        self.notify.debug('exitWaitPlayback')
        if hasattr(self, 'barrierPlayback') and self.barrierPlayback:
            self.barrierPlayback.cleanup()
            self.barrierPlayback = None
        return

    def enterCleanup(self):
        pass

    def exitCleanup(self):
        pass

    def handlePlaybackTimeout(self, task = None):
        self.notify.debug('handlePlaybackTimeout')
        self.handleWaitPlaybackDone()

    def getGolfCourseDoId(self):
        return self.golfCourse.doId

    def avatarDropped(self, avId):
        self.notify.warning('avId %d dropped, self.state=%s' % (avId, self.state))
        if self.barrierPlayback:
            self.barrierPlayback.clear(avId)
        else:
            if avId == self.trustedAvId:
                self.doAction()
            if avId == self.activeGolferId and not self.golfCourse.haveAllGolfersExited():
                self.selectNextGolfer()

    def setAvatarTee(self, chosenTee):
        golferId = self.air.getAvatarIdFromSender()
        self.teeChosen[golferId] = chosenTee
        self.ballPos[golferId] = self.teePositions[chosenTee]
        self.sendUpdate('setAvatarFinalTee', [golferId, chosenTee])
        self.sendUpdate('golfersTurn', [golferId])
        self.request('WaitSwing')

    def setBox(self, pos0, pos1, pos2, quat0, quat1, quat2, quat3, anV0, anV1, anV2, lnV0, lnV1, lnV2):
        self.sendUpdate('sendBox', [pos0,
         pos1,
         pos2,
         quat0,
         quat1,
         quat2,
         quat3,
         anV0,
         anV1,
         anV2,
         lnV0,
         lnV1,
         lnV2])

    def parseLocators(self, objectCollection, optional = 0):
        if optional and objectCollection.getNumPaths():
            if 'optionalMovers' in self.holeInfo:
                for optionalMoverId in self.holeInfo['optionalMovers']:
                    searchStr = 'optional_mover_' + str(optionalMoverId)
                    for objIndex in xrange(objectCollection.getNumPaths()):
                        object = objectCollection.getPath(objIndex)
                        if searchStr in object.getName():
                            self.fillLocator(objectCollection, objIndex)
                            break

        else:
            for index in xrange(objectCollection.getNumPaths()):
                self.fillLocator(objectCollection, index)

    def fillLocator(self, objectCollection, index):
        path = objectCollection[index]
        pathName = path.getName()
        pathArray = pathName.split('_')
        sizeX = None
        sizeY = None
        move = None
        type = None
        for subString in pathArray:
            if subString[:1] == 'X':
                dataString = subString[1:]
                dataString = dataString.replace('p', '.')
                sizeX = float(dataString)
            elif subString[:1] == 'Y':
                dataString = subString[1:]
                dataString = dataString.replace('p', '.')
                sizeY = float(dataString)
            elif subString[:1] == 'd':
                dataString = subString[1:]
                dataString = dataString.replace('p', '.')
                move = float(dataString)
            elif subString == 'mover':
                type = 4
            elif subString == 'windmillLocator':
                type = 3

        if type == 4 and move and sizeX and sizeY:
            self.createCommonObject(4, path.getPos(), path.getHpr(), sizeX, sizeY, move)
        elif type == 3:
            self.createCommonObject(3, path.getPos(), path.getHpr())
        return
class DistributedTwoDGameAI(DistributedMinigameAI):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        'DistributedTwoDGameAI')

    def __init__(self, air, minigameId):
        try:
            self.DistributedTwoDGameAI_initialized
        except:
            self.DistributedTwoDGame_initialized = 1
            DistributedMinigameAI.__init__(self, air, minigameId)
            self.gameFSM = ClassicFSM.ClassicFSM('DistributedTwoDGameAI', [
                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.finishedBonusDict = {}
            self.finishedTimeLeftDict = {}
            self.numFallDownDict = {}
            self.numHitByEnemyDict = {}
            self.numSquishDict = {}
            self.treasuresCollectedDict = {}
            self.sectionsSelected = []
            self.enemyHealthTable = []
            self.treasureTakenTable = []
            self.sectionIndexList = []

    def generate(self):
        self.notify.debug('generate')
        DistributedMinigameAI.generate(self)

    def delete(self):
        self.notify.debug('delete')
        del self.gameFSM
        DistributedMinigameAI.delete(self)

    def setTrolleyZone(self, trolleyZone):
        DistributedMinigameAI.setTrolleyZone(self, trolleyZone)
        self.setupSections()

    def setGameReady(self):
        self.notify.debug('setGameReady')
        DistributedMinigameAI.setGameReady(self)
        self.numTreasures = ToonBlitzGlobals.NumTreasures
        self.numEnemies = ToonBlitzGlobals.NumEnemies
        self.numTreasuresTaken = 0
        self.numEnemiesKilled = 0
        for avId in self.scoreDict.keys():
            self.scoreDict[avId] = 0
            self.finishedBonusDict[avId] = 0
            self.finishedTimeLeftDict[avId] = -1
            self.numFallDownDict[avId] = 0
            self.numHitByEnemyDict[avId] = 0
            self.numSquishDict[avId] = 0
            self.treasuresCollectedDict[avId] = [0, 0, 0, 0]

        for i in xrange(len(self.sectionsSelected)):
            sectionIndex = self.sectionsSelected[i][0]
            attribs = ToonBlitzGlobals.SectionTypes[sectionIndex]
            enemiesPool = attribs[3]
            self.enemyHealthTable += [[]]
            enemyIndicesSelected = self.sectionsSelected[i][1]
            for j in xrange(len(enemyIndicesSelected)):
                enemyIndex = enemyIndicesSelected[j]
                enemyType = enemiesPool[enemyIndex][0]
                self.enemyHealthTable[i] += [ToonBlitzGlobals.EnemyBaseHealth]
                self.enemyHealthTable[i][j] *= self.numPlayers
                if enemyType in ToonBlitzGlobals.EnemyHealthMultiplier:
                    self.enemyHealthTable[i][
                        j] *= ToonBlitzGlobals.EnemyHealthMultiplier[enemyType]

            self.treasureTakenTable += [[]]
            treasureIndicesSelected = self.sectionsSelected[i][2]
            for j in xrange(len(treasureIndicesSelected)):
                self.treasureTakenTable[i] += [0]

            enemyIndicesSelected = self.sectionsSelected[i][1]
            for j in xrange(len(enemyIndicesSelected)):
                self.treasureTakenTable[i] += [0]

    def setGameStart(self, timestamp):
        self.notify.debug('setGameStart')
        DistributedMinigameAI.setGameStart(self, timestamp)
        self.gameFSM.request('play')

    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')
        scoreList = []
        finishedBonusList = []
        timeLeftList = []
        treasureCollectedList = []
        playerErrorList = []
        for avId in self.avIdList:
            scoreList.append(self.scoreDict[avId])
            finishedBonusList.append(self.finishedBonusDict[avId])
            timeLeftList.append(self.finishedTimeLeftDict[avId])
            treasureCollectedList.append(self.treasuresCollectedDict[avId])
            playerError = [
                self.numFallDownDict[avId], self.numHitByEnemyDict[avId],
                self.numSquishDict[avId]
            ]
            playerErrorList.append(playerError)
            self.scoreDict[avId] = max(0, self.scoreDict[avId])
            jellybeans = sqrt(self.scoreDict[avId] *
                              ToonBlitzGlobals.ScoreToJellyBeansMultiplier)
            self.scoreDict[avId] = max(1, int(jellybeans))

        self.air.writeServerEvent(
            'minigame_twoD', self.doId, '%s|%s|%s|%s|%s|%s|%s|%s|%s' %
            (ToontownGlobals.TwoDGameId, self.getSafezoneId(), self.avIdList,
             scoreList, finishedBonusList, timeLeftList, treasureCollectedList,
             playerErrorList, self.sectionIndexList))
        self.notify.debug(
            'minigame_twoD%s: %s|%s|%s|%s|%s|%s|%s|%s|%s' %
            (self.doId, ToontownGlobals.TwoDGameId, self.getSafezoneId(),
             self.avIdList, scoreList, finishedBonusList, timeLeftList,
             treasureCollectedList, playerErrorList, self.sectionIndexList))
        self.gameFSM.request('cleanup')
        DistributedMinigameAI.gameOver(self)

    def enterInactive(self):
        self.notify.debug('enterInactive')

    def exitInactive(self):
        pass

    def enterPlay(self):
        self.notify.debug('enterPlay')

        def allToonsDone(self=self):
            self.notify.debug('allToonsDone')
            self.sendUpdate('setEveryoneDone')
            if not ToonBlitzGlobals.EndlessGame:
                self.gameOver()

        def handleTimeout(avIds, self=self):
            self.notify.debug(
                'handleTimeout: avatars %s did not report "done"' % avIds)
            self.setGameAbort()

        self.doneBarrier = ToonBarrier(
            'waitClientsDone', self.uniqueName('waitClientsDone'),
            self.avIdList,
            ToonBlitzGlobals.GameDuration[self.getSafezoneId()] +
            ToonBlitzGlobals.ShowScoresDuration +
            MinigameGlobals.latencyTolerance, allToonsDone, handleTimeout)

    def exitPlay(self):
        pass

    def enterCleanup(self):
        self.notify.debug('enterCleanup')
        self.doneBarrier.cleanup()
        del self.doneBarrier
        self.gameFSM.request('inactive')

    def exitCleanup(self):
        pass

    def claimTreasure(self, sectionIndex, treasureIndex):
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('treasure %s-%s claimed by %s' %
                          (sectionIndex, treasureIndex, avId))
        if sectionIndex < 0 or sectionIndex >= len(self.sectionsSelected):
            self.air.writeServerEvent(
                'warning', sectionIndex,
                'TwoDGameAI.claimTreasure sectionIndex out of range.')
            return
        if treasureIndex < 0 or treasureIndex >= len(
                self.treasureTakenTable[sectionIndex]):
            self.notify.warning(
                'Treasure %s: TwoDGameAI.claimTreasure treasureIndex out of range.'
                % treasureIndex)
            self.air.writeServerEvent(
                'warning', treasureIndex,
                'TwoDGameAI.claimTreasure treasureIndex out of range.')
            return
        if self.treasureTakenTable[sectionIndex][treasureIndex]:
            return
        initialTreasureList = self.sectionsSelected[sectionIndex][2]
        if treasureIndex < len(initialTreasureList):
            treasureValue = initialTreasureList[treasureIndex][1]
        else:
            treasureValue = self.numPlayers
        self.treasureTakenTable[sectionIndex][treasureIndex] = treasureValue
        self.treasuresCollectedDict[avId][treasureValue - 1] += 1
        self.scoreDict[
            avId] += ToonBlitzGlobals.ScoreGainPerTreasure * treasureValue
        self.numTreasuresTaken += 1
        self.sendUpdate('setTreasureGrabbed',
                        [avId, sectionIndex, treasureIndex])

    def claimEnemyShot(self, sectionIndex, enemyIndex):
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('enemy %s-%s shot claimed by %s' %
                          (sectionIndex, enemyIndex, avId))
        if sectionIndex < 0 or sectionIndex >= len(self.sectionsSelected):
            self.air.writeServerEvent(
                'warning', sectionIndex,
                'TwoDGameAI.claimEnemyShot sectionIndex out of range.')
            return
        if enemyIndex < 0 or enemyIndex >= len(
                self.sectionsSelected[sectionIndex][1]):
            self.air.writeServerEvent(
                'warning', enemyIndex,
                'TwoDGameAI.claimEnemyShot enemyIndex out of range.')
            return
        if self.enemyHealthTable[sectionIndex][enemyIndex] > 0:
            self.enemyHealthTable[sectionIndex][
                enemyIndex] -= ToonBlitzGlobals.DamagePerBullet
            if self.enemyHealthTable[sectionIndex][enemyIndex] <= 0:
                self.numEnemiesKilled += 1
            self.sendUpdate('setEnemyShot', [
                avId, sectionIndex, enemyIndex,
                self.enemyHealthTable[sectionIndex][enemyIndex]
            ])

    def reportDone(self):
        if self.gameFSM.getCurrentState(
        ) == None or self.gameFSM.getCurrentState().getName() != 'play':
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('reportDone: avatar %s is done' % avId)
        self.doneBarrier.clear(avId)
        return

    def toonVictory(self, avId, timestamp):
        if self.gameFSM.getCurrentState(
        ) == None or self.gameFSM.getCurrentState().getName() != 'play':
            msg = 'TwoDGameAI.toonVictory not in play state!'
            self.notify.warning('suspicious: ' + str(avId) + ' ' + msg)
            self.air.writeServerEvent('suspicious: ', avId, msg)
            return
        if avId not in self.scoreDict.keys():
            self.notify.warning('Avatar %s not in list.' % avId)
            self.air.writeServerEvent(
                'suspicious: ', avId,
                'TwoDGameAI.toonVictory toon not in list.')
            return
        curTime = self.getCurrentGameTime()
        timeLeft = ToonBlitzGlobals.GameDuration[
            self.getSafezoneId()] - curTime
        self.notify.debug('curTime =%s timeLeft = %s' % (curTime, timeLeft))
        addBonus = int(
            ToonBlitzGlobals.BaseBonusOnCompletion[self.getSafezoneId()] +
            ToonBlitzGlobals.BonusPerSecondLeft * timeLeft)
        self.notify.debug('addBOnus = %d' % addBonus)
        if addBonus < 0:
            addBonus = 0
        self.finishedBonusDict[avId] = addBonus
        timeLeftStr = '%.1f' % timeLeft
        self.finishedTimeLeftDict[avId] = timeLeftStr
        self.scoreDict[avId] += addBonus
        self.sendUpdate('addVictoryScore', [avId, addBonus])
        self.doneBarrier.clear(avId)
        return

    def toonFellDown(self, avId, timestamp):
        if avId not in self.scoreDict.keys():
            self.notify.warning('Avatar %s not in list.' % avId)
            self.air.writeServerEvent(
                'warning', avId, 'TwoDGameAI.toonFellDown toon not in list.')
            return
        self.numFallDownDict[avId] += 1
        self.scoreDict[avId] += ToonBlitzGlobals.ScoreLossPerFallDown[
            self.getSafezoneId()]

    def toonHitByEnemy(self, avId, timestamp):
        if avId not in self.scoreDict.keys():
            self.notify.warning('Avatar %s not in list.' % avId)
            self.air.writeServerEvent(
                'warning', avId, 'TwoDGameAI.toonHitByEnemy toon not in list.')
            return
        self.numHitByEnemyDict[avId] += 1
        self.scoreDict[avId] += ToonBlitzGlobals.ScoreLossPerEnemyCollision[
            self.getSafezoneId()]

    def toonSquished(self, avId, timestamp):
        if avId not in self.scoreDict.keys():
            self.notify.warning('Avatar %s not in list.' % avId)
            self.air.writeServerEvent(
                'warning', avId, 'TwoDGameAI.toonSquished toon not in list.')
            return
        self.numSquishDict[avId] += 1
        self.scoreDict[avId] += ToonBlitzGlobals.ScoreLossPerStomperSquish[
            self.getSafezoneId()]

    def setupSections(self):
        szId = self.getSafezoneId()
        sectionWeights = ToonBlitzGlobals.SectionWeights[szId]
        numSections = ToonBlitzGlobals.NumSections[szId]
        difficultyPool = []
        difficultyList = []
        sectionsPool = ToonBlitzGlobals.SectionsPool
        sectionTypes = ToonBlitzGlobals.SectionTypes
        sectionsPoolByDifficulty = [[], [], [], [], [], []]
        sectionsSelectedByDifficulty = [[], [], [], [], [], []]
        sectionIndicesSelected = []
        for weight in sectionWeights:
            difficulty, probability = weight
            difficultyPool += [difficulty] * probability

        for i in xrange(numSections):
            difficulty = random.choice(difficultyPool)
            difficultyList.append(difficulty)

        difficultyList.sort()
        for sectionIndex in sectionsPool:
            difficulty = sectionTypes[sectionIndex][0]
            sectionsPoolByDifficulty[difficulty] += [sectionIndex]

        for targetDifficulty in difficultyList:
            whileCount = 0
            difficulty = targetDifficulty
            while not len(sectionsPoolByDifficulty[difficulty]) > 0:
                difficulty += 1
                if difficulty >= 5:
                    difficulty = 0
                    whileCount += 1
                    if whileCount > 1:
                        break
            else:
                sectionIndexChoice = random.choice(
                    sectionsPoolByDifficulty[difficulty])
                sectionsSelectedByDifficulty[difficulty] += [
                    sectionIndexChoice
                ]
                sectionsPoolByDifficulty[difficulty].remove(sectionIndexChoice)

            if whileCount > 1:
                self.notify.debug(
                    'We need more sections than we have choices. We have to now repeat.'
                )

        for i in xrange(len(sectionsSelectedByDifficulty)):
            for j in xrange(len(sectionsSelectedByDifficulty[i])):
                sectionIndicesSelected.append(
                    sectionsSelectedByDifficulty[i][j])

        for i in xrange(len(sectionIndicesSelected)):
            sectionIndex = sectionIndicesSelected[i]
            self.sectionIndexList.append(sectionIndex)
            attribs = sectionTypes[sectionIndex]
            difficulty = attribs[0]
            length = attribs[1]
            blocksPool = attribs[2]
            enemiesPool = attribs[3]
            treasuresPool = attribs[4]
            spawnPointsPool = attribs[5]
            stompersPool = attribs[6]
            enemyIndicesPool = []
            enemyIndicesSelected = []
            if enemiesPool != None:
                minEnemies, maxEnemies = attribs[7]
                for i in xrange(len(enemiesPool)):
                    enemyIndicesPool += [i]

                numEnemies = maxEnemies * ToonBlitzGlobals.PercentMaxEnemies[
                    szId] / 100
                numEnemies = max(numEnemies, minEnemies)
                for j in xrange(int(numEnemies)):
                    if len(enemyIndicesPool) == 0:
                        break
                    enemyIndex = random.choice(enemyIndicesPool)
                    enemyIndicesSelected.append(enemyIndex)
                    enemyIndicesPool.remove(enemyIndex)

                enemyIndicesSelected.sort()
            treasureIndicesPool = []
            treasureValuePool = []
            for value in xrange(1, 5):
                treasureValuePool += [
                    value
                ] * ToonBlitzGlobals.TreasureValueProbability[value]

            treasureIndicesSelected = []
            if treasuresPool != None:
                minTreasures, maxTreasures = attribs[8]
                for i in xrange(len(treasuresPool)):
                    treasureIndicesPool += [i]

                numTreasures = maxTreasures * ToonBlitzGlobals.PercentMaxTreasures[
                    szId] / 100
                numTreasures = max(numTreasures, minTreasures)
                for i in xrange(int(numTreasures)):
                    if len(treasureIndicesPool) == 0:
                        break
                    treasureIndex = random.choice(treasureIndicesPool)
                    treasureValue = random.choice(treasureValuePool)
                    treasure = (treasureIndex, treasureValue)
                    treasureIndicesPool.remove(treasureIndex)
                    treasureIndicesSelected.append(treasure)

                treasureIndicesSelected.sort()
            spawnPointIndicesPool = []
            spawnPointIndicesSelected = []
            if spawnPointsPool != None:
                minSpawnPoints, maxSpawnPoints = attribs[9]
                for i in xrange(len(spawnPointsPool)):
                    spawnPointIndicesPool += [i]

                numSpawnPoints = maxSpawnPoints * ToonBlitzGlobals.PercentMaxSpawnPoints[
                    szId] / 100
                numSpawnPoints = max(numSpawnPoints, minSpawnPoints)
                for i in xrange(int(numSpawnPoints)):
                    if len(spawnPointIndicesPool) == 0:
                        break
                    spawnPoint = random.choice(spawnPointIndicesPool)
                    spawnPointIndicesSelected.append(spawnPoint)
                    spawnPointIndicesPool.remove(spawnPoint)

                spawnPointIndicesSelected.sort()
            stomperIndicesPool = []
            stomperIndicesSelected = []
            if stompersPool != None:
                minStompers, maxStompers = attribs[10]
                for i in xrange(len(stompersPool)):
                    stomperIndicesPool += [i]

                numStompers = maxStompers * ToonBlitzGlobals.PercentMaxStompers[
                    szId] / 100
                numStompers = max(numStompers, minStompers)
                for i in xrange(int(numStompers)):
                    if len(stomperIndicesPool) == 0:
                        break
                    stomper = random.choice(stomperIndicesPool)
                    stomperIndicesSelected.append(stomper)
                    stomperIndicesPool.remove(stomper)

                stomperIndicesSelected.sort()
            sctionTuple = (sectionIndex, enemyIndicesSelected,
                           treasureIndicesSelected, spawnPointIndicesSelected,
                           stomperIndicesSelected)
            self.sectionsSelected.append(sctionTuple)

        return

    def getSectionsSelected(self):
        return self.sectionsSelected
Exemplo n.º 23
0
    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)
class DistributedTwoDGameAI(DistributedMinigameAI):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedTwoDGameAI')

    def __init__(self, air, minigameId):
        try:
            self.DistributedTwoDGameAI_initialized
        except:
            self.DistributedTwoDGame_initialized = 1
            DistributedMinigameAI.__init__(self, air, minigameId)
            self.gameFSM = ClassicFSM.ClassicFSM('DistributedTwoDGameAI', [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.finishedBonusDict = {}
            self.finishedTimeLeftDict = {}
            self.numFallDownDict = {}
            self.numHitByEnemyDict = {}
            self.numSquishDict = {}
            self.treasuresCollectedDict = {}
            self.sectionsSelected = []
            self.enemyHealthTable = []
            self.treasureTakenTable = []
            self.sectionIndexList = []

    def generate(self):
        self.notify.debug('generate')
        DistributedMinigameAI.generate(self)

    def delete(self):
        self.notify.debug('delete')
        del self.gameFSM
        DistributedMinigameAI.delete(self)

    def setTrolleyZone(self, trolleyZone):
        DistributedMinigameAI.setTrolleyZone(self, trolleyZone)
        self.setupSections()

    def setGameReady(self):
        self.notify.debug('setGameReady')
        DistributedMinigameAI.setGameReady(self)
        self.numTreasures = ToonBlitzGlobals.NumTreasures
        self.numEnemies = ToonBlitzGlobals.NumEnemies
        self.numTreasuresTaken = 0
        self.numEnemiesKilled = 0
        for avId in self.scoreDict.keys():
            self.scoreDict[avId] = 0
            self.finishedBonusDict[avId] = 0
            self.finishedTimeLeftDict[avId] = -1
            self.numFallDownDict[avId] = 0
            self.numHitByEnemyDict[avId] = 0
            self.numSquishDict[avId] = 0
            self.treasuresCollectedDict[avId] = [0,
             0,
             0,
             0]

        for i in xrange(len(self.sectionsSelected)):
            sectionIndex = self.sectionsSelected[i][0]
            attribs = ToonBlitzGlobals.SectionTypes[sectionIndex]
            enemiesPool = attribs[3]
            self.enemyHealthTable += [[]]
            enemyIndicesSelected = self.sectionsSelected[i][1]
            for j in xrange(len(enemyIndicesSelected)):
                enemyIndex = enemyIndicesSelected[j]
                enemyType = enemiesPool[enemyIndex][0]
                self.enemyHealthTable[i] += [ToonBlitzGlobals.EnemyBaseHealth]
                self.enemyHealthTable[i][j] *= self.numPlayers
                if enemyType in ToonBlitzGlobals.EnemyHealthMultiplier:
                    self.enemyHealthTable[i][j] *= ToonBlitzGlobals.EnemyHealthMultiplier[enemyType]

            self.treasureTakenTable += [[]]
            treasureIndicesSelected = self.sectionsSelected[i][2]
            for j in xrange(len(treasureIndicesSelected)):
                self.treasureTakenTable[i] += [0]

            enemyIndicesSelected = self.sectionsSelected[i][1]
            for j in xrange(len(enemyIndicesSelected)):
                self.treasureTakenTable[i] += [0]

    def setGameStart(self, timestamp):
        self.notify.debug('setGameStart')
        DistributedMinigameAI.setGameStart(self, timestamp)
        self.gameFSM.request('play')

    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')
        scoreList = []
        finishedBonusList = []
        timeLeftList = []
        treasureCollectedList = []
        playerErrorList = []
        for avId in self.avIdList:
            scoreList.append(self.scoreDict[avId])
            finishedBonusList.append(self.finishedBonusDict[avId])
            timeLeftList.append(self.finishedTimeLeftDict[avId])
            treasureCollectedList.append(self.treasuresCollectedDict[avId])
            playerError = [self.numFallDownDict[avId], self.numHitByEnemyDict[avId], self.numSquishDict[avId]]
            playerErrorList.append(playerError)
            self.scoreDict[avId] = max(0, self.scoreDict[avId])
            jellybeans = sqrt(self.scoreDict[avId] * ToonBlitzGlobals.ScoreToJellyBeansMultiplier)
            self.scoreDict[avId] = max(1, int(jellybeans))

        self.air.writeServerEvent('minigame_twoD', self.doId, '%s|%s|%s|%s|%s|%s|%s|%s|%s' % (ToontownGlobals.TwoDGameId,
         self.getSafezoneId(),
         self.avIdList,
         scoreList,
         finishedBonusList,
         timeLeftList,
         treasureCollectedList,
         playerErrorList,
         self.sectionIndexList))
        self.notify.debug('minigame_twoD%s: %s|%s|%s|%s|%s|%s|%s|%s|%s' % (self.doId,
         ToontownGlobals.TwoDGameId,
         self.getSafezoneId(),
         self.avIdList,
         scoreList,
         finishedBonusList,
         timeLeftList,
         treasureCollectedList,
         playerErrorList,
         self.sectionIndexList))
        self.gameFSM.request('cleanup')
        DistributedMinigameAI.gameOver(self)

    def enterInactive(self):
        self.notify.debug('enterInactive')

    def exitInactive(self):
        pass

    def enterPlay(self):
        self.notify.debug('enterPlay')

        def allToonsDone(self = self):
            self.notify.debug('allToonsDone')
            self.sendUpdate('setEveryoneDone')
            if not ToonBlitzGlobals.EndlessGame:
                self.gameOver()

        def handleTimeout(avIds, self = self):
            self.notify.debug('handleTimeout: avatars %s did not report "done"' % avIds)
            self.setGameAbort()

        self.doneBarrier = ToonBarrier('waitClientsDone', self.uniqueName('waitClientsDone'), self.avIdList, ToonBlitzGlobals.GameDuration[self.getSafezoneId()] + ToonBlitzGlobals.ShowScoresDuration + MinigameGlobals.latencyTolerance, allToonsDone, handleTimeout)

    def exitPlay(self):
        pass

    def enterCleanup(self):
        self.notify.debug('enterCleanup')
        self.doneBarrier.cleanup()
        del self.doneBarrier
        self.gameFSM.request('inactive')

    def exitCleanup(self):
        pass

    def claimTreasure(self, sectionIndex, treasureIndex):
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('treasure %s-%s claimed by %s' % (sectionIndex, treasureIndex, avId))
        if sectionIndex < 0 or sectionIndex >= len(self.sectionsSelected):
            self.air.writeServerEvent('warning', sectionIndex, 'TwoDGameAI.claimTreasure sectionIndex out of range.')
            return
        if treasureIndex < 0 or treasureIndex >= len(self.treasureTakenTable[sectionIndex]):
            self.notify.warning('Treasure %s: TwoDGameAI.claimTreasure treasureIndex out of range.' % treasureIndex)
            self.air.writeServerEvent('warning', treasureIndex, 'TwoDGameAI.claimTreasure treasureIndex out of range.')
            return
        if self.treasureTakenTable[sectionIndex][treasureIndex]:
            return
        initialTreasureList = self.sectionsSelected[sectionIndex][2]
        if treasureIndex < len(initialTreasureList):
            treasureValue = initialTreasureList[treasureIndex][1]
        else:
            treasureValue = self.numPlayers
        self.treasureTakenTable[sectionIndex][treasureIndex] = treasureValue
        self.treasuresCollectedDict[avId][treasureValue - 1] += 1
        self.scoreDict[avId] += ToonBlitzGlobals.ScoreGainPerTreasure * treasureValue
        self.numTreasuresTaken += 1
        self.sendUpdate('setTreasureGrabbed', [avId, sectionIndex, treasureIndex])

    def claimEnemyShot(self, sectionIndex, enemyIndex):
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('enemy %s-%s shot claimed by %s' % (sectionIndex, enemyIndex, avId))
        if sectionIndex < 0 or sectionIndex >= len(self.sectionsSelected):
            self.air.writeServerEvent('warning', sectionIndex, 'TwoDGameAI.claimEnemyShot sectionIndex out of range.')
            return
        if enemyIndex < 0 or enemyIndex >= len(self.sectionsSelected[sectionIndex][1]):
            self.air.writeServerEvent('warning', enemyIndex, 'TwoDGameAI.claimEnemyShot enemyIndex out of range.')
            return
        if self.enemyHealthTable[sectionIndex][enemyIndex] > 0:
            self.enemyHealthTable[sectionIndex][enemyIndex] -= ToonBlitzGlobals.DamagePerBullet
            if self.enemyHealthTable[sectionIndex][enemyIndex] <= 0:
                self.numEnemiesKilled += 1
            self.sendUpdate('setEnemyShot', [avId,
             sectionIndex,
             enemyIndex,
             self.enemyHealthTable[sectionIndex][enemyIndex]])

    def reportDone(self):
        if self.gameFSM.getCurrentState() == None or self.gameFSM.getCurrentState().getName() != 'play':
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('reportDone: avatar %s is done' % avId)
        self.doneBarrier.clear(avId)
        return

    def toonVictory(self, avId, timestamp):
        if self.gameFSM.getCurrentState() == None or self.gameFSM.getCurrentState().getName() != 'play':
            msg = 'TwoDGameAI.toonVictory not in play state!'
            self.notify.warning('suspicious: ' + str(avId) + ' ' + msg)
            self.air.writeServerEvent('suspicious: ', avId, msg)
            return
        if avId not in self.scoreDict.keys():
            self.notify.warning('Avatar %s not in list.' % avId)
            self.air.writeServerEvent('suspicious: ', avId, 'TwoDGameAI.toonVictory toon not in list.')
            return
        curTime = self.getCurrentGameTime()
        timeLeft = ToonBlitzGlobals.GameDuration[self.getSafezoneId()] - curTime
        self.notify.debug('curTime =%s timeLeft = %s' % (curTime, timeLeft))
        addBonus = int(ToonBlitzGlobals.BaseBonusOnCompletion[self.getSafezoneId()] + ToonBlitzGlobals.BonusPerSecondLeft * timeLeft)
        self.notify.debug('addBOnus = %d' % addBonus)
        if addBonus < 0:
            addBonus = 0
        self.finishedBonusDict[avId] = addBonus
        timeLeftStr = '%.1f' % timeLeft
        self.finishedTimeLeftDict[avId] = timeLeftStr
        self.scoreDict[avId] += addBonus
        self.sendUpdate('addVictoryScore', [avId, addBonus])
        self.doneBarrier.clear(avId)
        return

    def toonFellDown(self, avId, timestamp):
        if avId not in self.scoreDict.keys():
            self.notify.warning('Avatar %s not in list.' % avId)
            self.air.writeServerEvent('warning', avId, 'TwoDGameAI.toonFellDown toon not in list.')
            return
        self.numFallDownDict[avId] += 1
        self.scoreDict[avId] += ToonBlitzGlobals.ScoreLossPerFallDown[self.getSafezoneId()]

    def toonHitByEnemy(self, avId, timestamp):
        if avId not in self.scoreDict.keys():
            self.notify.warning('Avatar %s not in list.' % avId)
            self.air.writeServerEvent('warning', avId, 'TwoDGameAI.toonHitByEnemy toon not in list.')
            return
        self.numHitByEnemyDict[avId] += 1
        self.scoreDict[avId] += ToonBlitzGlobals.ScoreLossPerEnemyCollision[self.getSafezoneId()]

    def toonSquished(self, avId, timestamp):
        if avId not in self.scoreDict.keys():
            self.notify.warning('Avatar %s not in list.' % avId)
            self.air.writeServerEvent('warning', avId, 'TwoDGameAI.toonSquished toon not in list.')
            return
        self.numSquishDict[avId] += 1
        self.scoreDict[avId] += ToonBlitzGlobals.ScoreLossPerStomperSquish[self.getSafezoneId()]

    def setupSections(self):
        szId = self.getSafezoneId()
        sectionWeights = ToonBlitzGlobals.SectionWeights[szId]
        numSections = ToonBlitzGlobals.NumSections[szId]
        difficultyPool = []
        difficultyList = []
        sectionsPool = ToonBlitzGlobals.SectionsPool
        sectionTypes = ToonBlitzGlobals.SectionTypes
        sectionsPoolByDifficulty = [[],
         [],
         [],
         [],
         [],
         []]
        sectionsSelectedByDifficulty = [[],
         [],
         [],
         [],
         [],
         []]
        sectionIndicesSelected = []
        for weight in sectionWeights:
            difficulty, probability = weight
            difficultyPool += [difficulty] * probability

        for i in xrange(numSections):
            difficulty = random.choice(difficultyPool)
            difficultyList.append(difficulty)

        difficultyList.sort()
        for sectionIndex in sectionsPool:
            difficulty = sectionTypes[sectionIndex][0]
            sectionsPoolByDifficulty[difficulty] += [sectionIndex]

        for targetDifficulty in difficultyList:
            whileCount = 0
            difficulty = targetDifficulty
            while not len(sectionsPoolByDifficulty[difficulty]) > 0:
                difficulty += 1
                if difficulty >= 5:
                    difficulty = 0
                    whileCount += 1
                    if whileCount > 1:
                        break
            else:
                sectionIndexChoice = random.choice(sectionsPoolByDifficulty[difficulty])
                sectionsSelectedByDifficulty[difficulty] += [sectionIndexChoice]
                sectionsPoolByDifficulty[difficulty].remove(sectionIndexChoice)

            if whileCount > 1:
                self.notify.debug('We need more sections than we have choices. We have to now repeat.')

        for i in xrange(len(sectionsSelectedByDifficulty)):
            for j in xrange(len(sectionsSelectedByDifficulty[i])):
                sectionIndicesSelected.append(sectionsSelectedByDifficulty[i][j])

        for i in xrange(len(sectionIndicesSelected)):
            sectionIndex = sectionIndicesSelected[i]
            self.sectionIndexList.append(sectionIndex)
            attribs = sectionTypes[sectionIndex]
            difficulty = attribs[0]
            length = attribs[1]
            blocksPool = attribs[2]
            enemiesPool = attribs[3]
            treasuresPool = attribs[4]
            spawnPointsPool = attribs[5]
            stompersPool = attribs[6]
            enemyIndicesPool = []
            enemyIndicesSelected = []
            if enemiesPool != None:
                minEnemies, maxEnemies = attribs[7]
                for i in xrange(len(enemiesPool)):
                    enemyIndicesPool += [i]

                numEnemies = maxEnemies * ToonBlitzGlobals.PercentMaxEnemies[szId] / 100
                numEnemies = max(numEnemies, minEnemies)
                for j in xrange(int(numEnemies)):
                    if len(enemyIndicesPool) == 0:
                        break
                    enemyIndex = random.choice(enemyIndicesPool)
                    enemyIndicesSelected.append(enemyIndex)
                    enemyIndicesPool.remove(enemyIndex)

                enemyIndicesSelected.sort()
            treasureIndicesPool = []
            treasureValuePool = []
            for value in xrange(1, 5):
                treasureValuePool += [value] * ToonBlitzGlobals.TreasureValueProbability[value]

            treasureIndicesSelected = []
            if treasuresPool != None:
                minTreasures, maxTreasures = attribs[8]
                for i in xrange(len(treasuresPool)):
                    treasureIndicesPool += [i]

                numTreasures = maxTreasures * ToonBlitzGlobals.PercentMaxTreasures[szId] / 100
                numTreasures = max(numTreasures, minTreasures)
                for i in xrange(int(numTreasures)):
                    if len(treasureIndicesPool) == 0:
                        break
                    treasureIndex = random.choice(treasureIndicesPool)
                    treasureValue = random.choice(treasureValuePool)
                    treasure = (treasureIndex, treasureValue)
                    treasureIndicesPool.remove(treasureIndex)
                    treasureIndicesSelected.append(treasure)

                treasureIndicesSelected.sort()
            spawnPointIndicesPool = []
            spawnPointIndicesSelected = []
            if spawnPointsPool != None:
                minSpawnPoints, maxSpawnPoints = attribs[9]
                for i in xrange(len(spawnPointsPool)):
                    spawnPointIndicesPool += [i]

                numSpawnPoints = maxSpawnPoints * ToonBlitzGlobals.PercentMaxSpawnPoints[szId] / 100
                numSpawnPoints = max(numSpawnPoints, minSpawnPoints)
                for i in xrange(int(numSpawnPoints)):
                    if len(spawnPointIndicesPool) == 0:
                        break
                    spawnPoint = random.choice(spawnPointIndicesPool)
                    spawnPointIndicesSelected.append(spawnPoint)
                    spawnPointIndicesPool.remove(spawnPoint)

                spawnPointIndicesSelected.sort()
            stomperIndicesPool = []
            stomperIndicesSelected = []
            if stompersPool != None:
                minStompers, maxStompers = attribs[10]
                for i in xrange(len(stompersPool)):
                    stomperIndicesPool += [i]

                numStompers = maxStompers * ToonBlitzGlobals.PercentMaxStompers[szId] / 100
                numStompers = max(numStompers, minStompers)
                for i in xrange(int(numStompers)):
                    if len(stomperIndicesPool) == 0:
                        break
                    stomper = random.choice(stomperIndicesPool)
                    stomperIndicesSelected.append(stomper)
                    stomperIndicesPool.remove(stomper)

                stomperIndicesSelected.sort()
            sctionTuple = (sectionIndex,
             enemyIndicesSelected,
             treasureIndicesSelected,
             spawnPointIndicesSelected,
             stomperIndicesSelected)
            self.sectionsSelected.append(sctionTuple)

        return

    def getSectionsSelected(self):
        return self.sectionsSelected
Exemplo n.º 25
0
class DistributedCatchGameAI(DistributedMinigameAI):

    def __init__(self, air, minigameId):
        try:
            self.DistributedCatchGameAI_initialized
        except:
            self.DistributedCatchGameAI_initialized = 1
            DistributedMinigameAI.__init__(self, air, minigameId)
            self.gameFSM = ClassicFSM.ClassicFSM('DistributedCatchGameAI', [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)

    def generate(self):
        self.notify.debug('generate')
        DistributedMinigameAI.generate(self)

    def delete(self):
        self.notify.debug('delete')
        del self.gameFSM
        DistributedMinigameAI.delete(self)

    def setGameReady(self):
        self.notify.debug('setGameReady')
        DistributedMinigameAI.setGameReady(self)

    def setGameStart(self, timestamp):
        self.notify.debug('setGameStart')
        DistributedMinigameAI.setGameStart(self, timestamp)
        self.gameFSM.request('play')

    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.notify.debug('fruits: %s, fruits caught: %s' % (self.numFruits, self.fruitsCaught))
        perfect = self.fruitsCaught >= self.numFruits
        for avId in self.avIdList:
            self.scoreDict[avId] = max(1, int(self.scoreDict[avId] / 2))
            if perfect:
                self.notify.debug('PERFECT GAME!')
                self.scoreDict[avId] += round(self.numFruits / 4.0)
                self.logAllPerfect()

        self.gameFSM.request('cleanup')
        DistributedMinigameAI.gameOver(self)

    def enterInactive(self):
        self.notify.debug('enterInactive')

    def exitInactive(self):
        pass

    def enterPlay(self):
        self.notify.debug('enterPlay')
        self.caughtList = [0] * 100
        table = CatchGameGlobals.NumFruits[self.numPlayers - 1]
        self.numFruits = table[self.getSafezoneId()]
        self.notify.debug('numFruits: %s' % self.numFruits)
        self.fruitsCaught = 0

        def allToonsDone(self = self):
            self.notify.debug('allToonsDone')
            self.sendUpdate('setEveryoneDone')
            if not CatchGameGlobals.EndlessGame:
                self.gameOver()

        def handleTimeout(avIds, self = self):
            self.notify.debug('handleTimeout: avatars %s did not report "done"' % avIds)
            self.setGameAbort()

        self.doneBarrier = ToonBarrier('waitClientsDone', self.uniqueName('waitClientsDone'), self.avIdList, CatchGameGlobals.GameDuration + MinigameGlobals.latencyTolerance, allToonsDone, handleTimeout)

    def exitPlay(self):
        del self.caughtList
        self.doneBarrier.cleanup()
        del self.doneBarrier

    def claimCatch(self, objNum, DropObjTypeId):
        if self.gameFSM.getCurrentState().getName() != 'play':
            return
        if DropObjTypeId < 0 or DropObjTypeId >= len(CatchGameGlobals.DOTypeId2Name):
            self.air.writeServerEvent('warning', DropObjTypeId, 'CatchGameAI.claimCatch DropObjTypeId out of range')
            return
        if objNum < 0 or objNum > 5000 or objNum >= 2 * len(self.caughtList):
            self.air.writeServerEvent('warning', objNum, 'CatchGameAI.claimCatch objNum is too high or negative')
            return
        if objNum >= len(self.caughtList):
            self.caughtList += [0] * len(self.caughtList)
        if not self.caughtList[objNum]:
            self.caughtList[objNum] = 1
            avId = self.air.getAvatarIdFromSender()
            self.sendUpdate('setObjectCaught', [avId, objNum])
            objName = CatchGameGlobals.DOTypeId2Name[DropObjTypeId]
            self.notify.debug('avatar %s caught object %s: %s' % (avId, objNum, objName))
            if CatchGameGlobals.Name2DropObjectType[objName].good:
                self.scoreDict[avId] += 1
                self.fruitsCaught += 1

    def reportDone(self):
        if not self.gameFSM or not self.gameFSM.getCurrentState() or self.gameFSM.getCurrentState().getName() != 'play':
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('reportDone: avatar %s is done' % avId)
        self.doneBarrier.clear(avId)

    def enterCleanup(self):
        self.notify.debug('enterCleanup')
        self.gameFSM.request('inactive')

    def exitCleanup(self):
        pass
 def enterWaitClientsReady(self):
     self.notify.debug('enterWaitClientsReady')
     self.nextRoundBarrier = ToonBarrier('nextRoundReady', self.uniqueName('nextRoundReady'), self.avIdList, PatternGameGlobals.ClientsReadyTimeout, self.__allPlayersReady, self.__clientsReadyTimeout)
     for avId in self.readyClients:
         self.nextRoundBarrier.clear(avId)
class DistributedPatternGameAI(DistributedMinigameAI):
    def __init__(self, air, minigameId):
        try:
            self.DistributedPatternGameAI_initialized
        except:
            self.DistributedPatternGameAI_initialized = 1
            DistributedMinigameAI.__init__(self, air, minigameId)
            self.gameFSM = ClassicFSM.ClassicFSM('DistributedPatternGameAI', [
                State.State('off', self.enterInactive, self.exitInactive,
                            ['waitClientsReady', 'cleanup']),
                State.State('waitClientsReady', self.enterWaitClientsReady,
                            self.exitWaitClientsReady,
                            ['generatePattern', 'cleanup']),
                State.State('generatePattern', self.enterGeneratePattern,
                            self.exitGeneratePattern,
                            ['waitForResults', 'cleanup']),
                State.State('waitForResults', self.enterWaitForResults,
                            self.exitWaitForResults,
                            ['waitClientsReady', 'cleanup']),
                State.State('cleanup', self.enterCleanup, self.exitCleanup, [])
            ], 'off', 'cleanup')
            self.addChildGameFSM(self.gameFSM)

    def delete(self):
        self.notify.debug('delete')
        del self.gameFSM
        DistributedMinigameAI.delete(self)

    def setGameReady(self):
        self.notify.debug('setGameReady')
        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.pattern = []
        self.round = 0
        self.perfectResults = {}
        for avId in self.avIdList:
            self.perfectResults[avId] = 1

        self.readyClients = []
        self.timeoutTaskName = self.uniqueName('PatternGameResultsTimeout')

    def enterWaitClientsReady(self):
        self.notify.debug('enterWaitClientsReady')
        self.nextRoundBarrier = ToonBarrier(
            'nextRoundReady', self.uniqueName('nextRoundReady'), self.avIdList,
            PatternGameGlobals.ClientsReadyTimeout, self.__allPlayersReady,
            self.__clientsReadyTimeout)
        for avId in self.readyClients:
            self.nextRoundBarrier.clear(avId)

    def reportPlayerReady(self):
        if not self._inState('waitClientsReady'):
            return
        avId = self.air.getAvatarIdFromSender()
        if avId not in self.avIdList:
            self.notify.warning(
                'Got reportPlayerReady from an avId: %s not in our list: %s' %
                (avId, self.avIdList))
        else:
            self.readyClients.append(avId)
            self.nextRoundBarrier.clear(avId)

    def __allPlayersReady(self):
        self.readyClients = []
        self.gameFSM.request('generatePattern')

    def __clientsReadyTimeout(self, avIds):
        self.notify.debug(
            '__clientsReadyTimeout: clients %s have not responded' % avIds)
        self.setGameAbort()

    def exitWaitClientsReady(self):
        self.nextRoundBarrier.cleanup()
        del self.nextRoundBarrier

    def enterGeneratePattern(self):
        self.notify.debug('enterGeneratePattern')
        self.round += 1
        targetLen = PatternGameGlobals.INITIAL_ROUND_LENGTH + PatternGameGlobals.ROUND_LENGTH_INCREMENT * (
            self.round - 1)
        count = targetLen - len(self.pattern)
        for i in xrange(0, count):
            self.pattern.append(random.randint(0, 3))

        self.gameFSM.request('waitForResults')
        self.sendUpdate('setPattern', [self.pattern])

    def exitGeneratePattern(self):
        pass

    def enterWaitForResults(self):
        self.notify.debug('enterWaitForResults')
        self.results = [None] * self.numPlayers
        self.fastestTime = PatternGameGlobals.InputTime * 2
        self.fastestAvId = 0
        self.resultsBarrier = ToonBarrier(
            'results', self.uniqueName('results'), self.avIdList,
            PatternGameGlobals.InputTimeout + 1.0 * self.round,
            self.__gotAllPatterns, self.__resultsTimeout)
        return

    def reportButtonPress(self, index, wrong):
        if not self._inState('waitForResults'):
            return
        avId = self.air.getAvatarIdFromSender()
        if avId not in self.avIdList:
            self.air.writeServerEvent(
                'suspicious', avId,
                'PatternGameAI.reportButtonPress avId not on list')
            return
        if index < 0 or index > 3:
            self.air.writeServerEvent(
                'warning', index,
                'PatternGameAI.reportButtonPress got bad index')
            return
        if wrong not in [0, 1]:
            self.air.writeServerEvent(
                'warning', wrong,
                "PatternGameAI.reportButtonPress got bad 'wrong'")
            return
        self.sendUpdate('remoteButtonPressed', [avId, index, wrong])

    def __resultsTimeout(self, avIds):
        self.notify.debug('__resultsTimeout: %s' % avIds)
        for avId in avIds:
            index = self.avIdList.index(avId)
            self.__acceptPlayerPattern(avId, [],
                                       PatternGameGlobals.InputTime * 2)

        self.__gotAllPatterns()

    def reportPlayerPattern(self, pattern, totalTime):
        if not self._inState('waitForResults'):
            return
        avId = self.air.getAvatarIdFromSender()
        self.__acceptPlayerPattern(avId, pattern, totalTime)
        self.resultsBarrier.clear(avId)

    def __acceptPlayerPattern(self, avId, pattern, totalTime):
        index = self.avIdList.index(avId)
        if self.results[index] != None:
            return
        self.results[index] = pattern
        if totalTime < self.fastestTime and pattern == self.pattern:
            self.fastestTime = totalTime
            self.fastestAvId = avId
            if self.numPlayers == 1:
                self.fastestAvId = 1
            else:
                self.scoreDict[self.fastestAvId] += 2
        return

    def __gotAllPatterns(self):
        patterns = [[]] * 4
        for i in xrange(0, len(self.results)):
            patterns[i] = self.results[i]
            if patterns[i] is None:
                patterns[i] = []

        self.sendUpdate('setPlayerPatterns', patterns + [self.fastestAvId])
        for i in xrange(0, self.numPlayers):
            avId = self.avIdList[i]
            if not self.results[i] == self.pattern:
                self.perfectResults[avId] = 0
            else:
                self.scoreDict[avId] += self.round

        if self.round < PatternGameGlobals.NUM_ROUNDS:
            self.gameFSM.request('waitClientsReady')
        else:
            for avId in self.avIdList:
                if self.perfectResults[avId]:
                    self.scoreDict[avId] += 4
                    self.logPerfectGame(avId)

            self.gameOver()
            self.gameFSM.request('cleanup')
        return

    def exitWaitForResults(self):
        self.resultsBarrier.cleanup()
        del self.resultsBarrier

    def enterCleanup(self):
        self.notify.debug('enterCleanup')

    def exitCleanup(self):
        pass
class DistributedPatternGameAI(DistributedMinigameAI):

    def __init__(self, air, minigameId):
        try:
            self.DistributedPatternGameAI_initialized
        except:
            self.DistributedPatternGameAI_initialized = 1
            DistributedMinigameAI.__init__(self, air, minigameId)
            self.gameFSM = ClassicFSM.ClassicFSM('DistributedPatternGameAI', [State.State('off', self.enterInactive, self.exitInactive, ['waitClientsReady', 'cleanup']),
             State.State('waitClientsReady', self.enterWaitClientsReady, self.exitWaitClientsReady, ['generatePattern', 'cleanup']),
             State.State('generatePattern', self.enterGeneratePattern, self.exitGeneratePattern, ['waitForResults', 'cleanup']),
             State.State('waitForResults', self.enterWaitForResults, self.exitWaitForResults, ['waitClientsReady', 'cleanup']),
             State.State('cleanup', self.enterCleanup, self.exitCleanup, [])], 'off', 'cleanup')
            self.addChildGameFSM(self.gameFSM)

    def delete(self):
        self.notify.debug('delete')
        del self.gameFSM
        DistributedMinigameAI.delete(self)

    def setGameReady(self):
        self.notify.debug('setGameReady')
        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.pattern = []
        self.round = 0
        self.perfectResults = {}
        for avId in self.avIdList:
            self.perfectResults[avId] = 1

        self.readyClients = []
        self.timeoutTaskName = self.uniqueName('PatternGameResultsTimeout')

    def enterWaitClientsReady(self):
        self.notify.debug('enterWaitClientsReady')
        self.nextRoundBarrier = ToonBarrier('nextRoundReady', self.uniqueName('nextRoundReady'), self.avIdList, PatternGameGlobals.ClientsReadyTimeout, self.__allPlayersReady, self.__clientsReadyTimeout)
        for avId in self.readyClients:
            self.nextRoundBarrier.clear(avId)

    def reportPlayerReady(self):
        if not self._inState('waitClientsReady'):
            return
        avId = self.air.getAvatarIdFromSender()
        if avId not in self.avIdList:
            self.notify.warning('Got reportPlayerReady from an avId: %s not in our list: %s' % (avId, self.avIdList))
        else:
            self.readyClients.append(avId)
            self.nextRoundBarrier.clear(avId)

    def __allPlayersReady(self):
        self.readyClients = []
        self.gameFSM.request('generatePattern')

    def __clientsReadyTimeout(self, avIds):
        self.notify.debug('__clientsReadyTimeout: clients %s have not responded' % avIds)
        self.setGameAbort()

    def exitWaitClientsReady(self):
        self.nextRoundBarrier.cleanup()
        del self.nextRoundBarrier

    def enterGeneratePattern(self):
        self.notify.debug('enterGeneratePattern')
        self.round += 1
        targetLen = PatternGameGlobals.INITIAL_ROUND_LENGTH + PatternGameGlobals.ROUND_LENGTH_INCREMENT * (self.round - 1)
        count = targetLen - len(self.pattern)
        for i in xrange(0, count):
            self.pattern.append(random.randint(0, 3))

        self.gameFSM.request('waitForResults')
        self.sendUpdate('setPattern', [self.pattern])

    def exitGeneratePattern(self):
        pass

    def enterWaitForResults(self):
        self.notify.debug('enterWaitForResults')
        self.results = [None] * self.numPlayers
        self.fastestTime = PatternGameGlobals.InputTime * 2
        self.fastestAvId = 0
        self.resultsBarrier = ToonBarrier('results', self.uniqueName('results'), self.avIdList, PatternGameGlobals.InputTimeout + 1.0 * self.round, self.__gotAllPatterns, self.__resultsTimeout)
        return

    def reportButtonPress(self, index, wrong):
        if not self._inState('waitForResults'):
            return
        avId = self.air.getAvatarIdFromSender()
        if avId not in self.avIdList:
            self.air.writeServerEvent('suspicious', avId, 'PatternGameAI.reportButtonPress avId not on list')
            return
        if index < 0 or index > 3:
            self.air.writeServerEvent('warning', index, 'PatternGameAI.reportButtonPress got bad index')
            return
        if wrong not in [0, 1]:
            self.air.writeServerEvent('warning', wrong, "PatternGameAI.reportButtonPress got bad 'wrong'")
            return
        self.sendUpdate('remoteButtonPressed', [avId, index, wrong])

    def __resultsTimeout(self, avIds):
        self.notify.debug('__resultsTimeout: %s' % avIds)
        for avId in avIds:
            index = self.avIdList.index(avId)
            self.__acceptPlayerPattern(avId, [], PatternGameGlobals.InputTime * 2)

        self.__gotAllPatterns()

    def reportPlayerPattern(self, pattern, totalTime):
        if not self._inState('waitForResults'):
            return
        avId = self.air.getAvatarIdFromSender()
        self.__acceptPlayerPattern(avId, pattern, totalTime)
        self.resultsBarrier.clear(avId)

    def __acceptPlayerPattern(self, avId, pattern, totalTime):
        index = self.avIdList.index(avId)
        if self.results[index] != None:
            return
        self.results[index] = pattern
        if totalTime < self.fastestTime and pattern == self.pattern:
            self.fastestTime = totalTime
            self.fastestAvId = avId
            if self.numPlayers == 1:
                self.fastestAvId = 1
            else:
                self.scoreDict[self.fastestAvId] += 2
        return

    def __gotAllPatterns(self):
        patterns = [[]] * 4
        for i in xrange(0, len(self.results)):
            patterns[i] = self.results[i]
            if patterns[i] is None:
                patterns[i] = []

        self.sendUpdate('setPlayerPatterns', patterns + [self.fastestAvId])
        for i in xrange(0, self.numPlayers):
            avId = self.avIdList[i]
            if not self.results[i] == self.pattern:
                self.perfectResults[avId] = 0
            else:
                self.scoreDict[avId] += self.round

        if self.round < PatternGameGlobals.NUM_ROUNDS:
            self.gameFSM.request('waitClientsReady')
        else:
            for avId in self.avIdList:
                if self.perfectResults[avId]:
                    self.scoreDict[avId] += 4
                    self.logPerfectGame(avId)

            self.gameOver()
            self.gameFSM.request('cleanup')
        return

    def exitWaitForResults(self):
        self.resultsBarrier.cleanup()
        del self.resultsBarrier

    def enterCleanup(self):
        self.notify.debug('enterCleanup')

    def exitCleanup(self):
        pass
Exemplo n.º 29
0
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 src.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)
                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))
            
    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))
            
    def addAimTime(self, avId, aimTime):
        if avId in self.aimTimes:
            self.aimTimes[avId] += aimTime