Esempio n. 1
0
    def scheduleDrops(self, genId = None):
        if genId is None:
            genId = self.getCurGeneration()
        gen = self._id2gen[genId]
        if gen.hasBeenScheduled:
            return
        fruitIndex = int((gen.startTime + 0.5 * self.DropPeriod) / PartyGlobals.CatchActivityDuration)
        fruitNames = ['apple',
         'orange',
         'pear',
         'coconut',
         'watermelon',
         'pineapple']
        fruitName = fruitNames[fruitIndex % len(fruitNames)]
        rng = RandomNumGen(genId + self._generationSeedBase)
        gen.droppedObjNames = [fruitName] * self.numFruits + ['anvil'] * self.numAnvils
        rng.shuffle(gen.droppedObjNames)
        dropPlacer = PartyRegionDropPlacer(self, gen.numPlayers, genId, gen.droppedObjNames, startTime=gen.startTime)
        gen.numItemsDropped = 0
        tIndex = gen.startTime % PartyGlobals.CatchActivityDuration
        tPercent = float(tIndex) / PartyGlobals.CatchActivityDuration
        gen.numItemsDropped += dropPlacer.skipPercent(tPercent)
        while not dropPlacer.doneDropping(continuous=True):
            nextDrop = dropPlacer.getNextDrop()
            gen.dropSchedule.append(nextDrop)

        gen.hasBeenScheduled = True
        return
    def startSuitWalkTask(self):
        ival = Parallel(name='catchGameMetaSuitWalk')
        rng = RandomNumGen(self.randomNumGen)
        delay = 0.0
        while delay < CatchGameGlobals.GameDuration:
            delay += lerp(self.SuitPeriodRange[0], self.SuitPeriodRange[0], rng.random())
            walkIval = Sequence(name='catchGameSuitWalk')
            walkIval.append(Wait(delay))

            def pickY(self = self, rng = rng):
                return lerp(-self.StageHalfHeight, self.StageHalfHeight, rng.random())

            m = [2.5,
             2.5,
             2.3,
             2.1][self.getNumPlayers() - 1]
            startPos = Point3(-(self.StageHalfWidth * m), pickY(), 0)
            stopPos = Point3(self.StageHalfWidth * m, pickY(), 0)
            if rng.choice([0, 1]):
                startPos, stopPos = stopPos, startPos
            walkIval.append(self.getSuitWalkIval(startPos, stopPos, rng))
            ival.append(walkIval)

        ival.start()
        self.suitWalkIval = ival
    def scheduleDrops(self, genId = None):
        if genId is None:
            genId = self.getCurGeneration()
        gen = self._id2gen[genId]
        if gen.hasBeenScheduled:
            return
        fruitIndex = int((gen.startTime + 0.5 * self.DropPeriod) / PartyGlobals.CatchActivityDuration)
        fruitNames = ['apple',
         'orange',
         'pear',
         'coconut',
         'watermelon',
         'pineapple']
        fruitName = fruitNames[fruitIndex % len(fruitNames)]
        rng = RandomNumGen(genId + self._generationSeedBase)
        gen.droppedObjNames = [fruitName] * self.numFruits + ['anvil'] * self.numAnvils
        rng.shuffle(gen.droppedObjNames)
        dropPlacer = PartyRegionDropPlacer(self, gen.numPlayers, genId, gen.droppedObjNames, startTime=gen.startTime)
        gen.numItemsDropped = 0
        tIndex = gen.startTime % PartyGlobals.CatchActivityDuration
        tPercent = float(tIndex) / PartyGlobals.CatchActivityDuration
        gen.numItemsDropped += dropPlacer.skipPercent(tPercent)
        while not dropPlacer.doneDropping(continuous=True):
            nextDrop = dropPlacer.getNextDrop()
            gen.dropSchedule.append(nextDrop)

        gen.hasBeenScheduled = True
        return
Esempio n. 4
0
 def __init__(self, serialNum, maze, randomNumGen, cellWalkPeriod, difficulty, suitDnaName = 'f', startTile = None, ticFreq = MazeGameGlobals.SUIT_TIC_FREQ, walkSameDirectionProb = MazeGameGlobals.WALK_SAME_DIRECTION_PROB, walkTurnAroundProb = MazeGameGlobals.WALK_TURN_AROUND_PROB, uniqueRandomNumGen = True, walkAnimName = None):
     self.serialNum = serialNum
     self.maze = maze
     if uniqueRandomNumGen:
         self.rng = RandomNumGen(randomNumGen)
     else:
         self.rng = randomNumGen
     self.difficulty = difficulty
     self._walkSameDirectionProb = walkSameDirectionProb
     self._walkTurnAroundProb = walkTurnAroundProb
     self._walkAnimName = walkAnimName or 'walk'
     self.suit = Suit.Suit()
     d = SuitDNA.SuitDNA()
     d.newSuit(suitDnaName)
     self.suit.setDNA(d)
     self.suit.nametag.setNametag2d(None)
     self.suit.nametag.setNametag3d(None)
     if startTile is None:
         defaultStartPos = MazeGameGlobals.SUIT_START_POSITIONS[self.serialNum]
         self.startTile = (defaultStartPos[0] * self.maze.width, defaultStartPos[1] * self.maze.height)
     else:
         self.startTile = startTile
     self.ticFreq = ticFreq
     self.ticPeriod = int(cellWalkPeriod)
     self.cellWalkDuration = float(self.ticPeriod) / float(self.ticFreq)
     self.turnDuration = 0.6 * self.cellWalkDuration
     return
Esempio n. 5
0
    def startSuitWalkTask(self):
        ival = Parallel(name='catchGameMetaSuitWalk')
        rng = RandomNumGen(self.randomNumGen)
        delay = 0.0
        while delay < CatchGameGlobals.GameDuration:
            delay += lerp(self.SuitPeriodRange[0], self.SuitPeriodRange[0],
                          rng.random())
            walkIval = Sequence(name='catchGameSuitWalk')
            walkIval.append(Wait(delay))

            def pickY(self=self, rng=rng):
                return lerp(-(self.StageHalfHeight), self.StageHalfHeight,
                            rng.random())

            m = [2.5, 2.5, 2.2999999999999998,
                 2.1000000000000001][self.getNumPlayers() - 1]
            startPos = Point3(-(self.StageHalfWidth * m), pickY(), 0)
            stopPos = Point3(self.StageHalfWidth * m, pickY(), 0)
            if rng.choice([0, 1]):
                startPos = stopPos
                stopPos = startPos

            walkIval.append(self.getSuitWalkIval(startPos, stopPos, rng))
            ival.append(walkIval)
        ival.start()
        self.suitWalkIval = ival
Esempio n. 6
0
 def __init__(self, randomNumGen, width, height, frameWallThickness=Globals.FrameWallThickness, cogdoMazeData=CogdoMazeData):
     self._rng = RandomNumGen(randomNumGen)
     self.width = width
     self.height = height
     self.frameWallThickness = frameWallThickness
     self._cogdoMazeData = cogdoMazeData
     self.quadrantSize = self._cogdoMazeData.QuadrantSize
     self.cellWidth = self._cogdoMazeData.QuadrantCellWidth
Esempio n. 7
0
 def generate(self):
     DistributedPartyActivity.generate(self)
     self.notify.info('localAvatar doId: %s' % base.localAvatar.doId)
     self.notify.info('generate()')
     self._generateFrame = globalClock.getFrameCount()
     self._id2gen = {}
     self._orderedGenerations = []
     self._orderedGenerationIndex = None
     rng = RandomNumGen(self.doId)
     self._generationSeedBase = rng.randrange(1000)
     self._lastDropTime = 0.0
 def generate(self):
     DistributedPartyActivity.generate(self)
     self.notify.info('localAvatar doId: %s' % base.localAvatar.doId)
     self.notify.info('generate()')
     self._generateFrame = globalClock.getFrameCount()
     self._id2gen = {}
     self._orderedGenerations = []
     self._orderedGenerationIndex = None
     rng = RandomNumGen(self.doId)
     self._generationSeedBase = rng.randrange(1000)
     self._lastDropTime = 0.0
     return
Esempio n. 9
0
    def __init__(self, editorFile, bakeryFolder):
        #id is a seed for the map and unique name for any cached heightmap images

        self.dice = RandomNumGen(TimeVal().getUsec())
        self.id = self.dice.randint(2, 1000000)

        # the overall smoothness/roughness of the terrain
        smoothness = 80
        # how quickly altitude and roughness shift
        self.consistency = smoothness * 8
        # waterHeight is expressed as a multiplier to the max height
        self.waterHeight = 0.3
        # for realism the flatHeight should be at or very close to waterHeight
        self.flatHeight = self.waterHeight + 0.04

        #creates noise objects that will be used by the getHeight function
        """Create perlin noise."""

        # See getHeight() for more details....

        # where perlin 1 is low terrain will be mostly low and flat
        # where it is high terrain will be higher and slopes will be exagerrated
        # increase perlin1 to create larger areas of geographic consistency
        self.perlin1 = StackedPerlinNoise2()
        perlin1a = PerlinNoise2(0, 0, 256, seed=self.id)
        perlin1a.setScale(self.consistency)
        self.perlin1.addLevel(perlin1a)
        perlin1b = PerlinNoise2(0, 0, 256, seed=self.id * 2 + 123)
        perlin1b.setScale(self.consistency / 2)
        self.perlin1.addLevel(perlin1b, 1 / 2)


        # perlin2 creates the noticeable noise in the terrain
        # without perlin2 everything would look unnaturally smooth and regular
        # increase perlin2 to make the terrain smoother
        self.perlin2 = StackedPerlinNoise2()
        frequencySpread = 3.0
        amplitudeSpread = 3.4
        perlin2a = PerlinNoise2(0, 0, 256, seed=self.id * 2)
        perlin2a.setScale(smoothness)
        self.perlin2.addLevel(perlin2a)
        perlin2b = PerlinNoise2(0, 0, 256, seed=self.id * 3 + 3)
        perlin2b.setScale(smoothness / frequencySpread)
        self.perlin2.addLevel(perlin2b, 1 / amplitudeSpread)
        perlin2c = PerlinNoise2(0, 0, 256, seed=self.id * 4 + 4)
        perlin2c.setScale(smoothness / (frequencySpread * frequencySpread))
        self.perlin2.addLevel(perlin2c, 1 / (amplitudeSpread * amplitudeSpread))
        perlin2d = PerlinNoise2(0, 0, 256, seed=self.id * 5 + 5)
        perlin2d.setScale(smoothness / (math.pow(frequencySpread, 3)))
        self.perlin2.addLevel(perlin2d, 1 / (math.pow(amplitudeSpread, 3)))
        perlin2e = PerlinNoise2(0, 0, 256, seed=self.id * 6 + 6)
        perlin2e.setScale(smoothness / (math.pow(frequencySpread, 4)))
        self.perlin2.addLevel(perlin2e, 1 / (math.pow(amplitudeSpread, 4)))
 def __init__(self,
              parent,
              quadLengthUnits,
              quadVisibilityAhead,
              quadVisibiltyBehind,
              rng=None):
     self.parent = parent
     self.quadLengthUnits = quadLengthUnits
     self.quadVisibiltyAhead = quadVisibilityAhead
     self.quadVisibiltyBehind = quadVisibiltyBehind
     if not rng:
         pass
     self._rng = RandomNumGen(1)
     self._level = None
