Example #1
0
def display_save_screen(game_data):
    """ Display a screen asking the user for a name to give to their save """
    # Create the main menu button/text objects
    txt_title = Entities.Text(title_font, "Save Game", Colours.WHITE,
                              width / 2, 38)
    txt_hint = Entities.Text(main_font, "Select a slot to save to",
                             Colours.WHITE, width / 2, 380)

    btn_save_1 = Entities.Button(main_font, "Save Slot 1", Colours.WHITE,
                                 width / 2, 120)
    btn_save_2 = Entities.Button(main_font, "Save Slot 2", Colours.WHITE,
                                 width / 2, 160)
    btn_save_3 = Entities.Button(main_font, "Save Slot 3", Colours.WHITE,
                                 width / 2, 200)
    btn_save_4 = Entities.Button(main_font, "Save Slot 4", Colours.WHITE,
                                 width / 2, 240)

    btn_return = Entities.Button(main_font, "Return to Game", Colours.WHITE,
                                 width / 2, 300)

    while True:
        # Handle events
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                quit_game()

            # Call the event handler for the button object and do necessary function call if needed
            if btn_return.event(e):
                return

            if btn_save_1.event(e):
                save_game(1, game_data)
                return
            if btn_save_2.event(e):
                save_game(2, game_data)
                return
            if btn_save_3.event(e):
                save_game(3, game_data)
                return
            if btn_save_4.event(e):
                save_game(4, game_data)
                return

        # Draw everything to the screen
        renderer.update_display(display)

        renderer.add(txt_title)
        renderer.add(btn_save_1)
        renderer.add(btn_save_2)
        renderer.add(btn_save_3)
        renderer.add(btn_save_4)
        renderer.add(btn_return)
        renderer.add(txt_hint)

        renderer.draw("bg_plain", Colours.BLACK)
Example #2
0
def display_winner(winner, score):
    """ Display winner of the current match to the users """
    # Create the main menu button/text objects
    txt_title = Entities.Text(title_font, "Congratulations!", Colours.WHITE,
                              width / 2, 38)
    txt_winner = Entities.Text(main_font, "The winner is " + winner + "!",
                               Colours.WHITE, width / 2, height / 2)

    btn_return = Entities.Button(main_font, "Return to Main Menu",
                                 Colours.WHITE, width / 2, 300)

    update_highscores(score, winner)

    while True:
        # Handle events
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                quit_game()

            # Call the event handler for the button object and do necessary function call if needed
            display_main_menu() if btn_return.event(e) else False

        # Draw everything to the screen
        renderer.update_display(display)

        renderer.add(txt_title)
        renderer.add(txt_winner)
        renderer.add(btn_return)

        renderer.draw("bg_plain")
Example #3
0
def display_rules(return_to=None):
    """ Display the game rules to the users """
    str_rules = \
        "Each player has 2 counters, the objective is for a player to get \n" \
        "each of their counters to the FINISH space before the other player.\n" \
        "The game uses a 5 sided dice. The result a dice throw is as follows:"

    str_die_results = \
        "+-----------+----------------------------------------------------+\n" \
        "| Dice Roll | Action                                             |\n" \
        "+-----------+----------------------------------------------------+\n" \
        "|     1     | Move a counter of choice 1 space closer to FINISH  |\n" \
        "+-----------+----------------------------------------------------+\n" \
        "|     2     | Move a counter of choice 2 spaces closer to FINISH |\n" \
        "+-----------+----------------------------------------------------+\n" \
        "|     3     | Move a counter of choice 3 spaces closer to FINISH |\n" \
        "+-----------+----------------------------------------------------+\n" \
        "|     4     | Move a counter of choice 1 space closer to START   |\n" \
        "+-----------+----------------------------------------------------+\n" \
        "|     5     | Select a counter to move to the next EMPTY row     |\n" \
        "+-----------+----------------------------------------------------+"

    # Create the main menu button/text objects
    txt_rules_title = Entities.Text(title_font, "Rules", Colours.WHITE,
                                    width / 2, 38)
    txt_goal = Entities.Text(small_font, str_rules, Colours.WHITE, width / 2,
                             100)
    txt_die_results = Entities.Text(small_font, str_die_results, Colours.WHITE,
                                    width / 2, 150)

    btn_return = Entities.Button(
        main_font,
        "Return to " + ("Main Menu" if return_to is "main" else "Game"),
        Colours.WHITE, width / 2, 300)

    while True:
        # Handle events
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                quit_game()

            # Call the event handler for the button object and do necessary function call if needed
            if return_to is "main" and btn_return.event(e):
                display_main_menu()
            elif return_to == "play" and btn_return.event(e):
                return

        # Draw everything to the screen
        renderer.update_display(display)

        renderer.add(txt_rules_title)
        renderer.add(txt_goal)
        renderer.add(txt_die_results)
        renderer.add(btn_return)

        renderer.draw("bg_plain")
