def newGameSession(self): self.terminate = False self.restart = True self.curr_song.fadeout(10) self.song_num = random.randint(0, len(self.difficulty_level.songs) - 1) self.curr_song = self.difficulty_level.songs[self.song_num] # reset the game counter (keeps track of what to do when by modulus operation) self.counter = 0 self.newHighScoreInput = TextField( "New High Score, type your name and press enter!:", self.screen)
def initialize(self): super(VideoURLDialog, self).initialize() self.textField = TextField(self, (3, 2)) self.addChild(self.textField) self.__progressMessage = None self.addButton(Button("OK", self.handleOK, Button.SHORTCUT_ENTER)) self.addButton(Button("Cancel", self.handleCancel, 'c'))
def initialize(self): super(ChooseDetailsDialog, self).initialize() self.filenameField = TextField(self, (2,2), (1,1)) self.addChild(self.filenameField) self.filenameField.setValue(self.__extractDefaultFilename()) self.formatBox = FormatBox(self, (4, 2)) self.formatBox.formats = self.__extractFormats() self.addChild(self.formatBox) self.addButton(Button("OK", self.handleOK, Button.SHORTCUT_ENTER)) self.addButton(Button("Cancel", self.handleCancel, 'c')) # This callable is called to notify we are done and have # successfully configured a DownloadConfiguration instance. # The function should accept the DownloadConfiguration instance # as its only argument and should end the modal session. self.doneHandler = None
def __init__(self): self.difficulty_level = difficulties[0] self.numTimesSpeedUp = self.difficulty_level.max_fpr - self.difficulty_level.min_fpr # the number of times that the game will speed up before it reaches the maximum speed self.framesPerRound = self.difficulty_level.max_fpr self.frames_per_round_iter = 1 # how often to speed up the game self.player_speed_iter = self.def_player_speed_iter # how much to increase the speed of the player when the game speeds up # initialize game clock self.gameClock = pygame.time.Clock() # how many tiles are shown on the screen as a grid (this number is the number of tiles per side of the grid, aka 3 means the grid is 3x3) self.tiles_wide = self.difficulty_level.tiles_wide self.screen = (800, 800) # screen width, height # create the pygame window and set the window caption self.gameWindow = pygame.display.set_mode(self.screen) pygame.display.set_caption("BLACKOUT") self.restart = True # whether or not this game session has ended (if True it returns you to main menu or game over screen) self.terminate = False # whether or not to restart a new game # initialize starter values self.game_state = self.game_states[ 'Main Menu'] # displays the epilepsy warning # variables to determine where the player is moving towards this frame self.playerYMove = 0 self.playerXMove = 0 # initialize frames per second(fps) self.fps = self.def_fps # set up the game board self.gameBoard = Board(self.screen[0] * 0.8, self.screen[0] * 0.8, self.tiles_wide, self.tiles_wide, self.screen) # set up the player object self.player = Player( self.gameBoard.activeTiles[self.difficulty_level.tiles_wide - 1 - 1].positionX + (self.gameBoard.activeTiles[self.difficulty_level.tiles_wide - 1 - 1].width / 2), self.gameBoard.activeTiles[self.difficulty_level.tiles_wide - 1 - 1].positionY + (self.gameBoard.activeTiles[self.difficulty_level.tiles_wide - 1 - 1].height / 2), int(self.gameBoard.tileHeight * 0.2)) # center the player's mouse over the player object (a circle on the screen) pygame.mouse.set_pos(self.player.posX, self.player.posY) self.gameplay_time = { # the time that the player lasted in the game this time (measured in minutes:seconds:milliseconds) 'minutes': 0, 'seconds': 0, 'milliseconds': 0 } # initialize all screens and menus self.mainMenu = MainMenu(self.screen[0], self.screen[1]) diff_index = -1 for i in range(len(difficulties)): if self.difficulty_level == difficulties[i]: diff_index = i if (diff_index != -1): self.gameOverScreen = GameOverScreen(self.screen, diff_index) else: raise Exception("Invalid difficulty index") self.curr_song = self.title_song self.pauseMenu = PauseMenu(self.curr_song, self.screen[0], self.screen[1]) # text field to gather new text input from the user that will be the 3 character long name associated with a new high score self.newHighScoreInput = TextField( "New High Score, type your name and press enter!:", self.screen)
class Application(): pygame.mixer.set_num_channels( 2 ) # set the maximum number of channels of playback that are allowed for audio songPlayback = pygame.mixer.Channel( 0 ) # the channel that will play the background music for the game during play # song that will play during the main menu title_song = Song("Assets/Music/Elektronomia - Limitless.wav", "Limitless", "Elektronomia", (4, 4)) # the different states that the game can be in game_states = { 'Main Menu': 0, 'Game Active': 1, 'Game Paused': 2, 'Game Over': 3, } def_fps = 60 # the default value for frames per second that the game will run at def_frames_per_round = 20 # the default value for the number of frames per "round" (a round is the period of time between each tile iteration on the game board) def_frames_per_round_iter = 1 # the default value for how much to decrement the tiles_per_round value each time the game speeds up def_player_speed_iter = 2 # the default value for the player's speed secondsPerIdealGame = 120 # the number of seconds that a player should be able to survive for (if this game had a win condition, it would be upon reaching this point) num_active_tiles = 4 def __init__(self): self.difficulty_level = difficulties[0] self.numTimesSpeedUp = self.difficulty_level.max_fpr - self.difficulty_level.min_fpr # the number of times that the game will speed up before it reaches the maximum speed self.framesPerRound = self.difficulty_level.max_fpr self.frames_per_round_iter = 1 # how often to speed up the game self.player_speed_iter = self.def_player_speed_iter # how much to increase the speed of the player when the game speeds up # initialize game clock self.gameClock = pygame.time.Clock() # how many tiles are shown on the screen as a grid (this number is the number of tiles per side of the grid, aka 3 means the grid is 3x3) self.tiles_wide = self.difficulty_level.tiles_wide self.screen = (800, 800) # screen width, height # create the pygame window and set the window caption self.gameWindow = pygame.display.set_mode(self.screen) pygame.display.set_caption("BLACKOUT") self.restart = True # whether or not this game session has ended (if True it returns you to main menu or game over screen) self.terminate = False # whether or not to restart a new game # initialize starter values self.game_state = self.game_states[ 'Main Menu'] # displays the epilepsy warning # variables to determine where the player is moving towards this frame self.playerYMove = 0 self.playerXMove = 0 # initialize frames per second(fps) self.fps = self.def_fps # set up the game board self.gameBoard = Board(self.screen[0] * 0.8, self.screen[0] * 0.8, self.tiles_wide, self.tiles_wide, self.screen) # set up the player object self.player = Player( self.gameBoard.activeTiles[self.difficulty_level.tiles_wide - 1 - 1].positionX + (self.gameBoard.activeTiles[self.difficulty_level.tiles_wide - 1 - 1].width / 2), self.gameBoard.activeTiles[self.difficulty_level.tiles_wide - 1 - 1].positionY + (self.gameBoard.activeTiles[self.difficulty_level.tiles_wide - 1 - 1].height / 2), int(self.gameBoard.tileHeight * 0.2)) # center the player's mouse over the player object (a circle on the screen) pygame.mouse.set_pos(self.player.posX, self.player.posY) self.gameplay_time = { # the time that the player lasted in the game this time (measured in minutes:seconds:milliseconds) 'minutes': 0, 'seconds': 0, 'milliseconds': 0 } # initialize all screens and menus self.mainMenu = MainMenu(self.screen[0], self.screen[1]) diff_index = -1 for i in range(len(difficulties)): if self.difficulty_level == difficulties[i]: diff_index = i if (diff_index != -1): self.gameOverScreen = GameOverScreen(self.screen, diff_index) else: raise Exception("Invalid difficulty index") self.curr_song = self.title_song self.pauseMenu = PauseMenu(self.curr_song, self.screen[0], self.screen[1]) # text field to gather new text input from the user that will be the 3 character long name associated with a new high score self.newHighScoreInput = TextField( "New High Score, type your name and press enter!:", self.screen) def run(self): self.fps = 30 self.gameClock.tick(self.fps) self.epilepsy_warning = EpilepsyWarning(self.screen) self.epilepsy_warning.run(self.gameWindow, self.fps, self.gameClock) while (self.restart): self.terminate = False while (not self.terminate): # counter variable to track the number of frames passed during game execution self.counter = 0 # the number of frames that pass between each tile iteration self.framesPerRound = self.difficulty_level.max_fpr # User is in the main menuif(self.game_state == self.game_states['Main Menu']): self.curr_song = self.title_song self.curr_song.play(self.fps / 2) while (self.game_state == self.game_states['Main Menu'] and not self.terminate): self.fps = 30 # make the mouse visible to the player pygame.mouse.set_visible(True) if (self.mainMenu.titleAnimationCreated): self.mainMenu.runTitleAnimation(self.gameWindow) else: self.mainMenu.startTitleAnimation(self.gameWindow) self.mainMenu.show(self.gameWindow, True) # event handling within the main menu for event in pygame.event.get(): if (event.type == pygame.QUIT): # user quits game self.endGame() if (event.type == pygame.MOUSEBUTTONDOWN): if (self.mainMenu.options[0].inBounds( pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1])): # user has clicked on the start game button self.difficulty_level = difficulties[0] self.prepNewGame() continue if (self.mainMenu.options[1].inBounds( pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1])): # user has clicked on the start game button self.difficulty_level = difficulties[1] self.prepNewGame() continue if (self.mainMenu.options[2].inBounds( pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1])): # user has clicked on the start game button self.difficulty_level = difficulties[2] self.prepNewGame() continue elif (self.mainMenu.options[3].inBounds( pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1])): # user has clicked the How to play button self.fps = 30 help = helpScreen(self.screen) helping = True while (helping): for event in pygame.event.get(): if (event.type == pygame.QUIT): self.terminate = True helping = False self.restart = False if (event.type == pygame.MOUSEBUTTONDOWN): if (help.returnBtn.inBounds( pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1]) ): helping = False help.update(self.gameWindow) pygame.display.update() self.gameClock.tick(self.fps) elif (self.mainMenu.options[4].inBounds( pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1])): # user has clicked the exit game button self.endGame() continue if (event.type == pygame.KEYDOWN): if (event.key == pygame.K_ESCAPE): # user wants to exit game self.endGame() continue self.gameClock.tick(self.fps) pygame.display.update() if (self.game_state == self.game_states['Game Over'] and not self.terminate): self.curr_song.fadeout(100) HighScores.importScores("Assets/highscores.txt") while (self.game_state == self.game_states['Game Over'] and not self.terminate): # player is seeing the game over screen pygame.mouse.set_visible(True) diff_index = -1 for i in range(len(difficulties)): if self.difficulty_level == difficulties[i]: diff_index = i if (diff_index != -1): self.gameOverScreen.update(self.gameWindow, self.screen, self.gameplay_time, diff_index) else: raise Exception("Invalid difficulty index") while (HighScores.newHighScore): for event in pygame.event.get(): if (event.type == pygame.QUIT): terminate = True restart = False HighScores.newHighScore = False continue if (event.type == pygame.KEYDOWN): if (event.key == pygame.K_RETURN): HighScores.newHighScore = False if (self.newHighScoreInput.nameIn == "(3 characters maximum)"): HighScores.newHighScoreInsert( self.gameplay_time, "-", self.difficulty_level) else: HighScores.newHighScoreInsert( self.gameplay_time, self.newHighScoreInput.nameIn[0:3], self.difficulty_level) if (event.key == pygame.K_ESCAPE): HighScores.newHighScore = False if (event.key == pygame.K_BACKSPACE): self.newHighScoreInput.nameIn = self.newHighScoreInput.nameIn[ 0:len(self.newHighScoreInput.nameIn) - 1] if (self.isAlphanumericKey(event)): if (self.newHighScoreInput.nameIn == "(3 characters maximum)"): self.newHighScoreInput.nameIn = self.getKeyVal( event).upper() else: if (len(self.newHighScoreInput.nameIn) < 3): self.newHighScoreInput.nameIn += self.getKeyVal( event).upper() self.newHighScoreInput.update(self.gameWindow) pygame.display.update() # event handling in the game over screen for event in pygame.event.get(): if (event.type == pygame.QUIT): self.endGame() continue if (event.type == pygame.KEYDOWN): if (event.key == pygame.K_ESCAPE): # user wants to exit game self.restartGame() self.game_state = self.game_states['Main Menu'] continue if (event.key == pygame.K_SPACE): # user wants to play again self.newGameSession() self.prepNewGame() continue if (event.type == pygame.MOUSEBUTTONDOWN): if (self.gameOverScreen.options[0].inBounds( pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1])): # user selected the play again button self.newGameSession() self.prepNewGame() self.game_state = self.game_states[ 'Game Active'] continue if (self.gameOverScreen.options[1].inBounds( pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1])): # user selected to return to the main menu self.newGameSession() self.game_state = self.game_states['Main Menu'] continue self.fps = 120 self.gameClock.tick(self.fps) pygame.display.update() while (self.game_state == self.game_states['Game Paused'] and not self.terminate): self.curr_song.pause() pygame.mouse.set_visible(True) self.fps = 60 self.pauseMenu.show(self.gameWindow, True) # event handling for pause menu actions for event in pygame.event.get(): if (event.type == pygame.QUIT): self.endGame() continue if (event.type == pygame.MOUSEBUTTONDOWN): if (self.pauseMenu.options[0].inBounds( pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1])): # user selected the resume game button self.unpauseGame() if (self.pauseMenu.options[1].inBounds( pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1])): # user selected the main menu button self.newGameSession() self.game_state = self.game_states['Main Menu'] continue if (event.type == pygame.KEYDOWN): if (event.key == pygame.K_SPACE): # user wants to resume the game self.unpauseGame() if (event.key == pygame.K_ESCAPE): # user wants to return to the main menu self.game_state = self.game_states['Main Menu'] self.newGameSession() continue if (event.key == pygame.K_r): self.newGameSession() self.prepNewGame() self.game_state = self.game_states[ 'Game Active'] continue self.gameClock.tick(self.fps) pygame.display.update() while (self.game_state == self.game_states['Game Active'] and not self.terminate): # active gameplay for the user pygame.mouse.set_visible(False) self.fps = 30 self.iterateTime() if (self.gameClock.get_fps() < 20): print(self.gameClock.get_fps()) # event handling for active gameplay for event in pygame.event.get(): if (event.type == pygame.QUIT): self.endGame() continue if (event.type == pygame.MOUSEMOTION): if (not (pygame.mouse.get_pos()[0] < self.gameBoard.x or pygame.mouse.get_pos()[0] > self.gameBoard.x + self.gameBoard.width) and pygame.mouse.get_focused() != 0): self.playerXMove = pygame.mouse.get_pos()[0] if (not (pygame.mouse.get_pos()[1] < self.gameBoard.y or pygame.mouse.get_pos()[1] > self.gameBoard.y + self.gameBoard.height) and pygame.mouse.get_focused() != 0): self.playerYMove = pygame.mouse.get_pos()[1] if (event.type == pygame.KEYDOWN): if (event.key == pygame.K_p): # user wants to pause the game self.pauseGame() self.terminate = False self.player.status = 1 continue if (event.key == pygame.K_r): self.newGameSession() self.prepNewGame() self.game_state = self.game_states[ 'Game Active'] continue if (event.key == pygame.K_ESCAPE): # user wants to return to the main menu self.newGameSession() self.game_state = self.game_states['Main Menu'] continue #check if the mouse is outside of the game board, and if it is, move them back inside the game board if (self.playerXMove < self.gameBoard.x + self.player.radius): self.playerXMove = self.gameBoard.x + self.player.radius elif (self.playerXMove > self.gameBoard.x + self.gameBoard.width - self.player.radius): self.playerXMove = self.gameBoard.x + self.gameBoard.width - self.player.radius if (self.playerYMove < self.gameBoard.y + self.player.radius): self.playerYMove = self.gameBoard.y + self.player.radius elif (self.playerYMove > self.gameBoard.y + self.gameBoard.height - self.player.radius): self.playerYMove = self.gameBoard.y + self.gameBoard.height - self.player.radius # move the player to their new position as specified by either mouse movement or "not-movement" self.player.move(self.playerXMove, self.playerYMove) # move the mouse to the center of the new player position pygame.mouse.set_pos(self.player.posX, self.player.posY) self.collisions = self.player.getTileCollisions( self.gameBoard.tiles) for tile in self.collisions: if (tile.value == 'x'): self.player.status = 0 self.terminate = True self.restart = True self.gameWindow.fill((10, 10, 10)) self.gameWindow.fill( Colors.black, pygame.Rect((0, 0), (self.screen[0], self.screen[1] * 0.1))) # update all non-board and non-player elements on the screen during active game state self.activeGameDisplay() if (self.counter % self.framesPerRound == 0 and self.counter != 0): # game board needs to iterate its tiles to the next set self.gameBoard.iterateTiles() # iterate tiles, increase speeds, etc. when the time is correct (as specified by the counter variable) if (self.counter % (int( self.fps * (self.secondsPerIdealGame / self.numTimesSpeedUp))) == 0 and self.counter != 0): # time to speed up the game if (self.framesPerRound > self.difficulty_level.min_fpr): self.framesPerRound -= self.frames_per_round_iter self.player.speed += self.player_speed_iter self.gameClock.tick(self.fps) self.boardPulseAnimation.iterate() self.boardPulseAnimation.update(self.gameWindow, 'center') self.gameBoard.update(self.gameWindow) self.player.update(self.gameWindow) pygame.display.update() self.counter += 1 # check if the player has "blacked out" and if they have, send them to the game over screen and let them choose what to do from there if (self.player.status == 0): self.game_state = self.game_states['Game Over'] # check if this player got a high score, and record it accordingly if (HighScores.isBestScore(self.gameplay_time, self.difficulty_level)): HighScores.newHighScore = True # function to handle resetting all required values and any other actions required when a new game session starts (the user just lost during their last game session) def newGameSession(self): self.terminate = False self.restart = True self.curr_song.fadeout(10) self.song_num = random.randint(0, len(self.difficulty_level.songs) - 1) self.curr_song = self.difficulty_level.songs[self.song_num] # reset the game counter (keeps track of what to do when by modulus operation) self.counter = 0 self.newHighScoreInput = TextField( "New High Score, type your name and press enter!:", self.screen) def prepNewGame(self): self.game_state = self.game_states['Game Active'] self.player.status = 1 self.terminate = False self.restart = True self.resetStopWatch() self.counter = 0 self.song_num = random.randint(0, len(self.difficulty_level.songs) - 1) self.curr_song = self.difficulty_level.songs[self.song_num] self.curr_song.play(self.fps / 2) diff_index = -1 for i in range(len(difficulties)): if self.difficulty_level == difficulties[i]: diff_index = i if (diff_index != -1): self.gameOverScreen = GameOverScreen(self.screen, diff_index) else: raise Exception("Invalid difficulty index") self.numTimesSpeedUp = self.difficulty_level.max_fpr - self.difficulty_level.min_fpr # the number of times that the game will speed up before it reaches the maximum speed # reset the gameboard to a new board as the game starts self.gameBoard = Board(self.screen[0] * 0.8, self.screen[0] * 0.8, self.difficulty_level.tiles_wide, self.difficulty_level.tiles_wide, self.screen) self.framesPerRound = self.difficulty_level.max_fpr #reset the player object self.player = Player( self.gameBoard.activeTiles[self.num_active_tiles - 1].positionX + (self.gameBoard.activeTiles[self.num_active_tiles - 1].width / 2), self.gameBoard.activeTiles[self.num_active_tiles - 1].positionY + (self.gameBoard.activeTiles[self.num_active_tiles - 1].height / 2), int(self.gameBoard.tileHeight * 0.2)) # reset the player position to the center of the first active tile on the board (the pure white tile) self.player.posX = self.gameBoard.activeTiles[ self.num_active_tiles - 1].positionX + ( self.gameBoard.activeTiles[self.num_active_tiles - 1].width / 2) self.player.posY = self.gameBoard.activeTiles[ self.num_active_tiles - 1].positionY + ( self.gameBoard.activeTiles[self.num_active_tiles - 1].height / 2) self.player.speed = defSpeed # move the player mouse to the center of the player object for ease of play at start of game pygame.mouse.set_pos(self.player.posX, self.player.posY) # move the player mouse to the center of the player object for ease of play at start of game pygame.mouse.set_pos(self.player.posX, self.player.posY) # set up the animation that will be played around the game board during play self.boardPulseAnimation = PulseAnimation( 'rectangle', [ i for i in range(int(self.gameBoard.x), int(self.gameBoard.x + 1)) ], [ i for i in range(int(self.gameBoard.y), int(self.gameBoard.y + 1)) ], [ i for i in range(int(self.gameBoard.height), int(self.gameBoard.height + 1)) ], [ i for i in range(int(self.gameBoard.width), int(self.gameBoard.width + 1)) ], [i for i in range(254, 255)], [i for i in range(0, 255)], [i for i in range(0, int(self.screen[0] * 0.05))], 15, 1, { 'left': int(self.gameBoard.x), 'right': int(self.gameBoard.x + self.gameBoard.width), 'top': int(self.gameBoard.y), 'bottom': int(self.gameBoard.y + self.gameBoard.height) }) # resets the stopwatch that tracks the time a player lasts during play def resetStopWatch(self): self.gameplay_time['minutes'] = 0 self.gameplay_time['seconds'] = 0 self.gameplay_time['milliseconds'] = 0 # ends the game and terminates the program def endGame(self): self.terminate = True self.restart = False # carry out necessary operations to start a new game def restartGame(self): self.terminate = True self.restart = True def unpauseGame(self): self.game_state = self.game_states['Game Active'] pygame.mouse.set_pos(self.player.posX, self.player.posY) self.curr_song.unpause() def pauseGame(self): self.game_state = self.game_states['Game Paused'] self.pauseMenu = PauseMenu(self.curr_song, self.screen[0], self.screen[1]) self.curr_song.pause() def iterateTime(self): self.gameplay_time['milliseconds'] += self.gameClock.get_time() if (self.gameplay_time['milliseconds'] >= 1000): self.gameplay_time['milliseconds'] -= 1000 self.gameplay_time['seconds'] += 1 if (self.gameplay_time['seconds'] >= 60): self.gameplay_time['minutes'] += 1 self.gameplay_time['seconds'] -= 60 def activeGameDisplay(self): #show the gameplay time on screen self.displayTimeActiveGame() # show some help statements for how to pause and restart the game while playing pauseTxt = Fonts.medSmall.render("(P)ause", False, Colors.white) restartTxt = Fonts.medSmall.render("(R)estart", False, Colors.white) self.gameWindow.blit( pauseTxt, (self.screen[0] * 0.95 - pauseTxt.get_width(), self.screen[1] * 0.1 * 0.5 - ((pauseTxt.get_height() + restartTxt.get_height()) / 2))) self.gameWindow.blit( restartTxt, (self.screen[0] * 0.95 - restartTxt.get_width(), self.screen[1] * 0.1 * 0.5 - ((pauseTxt.get_height() + restartTxt.get_height()) / 2) + pauseTxt.get_height())) if (HighScores.isHighScore(self.gameplay_time, self.difficulty_level)): newScoretxt = Fonts.standard.render("YOU GOT A NEW BEST SCORE!!", False, Colors.white) self.gameWindow.blit( newScoretxt, (self.screen[0] * 0.52 - newScoretxt.get_width() * 0.5, self.screen[1] * 0.1 * 0.5 - newScoretxt.get_height() * 0.5)) def displayTimeActiveGame(self): minutes = "" seconds = "" milliseconds = "" if (self.gameplay_time['minutes'] < 10): minutes = '0' + str('%.0f' % self.gameplay_time['minutes']) else: minutes = str('%.0f' % self.gameplay_time['minutes']) if (self.gameplay_time['seconds'] < 10): seconds = '0' + str('%.0f' % self.gameplay_time['seconds']) else: seconds = str('%.0f' % self.gameplay_time['seconds']) if (self.gameplay_time['milliseconds'] / 10 < 10): milliseconds = '0' + str('%.0f' % (self.gameplay_time['milliseconds'] / 10)) else: milliseconds = str('%.0f' % int(self.gameplay_time['milliseconds'] / 10)) gameStopWatchDisplay = Fonts.large.render( str(minutes + ":" + seconds + ":" + milliseconds), False, Colors.white) self.gameWindow.blit( gameStopWatchDisplay, (self.screen[0] * 0.05, self.screen[1] * 0.1 * 0.5 - (gameStopWatchDisplay.get_height() / 2))) #check if the given key pressed is a letter or number def isAlphanumericKey(self, event): for key in pygame_keycodes_alpha: if (event.key == pygame_keycodes_alpha[key]): return True return False #get the character value of a key pressed def getKeyVal(self, event): for key in pygame_keycodes_alpha: if (event.key == pygame_keycodes_alpha[key]): return key return ' '
class ChooseDetailsDialog(Alert): CONTENT_HEIGHT = 12 def __init__(self, parent, mediaObject, info): """Initializes the dialog. mediaObject - A MediaObject instance info - The dictionary from the mediaObject as returned by getMediaInformation. """ self.mediaObject = mediaObject self.mediaInformation = info super(ChooseDetailsDialog, self).__init__(parent) def initialize(self): super(ChooseDetailsDialog, self).initialize() self.filenameField = TextField(self, (2,2), (1,1)) self.addChild(self.filenameField) self.filenameField.setValue(self.__extractDefaultFilename()) self.formatBox = FormatBox(self, (4, 2)) self.formatBox.formats = self.__extractFormats() self.addChild(self.formatBox) self.addButton(Button("OK", self.handleOK, Button.SHORTCUT_ENTER)) self.addButton(Button("Cancel", self.handleCancel, 'c')) # This callable is called to notify we are done and have # successfully configured a DownloadConfiguration instance. # The function should accept the DownloadConfiguration instance # as its only argument and should end the modal session. self.doneHandler = None def __extractFormats(self): mo = self.mediaObject info = self.mediaInformation f = mo.extractAvailableFormatsFromInfo(info) f.reverse() for i in range(1, len(f)): mf = f[i] if mf.quality == MediaFormat.QUALITY_BEST: del f[i] f.insert(0, mf) break return f def __extractDefaultFilename(self): s = self.mediaInformation.get('title', 'Untitled') if type(s) != str: return 'Untitled' return self.__normalizeFilename(s) def __normalizeFilename(self, fn): # From http://stackoverflow.com/a/517974/262660 new = unicodedata.normalize('NFKD', fn) new = new.encode('ASCII', 'ignore').decode('utf-8') # Only allowed characters allowed = "-_.() %s%s" % (string.ascii_letters, string.digits) new = ''.join(c for c in new if c in allowed) return new # Drawing def layout(self): super(ChooseDetailsDialog, self).layout() # Filename w = self.size[1] - 4 if self.filenameField.size != (1, w): self.filenameField.size = (1, w) self.filenameField.setValue(self.filenameField.getValue()) # Format Box h = self.CONTENT_HEIGHT - 3 self.formatBox.size = (h, w) def display(self): super(ChooseDetailsDialog, self).display() y, x = self.abs(1, 1) self.addstr(y, x, "Filename:") y += 2 self.addstr(y, x, "Format:") # Events def handleOK(self): fn = self.__getFinalFilename() if fn == None: t = "Invalid filename." msg = "Please choose a valid filename. The file must " msg+= "be in the current directory and cannot contain " msg+= "any illegal characters." alert = MessageAlert(self, t, msg) b = Button("OK", self.__handleErrorOK, Button.SHORTCUT_ENTER) alert.addButton(b) self.beginModalScreen(alert) return mo = self.mediaObject mf = self.formatBox.selectedFormat() dc = DownloadConfiguration(mo, mf, fn) try: self.doneHandler(dc) except Exception as e: self.__handleException(e) def __handleException(self, exception): t = "An error occurred." m = str(exception) alert = MessageAlert(self, t, m) b = Button("OK", self.__handleErrorOK, Button.SHORTCUT_ENTER) alert.addButton(b) self.beginModalScreen(alert) def __handleErrorOK(self): self.endModalScreen(self.activeModalSession()) self.makeChildFirstResponder(self.filenameField) def handleCancel(self): self.parent.endModalScreen(self) def __getFinalFilename(self): selFormat = self.formatBox.selectedFormat() fn = self.filenameField.getValue() if '/' in fn or '\\' in fn: return None fn = self.__normalizeFilename(fn) if fn in ['', '.', '..']: return None ext = selFormat.extension if ext != None and len(ext) != 0: fn += '.' + ext return fn
def addTextField(self, tag, image, x, y, color=0xFFFFFF, size=16, text="", focused=False, active=True, visible=True, mask=None): newTextField = TextField(image, x, y, color, size, text, focused, active, visible, mask) newTextField.updateHover() self.textFields[tag] = newTextField
def __init__(self, nick, addr, port): self.width, self.height = 750, 500 self.card_w, self.card_h = 43, 62 # initialize pygame pygame.init() # 2 # initialize the screen self.screen = pygame.display.set_mode((self.width, self.height)) pygame.display.set_caption('Poker') # 3 # initialize pygame clock self.clock = pygame.time.Clock() self.nick_color, self.money_color, self.text_color = (150, 150, 150), (255, 255, 0), (50, 50, 50) self.bg_color = (220, 220, 220) self.is_turn = False self.is_playing = True self.is_waiting_to_start = True self.player_id = None self.is_out = False self.pot_val = None self.money = None self.big_blind = self.small_blind = None self.id_big_blind = self.id_small_blind = None self.card1 = self.card2 = None self.back_card = pygame.image.load(f'images/back.png') self.table_img = pygame.image.load('images/table.png') self.table_img_x, self.table_img_y = self.width // 2 - 700 // 2, 20 # self.font = pygame.font.Font('freesansbold.ttf', 16) self.font = pygame.font.SysFont('Arial', 16, bold=True) self.text_font = pygame.font.SysFont('Arial', 12) self.nick = nick self.error_font = pygame.font.Font('freesansbold.ttf', 12) self.error_raise_msg = self.error_font.render('INVALID VALUE', True, (255, 0, 0), (255, 255, 255)) self.error_time = 0 # other players self.is_opp_out = defaultdict( bool) # True when out of money, default to False self.opp_cards_img = {} self.is_opp_playing = {} self.id_turn = None self.opp_bet = {} self.players_nick = {} self.opp_ids = [] self.opp_money = {} self.players_pos = [(self.width * 0.75 // 5, self.height * 3.1 // 5), (self.width * 0.75 // 5, self.height * 1.7 // 5), (self.width // 2, 75), (self.width * 4.25 // 5, self.height * 1.7 // 5), (self.width * 4.25 // 5, self.height * 3.1 // 5)] # cards on the table self.on_table = [None] * 5 self.bet = 0 self.bet_on_table = 0 self.fold_b = Button('fold', (self.width - 270, self.height - 20), self.screen) self.check_b = Button('check', (self.width - 180, self.height - 20), self.screen) self.raise_b = Button('raise to', (self.width - 90, self.height - 20), self.screen) self.raise_t = TextField((self.width - 90, self.height - 50), self.screen) # self.mess = Messages((0, self.height-115), self.screen) self.mess = Messages((5, 5), self.screen) self.actions_mess = Messages((5, self.height - 35), self.screen, size=(275, 25)) self.Connect((addr, int(port)))
class Poker(ConnectionListener): def __init__(self, nick, addr, port): self.width, self.height = 750, 500 self.card_w, self.card_h = 43, 62 # initialize pygame pygame.init() # 2 # initialize the screen self.screen = pygame.display.set_mode((self.width, self.height)) pygame.display.set_caption('Poker') # 3 # initialize pygame clock self.clock = pygame.time.Clock() self.nick_color, self.money_color, self.text_color = (150, 150, 150), (255, 255, 0), (50, 50, 50) self.bg_color = (220, 220, 220) self.is_turn = False self.is_playing = True self.is_waiting_to_start = True self.player_id = None self.is_out = False self.pot_val = None self.money = None self.big_blind = self.small_blind = None self.id_big_blind = self.id_small_blind = None self.card1 = self.card2 = None self.back_card = pygame.image.load(f'images/back.png') self.table_img = pygame.image.load('images/table.png') self.table_img_x, self.table_img_y = self.width // 2 - 700 // 2, 20 # self.font = pygame.font.Font('freesansbold.ttf', 16) self.font = pygame.font.SysFont('Arial', 16, bold=True) self.text_font = pygame.font.SysFont('Arial', 12) self.nick = nick self.error_font = pygame.font.Font('freesansbold.ttf', 12) self.error_raise_msg = self.error_font.render('INVALID VALUE', True, (255, 0, 0), (255, 255, 255)) self.error_time = 0 # other players self.is_opp_out = defaultdict( bool) # True when out of money, default to False self.opp_cards_img = {} self.is_opp_playing = {} self.id_turn = None self.opp_bet = {} self.players_nick = {} self.opp_ids = [] self.opp_money = {} self.players_pos = [(self.width * 0.75 // 5, self.height * 3.1 // 5), (self.width * 0.75 // 5, self.height * 1.7 // 5), (self.width // 2, 75), (self.width * 4.25 // 5, self.height * 1.7 // 5), (self.width * 4.25 // 5, self.height * 3.1 // 5)] # cards on the table self.on_table = [None] * 5 self.bet = 0 self.bet_on_table = 0 self.fold_b = Button('fold', (self.width - 270, self.height - 20), self.screen) self.check_b = Button('check', (self.width - 180, self.height - 20), self.screen) self.raise_b = Button('raise to', (self.width - 90, self.height - 20), self.screen) self.raise_t = TextField((self.width - 90, self.height - 50), self.screen) # self.mess = Messages((0, self.height-115), self.screen) self.mess = Messages((5, 5), self.screen) self.actions_mess = Messages((5, self.height - 35), self.screen, size=(275, 25)) self.Connect((addr, int(port))) def update(self): connection.Pump() self.Pump() if self.is_waiting_to_start: for event in pygame.event.get(): # quit if the quit button was pressed if event.type == pygame.QUIT: exit() return # sleep to make the game 60 fps self.clock.tick(60) # clear the screen self.screen.fill(0) self._handle_actions() self._draw_table() self._draw_player() if self.is_turn: self._draw_buttons() if time.time() - self.error_time < 8: self.screen.blit(self.error_raise_msg, (self.width - 135, self.height - 80)) self._draw_others() # update the screen pygame.display.update() def Network_init(self, data): self.money = data['init_money'] self.big_blind = data['big_blind'] self.small_blind = self.big_blind // 2 self.player_id = data['player_id'] self.money = data['init_money'] print(f'my id: {self.player_id}') # send nickname self.Send({ 'action': 'info', 'player_id': self.player_id, 'nick': self.nick }) def Network_getcards(self, data): self.card1 = pygame.image.load(f'images/{data["cards"][0]}.png') self.card2 = pygame.image.load(f'images/{data["cards"][1]}.png') def Network_addplayer(self, data): id = data['player_id'] self.opp_ids.append(id) self.opp_money[id] = int(data['money']) self.opp_bet[id] = 0 self.is_opp_playing[id] = True self.opp_cards_img[id] = [ pygame.image.load('images/back.png'), pygame.image.load('images/back.png') ] self.players_nick[id] = 'nickname' self.is_opp_out[id] = None print(f'adding player with id: {id}') def Network_addnick(self, data): self.players_nick[data['player_id']] = data['nick'] print(f'added nick {data["nick"]} for id {data["player_id"]}') def Network_startgame(self, data): self.is_waiting_to_start = False def Network_nextround(self, data): self.id_big_blind = data['id_big_blind'] self.id_small_blind = data['id_small_blind'] self.opp_cards_img = { id: [ pygame.image.load('images/back.png'), pygame.image.load('images/back.png') ] for id in self.opp_ids } self.is_opp_out = {id: self.opp_money[id] == 0 for id in self.opp_ids} self.pot_val = self.big_blind * 1.5 self.bet = 0 self.opp_bet = {id: 0 for id in self.opp_ids} self.bet_on_table = self.big_blind self.is_turn = False self.is_out = self.money == 0 self.on_table = [None] * 5 self.check_b.change_txt(f'call {self.big_blind}') self.raise_t.change_txt(f'{2*self.big_blind}') if self.id_big_blind == self.player_id: self.money = max(0, self.money - self.big_blind) self.bet = self.big_blind self.check_b.change_txt('check') else: self.opp_money[self.id_big_blind] = max( 0, self.opp_money[self.id_big_blind] - self.big_blind) self.opp_bet[self.id_big_blind] = self.big_blind if self.id_small_blind == self.player_id: self.money = max(0, self.money - self.small_blind) self.bet = self.small_blind self.check_b.change_txt( f'call {self.big_blind - self.small_blind}') else: self.opp_money[self.id_big_blind] = max( 0, self.opp_money[self.id_small_blind] - self.small_blind) self.opp_bet[self.id_small_blind] = self.small_blind self.is_opp_playing = { id: self.opp_money[id] > 0 for id in self.opp_ids } moneys = data['moneys'] for id, v in moneys.items(): if id != self.player_id: self.opp_money[id] = v def Network_nextturn(self, data): self.raise_b.is_active = False if self.player_id == data['player_id_turn']: self.is_turn = True self.id_turn = None else: self.id_turn = data['player_id_turn'] def Network_flop(self, data): self.raise_b.is_active = False self.bet = self.bet_on_table = 0 self.opp_bet = {id: 0 for id in self.opp_ids} self.on_table[:3] = list( map(lambda c: pygame.image.load(f'images/{c}.png'), data['cards'])) self.raise_t.change_txt(str(self.big_blind)) def Network_turn(self, data): self.raise_b.is_active = False self.bet = self.bet_on_table = 0 self.opp_bet = {id: 0 for id in self.opp_ids} self.on_table[3] = pygame.image.load(f'images/{data["card"]}.png') self.raise_t.change_txt(str(self.big_blind)) def Network_river(self, data): self.raise_b.is_active = False self.bet = self.bet_on_table = 0 self.opp_bet = {id: 0 for id in self.opp_ids} self.on_table[4] = pygame.image.load(f'images/{data["card"]}.png') self.raise_t.change_txt(str(self.big_blind)) def Network_fold(self, data): id = data['player_id'] self.actions_mess.clear() if id == self.player_id: self.is_playing = False self.card1.fill((255, 255, 255, 100), None, pygame.BLEND_RGBA_MULT) self.card2.fill((255, 255, 255, 100), None, pygame.BLEND_RGBA_MULT) else: self.is_opp_playing[id] = False self.opp_cards_img[id][0].fill((255, 255, 255, 100), None, pygame.BLEND_RGBA_MULT) self.opp_cards_img[id][1].fill((255, 255, 255, 100), None, pygame.BLEND_RGBA_MULT) self.actions_mess.add_text(f'{self.players_nick[id]} folded') def Network_check(self, data): id = data['player_id'] self.actions_mess.clear() self.actions_mess.add_text(f'{self.players_nick[id]} checked') pass def Network_call(self, data): id = data['player_id'] if id != self.player_id: self.opp_money[id] = data['money'] self.opp_bet[id] = data['amount'] self.actions_mess.clear() self.actions_mess.add_text( f'{self.players_nick[id]} called {data["amount"]}') def Network_raise(self, data): id = data['player_id'] if id != self.player_id: self.opp_money[id] = data['money'] self.bet_on_table = data['amount'] self.raise_t.change_txt(f'{self.bet_on_table+self.big_blind}') self.check_b.change_txt(f'call {self.bet_on_table - self.bet}') self.opp_bet[id] = data['amount'] self.actions_mess.clear() self.actions_mess.add_text( f'{self.players_nick[id]} raised to {data["amount"]}') def Network_winner(self, data): id = data['player_id'] self.mess.add_text(f'{self.players_nick[id]} won {int(data["won"])}') if id == self.player_id: self.money += int(data['won']) else: self.opp_money[id] += int(data['won']) def Network_showcards(self, data): id = data['player_id'] if id != self.player_id: c1, c2 = data['cards'] self.opp_cards_img[id] = [ pygame.image.load(f'images/{c1}.png'), pygame.image.load(f'images/{c2}.png') ] def Network_updatepot(self, data): self.pot_val = data['pot_val'] def Network_clearmsg(self, data): self.mess.clear() def Network_addmsg(self, data): self.mess.add_text(data['msg']) def Network_logout(self, data): id = data['player_id'] print(f'{self.players_nick[id]} logged out') if id == self.player_id: exit() else: del self.players_nick[id] del self.opp_money[id] del self.opp_cards_img[id] del self.is_opp_playing[id] del self.is_opp_out[id] self.opp_ids.remove(id) def _fold(self): self.is_turn = False self.Send({'action': 'fold', 'player_id': self.player_id}) def _check(self): self.is_turn = False self.Send({'action': 'check', 'player_id': self.player_id}) def _call(self): self.is_turn = False extra_to_pot = self.bet_on_table - self.bet if self.bet_on_table - self.bet < self.money: self.money -= (self.bet_on_table - self.bet) self.bet = self.bet_on_table self.Send({ 'action': 'call', 'player_id': self.player_id, 'money': self.money, 'allin': False, 'extra_to_pot': extra_to_pot, 'amount': self.bet }) else: self.bet += self.money self.money = 0 self.Send({ 'action': 'call', 'player_id': self.player_id, 'money': self.money, 'allin': True, 'extra_to_pot': extra_to_pot, 'amount': self.bet }) self.check_b.to_check() def _raise(self, amount): self.is_turn = False extra_to_pot = amount - self.bet self.money -= (amount - self.bet) self.bet = self.bet_on_table = amount self.Send(({ 'action': 'raise', 'player_id': self.player_id, 'money': self.money, 'allin': self.money == 0, 'amount': self.bet, 'extra_to_pot': extra_to_pot })) self.check_b.to_check() def _handle_actions(self): for event in pygame.event.get(): # quit if the quit button was pressed if event.type == pygame.QUIT: print('attempt to logout') if self.is_playing: self.Send({'action': 'fold', 'player_id': self.player_id}) self.Send({'action': 'logout', 'player_id': self.player_id}) if self.is_turn: if event.type == pygame.MOUSEBUTTONDOWN: if self.fold_b.is_clicked(): self._fold() elif self.check_b.is_clicked() and self.bet_on_table == 0: self._check() elif self.check_b.is_clicked(): self._call() elif self.raise_b.is_clicked(): print(self.bet_on_table) val = self.raise_t.get_value() if val < self.bet_on_table + self.big_blind or val > self.money + self.bet: self.error_time = time.time() else: self._raise(val) elif self.raise_t.is_clicked(): self.raise_t.click_action() elif event.type == pygame.KEYDOWN: self.raise_t.update(event.key) def _draw_player(self): x, y = self.width // 2, self.height - 110 if not self.is_out and self.card1 is not None and self.card2 is not None: self.screen.blit(self.card1, (x - self.card_w - 3, y)) self.screen.blit(self.card2, (x + 3, y)) if self.player_id == self.id_big_blind: self.screen.blit( self.font.render('BB', True, self.text_color, self.bg_color), (x + 50, y + 20)) if self.player_id == self.id_small_blind: self.screen.blit( self.font.render('SB', True, self.text_color, self.bg_color), (x + 50, y + 20)) nick_label = self.font.render(self.nick, True, self.nick_color, None) nick_rect = nick_label.get_rect(center=(x, y + 80)) self.screen.blit(nick_label, nick_rect) bet_label = self.font.render(str(self.bet), True, self.money_color, None) self.screen.blit(bet_label, (x + 50, y - 5)) money_label = self.font.render(str(self.money), True, self.money_color, None) money_rect = money_label.get_rect(center=(x, y - 20)) self.screen.blit(money_label, money_rect) def _draw_others(self): for i, id in enumerate(self.opp_ids): nick = self.players_nick[id] if nick is None: continue x, y = self.players_pos[i] if not self.is_opp_out[id]: self.screen.blit(self.opp_cards_img[id][0], (x - self.card_w - 3, y)) self.screen.blit(self.opp_cards_img[id][1], (x + 3, y)) if id == self.id_big_blind: self.screen.blit( self.font.render('BB', True, self.text_color, self.bg_color), (x + 50, y + 20)) if id == self.id_small_blind: self.screen.blit( self.font.render('SB', True, self.text_color, self.bg_color), (x + 50, y + 20)) if self.id_turn == id: self.screen.blit( self.font.render('turn', True, self.text_color, self.bg_color), (x + 50, y + 40)) nick_label = self.font.render(nick, True, self.nick_color, None) nick_rect = nick_label.get_rect(center=(x, y + 80)) self.screen.blit(nick_label, nick_rect) bet_label = self.font.render(str(self.opp_bet[id]), True, self.money_color, None) self.screen.blit(bet_label, (x + 50, y - 5)) money_label = self.font.render(str(self.opp_money[id]), True, self.money_color, None) money_rect = money_label.get_rect(center=(x, y - 20)) self.screen.blit(money_label, money_rect) def _draw_buttons(self): self.fold_b.draw() self.check_b.draw() self.raise_b.draw() self.raise_t.draw() def _draw_table(self): self.screen.blit( self.text_font.render(f'big blind: {self.big_blind}', True, (255, 255, 255), None), (self.width - 100, 0)) self.mess.draw() self.actions_mess.draw() self.screen.blit(self.table_img, (self.table_img_x, self.table_img_y)) if self.pot_val is not None: pot_val_label = self.font.render(f'pot: {int(self.pot_val)}', True, self.money_color, None) pot_val_rect = pot_val_label.get_rect(center=(self.width // 2, self.height // 2 - 10)) self.screen.blit(pot_val_label, pot_val_rect) for i, card in enumerate(self.on_table): if card is None: break self.screen.blit(card, (self.width // 2 - (self.card_w // 2) - (2 - i) * (self.card_w + 3), self.height // 2))
from ProgressBar import ProgressBar from Table import Table from TextField import TextField if __name__ == "__main__": app = QtWidgets.QApplication([]) window = QtWidgets.QWidget() window.setGeometry(0, 0, 300, 300) # Button(title='', width=50, height=50, # left=0, top=100, callback=None, # tool_tip='test', # parent=window) # Dial(title='', width=50, height=50, # left=0, top=0, min_value=0, # max_value=10, # parent=window) # ProgressBar(title='', width=50, height=50, left=100, top=0, # min_value=0, max_value=10, parent=window) # Table(title='test', columns=5, rows=3, left=0, # top=0, height=5, width=10, parent=window) TextField(title='test', width=100, height=50, left=0, top=0, callback=None, parent=window) window.show() app.exec_()
def textfield(parentWindow, **kwds): from TextField import TextField return TextField(parentWindow, **kwds)
class VideoURLDialog(Alert): CONTENT_HEIGHT = 6 def initialize(self): super(VideoURLDialog, self).initialize() self.textField = TextField(self, (3, 2)) self.addChild(self.textField) self.__progressMessage = None self.addButton(Button("OK", self.handleOK, Button.SHORTCUT_ENTER)) self.addButton(Button("Cancel", self.handleCancel, 'c')) # Drawing def layout(self): super(VideoURLDialog, self).layout() self.textField.size = (1, self.size[1] - 4) def display(self): super(VideoURLDialog, self).display() y, x = self.abs(1, 1) self.addstr(y, x, "Video URL or YouTube hash:") self.__drawProgressMessage() def __drawProgressMessage(self): y, x = self.abs(5, 1) w = (self.size[1] - 4) self.addstr(y, x, ' '*w) if self.__progressMessage != None: y, x = self.abs(5, 1) self.addstr(y, x, self.__progressMessage[:w]) self.refresh() # Events def handleOK(self): self.__handleURL(self.textField.getValue()) def handleCancel(self): self.parent.endModalScreen(self) def __handleURL(self, url): invalidURL = False try: mo = MediaObject(url) mo.delegate = self info = mo.getMediaInformation() if info == None: raise UnsupportedURLError(url) except UnsupportedURLError: invalidURL = True finally: self.__progressMessage = None self.update() if invalidURL == True: t = "Could not extract information." m = "Invalid URL or video hash." self.__handleError(t, m) return # Choose details self.chooseDetailsDialog = ChooseDetailsDialog(self, mo, info) self.chooseDetailsDialog.doneHandler = self.__handleChooseDetailsDone self.beginModalScreen(self.chooseDetailsDialog) def __handleChooseDetailsDone(self, dc): self.parent.addDownloadConfiguration(dc) self.endModalScreen(self.chooseDetailsDialog) self.chooseDetailsDialog = None self.parent.endModalScreen(self) def __handleError(self, title, msg): self.errorAlert = MessageAlert(self.parent, title, msg) b = Button("OK", self.__handleErrorOK, Button.SHORTCUT_ENTER) self.errorAlert.addButton(b) self.parent.beginModalScreen(self.errorAlert) def __handleErrorOK(self): self.parent.endModalScreen(self.errorAlert) # Media Object delegate def mediaObjectMessage(self, msg): self.__progressMessage = msg self.__drawProgressMessage() def mediaObjectError(self, msg): self.__progressMessage = msg self.__drawProgressMessage()