def enemyCanMoveTo(destination: tuple, enemy: Enemy, level: Level): """ Check if the destination given can be moved to by a given enemy :param destination: tuple :param enemy: Enemy :param level: Level """ # TODO: not needed yet destBoardNumber = whichBoardInLevel(level, destination) enemyBoardNumber = whichBoardInLevel(level, enemy.location) # TODO: will need to change to enemyPossibleCardinalMoves when specs for # enemy movement come in, for now using player cardinal movement. possibleMoves = playerPossibleCardinalMoves(enemy.location, 2, level, enemyBoardNumber) if destination not in possibleMoves: return False board = level.boards[destBoardNumber] for tile in board.tiles: if tile.location == destination: if tile.tileType is not TileEnum.WALL: # TODO ghost/zombie return True return False
def playerCanMoveTo(destination: tuple, player: Player, level: Level, numMoves: int): """ Check if the destination given can be moved to by a given player. (True if destination does not have a player and is traversable) :param destination: tuple :param player: Player :param level: Level :param numMoves: int """ # NOTE this gets all locations in the board destBoardNumber = whichBoardInLevel(level, destination) playerBoardNumber = whichBoardInLevel(level, player.location) possibleMoves = playerPossibleCardinalMoves(player.location, numMoves, level) if destination not in possibleMoves: return False board = level.boards[destBoardNumber] if isTileOnBoard(destination, board): if board.tiles[destination[0]][ destination[1]].tileType is not TileEnum.WALL \ and not destHasPlayer(destination, board): return True return False
def convertJsonDungeon(jsonLevel: dict, jsonPlayers: list, jsonEnemies: list, jsonExitLocked: bool): level: Level = convertJsonLevel(jsonLevel["rooms"], jsonLevel["hallways"], jsonLevel["objects"]) level.exitUnlocked = not jsonExitLocked playerNames = [] for player in jsonPlayers: # make player newPlayer = convertJsonPlayer(player) playerNames.append(newPlayer.name) playerDict = {newPlayer.name: newPlayer} playerBoard = whichBoardInLevel(level, newPlayer.location) level.boards[playerBoard] = addPlayersToBoard( level.boards[playerBoard], playerDict) # Same for enemies enemyNames = [] for enemy in jsonEnemies: newEnemy = convertJsonEnemy(enemy) enemyNames.append(newEnemy.name) enemyDict = {newEnemy.name: newEnemy} enemyBoard = whichBoardInLevel(level, newEnemy.location) level.boards[enemyBoard] = addEnemiesToBoard(level.boards[enemyBoard], enemyDict) game = Dungeon([level], playerNames, 0, False) return game
def move(entityName: str, destination, game: Dungeon, isPlayer=True): """ Updates the game to reflect the movement of a player if they can move to the given destination in the game or skip a turn when destination is None. Returns an unmodified game if the player cannot move based on game rules. :param entityName: str :param destination: tuple | None :param game: Dungeon """ currLevel: Level = game.levels[game.currLevel] # Player move is skipped if destination is None: # only increment player turn updatedPlayerTurn = currLevel.playerTurn + 1 if updatedPlayerTurn == len(game.players) - 1: currLevel.playerTurn = 0 else: currLevel.playerTurn = updatedPlayerTurn return game entity = getPlayer(currLevel, entityName) if isPlayer else getEnemy( currLevel, entityName) currBoardNum = whichBoardInLevel(currLevel, entity.location) newBoardNum = whichBoardInLevel(currLevel, destination) numMoves = 2 if isPlayer and playerCanMoveTo(destination, entity, currLevel, numMoves): updatedLevel = moveEntity(currLevel, entityName, currBoardNum, newBoardNum, destination, isPlayer=True) if updatedLevel.playerTurn == len(game.players) - 1: updatedLevel.playerTurn = 0 updatedLevel.enemyTurn = updatedLevel.enemyTurn + 1 else: updatedLevel.playerTurn = updatedLevel.playerTurn + 1 updatedLevel.enemyTurn = updatedLevel.enemyTurn + 1 game.levels[game.currLevel] = updatedLevel updatedGame = interact(entityName, destination, game) return updatedGame elif not isPlayer: updatedLevel = moveEntity(currLevel, entityName, currBoardNum, newBoardNum, destination, isPlayer=False) game.levels[game.currLevel] = updatedLevel updatedGame = enemyInteract(entityName, destination, game) return updatedGame else: return game
def getActorsAroundPlayer(possMoves: list, game: Dungeon): """ Returns the actors around a player in JSON format. :params possMoves: list :params game: Dungeon """ acc = [] for loc in possMoves: level: Level = game.levels[game.currLevel] boardNum = whichBoardInLevel(level, loc) if destHasEnemy(loc, level.boards[boardNum]): enemy: Enemy = first_true(level.boards[boardNum].enemies.values(), pred=lambda enem: enem.location == loc) acc.append({ "type": enemy.enemyType, "name": enemy.name, "position": loc }) if destHasPlayer(loc, level.boards[boardNum]): player: Player = first_true( level.boards[boardNum].players.values(), pred=lambda playa: playa.location == loc) acc.append({ "type": "player", "name": player.name, "position": loc }) return acc
def move(playerName: str, destination: tuple, game: Dungeon): """ Updates the game to reflect the movement of a player if they can move to the given destination in the game. Returns an unmodified game if the player cannot move based on game rules. :param playerName: str :param destination: tuple :param game: Dungeon """ currLevel: Level = game.levels[game.currLevel] currBoardNum = whichBoardInLevel(currLevel, destination) currBoard: Board = currLevel.boards[currBoardNum] player = currBoard.players[playerName] numMoves = 2 if playerCanMoveTo(destination, player, currLevel, numMoves): updatedLevel = moveEntity(currLevel, playerName, currBoardNum, destination, isPlayer=True) game.levels[game.currLevel] = updatedLevel updatedGame = interact(playerName, destination, game) return updatedGame else: return game
def enemyPossibleMoves(enemy: Enemy, game: Dungeon): """ Gets a list of the possible moves a given enemy can feasibly make. In essence, gets all the moves are traversable within each enemy's walkable distance. :params enemy: Enemy :params game: Dungeon """ possibleMoves = [] enemyBoardNum = whichBoardInLevel(game.levels[game.currLevel], enemy.location) enemyBoard: Board = game.levels[game.currLevel].boards[enemyBoardNum] if enemy.enemyType == "zombie": tilesAround = getLocationsAround(enemy.location) for loc in tilesAround: if locationInBounds(loc, enemyBoard.origin, enemyBoard.dimensions): tile = enemyBoard.tiles[loc[0]][loc[1]] if tile.tileType != TileEnum.WALL and tile.tileType != TileEnum.DOOR: possibleMoves.append(loc) elif enemy.enemyType == "ghost": tilesAround = getLocationsAround(enemy.location) for loc in tilesAround: if locationInLevelBounds(game.levels[game.currLevel], loc): possibleMoves.append(loc) return possibleMoves
def main(): output = {} try: inputJson = sys.stdin.read() parsedJson = json.loads(inputJson.replace("\n", "")) jsonLevel, jsonPoint = parsedJson givenPoint = intifyTuple(tuple(jsonPoint)) rooms = jsonLevel["rooms"] hallways = jsonLevel["hallways"] objects = jsonLevel["objects"] level = convertJsonLevel(rooms, hallways, objects) currentRoom = whichBoardInLevel(level, givenPoint) if currentRoom != -1: outputTraversable = isTraversable(level, currentRoom, givenPoint) outputObject = objectOutput(objects, givenPoint) outputType = typeOutput(level, currentRoom) outputReachable = reachableRoomOrigins(level, currentRoom) else: outputTraversable = False outputObject = None outputType = 'void' outputReachable = [] output['traversable'] = outputTraversable output['object'] = outputObject output['type'] = outputType output['reachable'] = outputReachable print(json.dumps(output)) except json.JSONDecodeError: print("Malformed input.") sys.exit(1) except KeyboardInterrupt: print("Exiting...") sys.exit(0)
def enemyNextMove(enemy: Enemy, game: Dungeon): """ Selects the next move for a given enemy according to the predetermined move strategies for enemies. If no valid moves are possible, then returns the enemy's location. """ enemyBoardNum = whichBoardInLevel(game.levels[game.currLevel], enemy.location) possMoves = enemyPossibleMoves(enemy, game) log("possible enemy moves to choose from:", str(possMoves)) if len(possMoves) == 0: return enemy.location playersInOurRoom, playersInOurLevel = getPlayersInRoomAndLevel( enemyBoardNum, game) if len(playersInOurRoom) != 0: playerLocs = [player.location for player in playersInOurRoom] return enemyStrat(possMoves, playerLocs) elif len(playersInOurLevel) != 0: playerLocs = [player.location for player in playersInOurLevel] return enemyStrat(possMoves, playerLocs) else: # No valid move log("shouldn't EVER EZVER EVER get here. green man you must MOVE") return enemy.location
def validMoveForHarness(destination: tuple, level: Level): boardNum = whichBoardInLevel(level, destination) if boardNum == -1: return False if destHasPlayer(destination, level.boards[boardNum]): return False for tile in level.boards[boardNum].tiles: if tile.location == destination: return tile.tileType is not TileEnum.WALL return False
def enemyInteract(enemyName: str, destination: tuple, game: Dungeon): currLevel: Level = game.levels[game.currLevel] currBoardNum = whichBoardInLevel(currLevel, destination) currBoard: Board = currLevel.boards[currBoardNum] if destHasPlayer(destination, currBoard): return interactWithPlayer(destination, game) elif destHasWall(destination, currLevel): return interactWithWall(enemyName, destination, game) else: return game
def validMoveForHarness(destination: tuple, level: Level): boardNum = whichBoardInLevel(level, destination) if boardNum == -1: return False if destHasPlayer(destination, level.boards[boardNum]): return False if isTileOnBoard(destination, level.boards[boardNum]): tile = level.boards[boardNum].tiles[destination[0]][destination[1]] return tile.tileType is not TileEnum.WALL return False
def interactWithPlayer(dest: tuple, game: Dungeon): currLevel: Level = game.levels[game.currLevel] currBoardNum = whichBoardInLevel(currLevel, dest) currBoard: Board = currLevel.boards[currBoardNum] for player in currBoard.players.values(): if player.location == dest: updatedGame = removePlayer(player.name, currBoardNum, game) if len(getAllPlayers(currLevel)) == 0: updatedGame = endGame(updatedGame) return updatedGame return game
def reachableRoomOrigins(level: Level, currBoardIndex: int): reachable = [] givenRoom: Board = level.boards[currBoardIndex] if givenRoom.boardType == BoardEnum.HALLWAY: for connection in givenRoom.doorLocations: connIndex = whichBoardInLevel(level, connection) reachable.append(level.boards[connIndex].origin) else: for connection in givenRoom.doorLocations: for board in level.boards: if (board.boardType == BoardEnum.HALLWAY) and (connection in board.doorLocations): for loc in board.doorLocations: if loc != connection: connIndex = whichBoardInLevel(level, loc) if level.boards[connIndex].origin not in reachable: reachable.append( level.boards[connIndex].origin) return reachable
def getMoveStatus(currLevel: Level, playerName: str, move: dict): dest = intifyTuple(move["to"]) if destHasKey(dest, currLevel): return [playerName, move, "Key"] elif destHasExit(dest, currLevel): return [playerName, move, "Exit"] elif destHasEnemy(dest, currLevel.boards[whichBoardInLevel(currLevel, dest)]): return [playerName, move, "Eject"] else: return [playerName, move, "OK"]
def addPlayer(player: Player, game: Dungeon): """ Adds a new player to a game :param player: Player :param game: Dungeon """ currLevel: Level = game.levels[game.currLevel] currBoardNum = whichBoardInLevel(currLevel, player.location) currBoard: Board = currLevel.boards[currBoardNum] updatedBoard = addPlayersToBoard(currBoard, {player.name: player}) game.levels[game.currLevel] = updatedBoard return game
def destHasWall(destination: tuple, level: Level): """ Checks if moving to the destination will cause an interaction with a wall :param destination: tuple :param level: Level """ boardNum = whichBoardInLevel(level, destination) if boardNum != -1: board = level.boards[boardNum] tile = board.tiles[destination[0]][destination[1]] if tile.tileType == TileEnum.WALL: return True return False
def getEnemiesAroundPlayer(possMoves: list, game: Dungeon): acc = [] for loc in possMoves: level: Level = game.levels[game.currLevel] boardNum = whichBoardInLevel(level, loc) if destHasEnemy(loc, level.boards[boardNum]): enemy: Enemy = first_true(level.boards[boardNum].enemies.values(), pred=lambda enem: enem.location == loc) acc.append({ "type": enemy.enemyType, "name": enemy.name, "position": loc }) return acc
def getSuccessStatus(destination: tuple, initGame: Dungeon): level: Level = initGame.levels[0] destBoard = whichBoardInLevel(level, destination) # 1. exit if level.exitUnlocked and level.exitLocation == destination: status = MoveStatus.EXITED # 2. ejected elif destHasEnemy(destination, level.boards[destBoard]): status = MoveStatus.EJECTED elif destHasKey(destination, level): status = MoveStatus.KEY # 3. Success else: status = MoveStatus.SUCCESS return status
def getVisibleTiles(player: Player, level: Level): pLocRow, pLocCol = player.location origin = (pLocRow - 2, pLocCol - 2) fieldOfView = {} for r in range(5): fovRow = {} relRow = origin[0] + r for c in range(5): relCol = origin[1] + c relLoc = (relRow, relCol) if locationInLevelBounds(level, relLoc): boardNum = whichBoardInLevel(level, relLoc) tile = level.boards[boardNum].tiles[relRow][relCol] fovRow[relCol] = tile fieldOfView.update({relRow: fovRow}) return fieldOfView
def interactWithEnemy(playerName: str, location: tuple, game: Dungeon): """ Calculates the consequence of a player interacting with an enemy and updates the state of the game. :param playerName: str :param location: tuple :param game: Dungeon """ currLevel: Level = game.levels[game.currLevel] currBoardNum = whichBoardInLevel(currLevel, location) currBoard: Board = currLevel.boards[currBoardNum] for enemyName in currBoard.enemies.keys(): enemy: Enemy = currBoard.enemies[enemyName] if location == enemy.location: # fight! del currBoard.players[playerName] break return game
def interactWithExit(playerName: str, location: tuple, game: Dungeon): """ Computes the resulting game state of a player acquires an exit in the level. :param playerName: str :param location: tuple :param game: Dungeon """ for level in game.levels: if location == level.exitLocation: if level.exitUnlocked: currBoardNum = whichBoardInLevel(level, location) currBoard: Board = level.boards[currBoardNum] if len(currBoard.players.values()) == 1: # last player # FIXME return advanceLevel(game) return removePlayer(playerName, currBoardNum, game) else: return removePlayer(playerName, currBoardNum, game) return game
def interactWithEnemy(playerName: str, location: tuple, game: Dungeon): """ Calculates the consequence of a player interacting with an enemy and updates the state of the game. :param playerName: str :param location: tuple :param game: Dungeon """ currLevel: Level = game.levels[game.currLevel] currBoardNum = whichBoardInLevel(currLevel, location) currBoard: Board = currLevel.boards[currBoardNum] for enemyName in currBoard.enemies.keys(): enemy: Enemy = currBoard.enemies[enemyName] if location == enemy.location: # fight! updatedGame = ejectPlayer(playerName, currBoardNum, game) # if last player in level, game over if len(getAllPlayers(currLevel)) == 0: updatedGame = endGame(updatedGame) return updatedGame return game
def interactWithExit(playerName: str, location: tuple, game: Dungeon): """ Computes the resulting game state of a player acquires an exit in the level. :param playerName: str :param location: tuple :param game: Dungeon """ log("Interacting with exit") for level in game.levels: if location == level.exitLocation: if level.exitUnlocked: currBoardNum = whichBoardInLevel(level, location) log("Removing player") updatedGame = exitPlayer(playerName, currBoardNum, game) if len(getAllPlayers(level)) == 0: updatedGame = endGame(updatedGame) return updatedGame return game
def interact(playerName: str, location: tuple, game: Dungeon): """ Updates the game to reflect a player's interaction with a location in the game. :param playerName: str :param location: tuple :param game: Dungeon """ currLevel: Level = game.levels[game.currLevel] currBoardNum = whichBoardInLevel(currLevel, location) currBoard: Board = currLevel.boards[currBoardNum] if destHasEnemy(location, currBoard): return interactWithEnemy(playerName, location, game) elif destHasKey(location, currLevel): return interactWithKey(location, game) elif destHasExit(location, currLevel): return interactWithExit(playerName, location, game) # elif destHasItem(location, currBoard): # TODO implement interactWithItem # return game else: return game
def interactWithExit(playerName: str, location: tuple, game: Dungeon): """ Computes the resulting game state of a player acquires an exit in the level. :param playerName: str :param location: tuple :param game: Dungeon """ for level in game.levels: if location == level.exitLocation: if level.exitUnlocked: currBoardNum = whichBoardInLevel(level, location) playersLeft = getPlayersInLevel(level) if len(playersLeft) == 1: # last player # FIXME return advanceLevel(game) return advanceLevel(game) else: updatedGame = removePlayer(playerName, currBoardNum, game) if len(getAllPlayers(level)) == 0: updatedGame = endGame(updatedGame) return updatedGame return game
def start(args): log = logInFile("Server.py") # Global vars JSON_LEVELS = args['jsonLevels'] NUM_LEVELS = args['numLevels'] NUM_CLIENTS = args['numClients'] WAIT = args['wait'] OBSERVE = args['observe'] ADDRESS = args['address'] PORT = args['port'] # Ready to begin CONNS = {} SOCK = None try: SOCK = socket.socket(socket.AF_INET, socket.SOCK_STREAM) SOCK.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) SOCK.settimeout(WAIT) SOCK.bind((ADDRESS, PORT)) SOCK.listen(NUM_CLIENTS) CONNS = registerPlayers(NUM_CLIENTS, SOCK) # Setup game (Convert levels, populate players, populate enemies, # create dungeon) GAME, playerNames = setupGame(list(CONNS.keys()), JSON_LEVELS) # Broadcast initial game state broadcast(startLevelMsg(1, playerNames), CONNS) # Send initial player update msgs broadcastPlayerUpdates(CONNS, GAME) log("GAME INITIALIZED!") # Enter main loop while True: # Obtain the current level currLevel: Level = GAME.levels[GAME.currLevel] # Check if the level has been completed if isLevelOver(currLevel): GAME = advanceLevel(GAME) broadcastLevelOver(GAME, CONNS) # Check if game is over if GAME.isGameOver: broadcastGameOver(GAME, CONNS) broadcast("disconnect", CONNS) # Execute player turns for playerName in playerNames: try: player = getPlayer(currLevel, playerName) if player: initLoc = player.location playerTurn = GAME.levels[GAME.currLevel].playerTurn MAX_TRIES = 5 for tries in range(MAX_TRIES): time.sleep(1) playerMove = executeTurn(CONNS[playerName]) GAME = move(playerName, playerMove, GAME) playerAfter = getPlayer(currLevel, playerName) moveMade = not playerAfter or playerTurn != \ GAME.levels[ GAME.currLevel].playerTurn if moveMade: break # last turn and still no valid move made if not moveMade: if tries == (MAX_TRIES - 1): GAME = move(playerName, None, GAME) else: sendPlayer(playerName, "Invalid move. Try again...", CONNS) broadcastPlayerUpdates(CONNS, GAME) except PlayerDisconnect: # TODO broadcast?? log("PLAYER DISCONNECTED") player: Player = getPlayer(currLevel, playerName) playerBoardNum = whichBoardInLevel(currLevel, player.location) GAME = removePlayer(playerName, playerBoardNum, GAME) # TODO reset playerNames continue # Execute enemy turns currLevel: Level = GAME.levels[GAME.currLevel] for enemy in getEnemiesInLevel(currLevel): nextMove = enemyNextMove(enemy, GAME) GAME = move(enemy.name, nextMove, GAME, isPlayer=False) broadcastPlayerUpdates(CONNS, GAME) # for playerName in playerNames: # msg = enemy.name + " moved" # broadcast(playerUpdateMsg(playerName, GAME, msg), CONNS) except json.JSONDecodeError: print("Malformed level file. Check your formatting") closeConns(CONNS) if SOCK: SOCK.close() sys.exit(1) except KeyboardInterrupt: print("\nExiting...") closeConns(CONNS) if SOCK: SOCK.close() sys.exit(0)
def main(): DEFAULT_LEVEL = './tests/snarl.levels' numPlayers = 1 startLevel = 1 jsonLevels = [] isObserving = False numLevels = 0 parser = argparse.ArgumentParser() # initialize # this is how you add an optional argument parser.add_argument("--levels", help="Enter the name of an input JSON Level file", nargs='?', const=DEFAULT_LEVEL, type=str) parser.add_argument("--players", help="Enter an amount of players 1-4", nargs='?', const=numPlayers, type=int) parser.add_argument("--start", nargs='?', help="Enter the number of the level to start the game from", const=startLevel, type=int) parser.add_argument("--observe", help="Observe the game", action="store_true") # this is called after you define your optional args args = parser.parse_args() # Parse level if args.levels: log('got levels flag', args.levels) with open(args.levels) as file: wholeFile = file.read() portions = wholeFile.split('\n\n') cleaned = list(filter(lambda port: port != '', portions)) numLevels = cleaned[0] jsonLevels = cleaned[1:] else: log("using default level") with open(DEFAULT_LEVEL) as file: wholeFile = file.read() portions = wholeFile.split('\n\n') cleaned = list(filter(lambda port: port != '', portions)) numLevels = cleaned[0] jsonLevels = cleaned[1:] if args.players: if 1 <= args.players <= 4: log('got players flag', str(args.players)) numPlayers = args.players else: print("Players must be from 1-4") sys.exit(1) if args.start and 0 < args.start <= len(jsonLevels): log('got start flag', args.start) startLevel = args.start if args.observe: log('got observe') isObserving = True try: rawJsonGameLevels = jsonLevels[(startLevel - 1):] jsonGameLevels = [json.loads(rawJsonLevel) for rawJsonLevel in rawJsonGameLevels] log("got+converted {} levels".format(len(jsonGameLevels))) # this has all the levels needed with the starting level as the first # element in the list levels = [convertJsonLevel(jsonLevel["rooms"], jsonLevel["hallways"], jsonLevel["objects"]) for jsonLevel in jsonGameLevels] playerNames = [input("Player {}, enter your name > ".format(i + 1)) for i in range(numPlayers)] log("Using levels", str(levels)) forbidden = [levels[0].keyLocation, levels[0].exitLocation] players = [] playerLocs = [] i = 0 while i < numPlayers: # Populate players in level playerName = playerNames[i] randBoardNum, randBoard = getRandomRoomInLevel(levels[0]) log("Rand board", str(randBoardNum), str(randBoard.dimensions)) loc = genXRandCoords(1, forbidden, randBoard.origin, randBoard.dimensions).pop() if loc not in playerLocs: player = Player(playerName, loc) players.append(player) levels[0].boards[randBoardNum] = addPlayersToBoard(randBoard, { playerName: player}) playerLocs.append(loc) i += 1 game = Dungeon(levels, playerNames, startLevel - 1, False) enemies = [] # LIST of dictionaries for each level for i in range(len(game.levels)): numZombies = math.floor((i + 1) / 2) + 1 numGhosts = math.floor(((i + 1) - 1) / 2) log("NUM ZOMBIES", str(numZombies), "NUM GHOSTS", str(numGhosts)) levelEnemies = {} enemyLocs = [] for zombie in range(numZombies): randBoardNum, randBoard = getRandomRoomInLevel(levels[i]) name = "zombie" + str((zombie + 1)) # log("BUILDIGN NEW ZOMBIEEE") # log("NAME: ", name) loc = genXRandCoords(1, playerLocs + forbidden + enemyLocs, randBoard.origin, randBoard.dimensions).pop() log("LOC", str(loc)) enemyLocs.append(loc) newZombie = Enemy(name, loc) levelEnemies[name] = (randBoardNum, newZombie) for ghost in range(numGhosts): randBoardNum, randBoard = getRandomRoomInLevel(levels[i]) name = "ghost" + str((ghost + 1)) loc = genXRandCoords(1, playerLocs + forbidden + enemyLocs, randBoard.origin, randBoard.dimensions) # loc = getRandCoordInLevel(level, True) enemyLocs.append(loc) newGhost = Enemy(name, loc, "ghost") levelEnemies[name] = (randBoardNum, newGhost) enemies.append(levelEnemies) populateEnemies(i, levelEnemies, game) # Initialize screen pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode(Globals.SCREEN_DIMENSIONS, flags=pygame.RESIZABLE) pygame.display.set_caption("Local Snarl Demo") # Fill background. Draw onto this gameDisplaySize = ( Globals.GAME_DISPLAY_WIDTH, Globals.GAME_DISPLAY_HEIGHT) background = pygame.Surface(gameDisplaySize) statusBarSize = (Globals.STATUS_BAR_WIDTH, Globals.STATUS_BAR_HEIGHT) statusBar = pygame.Surface(statusBarSize) background = background.convert() # converts Surface to single-pixel statusBar = statusBar.convert() # converts Surface to single-pixel # format background.fill(Globals.BG_COLOR) statusBar.fill(Globals.BG_COLOR) currLevel0: Level = game.levels[game.currLevel] def getEnemies(enemiesDict: list): acc = [] for enemiesInLevel in enemiesDict: for enemyName in enemiesInLevel.keys(): acc.append(enemiesInLevel[enemyName][1]) return acc allEnemies = getEnemies(enemies) log("All enemies", str(allEnemies)) log("Level has this many boards", str(len(currLevel0.boards))) def locationInTiles(location: tuple, tiles: dict): lrow, lcol = location for row in tiles.keys(): if lrow == row: for col in tiles[row].keys(): if lcol == col: return True return False # if isObserving: # log("OBSERVER VIEW") # allTiles = getAllTiles(currLevel0) # view = ObserverView("observer", allTiles, [currLevel0.keyLocation], # [currLevel0.exitLocation], # players, allEnemies) # renderObserverView(background, view) # else: # log("PLAYER VIEW") # player: Player = getPlayer(currLevel0, playerNames[0]) # visibleTiles = getVisibleTiles(player, currLevel0) # nearbyEnemies = [enemy for enemy in allEnemies if # locationInTiles(enemy.location, visibleTiles)] # nearbyPlayers = [player for player in players if # locationInTiles(player.location, visibleTiles)] # view = PlayerView(playerNames[0], # visibleTiles, # player.location, # [currLevel0.keyLocation], # [currLevel0.exitLocation], # nearbyPlayers, nearbyEnemies) # # renderPlayerView(background, view) # Block events we don't care about and allow ones we do # (speeds processing) pygame.event.set_blocked(None) pygame.event.set_allowed([QUIT, MOUSEBUTTONDOWN, MOUSEBUTTONUP]) hasMoved = {} for player in game.players: hasMoved[player] = 0 while True: # pygame.time.wait(250) clock.tick(30) # cap at 30fps currLevel: Level = game.levels[game.currLevel] if game.isGameOver: log("The game is over! If you won, congrats!") sys.exit(0) log("Player turn is ", str(currLevel.playerTurn)) playerName = game.players[currLevel.playerTurn] player: Player = getPlayer(currLevel, playerName) log("Game players", str(game.players)) log("Level players", str(getAllPlayers(currLevel))) # player not in level (ejected or exited) if not player: log("Skipping turn") hasMoved[playerName] = 1 log("HASSSMOVVVEEEEDD POST ENEMIESS", str(hasMoved)) if currLevel.playerTurn == len(game.players) - 1: currLevel.playerTurn = 0 else: currLevel.playerTurn = currLevel.playerTurn + 1 # currLevel.playerTurn = currLevel.playerTurn + 1 # currLevel.enemyTurn = currLevel.enemyTurn + 1 continue log("Player turn", str(currLevel.playerTurn)) log("Enemy turn:", str(currLevel.enemyTurn)) # Move all enemies at beginning of rounds (all players moved) numPlayersInGame = len(game.players) - 1 # log("numPlayersInGame", str(numPlayersInGame)) # if currLevel.enemyTurn == numPlayersInGame: if all(hasMoved.values()): for enemy in getEnemiesInLevel(currLevel): nextMove = EnemyMove.enemyNextMove(enemy, game) log("Next move is", str(nextMove)) GameManager.move(enemy.name, nextMove, game, isPlayer=False) # currLevel.enemyTurn = -1 for moved in hasMoved.keys(): hasMoved[moved] = 0 log("HASSSMOVVVEEEEDD POST ENEMIESS", str(hasMoved)) board1: Board = currLevel.boards[ whichBoardInLevel(currLevel, player.location)] # Render appropriate view if isObserving: allTiles = getAllTiles(currLevel) allPlayers = getAllPlayers(currLevel) allEnemies = getAllEnemies(currLevel) view = ObserverView("observer", allTiles, [currLevel.keyLocation], [currLevel.exitLocation], allPlayers, allEnemies) renderObserverView(background, view) else: visibleTiles = getVisibleTiles(player, currLevel) visiblePlayers = [board1.players[pname] for pname in board1.players.keys() if locationInTiles( # FIXME bug when player next to you board1.players[pname].location, visibleTiles)] visibleEnemies = [board1.enemies[ename] for ename in board1.enemies.keys() if locationInTiles( board1.enemies[ename].location, visibleTiles)] newView = PlayerView(playerName, visibleTiles, player.location, [currLevel.keyLocation], [currLevel.exitLocation], visiblePlayers, visibleEnemies) renderPlayerView(background, newView) # Everyone gets a status bar (yay) renderStatusBar(statusBar, game) # handle user events for event in pygame.event.get(): if event.type == QUIT: sys.exit(0) if event.type == MOUSEBUTTONDOWN: # FIXME and not isObserving: newLoc = translateScreenLocation(event.pos) if not locationInLevelBounds(currLevel, newLoc): continue # log("Got click at", str(event.pos), "--->", str(newLoc)) GameManager.move(playerName, newLoc, game) hasMoved[playerName] = 1 log("HASSSMOVVVEEEEDD", str(hasMoved)) """ gameCollection ---> {gameName: dungeon} observerCollection ---> {observerName: gameName} when observe requested/game state change Observer.send(observerName, gameCollection[observerCollection[observerName]]) """ # map of keys pressed # keys = pygame.key.get_pressed() screen.blit(background, (0, Globals.STATUS_BAR_HEIGHT)) # render pixels to screen.blit(statusBar, (0, 0)) pygame.display.update() # update except FileNotFoundError: print("Couldn't find that level file. Try again") sys.exit(1) except json.JSONDecodeError: print("Malformed levels") sys.exit(1) except KeyboardInterrupt: print("\nExiting...") sys.exit(0)