Example #4
0
def display_main_menu():
    """ Display the main menu to the users """
    # Create the main menu button/text objects
    txt_title = Entities.Text(title_font, "NTU Python Assessment",
                              Colours.WHITE, width / 2, 38)

    btn_play = Entities.Button(main_font, "New Game", Colours.BLACK, width / 2,
                               125)
    btn_load = Entities.Button(main_font, "Load Game", Colours.BLACK,
                               width / 2, 175)
    btn_rules = Entities.Button(main_font, "Rules", Colours.BLACK, width / 2,
                                225)
    btn_scores = Entities.Button(main_font, "Highscores", Colours.BLACK,
                                 width / 2, 275)
    btn_quit = Entities.Button(main_font, "Quit", Colours.BLACK, width / 2,
                               325)

    while True:
        # Handle events
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                quit_game()

            # Call the event handler for each button object and do necessary function call if needed
            play() if btn_play.event(e) else False
            display_saved_games("main") if btn_load.event(e) else False
            display_rules("main") if btn_rules.event(e) else False
            display_highscores() if btn_scores.event(e) else False
            quit_game() if btn_quit.event(e) else False

        # Draw everything to the screen
        renderer.update_display(display)

        renderer.add((128, 89, 224, 272))
        renderer.add(txt_title)
        renderer.add(btn_play)
        renderer.add(btn_load)
        renderer.add(btn_rules)
        renderer.add(btn_scores)
        renderer.add(btn_quit)

        renderer.draw("bg_plain")
Example #5
0
def display_enter_player_names():
    """ Ask the users to enter their names """
    # Create the menu button/text/field objects
    txt_title = Entities.Text(title_font, "Enter Player Names", Colours.WHITE,
                              width / 2, 38)
    txt_user = Entities.Text(main_font, "Player 1, enter your name:",
                             Colours.WHITE, width / 2, 150)
    txt_hint = Entities.Text(main_font, "Enter name (press enter to set)",
                             Colours.WHITE, width / 2, 380)

    name_field = Entities.InputField(main_font, "Player 1", Colours.BLACK,
                                     width / 2, 200, 14)

    btn_return = Entities.Button(main_font, "Return to Main Menu",
                                 Colours.WHITE, width / 2, 300)

    player = 1
    player_names = ["Player 1", "Player 2"]

    while True:
        # Handle events
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                quit_game()

            # Call the event handler for the button object and do necessary function call if needed
            if btn_return.event(e):
                display_main_menu()

            if name_field.event(e):
                field_text = name_field.get_text()

                if field_text:
                    player_names[player - 1] = field_text

                player += 1
                name_field.reset("Player 2")
                txt_user.update_text("Player 2, enter your name:")

        # Draw everything to the screen
        renderer.update_display(display)

        renderer.add(txt_title)
        renderer.add(txt_user)
        renderer.add(name_field)
        renderer.add(btn_return)
        renderer.add(txt_hint)

        renderer.draw("bg_plain", Colours.BLACK)

        if player > 2:
            return player_names