Esempio n. 11
0
 def __init__(self, serialNum, maze, randomNumGen, cellWalkPeriod, difficulty, suitDnaName = 'f', startTile = None, ticFreq = MazeGameGlobals.SUIT_TIC_FREQ, walkSameDirectionProb = MazeGameGlobals.WALK_SAME_DIRECTION_PROB, walkTurnAroundProb = MazeGameGlobals.WALK_TURN_AROUND_PROB, uniqueRandomNumGen = True, walkAnimName = None):
     self.serialNum = serialNum
     self.maze = maze
     if uniqueRandomNumGen:
         self.rng = RandomNumGen(randomNumGen)
     else:
         self.rng = randomNumGen
     self.difficulty = difficulty
     self._walkSameDirectionProb = walkSameDirectionProb
     self._walkTurnAroundProb = walkTurnAroundProb
     if not walkAnimName:
         pass
     self._walkAnimName = 'walk'
     self.suit = Suit.Suit()
     d = SuitDNA.SuitDNA()
     d.newSuit(suitDnaName)
     self.suit.setDNA(d)
     if startTile is None:
         defaultStartPos = MazeGameGlobals.SUIT_START_POSITIONS[self.serialNum]
         self.startTile = (defaultStartPos[0] * self.maze.width, defaultStartPos[1] * self.maze.height)
     else:
         self.startTile = startTile
     self.ticFreq = ticFreq
     self.ticPeriod = int(cellWalkPeriod)
     self.cellWalkDuration = float(self.ticPeriod) / float(self.ticFreq)
     self.turnDuration = 0.59999999999999998 * self.cellWalkDuration
 def __init__(self, parent, quadLengthUnits, quadVisibilityAhead, quadVisibiltyBehind, rng = None):
     self._parent = parent
     self.quadLengthUnits = quadLengthUnits
     self.quadVisibiltyAhead = quadVisibilityAhead
     self.quadVisibiltyBehind = quadVisibiltyBehind
     self._rng = rng or RandomNumGen(1)
     self.isOrg = self._rng.randint(0, 1)
     self._level = None
 def __init__(self, randomNumGen, width, height, frameWallThickness = Globals.FrameWallThickness, cogdoMazeData = CogdoMazeData):
     self._rng = RandomNumGen(randomNumGen)
     self.width = width
     self.height = height
     self.frameWallThickness = frameWallThickness
     self._cogdoMazeData = cogdoMazeData
     self.quadrantSize = self._cogdoMazeData.QuadrantSize
     self.cellWidth = self._cogdoMazeData.QuadrantCellWidth
Esempio n. 14
0
 def __init__(self, maze, exit, rng):
     CogdoGameMovie.__init__(self)
     self._maze = maze
     self._exit = exit
     self._rng = RandomNumGen(rng)
     self._camTarget = None
     self._state = 0
     self._suits = []
    def createRandomSpotsList(self, numSpots, randomNumGen):
        randomNumGen = RandomNumGen(randomNumGen)
        width = self.width
        height = self.height
        halfWidth = int(width / 2)
        halfHeight = int(height / 2)
        quadrants = [(0,
          0,
          halfWidth - 1,
          halfHeight - 1),
         (halfWidth,
          0,
          width - 1,
          halfHeight - 1),
         (0,
          halfHeight,
          halfWidth - 1,
          height - 1),
         (halfWidth,
          halfHeight,
          width - 1,
          height - 1)]
        spotsTaken = []

        def getEmptySpotInQuadrant(quadrant):
            tX = -1
            tY = -1
            while tX < 0 or not self.isWalkable(tX, tY, spotsTaken):
                tX = randomNumGen.randint(quadrant[0], quadrant[2])
                tY = randomNumGen.randint(quadrant[1], quadrant[3])

            spot = (tX, tY)
            spotsTaken.append(spot)
            return spot

        def getSpotList(length):
            randomNumGen.shuffle(quadrants)
            l = []
            remaining = length
            for quadrant in quadrants:
                for u in xrange(int(length / 4)):
                    l.append(getEmptySpotInQuadrant(quadrant))

                remaining -= int(length / 4)

            for u in xrange(remaining):
                quadrant = quadrants[randomNumGen.randint(0, len(quadrants) - 1)]
                l.append(getEmptySpotInQuadrant(quadrant))

            return l

        if type(numSpots) == tuple or type(numSpots) == list:
            spots = []
            for i in numSpots:
                spots.append(getSpotList(i))

            return spots
        return getSpotList(numSpots)
Esempio n. 16
0
 def create_pid(self):
     """
     Create a new PID
     @return: a new, unique PID
     @rtype: int
     """
     pid = None
     while not pid:
         temp_pid = RandomNumGen(int(round(time.time() * 1000))).randint(
             0, 65535)
         if temp_pid not in self.active_connections:
             pid = temp_pid
     return pid
Esempio n. 17
0
 def __init__(self,
              parent,
              quadLengthUnits,
              quadVisibilityAhead,
              quadVisibiltyBehind,
              rng=None):
     self.parent_ = parent
     self.quadLengthUnits = quadLengthUnits
     self.quadVisibiltyAhead = quadVisibilityAhead
     self.quadVisibiltyBehind = quadVisibiltyBehind
     self._rng = rng or RandomNumGen(1)
     self._level = None
     return
Esempio n. 18
0
 def load(self):
     self.accept(self.distGame.getRemoteActionEventName(),
                 self.handleRemoteAction)
     self.audioMgr = CogdoGameAudioManager(Globals.Audio.MusicFiles,
                                           Globals.Audio.SfxFiles,
                                           base.localAvatar,
                                           cutoff=Globals.Audio.Cutoff)
     factory = CogdoFlyingLevelFactory(render,
                                       Globals.Level.QuadLengthUnits,
                                       Globals.Level.QuadVisibilityAhead,
                                       Globals.Level.QuadVisibilityBehind,
                                       rng=RandomNumGen(self.distGame.doId))
     self.level = factory.createLevel(self.distGame.getSafezoneId())
     self.level.setCamera(camera)
     self.guiMgr = CogdoFlyingGuiManager(self.level)
     self.levelFog = factory.createLevelFog()
     self._initLegalEagles()
Esempio n. 19
0
    def create_game(self, pid):
        """
        Creates a game for the PID given
        @param pid: PID of player wanting to join a game
        @type pid: int
        @return: if successful
        @rtype: bool
        """
        gid = RandomNumGen(int(round(time.time() * 1000))).randint(0, 65535)

        self.notify.debug(f"[create_game] Create game {gid} for player {pid}")

        # create game
        game = Game(gid, self)
        self.games[gid] = game

        self.add_player_to_game(pid, game.gid)

        return True
 def createRandomNumGen(self):
     return RandomNumGen(self.doId)
Esempio n. 21
0
    def generateMaze(self, xsize, ysize, 
                     prevMaze = None, seed = None):
        if seed is None:
            seed = int(time.time())
        self.random = RandomNumGen(seed)

        # Delete the old maze, if any
        self.deleteMaze()

        self.xsize = xsize
        self.ysize = ysize
        self.map = []
        for sy in range(self.ysize):
            row = []
            for sx in range(self.xsize):
                zoneId = self.air.zoneAllocator.allocate()
                cell = CellAI(self.air)
                cell.setGeometry(Globals.AllDirs, sx, sy)
                cell.generateWithRequired(zoneId)
                row.append(cell)
            self.map.append(row)

        # Start by choosing a random square and a random direction.
        self.numSquares = self.xsize * self.ysize - 1
        self.paths = []
        nextStep = self.__findEmptySquare()
        self.paths.append(nextStep)
        while self.numSquares > 0:
            self.__generateMazeSteps()

        # Count up the number of walls.
        walls = []
        for row in self.map:
            for cell in row:
                walls += cell.getWalls()
        self.numWalls = len(walls)
        
        random.shuffle(walls)

        if prevMaze:
            # Put our previous art paintings up on the walls,
            # including any poster data.
            for i in range(len(prevMaze.artPaintings)):
                dir, name, color, posterData, imgData = prevMaze.artPaintings[i]
                sx, sy, wallDir = walls[i]
                cell = self.map[sy][sx]
                while posterData[0] and cell.posterDir:
                    # We've already placed a poster in this cell.  Go
                    # on to the next one.
                    del walls[i]
                    sx, sy, wallDir = walls[i]
                    cell = self.map[sy][sx]
                
                if dir & Globals.AllDirs != 0:
                    # It's not a floor or ceiling, so use the wall we
                    # picked, instead of the wall it was on in the
                    # previous maze.
                    dir = wallDir
                else:
                    # It is a floor or ceiling, so keep it there.
                    pass

                cell.preloadPrevPainting(dir, posterData, imgData)

                # Record the player's color so we can identify him
                # when he comes back in and give him the points for
                # this paint immediately.
                self.prevPlayers.setdefault(color, []).append((cell, dir))

##         # Temp hack for debugging.
##         painted = PNMImage()
##         painted.read('paint.rgb')
##         for sx, sy, dir in walls:
##             cell = self.map[sy][sx]
##             for dir in Globals.AllDirsList:
##                 if cell.bits & dir:
##                     cell.painted[dir] = PNMImage(painted)

        self.drawMap()
        self.determineVisibility()
Esempio n. 22
0
class ADBakery(Bakery):

    """
    A factory for tiles based on panda3d's perlin noise
    """

    def __init__(self, editorFile, bakeryFolder):
        #id is a seed for the map and unique name for any cached heightmap images

        self.dice = RandomNumGen(TimeVal().getUsec())
        self.id = self.dice.randint(2, 1000000)

        # the overall smoothness/roughness of the terrain
        smoothness = 80
        # how quickly altitude and roughness shift
        self.consistency = smoothness * 8
        # waterHeight is expressed as a multiplier to the max height
        self.waterHeight = 0.3
        # for realism the flatHeight should be at or very close to waterHeight
        self.flatHeight = self.waterHeight + 0.04

        #creates noise objects that will be used by the getHeight function
        """Create perlin noise."""

        # See getHeight() for more details....

        # where perlin 1 is low terrain will be mostly low and flat
        # where it is high terrain will be higher and slopes will be exagerrated
        # increase perlin1 to create larger areas of geographic consistency
        self.perlin1 = StackedPerlinNoise2()
        perlin1a = PerlinNoise2(0, 0, 256, seed=self.id)
        perlin1a.setScale(self.consistency)
        self.perlin1.addLevel(perlin1a)
        perlin1b = PerlinNoise2(0, 0, 256, seed=self.id * 2 + 123)
        perlin1b.setScale(self.consistency / 2)
        self.perlin1.addLevel(perlin1b, 1 / 2)


        # perlin2 creates the noticeable noise in the terrain
        # without perlin2 everything would look unnaturally smooth and regular
        # increase perlin2 to make the terrain smoother
        self.perlin2 = StackedPerlinNoise2()
        frequencySpread = 3.0
        amplitudeSpread = 3.4
        perlin2a = PerlinNoise2(0, 0, 256, seed=self.id * 2)
        perlin2a.setScale(smoothness)
        self.perlin2.addLevel(perlin2a)
        perlin2b = PerlinNoise2(0, 0, 256, seed=self.id * 3 + 3)
        perlin2b.setScale(smoothness / frequencySpread)
        self.perlin2.addLevel(perlin2b, 1 / amplitudeSpread)
        perlin2c = PerlinNoise2(0, 0, 256, seed=self.id * 4 + 4)
        perlin2c.setScale(smoothness / (frequencySpread * frequencySpread))
        self.perlin2.addLevel(perlin2c, 1 / (amplitudeSpread * amplitudeSpread))
        perlin2d = PerlinNoise2(0, 0, 256, seed=self.id * 5 + 5)
        perlin2d.setScale(smoothness / (math.pow(frequencySpread, 3)))
        self.perlin2.addLevel(perlin2d, 1 / (math.pow(amplitudeSpread, 3)))
        perlin2e = PerlinNoise2(0, 0, 256, seed=self.id * 6 + 6)
        perlin2e.setScale(smoothness / (math.pow(frequencySpread, 4)))
        self.perlin2.addLevel(perlin2e, 1 / (math.pow(amplitudeSpread, 4)))

    def hasTile(self, xStart, yStart, tileSize):
        """
        If one is using a cashed tile source instead of a live bakery, this would be sometimes be false
        """
        return True

    def getTile(self, xStart, yStart, scale):
        """
        returns a tile for the specified positions and size
        """
        sizeY = tileMapSize
        sizeX = tileMapSize
        getHeight = self.getHeight
        
        noiseTex=Texture("NoiseTex")
        noiseTex.setup2dTexture(sizeX, sizeY, Texture.TUnsignedByte, Texture.FRgb)
        p=noiseTex.modifyRamImage()
        step=noiseTex.getNumComponents()*noiseTex.getComponentWidth()
        scalar=.4
        for y in range(sizeY):
            yPos=scalar*(1.0*y*scale/(sizeY-1)+yStart)
            for x in range(sizeX):
                height = getHeight(scalar*(1.0*x*scale/(sizeX-1) + xStart), yPos)
                r=min(255,max(0,height*256))
                g=r*256
                b=g*256
                index = (sizeX * y + x)*step
                p.setElement(index, b%256)#Blue
                p.setElement(index+1, g%256)#Green
                p.setElement(index+2, r)#Red
        
        return Tile({"height":Map("height", noiseTex)},[], xStart, yStart, scale)

    def asyncGetTile(self, xStart, yStart, scale, callback, callbackParams=[]):
        """
        like getTile, but calls callback(tile,*callbackParams) when done
        """
        callback(self.getTile(xStart, yStart, scale), *callbackParams)
    
    def getHeight(self, x, y):
        """Returns the height at the specified terrain coordinates.

        The values returned should be between 0 and 1 and use the full range.
        Heights should be the smoothest and flatest at flatHeight.

        """

        # all of these should be in the range of 0 to 1
        p1 = (self.perlin1(x, y) + 1) / 2 # low frequency
        p2 = (self.perlin2(x, y) + 1) / 2 # high frequency
        fh = self.flatHeight

        # p1 varies what kind of terrain is in the area, p1 alone would be smooth
        # p2 introduces the visible noise and roughness
        # when p1 is high the altitude will be high overall
        # when p1 is close to fh most of the visible noise will be muted
        return (p1 - fh + (p1 - fh) * (p2 - fh)) / 2 + fh
        # if p1 = fh, the whole equation simplifies to...
        # 1. (fh - fh + (fh - fh) * (p2 - fh)) / 2 + fh
        # 2. ( 0 + 0 * (p2 - fh)) / 2 + fh
        # 3. (0 + 0 ) / 2 + fh
        # 4. fh
        # The important part to understanding the equation is at step 2.
        # The closer p1 is to fh, the smaller the mutiplier for p2 becomes.
        # As p2 diminishes, so does the roughness.
