text: from otp.level.BasicEntities import DistributedNodePathEntity
  from panda3d.core import *
  from direct.interval.IntervalGlobal import *
  from toontown.toonbase.ToontownGlobals import *
  import random
  from direct.directnotify import DirectNotifyGlobal
  from direct.distributed.ClockDelta import globalClockDelta
  import DistributedBarrelBase
  from otp.level.BasicEntities import DistributedNodePathEntity
  from toontown.toonbase import ToontownGlobals
  from toontown.toonbase import TTLocalizer
  from toontown.toonbase import ToontownTimer
  from direct.task import Task
  from direct.gui.DirectGui import DGG, DirectFrame, DirectLabel
  
  class DistributedMaze(DistributedNodePathEntity):
      notify = DirectNotifyGlobal.directNotify.newCategory('DistributedMaze')
      ScheduleTaskName = 'mazeScheduler'
      RemoveBlocksDict = {2: ('HedgeBlock_0_1',),
       4: (('HedgeBlock_0_1', 'HedgeBlock_1_3', 'HedgeBlock_2_3'), ('HedgeBlock_0_2', 'HedgeBlock_2_3', 'HedgeBlock_1_3'), ('HedgeBlock_0_1', 'HedgeBlock_0_2', 'HedgeBlock_1_3', 'HedgeBlock_2_3'))}
  
      def __init__(self, cr):
          DistributedNodePathEntity.__init__(self, cr)
          self.numSections = 0
          self.GameDuration = 35.0 + self.numSections * 15.0
          self.timer = None
          self.frame2D = None
          self.gameLabel = None
          self.gameStarted = 0
          self.finished = 0
          self.timedOut = 0
          self.toonFinishedText = TTLocalizer.toonFinishedHedgeMaze
          self.toonEnteredText = TTLocalizer.enterHedgeMaze
          return
  
      def announceGenerate(self):
          DistributedNodePathEntity.announceGenerate(self)
          self.addHints(self.roomHold)
          self.loadGui()
  
      def disable(self):
          DistributedNodePathEntity.disable(self)
          self.unloadGui()
          self.cleanupTimer()
          self.ignoreAll()
  
      def delete(self):
          self.cleanupTimer()
          DistributedNodePathEntity.delete(self)
  
      def setRoomDoId(self, roomDoId):
          self.roomDoId = roomDoId
          room = self.cr.doId2do.get(roomDoId)
          if room:
              self.gotRoom([room])
          else:
              self.roomRequest = self.cr.relatedObjectMgr.requestObjects([roomDoId], allCallback=self.gotRoom, timeout=5)
  
      def gotRoom(self, rooms):
          self.roomRequest = None
          room = rooms[0]
          self.roomHold = room
          rotations = [0,
           0,
           90,
           90,
           180,
           180,
           270,
           270]
          self.getRng().shuffle(rotations)
          self.numSections = 0
          for i in xrange(0, 4):
              maze = room.getGeom().find('**/Maze_Inside_%d' % i)
              if not maze.isEmpty():
                  self.numSections += 1
                  if rotations:
                      maze.setH(rotations.pop())
  
          self.GameDuration = 35.0 + self.numSections * 15.0
          self.removeHedgeBlocks(room)
          return
  
      def addHints(self, room):
          self.focusPoint = self.attachNewNode('GolfGreenGameFrame')
          hintList = room.getGeom().findAllMatches('**/dead*')
          for hint in hintList:
              self.actSphere = CollisionSphere(0, 0, 0, 7.0)
              self.actSphereNode = CollisionNode('mazegame_hint-%s-%s' % (self.level.getLevelId(), self.entId))
              self.actSphereNode.addSolid(self.actSphere)
              self.actSphereNodePath = hint.attachNewNode(self.actSphereNode)
              self.actSphereNode.setCollideMask(WallBitmask)
              self.actSphere.setTangible(0)
              self.enterEvent = 'enter' + self.actSphereNode.getName()
              self.accept(self.enterEvent, self.__handleToonEnterHint)
              self.exitEvent = 'exit' + self.actSphereNode.getName()
              self.accept(self.exitEvent, self.__handleToonExitHint)
  
          enterance = room.getGeom().find('**/ENTRANCE')
          self.enterSphere = CollisionSphere(0, 0, 0, 8.0)
          self.enterSphereNode = CollisionNode('mazegame_enter-%s-%s' % (self.level.getLevelId(), self.entId))
          self.enterSphereNode.addSolid(self.enterSphere)
          self.enterSphereNodePath = enterance.attachNewNode(self.enterSphereNode)
          self.enterSphereNode.setCollideMask(WallBitmask)
          self.enterSphere.setTangible(0)
          self.enteranceEvent = 'enter' + self.enterSphereNode.getName()
          self.accept(self.enteranceEvent, self.__handleToonEnterance)
          finish = room.getGeom().find('**/finish')
          self.finishSphere = CollisionSphere(0, 0, 0, 15.0)
          self.finishSphereNode = CollisionNode('mazegame_finish-%s-%s' % (self.level.getLevelId(), self.entId))
          self.finishSphereNode.addSolid(self.finishSphere)
          self.finishSphereNodePath = finish.attachNewNode(self.finishSphereNode)
          self.finishSphereNode.setCollideMask(WallBitmask)
          self.finishSphere.setTangible(0)
          self.finishEvent = 'enter' + self.finishSphereNode.getName()
          self.accept(self.finishEvent, self.__handleToonFinish)
  
      def __handleToonEnterance(self, collEntry):
          if not self.gameStarted:
              self.notify.debug('sending clientTriggered for %d' % self.doId)
              self.sendUpdate('setClientTriggered', [])
              self.level.countryClub.showInfoText(self.toonEnteredText)
  
      def __handleToonFinish(self, collEntry):
          self.sendUpdate('setFinishedMaze', [])
          self.finished = 1
  
      def __handleToonEnterHint(self, collEntry):
          camHeight = base.localAvatar.getClampedAvatarHeight()
          heightScaleFactor = camHeight * 0.3333333333
          defLookAt = Point3(0.0, 1.5, camHeight)
          cameraPoint = Point3(0.0, -22.0 * heightScaleFactor, camHeight + 54.0)
          base.localAvatar.stopUpdateSmartCamera()
          base.localAvatar.startUpdateSmartCamera(push=0)
          base.localAvatar.setIdealCameraPos(cameraPoint)
  
      def __handleToonExitHint(self, collEntry):
          base.localAvatar.stopUpdateSmartCamera()
          base.localAvatar.startUpdateSmartCamera()
          base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex)
          self.cameraHold = None
          return
  
      def getRng(self):
          return random.Random(self.entId * self.doId)
  
      def removeHedgeBlocks(self, room):
          if self.numSections in self.RemoveBlocksDict:
              blocksToRemove = self.getRng().choice(self.RemoveBlocksDict[self.numSections])
              for blockName in blocksToRemove:
                  block = room.getGeom().find('**/%s' % blockName)
                  if not block.isEmpty():
                      block.removeNode()
  
      def setGameStart(self, timestamp):
          self.notify.debug('%d setGameStart: Starting game' % self.doId)
          self.gameStartTime = globalClockDelta.networkToLocalTime(timestamp)
          self.gameStarted = True
          curGameTime = self.getCurrentGameTime()
          timeLeft = self.GameDuration - curGameTime
          self.cleanupTimer()
          self.timer = ToontownTimer.ToontownTimer()
          self.timer.posBelowTopRightCorner()
          self.timer.setTime(timeLeft)
          self.timer.countdown(timeLeft, self.timerExpired)
          self.startScheduleTask()
          self.frame2D.show()
  
      def setGameOver(self):
          self.timedOut = 1
          if not self.finished:
              self.sendUpdate('damageMe', [])
              roomNum = self.level.roomNum
              club = self.level.countryClub
              self.gameOverTrack = Sequence()
              self.gameOverTrack.append(localAvatar.getTeleportOutTrack())
              self.gameOverTrack.append(Func(localAvatar.setPos, self.finishSphereNodePath.getPos(render)))
              self.gameOverTrack.append(Func(localAvatar.play, 'jump'))
              self.gameOverTrack.append(Func(self.level.countryClub.camEnterRoom, roomNum))
              self.gameOverTrack.start()
          self.timerExpired()
  
      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 startScheduleTask(self):
          taskMgr.add(self.scheduleTask, self.ScheduleTaskName)
  
      def stopScheduleTask(self):
          taskMgr.remove(self.ScheduleTaskName)
  
      def scheduleTask(self, task):
          curTime = self.getCurrentGameTime()
  
      def cleanupTimer(self):
          if self.timer:
              self.timer.stop()
              self.timer.destroy()
              self.timer = None
          return
  
      def timerExpired(self):
          self.cleanupTimer()
          self.unloadGui()
  
      def loadGui(self):
          self.frame2D = DirectFrame(scale=1.0, pos=(0.0, 0, 0.9), relief=DGG.FLAT, parent=aspect2d, frameSize=(-0.3,
           0.3,
           -0.05,
           0.05), frameColor=(0.737, 0.573, 0.345, 0.3))
          self.frame2D.hide()
          self.gameLabel = DirectLabel(parent=self.frame2D, relief=None, pos=(0, 0, 0), scale=1.0, text=TTLocalizer.mazeLabel, text_font=ToontownGlobals.getSignFont(), text0_fg=(1, 1, 1, 1), text_scale=0.075, text_pos=(0, -0.02))
          return
  
      def unloadGui(self):
          if self.frame2D:
              self.frame2D.destroy()
          self.frame2D = None
          if self.gameLabel:
              self.gameLabel.destroy()
          self.gameLabel = None
          return
  
      def toonFinished(self, avId, place, lastToon):
          toon = base.cr.doId2do.get(avId)
          if toon and not self.timedOut:
              self.level.countryClub.showInfoText(self.toonFinishedText % (toon.getName(), TTLocalizer.hedgeMazePlaces[place]))
          if lastToon:
              self.setGameOver()
  