Example #6
0
def display_highscores():
    # First, load the scores
    scores = load_highscores()
    displayable_score = ""

    if scores is None:
        displayable_score = "There are no high scores!"
    else:
        for i, score in enumerate(scores, 1):
            displayable_score += str(score[0]) + " achieved by " + score[1] + (
                "\n" + "-" * 40 + "\n" if i < len(scores) else "")

    # Create the main menu button/text objects
    txt_rules_title = Entities.Text(title_font, "Top 5 Scores", Colours.WHITE,
                                    width / 2, 38)
    txt_goal = Entities.Text(main_font, displayable_score, Colours.WHITE,
                             width / 2, 125)

    btn_return = Entities.Button(main_font, "Return to Main Menu",
                                 Colours.WHITE, width / 2, 300)

    while True:
        # Handle events
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                quit_game()

            # Call the event handler for the button object and do necessary function call if needed
            if btn_return.event(e):
                display_main_menu()

        # Draw everything to the screen
        renderer.update_display(display)

        renderer.add(txt_rules_title)
        renderer.add(txt_goal)
        renderer.add(btn_return)

        renderer.draw("bg_plain")
Example #7
0
def display_saved_games(return_to):
    """ Display the available saved games from /game_saves """
    # Create the main menu button/text objects
    txt_title = Entities.Text(title_font, "Load Game", Colours.WHITE,
                              width / 2, 38)
    txt_hint = Entities.Text(main_font, "Select a slot to load from",
                             Colours.WHITE, width / 2, 380)

    btn_load_1 = Entities.Button(main_font, "Load Slot 1", Colours.WHITE,
                                 width / 2, 120)
    btn_load_2 = Entities.Button(main_font, "Load Slot 2", Colours.WHITE,
                                 width / 2, 160)
    btn_load_3 = Entities.Button(main_font, "Load Slot 3", Colours.WHITE,
                                 width / 2, 200)
    btn_load_4 = Entities.Button(main_font, "Load Slot 4", Colours.WHITE,
                                 width / 2, 240)

    btn_return = Entities.Button(
        main_font,
        "Return to " + ("Main Menu" if return_to is "main" else "Game"),
        Colours.WHITE, width / 2, 300)

    while True:
        # Handle events
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                quit_game()

            # Call the event handler for the button object and do necessary function call if needed
            if return_to is "main" and btn_return.event(e):
                display_main_menu()
            elif return_to == "play" and btn_return.event(e):
                return
            elif btn_return.event(e):
                print("Invalid return_to parameter:", return_to)

            if btn_load_1.event(e):
                if load_game(1) is None:
                    txt_hint.update_text("No save under slot 1!")
            if btn_load_2.event(e):
                if load_game(2) is None:
                    txt_hint.update_text("No save under slot 2!")
            if btn_load_3.event(e):
                if load_game(3) is None:
                    txt_hint.update_text("No save under slot 3!")
            if btn_load_4.event(e):
                if load_game(4) is None:
                    txt_hint.update_text("No save under slot 4!")

        # Draw everything to the screen
        renderer.update_display(display)

        renderer.add(txt_title)
        renderer.add(txt_hint)
        renderer.add(btn_load_1)
        renderer.add(btn_load_2)
        renderer.add(btn_load_3)
        renderer.add(btn_load_4)
        renderer.add(btn_return)

        renderer.draw("bg_plain", Colours.BLACK)