class CogdoMazeFactory:

    def __init__(self, randomNumGen, width, height, frameWallThickness = Globals.FrameWallThickness, cogdoMazeData = CogdoMazeData):
        self._rng = RandomNumGen(randomNumGen)
        self.width = width
        self.height = height
        self.frameWallThickness = frameWallThickness
        self._cogdoMazeData = cogdoMazeData
        self.quadrantSize = self._cogdoMazeData.QuadrantSize
        self.cellWidth = self._cogdoMazeData.QuadrantCellWidth

    def getMazeData(self):
        if not hasattr(self, '_data'):
            self._generateMazeData()
        return self._data

    def createCogdoMaze(self, flattenModel = True):
        if not hasattr(self, '_maze'):
            self._loadAndBuildMazeModel(flatten=flattenModel)
        return CogdoMaze(self._model, self._data, self.cellWidth)

    def _gatherQuadrantData(self):
        self.openBarriers = []
        barrierItems = range(Globals.TotalBarriers)
        self._rng.shuffle(barrierItems)
        for i in barrierItems[0:len(barrierItems) - Globals.NumBarriers]:
            self.openBarriers.append(i)

        self.quadrantData = []
        quadrantKeys = self._cogdoMazeData.QuadrantCollisions.keys()
        self._rng.shuffle(quadrantKeys)
        i = 0
        for y in range(self.height):
            for x in range(self.width):
                key = quadrantKeys[i]
                collTable = self._cogdoMazeData.QuadrantCollisions[key]
                angle = self._cogdoMazeData.QuadrantAngles[self._rng.randint(0, len(self._cogdoMazeData.QuadrantAngles) - 1)]
                self.quadrantData.append((key, collTable[angle], angle))
                i += 1
                if x * y >= self._cogdoMazeData.NumQuadrants:
                    i = 0

    def _generateBarrierData(self):
        data = []
        for y in range(self.height):
            data.append([])
            for x in range(self.width):
                if x == self.width - 1:
                    ax = -1
                else:
                    ax = 1
                if y == self.height - 1:
                    ay = -1
                else:
                    ay = 1
                data[y].append([ax, ay])

        dirUp = 0
        dirDown = 1
        dirLeft = 2
        dirRight = 3

        def getAvailableDirections(ax, ay, ignore = None):
            dirs = []
            if ax - 1 >= 0 and data[ay][ax - 1][BARRIER_DATA_RIGHT] == 1 and (ax, ay) != ignore:
                dirs.append(dirLeft)
            if ax + 1 < self.width and data[ay][ax][BARRIER_DATA_RIGHT] == 1 and (ax, ay) != ignore:
                dirs.append(dirRight)
            if ay - 1 >= 0 and data[ay - 1][ax][BARRIER_DATA_TOP] == 1 and (ax, ay) != ignore:
                dirs.append(dirDown)
            if ay + 1 < self.height and data[ay][ax][BARRIER_DATA_TOP] == 1 and (ax, ay) != ignore:
                dirs.append(dirUp)
            return dirs

        visited = []

        def tryVisitNeighbor(ax, ay, ad):
            if ad == dirUp:
                if data[ay][ax] in visited:
                    return None
                visited.append(data[ay][ax])
                data[ay][ax][BARRIER_DATA_TOP] = 0
                ay += 1
            elif ad == dirDown:
                if data[ay - 1][ax] in visited:
                    return None
                visited.append(data[ay - 1][ax])
                data[ay - 1][ax][BARRIER_DATA_TOP] = 0
                ay -= 1
            elif ad == dirLeft:
                if data[ay][ax - 1] in visited:
                    return None
                visited.append(data[ay][ax - 1])
                data[ay][ax - 1][BARRIER_DATA_RIGHT] = 0
                ax -= 1
            elif ad == dirRight:
                if data[ay][ax] in visited:
                    return None
                visited.append(data[ay][ax])
                data[ay][ax][BARRIER_DATA_RIGHT] = 0
                ax += 1
            return ax, ay

        def openBarriers(x, y):
            dirs = getAvailableDirections(x, y)
            for dir in dirs:
                next = tryVisitNeighbor(x, y, dir)
                if next is not None:
                    openBarriers(*next)

        x = self._rng.randint(0, self.width - 1)
        y = self._rng.randint(0, self.height - 1)
        openBarriers(x, y)
        self._barrierData = data

    def _generateMazeData(self):
        if not hasattr(self, 'quadrantData'):
            self._gatherQuadrantData()
        self._data = {'width': (self.width + 1) * self.frameWallThickness + self.width * self.quadrantSize,
                      'height': (self.height + 1) * self.frameWallThickness + self.height * self.quadrantSize}
        self._data['originX'] = int(self._data['width'] / 2)
        self._data['originY'] = int(self._data['height'] / 2)
        collisionTable = []
        horizontalWall = [ 1 for x in range(self._data['width']) ]
        collisionTable.append(horizontalWall)
        for i in range(0, len(self.quadrantData), self.width):
            for y in range(self.quadrantSize):
                row = [1]
                for x in range(i, i + self.width):
                    if x == 1 and y < self.quadrantSize / 2 - 2:
                        newData = []
                        for j in self.quadrantData[x][1][y]:
                            if j == 0:
                                newData.append(2)
                            else:
                                newData.append(j + 0)

                        row += newData + [1]
                    else:
                        row += self.quadrantData[x][1][y] + [1]

                collisionTable.append(row)

            collisionTable.append(horizontalWall[:])

        barriers = Globals.MazeBarriers
        for i in range(len(barriers)):
            for coords in barriers[i]:
                collisionTable[coords[1]][coords[0]] = 0

        y = self._data['originY']
        for x in range(len(collisionTable[y])):
            if collisionTable[y][x] == 0:
                collisionTable[y][x] = 2

        x = self._data['originX']
        for y in range(len(collisionTable)):
            if collisionTable[y][x] == 0:
                collisionTable[y][x] = 2

        self._data['collisionTable'] = collisionTable

    def _loadAndBuildMazeModel(self, flatten = False):
        self.getMazeData()
        self._model = NodePath('CogdoMazeModel')
        levelModel = CogdoUtil.loadMazeModel('level')
        self.quadrants = []
        quadrantUnitSize = int(self.quadrantSize * self.cellWidth)
        frameActualSize = self.frameWallThickness * self.cellWidth
        size = quadrantUnitSize + frameActualSize
        halfWidth = int(self.width / 2)
        halfHeight = int(self.height / 2)
        i = 0
        for y in range(self.height):
            for x in range(self.width):
                ax = (x - halfWidth) * size
                ay = (y - halfHeight) * size
                extension = ''
                if hasattr(getBase(), 'air'):
                    extension = '.bam'
                filepath = self.quadrantData[i][0] + extension
                angle = self.quadrantData[i][2]
                m = self._createQuadrant(filepath, i, angle, quadrantUnitSize)
                m.setPos(ax, ay, 0)
                m.reparentTo(self._model)
                self.quadrants.append(m)
                i += 1

        quadrantHalfUnitSize = quadrantUnitSize * 0.5
        barrierModel = CogdoUtil.loadMazeModel('grouping_blockerDivider').find('**/divider')
        y = 3
        for x in range(self.width):
            if x == (self.width - 1) / 2:
                continue
            ax = (x - halfWidth) * size
            ay = (y - halfHeight) * size - quadrantHalfUnitSize - (self.cellWidth - 0.5)
            b = NodePath('barrier')
            barrierModel.instanceTo(b)
            b.setPos(ax, ay, 0)
            b.reparentTo(self._model)

        offset = self.cellWidth - 0.5
        for x in (0, 3):
            for y in range(self.height):
                ax = (x - halfWidth) * size - quadrantHalfUnitSize - frameActualSize + offset
                ay = (y - halfHeight) * size
                b = NodePath('barrier')
                barrierModel.instanceTo(b)
                b.setPos(ax, ay, 0)
                b.setH(90)
                b.reparentTo(self._model)

            offset -= 2.0

        barrierModel.removeNode()
        levelModel.getChildren().reparentTo(self._model)
        for np in self._model.findAllMatches('**/*lightCone*'):
            CogdoUtil.initializeLightCone(np, 'fixed', 3)

        if flatten:
            self._model.flattenStrong()
        return self._model

    def _createQuadrant(self, filepath, serialNum, angle, size):
        root = NodePath('QuadrantRoot-%i' % serialNum)
        quadrant = loader.loadModel(filepath)
        quadrant.getChildren().reparentTo(root)
        root.setH(angle)
        return root
