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 __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
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
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 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
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
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
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)
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
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
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()
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)
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()
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
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)
def startIntro(self): self._movie = CogdoFlyingGameIntro(self.level, RandomNumGen(self.distGame.doId)) self._movie.load() self._movie.play() self.audioMgr.playMusic('normal')
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)
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)
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
def _createRng(self): self.rng = RandomNumGen(self.generationId + self.game.doId)
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)
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', [])