Example #8
0
def play(need_load_game=False, data=None):
    """ This is the main play function, the game essentially takes place here """
    # Initial game object initialisations
    if need_load_game:
        p1_c1 = data["p1_c1"]
        p1_c2 = data["p1_c2"]
        p2_c1 = data["p2_c1"]
        p2_c2 = data["p2_c2"]
        die = data["die"]

        # Update the rects for the counters and die
        p1_c1.from_load()
        p1_c2.from_load()
        p2_c1.from_load()
        p2_c2.from_load()
        die.from_load()

        # Game play variables
        names = data["names"]

        p1_c1_move = data["p1_c1_move"]
        p1_c2_move = data["p1_c2_move"]
        p2_c1_move = data["p2_c1_move"]
        p2_c2_move = data["p2_c2_move"]

        die_result = data["die_result"]
        die_rolled = data["die_rolled"]

        move_by = data["move_by"]

        turn = data["turn"]  # 1 or 2

        scores = data["scores"]
    else:
        p1_c1 = Entities.Counter(1, 1)
        p1_c2 = Entities.Counter(1, 2)
        p2_c1 = Entities.Counter(2, 1)
        p2_c2 = Entities.Counter(2, 2)
        die = Entities.Die()

        # Game play variables
        names = display_enter_player_names()

        p1_c1_move = True, None
        p1_c2_move = True, None
        p2_c1_move = True, None
        p2_c2_move = True, None

        die_result = 0
        die_rolled = False

        move_by = 0

        turn = 1  # 1 or 2

        scores = [0, 0]  # Player 1 score, Player 2 score

    # Set up text and button objects
    current_player = Entities.Text(small_font, "Current Player", Colours.WHITE,
                                   430, 135)
    txt_player_one = Entities.Text(small_font, names[0], Colours.WHITE, 430,
                                   150)
    txt_player_two = Entities.Text(small_font, names[1], Colours.WHITE, 430,
                                   150)
    txt_hint = Entities.Text(small_font, "Test", Colours.WHITE, width / 2, 380)

    btn_load = Entities.Button(small_font, "Load", Colours.WHITE, 430, 214)
    btn_save = Entities.Button(small_font, "Save", Colours.WHITE, 430, 246)
    btn_rules = Entities.Button(small_font, "Rules", Colours.WHITE, 430, 278)
    btn_return = Entities.Button(small_font, "Return to\nMenu", Colours.WHITE,
                                 430, 305)

    # Draw to the screen
    def render_board():
        renderer.update_display(display)

        renderer.add(p1_c1)
        renderer.add(p1_c2)
        renderer.add(p2_c1)
        renderer.add(p2_c2)
        renderer.add(die)
        renderer.add(current_player)
        renderer.add(txt_player_one if turn == 1 else txt_player_two)
        renderer.add(btn_load)
        renderer.add(btn_save)
        renderer.add(btn_rules)
        renderer.add(btn_return)
        renderer.add(txt_hint)

        renderer.draw("bg_play", Colours.BLACK)

    def end_turn():
        """ Handle end of turn information such as switching of turns, die image reset etc. """
        new_turn = 1 if turn == 2 else 2
        die.update_image(0)

        check_winner()

        return new_turn, False, 0, 1

    def check_winner():
        """ Check if a player has both of their counters on row 11 (FINISH) """
        if p1_c1.get_row() == 11 and p1_c2.get_row() == 11:
            display_winner(names[0], scores[0])

        if p2_c1.get_row() == 11 and p2_c2.get_row() == 11:
            display_winner(names[1], scores[1])

    def calculate_move_by(result):
        """ Calculate the move_by variable based on the die result, essentially convert the die result
        into the movement distance as specified by the rules """
        movement = 0

        if result in [1, 2, 3]:
            return result
        elif result == 4:
            movement = -1
        elif result == 5:
            movement = "available"

        return movement

    def get_move_text(movement):
        """ Return the text to display to the user based on their movement result """
        if movement == 1:
            return "select counter to move 1 space closer to FINISH!"
        elif movement in [2, 3]:
            return "select counter to move " + str(
                movement) + " spaces closer to FINISH!"
        elif movement == -1:
            return "select counter to move 1 space closer to START!"
        elif movement == "available":
            return "select counter to move to next EMPTY row!"

    # Main game loop
    while True:
        # Handle events (beginning of game logic - i.e clicks on the window)
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                quit_game()

            die_event = die.event(e, die_rolled)

            # Check if the die was clicked
            if die_event[0]:
                if not die_rolled:
                    die_result = die_event[1]
                    die_rolled = True
                    move_by = calculate_move_by(die_result)
                    if turn == 1:
                        p1_c1_move = p1_c1.can_move(move_by, p1_c2.get_row(),
                                                    p2_c1.get_row(),
                                                    p2_c2.get_row())
                        p1_c2_move = p1_c2.can_move(move_by, p1_c1.get_row(),
                                                    p2_c1.get_row(),
                                                    p2_c2.get_row())
                    elif turn == 2:
                        p2_c1_move = p2_c1.can_move(move_by, p2_c2.get_row(),
                                                    p1_c1.get_row(),
                                                    p1_c2.get_row())
                        p2_c2_move = p2_c2.can_move(move_by, p2_c1.get_row(),
                                                    p1_c1.get_row(),
                                                    p1_c2.get_row())
                else:
                    txt_hint.update_text("You can only roll once!", 2)

            # Game logic for each player turn
            if turn == 1:
                if p2_c1.event(e) or p2_c2.event(e):
                    txt_hint.update_text("This isn't your counter!", 2)
                elif die_rolled:
                    if not p1_c1_move[0] and p1_c1.event(e):
                        txt_hint.update_text("This counter cannot be moved!",
                                             2)
                    elif p1_c1_move[0] and p1_c1.event(e):
                        p1_c1.move(p1_c1_move[1])
                        scores[0] += p2_c1.counter_moved(p1_c1.get_row())
                        scores[0] += p2_c2.counter_moved(p1_c1.get_row())
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                    elif not p1_c2_move[0] and p1_c2.event(e):
                        txt_hint.update_text("This counter cannot be moved!",
                                             2)
                    elif p1_c2_move[0] and p1_c2.event(e):
                        p1_c2.move(p1_c2_move[1])
                        scores[0] += p2_c1.counter_moved(p1_c2.get_row())
                        scores[0] += p2_c2.counter_moved(p1_c2.get_row())
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                    elif not p1_c1_move[0] and not p1_c2_move[0]:
                        txt_hint.update_text(
                            "No counter can move, ending turn...", 3)
                        render_board()
                        time.sleep(5)
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                elif p1_c1.event(e) or p1_c2.event(e):
                    txt_hint.update_text(
                        names[turn - 1] + ", you need to roll the die first!",
                        2)
            elif turn == 2:
                if p1_c1.event(e) or p1_c2.event(e):
                    txt_hint.update_text("This isn't your counter!", 2)
                elif die_rolled:
                    if not p2_c1_move[0] and p2_c1.event(e):
                        txt_hint.update_text("This counter cannot be moved!",
                                             2)
                    elif p2_c1_move[0] and p2_c1.event(e):
                        p2_c1.move(p2_c1_move[1])
                        scores[1] += p1_c1.counter_moved(p2_c1.get_row())
                        scores[1] += p1_c2.counter_moved(p2_c1.get_row())
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                    if not p2_c2_move[0] and p2_c2.event(e):
                        txt_hint.update_text("This counter cannot be moved!",
                                             2)
                    elif p2_c2_move[0] and p2_c2.event(e):
                        p2_c2.move(p2_c2_move[1])
                        scores[1] += p1_c1.counter_moved(p2_c2.get_row())
                        scores[1] += p1_c2.counter_moved(p2_c2.get_row())
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                    elif not p2_c1_move[0] and not p2_c2_move[0]:
                        txt_hint.update_text(
                            "No counter can move, ending turn...", 2)
                        render_board()
                        time.sleep(5)
                        turn, die_rolled, die_result, txt_hint.get_text_manager(
                        ).priority = end_turn()
                elif p2_c1.event(e) or p2_c2.event(e):
                    txt_hint.update_text(
                        names[turn - 1] + ", you need to roll the die first!",
                        2)

            # Current data - used if user clicks save from side menu
            current_data = {
                "p1_c1": p1_c1,
                "p1_c2": p1_c2,
                "p2_c1": p2_c1,
                "p2_c2": p2_c2,
                "die": die,
                "names": names,
                "p1_c1_move": p1_c1_move,
                "p1_c2_move": p1_c2_move,
                "p2_c1_move": p2_c1_move,
                "p2_c2_move": p2_c2_move,
                "die_result": die_result,
                "die_rolled": die_rolled,
                "move_by": move_by,
                "turn": turn,
                "scores": scores
            }

            display_saved_games("play") if btn_load.event(e) else False
            display_save_screen(current_data) if btn_save.event(e) else False
            display_rules("play") if btn_rules.event(e) else False
            display_main_menu() if btn_return.event(e) else False

        # Remaining game logic
        if not die_rolled:
            txt_hint.update_text(names[turn - 1] + ", click the die to roll!")
        elif die_result != 0:
            txt_hint.update_text(names[turn - 1] + " rolled a " +
                                 str(die_result) + ", " +
                                 get_move_text(move_by))

        # Render the game board to the screen
        render_board()

        # Pause loop for a time so that we can get the TARGET_FPS
        clock.tick(TARGET_FPS)