Esempio n. 24
0
class MazeSuit(DirectObject):
    COLL_SPHERE_NAME = 'MazeSuitSphere'
    COLLISION_EVENT_NAME = 'MazeSuitCollision'
    MOVE_IVAL_NAME = 'moveMazeSuit'
    DIR_UP = 0
    DIR_DOWN = 1
    DIR_LEFT = 2
    DIR_RIGHT = 3
    oppositeDirections = [DIR_DOWN, DIR_UP, DIR_RIGHT, DIR_LEFT]
    directionHs = [0, 180, 90, 270]
    DEFAULT_SPEED = 4.0
    SUIT_Z = 0.1

    def __init__(
            self,
            serialNum,
            maze,
            randomNumGen,
            cellWalkPeriod,
            difficulty,
            suitDnaName='f',
            startTile=None,
            ticFreq=MazeGameGlobals.SUIT_TIC_FREQ,
            walkSameDirectionProb=MazeGameGlobals.WALK_SAME_DIRECTION_PROB,
            walkTurnAroundProb=MazeGameGlobals.WALK_TURN_AROUND_PROB,
            uniqueRandomNumGen=True,
            walkAnimName=None):
        self.serialNum = serialNum
        self.maze = maze
        if uniqueRandomNumGen:
            self.rng = RandomNumGen(randomNumGen)
        else:
            self.rng = randomNumGen
        self.difficulty = difficulty
        self._walkSameDirectionProb = walkSameDirectionProb
        self._walkTurnAroundProb = walkTurnAroundProb
        self._walkAnimName = walkAnimName or 'walk'
        self.suit = Suit.Suit()
        d = SuitDNA.SuitDNA()
        d.newSuit(suitDnaName)
        self.suit.setDNA(d)
        self.suit.nametag3d.stash()
        self.suit.nametag.destroy()
        if startTile is None:
            defaultStartPos = MazeGameGlobals.SUIT_START_POSITIONS[
                self.serialNum]
            self.startTile = (defaultStartPos[0] * self.maze.width,
                              defaultStartPos[1] * self.maze.height)
        else:
            self.startTile = startTile
        self.ticFreq = ticFreq
        self.ticPeriod = int(cellWalkPeriod)
        self.cellWalkDuration = float(self.ticPeriod) / float(self.ticFreq)
        self.turnDuration = 0.6 * self.cellWalkDuration
        return

    def destroy(self):
        self.suit.delete()

    def uniqueName(self, str):
        return str + ` (self.serialNum) `

    def gameStart(self, gameStartTime):
        self.gameStartTime = gameStartTime
        self.initCollisions()
        self.startWalkAnim()
        self.occupiedTiles = [(self.nextTX, self.nextTY)]
        n = 20
        self.nextThinkTic = self.serialNum * self.ticFreq / n
        self.fromPos = Point3(0, 0, 0)
        self.toPos = Point3(0, 0, 0)
        self.fromHpr = Point3(0, 0, 0)
        self.toHpr = Point3(0, 0, 0)
        self.moveIval = WaitInterval(1.0)

    def gameEnd(self):
        self.moveIval.pause()
        del self.moveIval
        self.shutdownCollisions()
        self.suit.loop('neutral')

    def initCollisions(self):
        self.collSphere = CollisionSphere(0, 0, 0, 2.0)
        self.collSphere.setTangible(0)
        self.collNode = CollisionNode(self.uniqueName(self.COLL_SPHERE_NAME))
        self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = self.suit.attachNewNode(self.collNode)
        self.collNodePath.hide()
        self.accept(self.uniqueName('enter' + self.COLL_SPHERE_NAME),
                    self.handleEnterSphere)

    def shutdownCollisions(self):
        self.ignore(self.uniqueName('enter' + self.COLL_SPHERE_NAME))
        del self.collSphere
        self.collNodePath.removeNode()
        del self.collNodePath
        del self.collNode

    def handleEnterSphere(self, collEntry):
        messenger.send(self.COLLISION_EVENT_NAME, [self.serialNum])

    def __getWorldPos(self, sTX, sTY):
        wx, wy = self.maze.tile2world(sTX, sTY)
        return Point3(wx, wy, self.SUIT_Z)

    def onstage(self):
        sTX = int(self.startTile[0])
        sTY = int(self.startTile[1])
        c = 0
        lim = 0
        toggle = 0
        direction = 0
        while not self.maze.isWalkable(sTX, sTY):
            if 0 == direction:
                sTX -= 1
            elif 1 == direction:
                sTY -= 1
            elif 2 == direction:
                sTX += 1
            elif 3 == direction:
                sTY += 1
            c += 1
            if c > lim:
                c = 0
                direction = (direction + 1) % 4
                toggle += 1
                if not toggle & 1:
                    lim += 1

        self.TX = sTX
        self.TY = sTY
        self.direction = self.DIR_DOWN
        self.lastDirection = self.direction
        self.nextTX = self.TX
        self.nextTY = self.TY
        self.suit.setPos(self.__getWorldPos(self.TX, self.TY))
        self.suit.setHpr(self.directionHs[self.direction], 0, 0)
        self.suit.reparentTo(render)
        self.suit.pose(self._walkAnimName, 0)
        self.suit.loop('neutral')

    def offstage(self):
        self.suit.reparentTo(hidden)

    def startWalkAnim(self):
        self.suit.loop(self._walkAnimName)
        speed = float(self.maze.cellWidth) / self.cellWalkDuration
        self.suit.setPlayRate(speed / self.DEFAULT_SPEED, self._walkAnimName)

    def __applyDirection(self, dir, TX, TY):
        if self.DIR_UP == dir:
            TY += 1
        elif self.DIR_DOWN == dir:
            TY -= 1
        elif self.DIR_LEFT == dir:
            TX -= 1
        elif self.DIR_RIGHT == dir:
            TX += 1
        return (TX, TY)

    def __chooseNewWalkDirection(self, unwalkables):
        if not self.rng.randrange(self._walkSameDirectionProb):
            newTX, newTY = self.__applyDirection(self.direction, self.TX,
                                                 self.TY)
            if self.maze.isWalkable(newTX, newTY, unwalkables):
                return self.direction
        if self.difficulty >= 0.5:
            if not self.rng.randrange(self._walkTurnAroundProb):
                oppositeDir = self.oppositeDirections[self.direction]
                newTX, newTY = self.__applyDirection(oppositeDir, self.TX,
                                                     self.TY)
                if self.maze.isWalkable(newTX, newTY, unwalkables):
                    return oppositeDir
        candidateDirs = [
            self.DIR_UP, self.DIR_DOWN, self.DIR_LEFT, self.DIR_RIGHT
        ]
        candidateDirs.remove(self.oppositeDirections[self.direction])
        while len(candidateDirs):
            dir = self.rng.choice(candidateDirs)
            newTX, newTY = self.__applyDirection(dir, self.TX, self.TY)
            if self.maze.isWalkable(newTX, newTY, unwalkables):
                return dir
            candidateDirs.remove(dir)

        return self.oppositeDirections[self.direction]

    def getThinkTimestampTics(self, curTic):
        if curTic < self.nextThinkTic:
            return []
        else:
            r = range(self.nextThinkTic, curTic + 1, self.ticPeriod)
            self.lastTicBeforeRender = r[-1]
            return r

    def prepareToThink(self):
        self.occupiedTiles = [(self.nextTX, self.nextTY)]

    def think(self, curTic, curT, unwalkables):
        self.TX = self.nextTX
        self.TY = self.nextTY
        self.lastDirection = self.direction
        self.direction = self.__chooseNewWalkDirection(unwalkables)
        self.nextTX, self.nextTY = self.__applyDirection(
            self.direction, self.TX, self.TY)
        self.occupiedTiles = [(self.TX, self.TY), (self.nextTX, self.nextTY)]
        if curTic == self.lastTicBeforeRender:
            fromCoords = self.maze.tile2world(self.TX, self.TY)
            toCoords = self.maze.tile2world(self.nextTX, self.nextTY)
            self.fromPos.set(fromCoords[0], fromCoords[1], self.SUIT_Z)
            self.toPos.set(toCoords[0], toCoords[1], self.SUIT_Z)
            self.moveIval = LerpPosInterval(self.suit,
                                            self.cellWalkDuration,
                                            self.toPos,
                                            startPos=self.fromPos,
                                            name=self.uniqueName(
                                                self.MOVE_IVAL_NAME))
            if self.direction != self.lastDirection:
                self.fromH = self.directionHs[self.lastDirection]
                toH = self.directionHs[self.direction]
                if self.fromH == 270 and toH == 0:
                    self.fromH = -90
                elif self.fromH == 0 and toH == 270:
                    self.fromH = 360
                self.fromHpr.set(self.fromH, 0, 0)
                self.toHpr.set(toH, 0, 0)
                turnIval = LerpHprInterval(
                    self.suit,
                    self.turnDuration,
                    self.toHpr,
                    startHpr=self.fromHpr,
                    name=self.uniqueName('turnMazeSuit'))
                self.moveIval = Parallel(self.moveIval,
                                         turnIval,
                                         name=self.uniqueName(
                                             self.MOVE_IVAL_NAME))
            else:
                self.suit.setH(self.directionHs[self.direction])
            moveStartT = float(self.nextThinkTic) / float(self.ticFreq)
            self.moveIval.start(curT - (moveStartT + self.gameStartTime))
        self.nextThinkTic += self.ticPeriod

    @staticmethod
    def thinkSuits(suitList, startTime, ticFreq=MazeGameGlobals.SUIT_TIC_FREQ):
        curT = globalClock.getFrameTime() - startTime
        curTic = int(curT * float(ticFreq))
        suitUpdates = []
        for i in xrange(len(suitList)):
            updateTics = suitList[i].getThinkTimestampTics(curTic)
            suitUpdates.extend(zip(updateTics, [i] * len(updateTics)))

        suitUpdates.sort(lambda a, b: a[0] - b[0])
        if len(suitUpdates) > 0:
            curTic = 0
            for i in xrange(len(suitUpdates)):
                update = suitUpdates[i]
                tic = update[0]
                suitIndex = update[1]
                suit = suitList[suitIndex]
                if tic > curTic:
                    curTic = tic
                    j = i + 1
                    while j < len(suitUpdates):
                        if suitUpdates[j][0] > tic:
                            break
                        suitList[suitUpdates[j][1]].prepareToThink()
                        j += 1

                unwalkables = []
                for si in xrange(suitIndex):
                    unwalkables.extend(suitList[si].occupiedTiles)

                for si in xrange(suitIndex + 1, len(suitList)):
                    unwalkables.extend(suitList[si].occupiedTiles)

                suit.think(curTic, curT, unwalkables)
Esempio n. 25
0
 def startIntro(self):
     self._movie = CogdoFlyingGameIntro(self.level, RandomNumGen(self.distGame.doId))
     self._movie.load()
     self._movie.play()
     self.audioMgr.playMusic('normal')
Esempio n. 26
0
class MazeAI(DistributedObjectAI):

    notify = directNotify.newCategory("MazeAI")

    TurnChance = 75
    ForkChance = 20
    StopChance = 10

    def __init__(self, air, gameId):
        DistributedObjectAI.__init__(self, air)

        self.gameId = gameId
        self.xsize = 0
        self.ysize = 0
        self.numWalls = 0
        self.map = None
        self.root = None

        self.prevPlayers = {}

    def getSize(self):
        return self.xsize, self.ysize

    def getNumWalls(self):
        return self.numWalls

    def deleteMaze(self):
        if self.map:
            for row in self.map:
                for cell in row:
                    self.air.zoneAllocator.free(cell.zoneId)
                    cell.requestDelete()

    def generateMaze(self, xsize, ysize, 
                     prevMaze = None, seed = None):
        if seed is None:
            seed = int(time.time())
        self.random = RandomNumGen(seed)

        # Delete the old maze, if any
        self.deleteMaze()

        self.xsize = xsize
        self.ysize = ysize
        self.map = []
        for sy in range(self.ysize):
            row = []
            for sx in range(self.xsize):
                zoneId = self.air.zoneAllocator.allocate()
                cell = CellAI(self.air)
                cell.setGeometry(Globals.AllDirs, sx, sy)
                cell.generateWithRequired(zoneId)
                row.append(cell)
            self.map.append(row)

        # Start by choosing a random square and a random direction.
        self.numSquares = self.xsize * self.ysize - 1
        self.paths = []
        nextStep = self.__findEmptySquare()
        self.paths.append(nextStep)
        while self.numSquares > 0:
            self.__generateMazeSteps()

        # Count up the number of walls.
        walls = []
        for row in self.map:
            for cell in row:
                walls += cell.getWalls()
        self.numWalls = len(walls)
        
        random.shuffle(walls)

        if prevMaze:
            # Put our previous art paintings up on the walls,
            # including any poster data.
            for i in range(len(prevMaze.artPaintings)):
                dir, name, color, posterData, imgData = prevMaze.artPaintings[i]
                sx, sy, wallDir = walls[i]
                cell = self.map[sy][sx]
                while posterData[0] and cell.posterDir:
                    # We've already placed a poster in this cell.  Go
                    # on to the next one.
                    del walls[i]
                    sx, sy, wallDir = walls[i]
                    cell = self.map[sy][sx]
                
                if dir & Globals.AllDirs != 0:
                    # It's not a floor or ceiling, so use the wall we
                    # picked, instead of the wall it was on in the
                    # previous maze.
                    dir = wallDir
                else:
                    # It is a floor or ceiling, so keep it there.
                    pass

                cell.preloadPrevPainting(dir, posterData, imgData)

                # Record the player's color so we can identify him
                # when he comes back in and give him the points for
                # this paint immediately.
                self.prevPlayers.setdefault(color, []).append((cell, dir))

##         # Temp hack for debugging.
##         painted = PNMImage()
##         painted.read('paint.rgb')
##         for sx, sy, dir in walls:
##             cell = self.map[sy][sx]
##             for dir in Globals.AllDirsList:
##                 if cell.bits & dir:
##                     cell.painted[dir] = PNMImage(painted)

        self.drawMap()
        self.determineVisibility()

    def getPosterData(self):
        return self.posterData
        
    def determineVisibility(self):
        """ Determines which cells can be seen from which other
        cells, based on straight-line visibility. """

        self.visCollWalls = self.makeCollisionWalls()
        self.visTrav = CollisionTraverser('visTrav')
        self.visQueue = CollisionHandlerQueue()
        self.visNode = CollisionNode('visNode')
        self.visNP = self.visCollWalls.attachNewNode(self.visNode)
        self.visNP.setCollideMask(0)
        self.visTrav.addCollider(self.visNP, self.visQueue)

        for sy in range(self.ysize):
            self.notify.info("%s determineVisibility: %d%%" % (
                self.gameId, 100.0 * sy / self.ysize))
            row = self.map[sy]
            for cell in row:
                self.__determineVisibilityForCell(cell, 1, Globals.AllDirs)

        # Now build the expanded visibility, including neighbor
        # visibility, for smooth transitions.
        for row in self.map:
            for cell in row:
                self.__expandVisibilityForCell(cell)
        self.notify.info("%s done" % (self.gameId))

    def __expandVisibilityForCell(self, cell):
        """ Build cell.expandedZoneIds, representing the union of
        visibleZoneIds for the cell and all of its eight neigbors. """

        cell.expandedZoneIds = set()
        for sy in range(max(cell.sy - 1, 0), min(cell.sy + 2, self.ysize)):
            for sx in range(max(cell.sx - 1, 0), min(cell.sx + 2, self.xsize)):
                c2 = self.map[sy][sx]
                cell.expandedZoneIds |= c2.visibleZoneIds
        assert cell.expandedZoneIds | cell.visibleZoneIds == cell.expandedZoneIds

    def __determineVisibilityForCell(self, cell, radius, dirBits):
        """ Determines the set of visible cells that can be seen from
        this cell, for the given radius. """
        cell.visibleZoneIds.add(cell.zoneId)
        
        numVisible = 0
        nextDirs = 0
        for i in range(-radius, radius):
            if dirBits & Globals.North:
                # North wall
                sx = cell.sx - i
                sy = cell.sy + radius
                if self.__checkCellVisibility(cell, sx, sy):
                    nextDirs |= Globals.North

            if dirBits & Globals.East:
                # East wall
                sx = cell.sx + radius
                sy = cell.sy + i
                if self.__checkCellVisibility(cell, sx, sy):
                    nextDirs |= Globals.East

            if dirBits & Globals.South:
                # South wall
                sx = cell.sx + i
                sy = cell.sy - radius
                if self.__checkCellVisibility(cell, sx, sy):
                    nextDirs |= Globals.South

            if dirBits & Globals.West:
                # West wall
                sx = cell.sx - radius
                sy = cell.sy - i
                if self.__checkCellVisibility(cell, sx, sy):
                    nextDirs |= Globals.West

        if nextDirs:
            # Recursively check the higher radius
            self.__determineVisibilityForCell(cell, radius + 1, nextDirs)

    def __checkCellVisibility(self, source, sx, sy):
        """ Looks up the target cell, and returns true if the target
        can be seen from source, false otherwise. """
        if sx < 0 or sx >= self.xsize or sy < 0 or sy >= self.ysize:
            # Not even a real cell.
            return False
        target = self.map[sy][sx]
        if not self.__doVisibilityTest(source, target):
            return False

        # target is visible.
        source.visibleZoneIds.add(target.zoneId)
        return True
            
    def __doVisibilityTest(self, source, target):
        """ Returns true if target can be seen from source, false
        otherwise. """

        # We naively check 16 lines: each of the four corners of
        # target from the four corners of source.  If any of them has
        # a line of sight--that is, any one of them does *not*
        # generate a collision event--we're in.

        # We use a point just inside each corner, so we don't have to
        # deal with ambiguities at the precise corner.

        self.visQueue.clearEntries()
        self.visNode.clearSolids()

        segs = {}
        for ax, ay in [(source.sx + 0.1, source.sy + 0.1),
                       (source.sx + 0.9, source.sy + 0.1),
                       (source.sx + 0.9, source.sy + 0.9),
                       (source.sx + 0.1, source.sy + 0.9)]:
            for bx, by in [(target.sx + 0.1, target.sy + 0.1),
                           (target.sx + 0.9, target.sy + 0.1),
                           (target.sx + 0.9, target.sy + 0.9),
                           (target.sx + 0.1, target.sy + 0.9)]:
                seg = CollisionSegment(ax, ay, 0.5, bx, by, 0.5)
                self.visNode.addSolid(seg)
                segs[seg] = True

        self.visTrav.traverse(self.visCollWalls)

        # Now see which segments detected a collision.
        for entry in self.visQueue.getEntries():
            seg = entry.getFrom()
            if seg in segs:
                del segs[seg]

        # If any are left, we've got a line of sight.
        if segs:
            return True

        # If none are left, we're blocked.
        return False

    def __generateMazeSteps(self):
        """ Moves all of the active paths forward one step. """

        if not self.paths:
            # Ran out of open paths.  Go find a likely square to pick
            # up from again.
            nextStep = self.__findEmptySquare()
            self.paths.append(nextStep)

        paths = self.paths
        self.paths = []
        for sx, sy, dir in paths:
            self.__generateMazeOneStep(sx, sy, dir)

    def __generateMazeOneStep(self, sx, sy, dir):
        """ Moves this path forward one step. """

        if self.random.randint(0, 99) < self.StopChance:
            # Abandon this path.
            return

        numNextSteps = 1
        while numNextSteps < 4 and self.random.randint(0, 99) < self.ForkChance:
            # Consider a fork.
            numNextSteps += 1

        nextDirs = Globals.AllDirsList[:]
        nextDirs.remove(dir)
        self.random.shuffle(nextDirs)

        if self.random.randint(0, 99) < self.TurnChance:
            # Consider a turn.  Put the current direction at the end.
            nextDirs.append(dir)
        else:
            # Don't consider a turn.  Put the current direction at the
            # front.
            nextDirs = [dir] + nextDirs

        for dir in nextDirs:
            nextStep = self.__makeStep(sx, sy, dir)
            if nextStep:
                # That step was valid, save the current path for next
                # pass.
                self.numSquares -= 1
                self.paths.append(nextStep)
                numNextSteps -= 1
                if numNextSteps == 0:
                    return
                
            # Try the next direction.

        # Couldn't go anywhere else.  We're done.
        return
                
    def __makeStep(self, sx, sy, dir):
        """ Attempts to move this path forward in the indicated
        direction.  Returns the new sx, sy, dir if successful, or None
        on failure. """
        if dir == Globals.South:
            if sy == 0:
                return None
            if self.map[sy][sx].bits & Globals.South == 0:
                return None
            if self.map[sy - 1][sx].bits != Globals.AllDirs:
                return None
            self.map[sy][sx].bits &= ~Globals.South
            self.map[sy - 1][sx].bits &= ~Globals.North
            return (sx, sy - 1, dir)

        elif dir == Globals.West:
            if sx == 0:
                return None
            if self.map[sy][sx].bits & Globals.West == 0:
                return None
            if self.map[sy][sx - 1].bits != Globals.AllDirs:
                return None
            self.map[sy][sx].bits &= ~Globals.West
            self.map[sy][sx - 1].bits &= ~Globals.East
            return (sx - 1, sy, dir)

        elif dir == Globals.North:
            if sy == self.ysize - 1:
                return None
            if self.map[sy][sx].bits & Globals.North == 0:
                return None
            if self.map[sy + 1][sx].bits != Globals.AllDirs:
                return None
            self.map[sy][sx].bits &= ~Globals.North
            self.map[sy + 1][sx].bits &= ~Globals.South
            return (sx, sy + 1, dir)

        elif dir == Globals.East:
            if sx == self.xsize - 1:
                return None
            if self.map[sy][sx].bits & Globals.East == 0:
                return None
            if self.map[sy][sx + 1].bits != Globals.AllDirs:
                return None
            self.map[sy][sx].bits &= ~Globals.East
            self.map[sy][sx + 1].bits &= ~Globals.West
            return (sx + 1, sy, dir)

        assert False

    def __findEmptySquare(self):
        """ Finds an empty square next door to a non-empty square, and
        starts a new path. """

        if self.numSquares == self.xsize * self.ysize - 1:
            # All squares are still empty.
            sx = self.random.randint(0, self.xsize - 1)
            sy = self.random.randint(0, self.ysize - 1)
            dir = self.random.choice(Globals.AllDirsList)
            return (sx, sy, dir)

        # First, get the map squares in random order.
        ylist = list(range(self.ysize))
        xlist = list(range(self.xsize))
        self.random.shuffle(ylist)
        self.random.shuffle(xlist)

        for sy in ylist:
            for sx in xlist:
                if self.map[sy][sx].bits != Globals.AllDirs:
                    continue
                if sy > 0 and self.map[sy - 1][sx].bits != Globals.AllDirs:
                    return (sx, sy - 1, Globals.North)
                elif sy < self.ysize - 1 and self.map[sy + 1][sx].bits != Globals.AllDirs:
                    return (sx, sy + 1, Globals.South)
                elif sx > 0 and self.map[sy][sx - 1].bits != Globals.AllDirs:
                    return (sx - 1, sy, Globals.East)
                elif sx < self.xsize - 1 and self.map[sy][sx + 1].bits != Globals.AllDirs:
                    return (sx + 1, sy, Globals.West)

        self.drawMap()
        assert False

    def makeCollisionWalls(self):
        """ Creates and returns a scene graph that contains a
        collision wall for each West and South wall in the maze, for
        the purposes of determining visibility. """
        root = self.__makeCollisionQuadtree(0, 0, self.xsize, self.ysize)
        root.flattenLight()
        return root

    def __makeCollisionQuadtree(self, ax, ay, bx, by):
        # We recursively create a quadtree hierarchy, in an attempt to
        # ensure the collisions remain scalable with very large maps.
        xsize = bx - ax
        ysize = by - ay
        if xsize > 1 or ysize > 1:
            # Recurse.
            root = NodePath('%s_%s__%s_%s' % (ax, ay, bx, by))
            xsize = max((xsize + 1) / 2, 1)
            ysize = max((ysize + 1) / 2, 1)
            py = ay
            while py < by:
                px = ax
                while px < bx:
                    np = self.__makeCollisionQuadtree(px, py, min(px + xsize, bx), min(py + ysize, by))
                    np.reparentTo(root)
                    px += xsize
                py += ysize
            return root

        # One cell.  Handle it.
        node = CollisionNode('%s_%s' % (ax, ay))
        cell = self.map[ay][ax]
        if cell.bits & Globals.West:
            node.addSolid(CollisionPolygon(Point3(0, 0, 0), Point3(0, 1, 0),
                                           Point3(0, 1, 1), Point3(0, 0, 1)))
        if cell.bits & Globals.South:
            node.addSolid(CollisionPolygon(Point3(1, 0, 0), Point3(0, 0, 0),
                                           Point3(0, 0, 1), Point3(1, 0, 1)))
        np = NodePath(node)
        np.setPos(cell.sx, cell.sy, 0)
        return np

    def drawMap(self):
        line = '+'
        for xi in range(self.xsize):
            line += '---+'
        print line

        for yi in range(self.ysize - 1, -1, -1):
            row = self.map[yi]
            line = '|'
            for cell in row:
                if cell.bits & Globals.East:
                    line += '   |' 
                else:
                    line += '    ' 
            print line
            line = '+'
            for cell in row:
                if cell.bits & Globals.South:
                    line += '---+'
                else:
                    line += '   +'
            print line
        
    def makeGeom(self):
        """ Generates a set of renderable geometry. """

        if self.root:
            self.root.removeNode()

        self.root = NodePath('root')
        for sy in range(self.ysize):
            geomRow = []
            for sx in range(self.xsize):
                nodeGeom = self.map[sy][sx].makeGeomCell(sx, sy)
                nodeGeom.reparentTo(self.root)
                geomRow.append(nodeGeom)
        return self.root
        

    def chooseArtPaintings(self, game):
        """ Give score bonuses to the players with the 3 "best" art
        paintings. """

        # Now score each wall painting.
        anyPosters = False
        artPaintings = []
        for row in self.map:
            for cell in row:
                for dir, score in cell.artScore.items():
                    # Normally, the player with the most paint gets
                    # the bonus for the art painting.
                    player = cell.wonPlayers.get(dir, None)

                    # But if there's a poster on this wall, the player
                    # who owns the poster gets that bonus instead.
                    if dir == cell.posterDir:
                        anyPosters = True
                        pp = self.cr.doId2do.get(cell.posterPlayerId)
                        if pp:
                            player = pp
                        
                    p = cell.painted.get(dir, None)
                    if p and player and not player.isDeleted():
                        artPaintings.append((-score, cell, dir, player, p))

        # Sort the list so that the highest scores appear at the top.
        artPaintings.sort()

        self.artPaintings = []

        # We must have at least one poster in the list.
        needPoster = True

        # Unless there are no posters with paint on them, in which
        # case never mind.
        if not anyPosters:
            needPoster = False
        
        for i in range(len(artPaintings)):
            score, cell, dir, player, p = artPaintings[i]

            if dir == cell.posterDir:
                needPoster = False

            if len(self.artPaintings) == len(Globals.ArtPaintingBonus) - 1 and needPoster:
                # If we've reached the end of the list and we haven't
                # yet met our poster need, don't consider any
                # art paintings that aren't made on posters.
                continue

            bonus = Globals.ArtPaintingBonus[len(self.artPaintings)]
            player.artBonus += bonus
            player.score += bonus
            
            data = StringStream()
            p.write(data, Globals.ImageFormat)
            imgData = data.getData()

            posterData = ('', 0)
            if dir == cell.posterDir:
                posterData = cell.posterData
            
            self.artPaintings.append((dir, player.name, player.color, posterData, imgData))
            if len(self.artPaintings) >= len(Globals.ArtPaintingBonus):
                break

    def chooseRandomPosterCell(self, player):
        """ Selects a cell without a poster already applied, and
        applies this player's poster to it. """

        cells = []
        for row in self.map:
            cells += row[:]

        while True:
            if not cells:
                print "No cell available for user's poster."
                return
            
            cell = random.choice(cells)
            cells.remove(cell)
            if cell.posterDir:
                # Already taken.
                continue
            if cell.bits & Globals.AllDirs == 0:
                # No walls to hold a poster.
                continue
            break

        dirs = Globals.AllDirsList[:]
        while True:
            dir = random.choice(dirs)
            if cell.bits & dir:
                break
            dirs.remove(dir)

        cell.posterDir = dir
        cell.posterPlayerId = player.doId
        player.posterCell = cell

        print "posterData = %s, %s" % (len(player.posterData[0]), player.posterData[1])
        cell.updatePosterData(player.posterData)
Esempio n. 27
0
 def __init__(self, level, rng):
     CogdoGameMovie.__init__(self)
     self._level = level
     self._rng = RandomNumGen(rng)
     self._exit = self._level.getExit()
class CogdoFlyingLevelFactory:
    def __init__(self,
                 parent,
                 quadLengthUnits,
                 quadVisibilityAhead,
                 quadVisibiltyBehind,
                 rng=None):
        self.parent = parent
        self.quadLengthUnits = quadLengthUnits
        self.quadVisibiltyAhead = quadVisibilityAhead
        self.quadVisibiltyBehind = quadVisibiltyBehind
        if not rng:
            pass
        self._rng = RandomNumGen(1)
        self._level = None

    def loadAndBuildLevel(self, safezoneId):
        levelNode = NodePath('level')
        frameModel = CogdoUtil.loadFlyingModel('level')
        startPlatformModel = CogdoUtil.loadFlyingModel('levelStart')
        endPlatformModel = CogdoUtil.loadFlyingModel('levelEnd')
        for fan in frameModel.findAllMatches('**/*wallFan'):
            fan.flattenStrong()

        frameModel.find('**/fogOpaque').setBin('background', 1)
        frameModel.find('**/ceiling').setBin('background', 2)
        frameModel.find('**/fogTranslucent_bm').setBin('fixed', 1)
        frameModel.find('**/wallR').setBin('opaque', 2)
        frameModel.find('**/wallL').setBin('opaque', 2)
        frameModel.find('**/fogTranslucent_top').setBin('fixed', 2)
        frameModel.getChildren().reparentTo(levelNode)
        levelNode.hide()
        self._level = CogdoFlyingLevel(self.parent, levelNode,
                                       startPlatformModel, endPlatformModel,
                                       self.quadLengthUnits,
                                       self.quadVisibiltyAhead,
                                       self.quadVisibiltyBehind)
        if Globals.Dev.WantTempLevel:
            quads = Globals.Dev.DevQuadsOrder
        else:
            levelInfo = Globals.Level.DifficultyOrder[safezoneId]
            quads = []
            for difficulty in levelInfo:
                quadList = Globals.Level.QuadsByDifficulty[difficulty]
                quads.append(quadList[self._rng.randint(0, len(quadList) - 1)])

        for i in quads:
            filePath = CogdoUtil.getModelPath('quadrant%i' % i, 'flying')
            quadModel = loader.loadModel(filePath)
            for np in quadModel.findAllMatches('**/*lightCone*'):
                CogdoUtil.initializeLightCone(np, 'fixed', 3)

            self._level.appendQuadrant(quadModel)

        self._level.ready()

    def createLevel(self, safezoneId=2000):
        if self._level is None:
            self.loadAndBuildLevel(safezoneId)

        return self._level

    def createLevelFog(self):
        if self._level is None:
            self.loadAndBuildLevel()

        return CogdoFlyingLevelFog(self._level)
Esempio n. 29
0
class CogdoMazeFactory:

    def __init__(self, randomNumGen, width, height, frameWallThickness=Globals.FrameWallThickness, cogdoMazeData=CogdoMazeData):
        self._rng = RandomNumGen(randomNumGen)
        self.width = width
        self.height = height
        self.frameWallThickness = frameWallThickness
        self._cogdoMazeData = cogdoMazeData
        self.quadrantSize = self._cogdoMazeData.QuadrantSize
        self.cellWidth = self._cogdoMazeData.QuadrantCellWidth

    def getMazeData(self):
        if not hasattr(self, '_data'):
            self._generateMazeData()
        return self._data

    def createCogdoMaze(self, flattenModel=True):
        if not hasattr(self, '_maze'):
            self._loadAndBuildMazeModel(flatten=flattenModel)
        return CogdoMaze(self._model, self._data, self.cellWidth)

    def _gatherQuadrantData(self):
        self.openBarriers = []
        barrierItems = range(Globals.TotalBarriers)
        self._rng.shuffle(barrierItems)
        for i in barrierItems[0:len(barrierItems) - Globals.NumBarriers]:
            self.openBarriers.append(i)

        self.quadrantData = []
        quadrantKeys = self._cogdoMazeData.QuadrantCollisions.keys()
        self._rng.shuffle(quadrantKeys)
        i = 0
        for y in xrange(self.height):
            for x in xrange(self.width):
                key = quadrantKeys[i]
                collTable = self._cogdoMazeData.QuadrantCollisions[key]
                angle = self._cogdoMazeData.QuadrantAngles[self._rng.randint(0, len(self._cogdoMazeData.QuadrantAngles) - 1)]
                self.quadrantData.append((key, collTable[angle], angle))
                i += 1
                if x * y >= self._cogdoMazeData.NumQuadrants:
                    i = 0

    def _generateBarrierData(self):
        data = []
        for y in xrange(self.height):
            data.append([])
            for x in xrange(self.width):
                if x == self.width - 1:
                    ax = -1
                else:
                    ax = 1
                if y == self.height - 1:
                    ay = -1
                else:
                    ay = 1
                data[y].append([ax, ay])

        dirUp = 0
        dirDown = 1
        dirLeft = 2
        dirRight = 3

        def getAvailableDirections(ax, ay, ignore=None):
            dirs = []
            if ax - 1 >= 0 and data[ay][(ax - 1)][BARRIER_DATA_RIGHT] == 1 and (ax, ay) != ignore:
                dirs.append(dirLeft)
            if ax + 1 < self.width and data[ay][ax][BARRIER_DATA_RIGHT] == 1 and (ax, ay) != ignore:
                dirs.append(dirRight)
            if ay - 1 >= 0 and data[(ay - 1)][ax][BARRIER_DATA_TOP] == 1 and (ax, ay) != ignore:
                dirs.append(dirDown)
            if ay + 1 < self.height and data[ay][ax][BARRIER_DATA_TOP] == 1 and (ax, ay) != ignore:
                dirs.append(dirUp)
            return dirs

        visited = []

        def tryVisitNeighbor(ax, ay, ad):
            if ad == dirUp:
                if data[ay][ax] in visited:
                    return None
                visited.append(data[ay][ax])
                data[ay][ax][BARRIER_DATA_TOP] = 0
                ay += 1
            elif ad == dirDown:
                if data[(ay - 1)][ax] in visited:
                    return None
                visited.append(data[(ay - 1)][ax])
                data[(ay - 1)][ax][BARRIER_DATA_TOP] = 0
                ay -= 1
            elif ad == dirLeft:
                if data[ay][(ax - 1)] in visited:
                    return None
                visited.append(data[ay][(ax - 1)])
                data[ay][(ax - 1)][BARRIER_DATA_RIGHT] = 0
                ax -= 1
            elif ad == dirRight:
                if data[ay][ax] in visited:
                    return None
                visited.append(data[ay][ax])
                data[ay][ax][BARRIER_DATA_RIGHT] = 0
                ax += 1
            return (ax, ay)

        def openBarriers(x, y):
            dirs = getAvailableDirections(x, y)
            for dir in dirs:
                next = tryVisitNeighbor(x, y, dir)
                if next is not None:
                    openBarriers(*next)

            return

        x = self._rng.randint(0, self.width - 1)
        y = self._rng.randint(0, self.height - 1)
        openBarriers(x, y)
        self._barrierData = data
        return

    def _generateMazeData(self):
        if not hasattr(self, 'quadrantData'):
            self._gatherQuadrantData()
        self._data = {}
        self._data['width'] = (self.width + 1) * self.frameWallThickness + self.width * self.quadrantSize
        self._data['height'] = (self.height + 1) * self.frameWallThickness + self.height * self.quadrantSize
        self._data['originX'] = int(self._data['width'] / 2)
        self._data['originY'] = int(self._data['height'] / 2)
        collisionTable = []
        horizontalWall = [ 1 for x in xrange(self._data['width']) ]
        collisionTable.append(horizontalWall)
        for i in xrange(0, len(self.quadrantData), self.width):
            for y in xrange(self.quadrantSize):
                row = [
                 1]
                for x in xrange(i, i + self.width):
                    if x == 1 and y < self.quadrantSize / 2 - 2:
                        newData = []
                        for j in self.quadrantData[x][1][y]:
                            if j == 0:
                                newData.append(2)
                            else:
                                newData.append(j + 0)

                        row += newData + [1]
                    else:
                        row += self.quadrantData[x][1][y] + [1]

                collisionTable.append(row)

            collisionTable.append(horizontalWall[:])

        barriers = Globals.MazeBarriers
        for i in xrange(len(barriers)):
            for coords in barriers[i]:
                collisionTable[coords[1]][coords[0]] = 0

        y = self._data['originY']
        for x in xrange(len(collisionTable[y])):
            if collisionTable[y][x] == 0:
                collisionTable[y][x] = 2

        x = self._data['originX']
        for y in xrange(len(collisionTable)):
            if collisionTable[y][x] == 0:
                collisionTable[y][x] = 2

        self._data['collisionTable'] = collisionTable

    def _loadAndBuildMazeModel(self, flatten=False):
        self.getMazeData()
        self._model = NodePath('CogdoMazeModel')
        levelModel = CogdoUtil.loadMazeModel('level')
        self.quadrants = []
        quadrantUnitSize = int(self.quadrantSize * self.cellWidth)
        frameActualSize = self.frameWallThickness * self.cellWidth
        size = quadrantUnitSize + frameActualSize
        halfWidth = int(self.width / 2)
        halfHeight = int(self.height / 2)
        i = 0
        for y in xrange(self.height):
            for x in xrange(self.width):
                ax = (x - halfWidth) * size
                ay = (y - halfHeight) * size
                extension = ''
                if hasattr(getBase(), 'air'):
                    extension = '.bam'
                filepath = self.quadrantData[i][0] + extension
                angle = self.quadrantData[i][2]
                m = self._createQuadrant(filepath, i, angle, quadrantUnitSize)
                m.setPos(ax, ay, 0)
                m.reparentTo(self._model)
                self.quadrants.append(m)
                i += 1

        quadrantHalfUnitSize = quadrantUnitSize * 0.5
        barrierModel = CogdoUtil.loadMazeModel('grouping_blockerDivider').find('**/divider')
        y = 3
        for x in xrange(self.width):
            if x == (self.width - 1) / 2:
                continue
            ax = (x - halfWidth) * size
            ay = (y - halfHeight) * size - quadrantHalfUnitSize - (self.cellWidth - 0.5)
            b = NodePath('barrier')
            barrierModel.instanceTo(b)
            b.setPos(ax, ay, 0)
            b.reparentTo(self._model)

        offset = self.cellWidth - 0.5
        for x in (0, 3):
            for y in xrange(self.height):
                ax = (x - halfWidth) * size - quadrantHalfUnitSize - frameActualSize + offset
                ay = (y - halfHeight) * size
                b = NodePath('barrier')
                barrierModel.instanceTo(b)
                b.setPos(ax, ay, 0)
                b.setH(90)
                b.reparentTo(self._model)

            offset -= 2.0

        barrierModel.removeNode()
        levelModel.getChildren().reparentTo(self._model)
        for np in self._model.findAllMatches('**/*lightCone*'):
            CogdoUtil.initializeLightCone(np, 'fixed', 3)

        if flatten:
            self._model.flattenStrong()
        return self._model

    def _createQuadrant(self, filepath, serialNum, angle, size):
        root = NodePath('QuadrantRoot-%i' % serialNum)
        quadrant = loader.loadModel(filepath)
        quadrant.getChildren().reparentTo(root)
        root.setH(angle)
        return root
Esempio n. 30
0
 def _createRng(self):
     self.rng = RandomNumGen(self.generationId + self.game.doId)
Esempio n. 31
0
class MazeSuit(DirectObject):
    COLL_SPHERE_NAME = 'MazeSuitSphere'
    COLLISION_EVENT_NAME = 'MazeSuitCollision'
    MOVE_IVAL_NAME = 'moveMazeSuit'
    DIR_UP = 0
    DIR_DOWN = 1
    DIR_LEFT = 2
    DIR_RIGHT = 3
    oppositeDirections = [
        DIR_DOWN,
        DIR_UP,
        DIR_RIGHT,
        DIR_LEFT]
    directionHs = [
        0,
        180,
        90,
        270]
    DEFAULT_SPEED = 4.0
    SUIT_Z = 0.10000000000000001
    
    def __init__(self, serialNum, maze, randomNumGen, cellWalkPeriod, difficulty, suitDnaName = 'f', startTile = None, ticFreq = MazeGameGlobals.SUIT_TIC_FREQ, walkSameDirectionProb = MazeGameGlobals.WALK_SAME_DIRECTION_PROB, walkTurnAroundProb = MazeGameGlobals.WALK_TURN_AROUND_PROB, uniqueRandomNumGen = True, walkAnimName = None):
        self.serialNum = serialNum
        self.maze = maze
        if uniqueRandomNumGen:
            self.rng = RandomNumGen(randomNumGen)
        else:
            self.rng = randomNumGen
        self.difficulty = difficulty
        self._walkSameDirectionProb = walkSameDirectionProb
        self._walkTurnAroundProb = walkTurnAroundProb
        if not walkAnimName:
            pass
        self._walkAnimName = 'walk'
        self.suit = Suit.Suit()
        d = SuitDNA.SuitDNA()
        d.newSuit(suitDnaName)
        self.suit.setDNA(d)
        if startTile is None:
            defaultStartPos = MazeGameGlobals.SUIT_START_POSITIONS[self.serialNum]
            self.startTile = (defaultStartPos[0] * self.maze.width, defaultStartPos[1] * self.maze.height)
        else:
            self.startTile = startTile
        self.ticFreq = ticFreq
        self.ticPeriod = int(cellWalkPeriod)
        self.cellWalkDuration = float(self.ticPeriod) / float(self.ticFreq)
        self.turnDuration = 0.59999999999999998 * self.cellWalkDuration

    
    def destroy(self):
        self.suit.delete()

    
    def uniqueName(self, str):
        return str + `self.serialNum`

    
    def gameStart(self, gameStartTime):
        self.gameStartTime = gameStartTime
        self.initCollisions()
        self.startWalkAnim()
        self.occupiedTiles = [
            (self.nextTX, self.nextTY)]
        n = 20
        self.nextThinkTic = self.serialNum * self.ticFreq / n
        self.fromPos = Point3(0, 0, 0)
        self.toPos = Point3(0, 0, 0)
        self.fromHpr = Point3(0, 0, 0)
        self.toHpr = Point3(0, 0, 0)
        self.moveIval = WaitInterval(1.0)

    
    def gameEnd(self):
        self.moveIval.pause()
        del self.moveIval
        self.shutdownCollisions()
        self.suit.loop('neutral')

    
    def initCollisions(self):
        self.collSphere = CollisionSphere(0, 0, 0, 2.0)
        self.collSphere.setTangible(0)
        self.collNode = CollisionNode(self.uniqueName(self.COLL_SPHERE_NAME))
        self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = self.suit.attachNewNode(self.collNode)
        self.collNodePath.hide()
        self.accept(self.uniqueName('enter' + self.COLL_SPHERE_NAME), self.handleEnterSphere)

    
    def shutdownCollisions(self):
        self.ignore(self.uniqueName('enter' + self.COLL_SPHERE_NAME))
        del self.collSphere
        self.collNodePath.removeNode()
        del self.collNodePath
        del self.collNode

    
    def handleEnterSphere(self, collEntry):
        messenger.send(self.COLLISION_EVENT_NAME, [
            self.serialNum])

    
    def _MazeSuit__getWorldPos(self, sTX, sTY):
        (wx, wy) = self.maze.tile2world(sTX, sTY)
        return Point3(wx, wy, self.SUIT_Z)

    
    def onstage(self):
        sTX = int(self.startTile[0])
        sTY = int(self.startTile[1])
        c = 0
        lim = 0
        toggle = 0
        direction = 0
        while not self.maze.isWalkable(sTX, sTY):
            if 0 == direction:
                sTX -= 1
            elif 1 == direction:
                sTY -= 1
            elif 2 == direction:
                sTX += 1
            elif 3 == direction:
                sTY += 1
            
            c += 1
            if c > lim:
                c = 0
                direction = (direction + 1) % 4
                toggle += 1
                if not toggle & 1:
                    lim += 1
                
        self.TX = sTX
        self.TY = sTY
        self.direction = self.DIR_DOWN
        self.lastDirection = self.direction
        self.nextTX = self.TX
        self.nextTY = self.TY
        self.suit.setPos(self._MazeSuit__getWorldPos(self.TX, self.TY))
        self.suit.setHpr(self.directionHs[self.direction], 0, 0)
        self.suit.reparentTo(render)
        self.suit.pose(self._walkAnimName, 0)
        self.suit.loop('neutral')

    
    def offstage(self):
        self.suit.reparentTo(hidden)

    
    def startWalkAnim(self):
        self.suit.loop(self._walkAnimName)
        speed = float(self.maze.cellWidth) / self.cellWalkDuration
        self.suit.setPlayRate(speed / self.DEFAULT_SPEED, self._walkAnimName)

    
    def _MazeSuit__applyDirection(self, dir, TX, TY):
        if self.DIR_UP == dir:
            TY += 1
        elif self.DIR_DOWN == dir:
            TY -= 1
        elif self.DIR_LEFT == dir:
            TX -= 1
        elif self.DIR_RIGHT == dir:
            TX += 1
        
        return (TX, TY)

    
    def _MazeSuit__chooseNewWalkDirection(self, unwalkables):
        if not self.rng.randrange(self._walkSameDirectionProb):
            (newTX, newTY) = self._MazeSuit__applyDirection(self.direction, self.TX, self.TY)
            if self.maze.isWalkable(newTX, newTY, unwalkables):
                return self.direction
            
        
        if self.difficulty >= 0.5:
            if not self.rng.randrange(self._walkTurnAroundProb):
                oppositeDir = self.oppositeDirections[self.direction]
                (newTX, newTY) = self._MazeSuit__applyDirection(oppositeDir, self.TX, self.TY)
                if self.maze.isWalkable(newTX, newTY, unwalkables):
                    return oppositeDir
                
            
        
        candidateDirs = [
            self.DIR_UP,
            self.DIR_DOWN,
            self.DIR_LEFT,
            self.DIR_RIGHT]
        candidateDirs.remove(self.oppositeDirections[self.direction])
        while len(candidateDirs):
            dir = self.rng.choice(candidateDirs)
            (newTX, newTY) = self._MazeSuit__applyDirection(dir, self.TX, self.TY)
            if self.maze.isWalkable(newTX, newTY, unwalkables):
                return dir
            
            candidateDirs.remove(dir)
        return self.oppositeDirections[self.direction]

    
    def getThinkTimestampTics(self, curTic):
        if curTic < self.nextThinkTic:
            return []
        else:
            r = range(self.nextThinkTic, curTic + 1, self.ticPeriod)
            self.lastTicBeforeRender = r[-1]
            return r

    
    def prepareToThink(self):
        self.occupiedTiles = [
            (self.nextTX, self.nextTY)]

    
    def think(self, curTic, curT, unwalkables):
        self.TX = self.nextTX
        self.TY = self.nextTY
        self.lastDirection = self.direction
        self.direction = self._MazeSuit__chooseNewWalkDirection(unwalkables)
        (self.nextTX, self.nextTY) = self._MazeSuit__applyDirection(self.direction, self.TX, self.TY)
        self.occupiedTiles = [
            (self.TX, self.TY),
            (self.nextTX, self.nextTY)]
        if curTic == self.lastTicBeforeRender:
            fromCoords = self.maze.tile2world(self.TX, self.TY)
            toCoords = self.maze.tile2world(self.nextTX, self.nextTY)
            self.fromPos.set(fromCoords[0], fromCoords[1], self.SUIT_Z)
            self.toPos.set(toCoords[0], toCoords[1], self.SUIT_Z)
            self.moveIval = LerpPosInterval(self.suit, self.cellWalkDuration, self.toPos, startPos = self.fromPos, name = self.uniqueName(self.MOVE_IVAL_NAME))
            if self.direction != self.lastDirection:
                self.fromH = self.directionHs[self.lastDirection]
                toH = self.directionHs[self.direction]
                if self.fromH == 270 and toH == 0:
                    self.fromH = -90
                elif self.fromH == 0 and toH == 270:
                    self.fromH = 360
                
                self.fromHpr.set(self.fromH, 0, 0)
                self.toHpr.set(toH, 0, 0)
                turnIval = LerpHprInterval(self.suit, self.turnDuration, self.toHpr, startHpr = self.fromHpr, name = self.uniqueName('turnMazeSuit'))
                self.moveIval = Parallel(self.moveIval, turnIval, name = self.uniqueName(self.MOVE_IVAL_NAME))
            else:
                self.suit.setH(self.directionHs[self.direction])
            moveStartT = float(self.nextThinkTic) / float(self.ticFreq)
            self.moveIval.start(curT - moveStartT + self.gameStartTime)
        
        self.nextThinkTic += self.ticPeriod

    
    def thinkSuits(suitList, startTime, ticFreq = MazeGameGlobals.SUIT_TIC_FREQ):
        curT = globalClock.getFrameTime() - startTime
        curTic = int(curT * float(ticFreq))
        suitUpdates = []
        for i in xrange(len(suitList)):
            updateTics = suitList[i].getThinkTimestampTics(curTic)
            suitUpdates.extend(zip(updateTics, [
                i] * len(updateTics)))
        
        suitUpdates.sort(lambda a, b: a[0] - b[0])
        if len(suitUpdates) > 0:
            curTic = 0
            for i in xrange(len(suitUpdates)):
                update = suitUpdates[i]
                tic = update[0]
                suitIndex = update[1]
                suit = suitList[suitIndex]
                if tic > curTic:
                    curTic = tic
                    j = i + 1
                    while j < len(suitUpdates):
                        if suitUpdates[j][0] > tic:
                            break
                        
                        suitList[suitUpdates[j][1]].prepareToThink()
                        j += 1
                
                unwalkables = []
                for si in xrange(suitIndex):
                    unwalkables.extend(suitList[si].occupiedTiles)
                
                for si in xrange(suitIndex + 1, len(suitList)):
                    unwalkables.extend(suitList[si].occupiedTiles)
                
                suit.think(curTic, curT, unwalkables)
            
        

    thinkSuits = staticmethod(thinkSuits)
    def load(self, cogdoMazeFactory, numSuits, bossCode):
        self._initAudio()
        self.maze = cogdoMazeFactory.createCogdoMaze()
        suitSpawnSpot = self.maze.createRandomSpotsList(numSuits, self.distGame.randomNumGen)
        self.guiMgr = CogdoMazeGuiManager(self.maze, bossCode)
        self.suits = []
        self.suitsById = {}
        self.shakers = []
        self.toonsThatRevealedDoor = []
        self.quake = 0
        self.dropCounter = 0
        self.drops = {}
        self.gagCounter = 0
        self.gags = []
        self.hackTemp = False
        self.dropGen = RandomNumGen(self.distGame.doId)
        self.gagTimeoutTasks = []
        self.finished = False
        self.lastBalloonTimestamp = None
        difficulty = self.distGame.getDifficulty()
        serialNum = 0
        for i in range(numSuits[0]):
            suitRng = RandomNumGen(self.distGame.doId + serialNum * 10)
            suit = CogdoMazeBossSuit(serialNum, self.maze, suitRng, difficulty, startTile=suitSpawnSpot[0][i])
            self.addSuit(suit)
            self.guiMgr.mazeMapGui.addSuit(suit.suit)
            serialNum += 1

        for i in range(numSuits[1]):
            suitRng = RandomNumGen(self.distGame.doId + serialNum * 10)
            suit = CogdoMazeFastMinionSuit(serialNum, self.maze, suitRng, difficulty, startTile=suitSpawnSpot[1][i])
            self.addSuit(suit)
            serialNum += 1

        for i in range(numSuits[2]):
            suitRng = RandomNumGen(self.distGame.doId + serialNum * 10)
            suit = CogdoMazeSlowMinionSuit(serialNum, self.maze, suitRng, difficulty, startTile=suitSpawnSpot[2][i])
            self.addSuit(suit)
            serialNum += 1

        self.toonId2Door = {}
        self.keyIdToKey = {}
        self.players = []
        self.toonId2Player = {}
        cellPos = (int(self.maze.width / 2), self.maze.height - 1)
        pos = self.maze.tile2world(*cellPos)
        self._exit = CogdoMazeExit()
        self._exit.reparentTo(render)
        self._exit.setPos(self.maze.exitPos)
        self._exit.stash()
        self.guiMgr.mazeMapGui.placeExit(*cellPos)
        self._collNode2waterCooler = {}
        for waterCooler in self.maze.getWaterCoolers():
            pos = waterCooler.getPos(render)
            tpos = self.maze.world2tile(pos[0], pos[1])
            self.guiMgr.mazeMapGui.addWaterCooler(*tpos)
            self._collNode2waterCooler[waterCooler.collNode] = waterCooler

        self.pickups = []
        self.gagModel = CogdoUtil.loadMazeModel('waterBalloon')
        self._movie = CogdoMazeGameIntro(self.maze, self._exit, self.distGame.randomNumGen)
        self._movie.load()
        return
 def announceGenerate(self):
     DistributedNPCToonBase.announceGenerate(self)
     self.rng = RandomNumGen(self.doId)
     self.setHat(59, 0, 0)
     if self.style.gender == 'm':
         self.setGlasses(22, 0, 0)
Esempio n. 34
0
 def randomColor(self):
     rand = RandomNumGen(globalClock.getFrameTime())
     self.panda.setColorScale(rand.random(), rand.random(), rand.random(),
                              1)
class DistributedNPCPrizeClerk(DistributedNPCToonBase):
    def __init__(self, cr):
        DistributedNPCToonBase.__init__(self, cr)
        self.rng = None
        self.gui = None
        self.isLocalToon = 0
        self.av = None
        self.numHouseItems = None
        return

    def announceGenerate(self):
        DistributedNPCToonBase.announceGenerate(self)
        self.rng = RandomNumGen(self.doId)
        self.setHat(59, 0, 0)
        if self.style.gender == 'm':
            self.setGlasses(22, 0, 0)

    def disable(self):
        self.ignoreAll()
        taskMgr.remove(self.uniqueName('popupPrizeGUI'))
        taskMgr.remove(self.uniqueName('lerpCamera'))
        if self.gui:
            self.gui.exit()
            self.gui = None
        self.av = None
        base.localAvatar.posCamera(0, 0)
        DistributedNPCToonBase.disable(self)
        return

    def allowedToEnter(self):
        if hasattr(base,
                   'ttAccess') and base.ttAccess and base.ttAccess.canAccess():
            return True
        return False

    def handleOkTeaser(self):
        self.dialog.destroy()
        del self.dialog
        place = base.cr.playGame.getPlace()
        if place:
            place.fsm.request('walk')

    def handleCollisionSphereEnter(self, collEntry):
        if self.allowedToEnter():
            base.cr.playGame.getPlace().fsm.request('purchase')
            self.sendUpdate('avatarEnter', [])
        else:
            place = base.cr.playGame.getPlace()
            if place:
                place.fsm.request('stopped')
            self.dialog = TeaserPanel.TeaserPanel(pageName='otherGags',
                                                  doneFunc=self.handleOkTeaser)

    def initToonState(self):
        self.setAnimState('neutral', 1.05, None, None)
        npcOrigin = self.cr.playGame.hood.loader.geom.find(
            '**/npc_prizeclerk_origin_%s;+s' % self.posIndex)
        if not npcOrigin.isEmpty():
            self.reparentTo(npcOrigin)
            self.clearMat()
        else:
            self.notify.warning(
                'announceGenerate: Could not find npc_prizeclerk_origin_' +
                str(self.posIndex))
        return

    def __handleUnexpectedExit(self):
        self.notify.warning('unexpected exit')
        self.av = None
        return

    def resetClerk(self):
        self.ignoreAll()
        taskMgr.remove(self.uniqueName('popupPrizeGUI'))
        taskMgr.remove(self.uniqueName('lerpCamera'))
        if self.gui:
            self.gui.exit()
            self.gui = None
        self.clearMat()
        self.startLookAround()
        self.detectAvatars()
        if self.isLocalToon:
            self.freeAvatar()
        return Task.done

    def setLimits(self, numHouseItems):
        self.numHouseItems = numHouseItems

    def setMovie(self, mode, npcId, avId, timestamp):
        timeStamp = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
        self.remain = NPCToons.CLERK_COUNTDOWN_TIME - timeStamp
        self.isLocalToon = avId == base.localAvatar.doId
        if mode == NPCToons.PURCHASE_MOVIE_CLEAR:
            return
        if mode == NPCToons.PURCHASE_MOVIE_START:
            self.av = base.cr.doId2do.get(avId)
            if self.av is None:
                self.notify.warning('Avatar %d not found in doId' % avId)
                return
            self.accept(self.av.uniqueName('disable'),
                        self.__handleUnexpectedExit)
            self.setupAvatars(self.av)
            if self.isLocalToon:
                camera.wrtReparentTo(render)
                self.cameraLerp = LerpPosQuatInterval(
                    camera,
                    1,
                    Point3(-4, 16,
                           self.getHeight() - 0.5),
                    Point3(-150, -2, 0),
                    other=self,
                    blendType='easeInOut')
                self.cameraLerp.start()
            self.setChatAbsolute(
                self.rng.choice(TTLocalizer.TF_STOREOWNER_GREETING),
                CFSpeech | CFTimeout)
            if self.isLocalToon:
                taskMgr.doMethodLater(1.0, self.popupPrizeGUI,
                                      self.uniqueName('popupPrizeGUI'))
        else:
            if MODE_TO_PHRASE.has_key(mode):
                self.setChatAbsolute(self.rng.choice(MODE_TO_PHRASE[mode]),
                                     CFSpeech | CFTimeout)
            else:
                if mode == NPCToons.PURCHASE_MOVIE_TIMEOUT:
                    self.setChatAbsolute(
                        self.rng.choice(TTLocalizer.TF_STOREOWNER_TOOKTOOLONG),
                        CFSpeech | CFTimeout)
                    self.resetClerk()
                else:
                    if mode == NPCToons.PURCHASE_MOVIE_COMPLETE:
                        self.setChatAbsolute(
                            self.rng.choice(TTLocalizer.TF_STOREOWNER_GOODBYE),
                            CFSpeech | CFTimeout)
                        self.resetClerk()
        return

    def popupPrizeGUI(self, task):
        self.accept(DONE_EVENT, self.__handleGuiDone)
        self.gui = ToonfestPrizeCollect.ToonfestPrizeCollect(
            npc=self, random=self.rng, doneEvent=DONE_EVENT)
        self.gui.show()
        return Task.done

    def __handleGuiDone(self):
        self.ignore(DONE_EVENT)
        self.d_requestFinished()
        self.gui = None
        return

    def requestPurchase(self, item, callback, optional=-1):
        blob = item.getBlob(store=CatalogItem.Customization)
        context = self.getCallbackContext(callback, [item])
        self.d_requestPrize(context, blob, optional)

    def d_requestPrize(self, context, blob, optional):
        self.sendUpdate('requestPrize', [context, blob, optional])

    def d_requestPrizeInfo(self, context, retcode):
        self.doCallbackContext(context, [retcode])

    def d_requestFinished(self):
        self.sendUpdate('requestFinished', [])