def test_reject_duplicate_ids():
    with pytest.raises(ValueError) as excinfo:
        DialogGraph("DUPLICATE", [
            DialogNode("DUPLICATE", "::text::", [],
                       NodeGraphics(image_ids=["::image::"])),
            DialogNode("DUPLICATE", "::text::", [],
                       NodeGraphics(image_ids=["::image::"]))
        ])
    assert "Duplicate node ID found: DUPLICATE" in str(excinfo.value)
def test_state_after_making_choice():
    first_node = DialogNode("START", "Hello!",
                            [DialogChoice("Good bye!", "END")],
                            NodeGraphics(image_ids=["::image::"]))
    second_node = DialogNode("END", "It's over.", [],
                             NodeGraphics(image_ids=["::image::"]))
    graph = DialogGraph("START", [first_node, second_node])
    graph.make_choice(0)
    assert graph.current_node() == second_node
def test_reject_missing_root():
    with pytest.raises(ValueError) as excinfo:
        DialogGraph("MISSING", [
            DialogNode("::id::", "::text::", [],
                       NodeGraphics(image_ids=["::image::"]))
        ])
    assert "No node found with ID: MISSING" in str(excinfo.value)
def test_simple_graphviz():
    dialog_graph = DialogGraph(
        root_node_id="ROOT_NODE",
        nodes=[
            DialogNode("ROOT_NODE", "Start text",
                       [DialogChoice("Choice text", "OTHER_NODE")],
                       NodeGraphics(image_ids=["some_image.png"])),
            DialogNode("OTHER_NODE", "Other text", [],
                       NodeGraphics(image_ids=["other_image.png"]))
        ])

    graph = generate_graphviz("Some name", dialog_graph)

    assert graph.name == "Some name"
    assert set(graph.body) == {
        '\tROOT_NODE [label="Start text"]',
        '\tROOT_NODE -> OTHER_NODE [label="Choice text"]',
        '\tOTHER_NODE [label="Other text"]'
    }
def test_reject_missing_child():
    with pytest.raises(ValueError) as excinfo:
        DialogGraph("ROOT", [
            DialogNode(
                "ROOT",
                "::text::",
                [DialogChoice("::text::", "MISSING_CHILD")],
                NodeGraphics(image_ids=["::image::"]),
            )
        ])
    assert "Dialog choice leading to missing node: MISSING_CHILD" in str(
        excinfo.value)
def test_initial_state():
    node = DialogNode("START", "Hello!", [DialogChoice("Good bye!", "START")],
                      NodeGraphics(image_ids=["::image::"]))
    graph = DialogGraph("START", [node])
    assert graph.current_node() == node
Beispiel #7
0
def main():
    dialog_graph = DialogGraph(
        root_node_id="START",
        nodes=[
            DialogNode(
                node_id="START",
                text="You are in a dimly lit room. There are two doors leading out of the room, one to the west and "
                     "another one to the east.",
                choices=[DialogChoice("Exit west", "WEST"),
                         DialogChoice("Exit east", "EAST")]),
            DialogNode(
                node_id="WEST",
                text="You are in a library. There seems to be nothing here of interest.",
                choices=[DialogChoice("Leave the library", "START")]),
            DialogNode(
                node_id="EAST",
                text="You are in a narrow and straight corridor. On the east end of it, there's a hole in the floor!",
                choices=[DialogChoice("Leave corridor to the west", "START"),
                         DialogChoice("Jump down in the hole", "BASEMENT")]),
            DialogNode(
                node_id="BASEMENT",
                text="You hurt yourself quite badly in the fall, and find yourself in a dark cellar. You can't see "
                     "anything.",
                choices=[DialogChoice("Sit down and wait for better days", "SUNLIGHT"),
                         DialogChoice("Feel your way through the room", "SPEAR")]),
            DialogNode(
                node_id="SUNLIGHT",
                text="Eventually the room gets brighter. The sun is shining in through a window and you can see a "
                     "door at the other end of the cellar leading to the outside. The walls are full of mounted spears "
                     "and other nasty things, and you think to yourself that it was a good thing you didn't try to "
                     "navigate here in the dark.",
                choices=[DialogChoice("Leave through the door", "VICTORY")]),
            DialogNode(
                node_id="SPEAR",
                text="You accidentally walk into spear that's mounted to the wall. You are dead.",
                choices=[DialogChoice("Retry", "START"),
                         DialogChoice("Exit game", "EXIT")]),
            DialogNode(
                node_id="VICTORY",
                text="Hooray, you escaped!",
                choices=[DialogChoice("Start from beginning", "START"),
                         DialogChoice("Exit game", "EXIT")]),
            DialogNode(
                node_id="EXIT",
                text="",
                choices=[]),
        ],
    )

    while True:
        node = dialog_graph.current_node()

        if node.node_id == "EXIT":
            break

        print("")
        print_in_box(node.text, 50)
        print("")

        time.sleep(0.5)

        print("Select one of these choices:")
        for i, choice in enumerate(node.choices):
            time.sleep(0.15)
            print(f"{i} : {choice.text}")

        choice = -1
        valid_choices = range(len(node.choices))
        while choice not in valid_choices:
            text_input = input("> ")
            try:
                choice = int(text_input)
                if choice not in valid_choices:
                    print("Invalid choice. Select one of the listed numbers!")
            except ValueError:
                print("Invalid input. Type a number!")

        print(f"\"{node.choices[choice].text.upper()}\"")
        time.sleep(0.5)

        dialog_graph.make_choice(choice)
Beispiel #8
0
def main():
    pygame.init()
    directory = Path(__file__).parent
    font = Font(str(directory.joinpath("demo_font.dfont")), 13)

    screen_size = (500, 500)
    dialog_margin = 30
    dialog_padding = 5
    outer_dialog_size = (screen_size[0] - dialog_margin * 2, 330)
    dialog_size = (outer_dialog_size[0] - dialog_padding * 2,
                   outer_dialog_size[1] - dialog_padding * 2)
    picture_component_size = (dialog_size[0], 200)

    screen = pygame.display.set_mode(screen_size)
    dialog_surface = Surface(dialog_size)
    dialog_pos = (dialog_margin + dialog_padding,
                  dialog_margin + dialog_padding)
    dialog_rect = Rect(dialog_pos, dialog_size)

    images = {
        "demo1_background": filled_surface(picture_component_size, (0, 50, 35))
    }
    animations = {"demo1_animation": create_animation(picture_component_size)}
    text_blip_sound = load_sound("blip.ogg")
    select_blip_sound = load_sound("blip_2.ogg")
    select_blip_sound_id = "blip"
    sound_player = SoundPlayer(
        sounds={select_blip_sound_id: select_blip_sound},
        text_blip_sound=text_blip_sound)

    dialog_closed_node_id = "DIALOG_CLOSED"
    dialog_graph = DialogGraph(
        root_node_id="ROOT",
        nodes=[
            DialogNode(
                node_id="ROOT",
                text=
                "This is a minimal demo app. Let this text slowly appear or click any key to skip it. "
                "Use the UP/DOWN keys to switch between your dialog choices, and click RETURN to go "
                "for that choice. Or you could just use the mouse!",
                choices=[
                    DialogChoice("See this dialog again", "ROOT"),
                    DialogChoice("Close dialog", dialog_closed_node_id)
                ],
                graphics=NodeGraphics(animation_id="demo1_animation")),
            DialogNode(node_id=dialog_closed_node_id,
                       text="",
                       choices=[],
                       graphics=NodeGraphics(animation_id="demo1_animation")),
        ],
        title="DEMO 1",
        background_image_id="demo1_background")

    pygame.display.set_caption(dialog_graph.title)

    dialog_component = DialogComponent(
        surface=dialog_surface,
        dialog_font=font,
        choice_font=font,
        images=images,
        animations=animations,
        sound_player=sound_player,
        dialog_graph=dialog_graph,
        picture_size=picture_component_size,
        select_blip_sound_id=select_blip_sound_id)

    clock = Clock()

    is_dialog_shown = True

    while True:

        elapsed_time = Millis(clock.tick())

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                _exit_game()
            elif event.type == pygame.KEYDOWN:
                if is_dialog_shown:
                    dialog_component.skip_text()
                    if event.key == pygame.K_RETURN:
                        dialog_component.commit_selected_choice()
                        if dialog_component.current_node_id(
                        ) == dialog_closed_node_id:
                            is_dialog_shown = False
                    elif event.key == pygame.K_DOWN:
                        dialog_component.move_choice_selection(1)
                    elif event.key == pygame.K_UP:
                        dialog_component.move_choice_selection(-1)
            elif event.type == pygame.MOUSEBUTTONDOWN:
                ui_coordinates = translate_screen_to_ui_coordinates(
                    dialog_rect, pygame.mouse.get_pos())
                if ui_coordinates:
                    dialog_component.commit_choice_at_position(ui_coordinates)
                    if dialog_component.current_node_id(
                    ) == dialog_closed_node_id:
                        is_dialog_shown = False
            elif event.type == pygame.MOUSEMOTION:
                ui_coordinates = translate_screen_to_ui_coordinates(
                    dialog_rect, pygame.mouse.get_pos())
                if ui_coordinates:
                    dialog_component.select_choice_at_position(ui_coordinates)

        if is_dialog_shown:
            dialog_component.update(elapsed_time)
            dialog_component.redraw()

        screen.fill(BLACK)
        if is_dialog_shown:
            screen.blit(dialog_component.surface, dialog_pos)
        pygame.draw.rect(screen, (255, 100, 100),
                         Rect((dialog_margin, dialog_margin),
                              outer_dialog_size),
                         width=1)

        fps_string = str(int(clock.get_fps())).rjust(3, ' ')
        rendered_fps = font.render(f"FPS: {fps_string}", True, WHITE,
                                   (0, 0, 0))
        screen.blit(rendered_fps, (5, 5))

        screen.blit(
            font.render(
                "The dialog library is confined to the red rectangle above.",
                True, WHITE), (15, 400))
        screen.blit(
            font.render("This text is handled separately from the dialog.",
                        True, WHITE), (15, 430))
        if not is_dialog_shown:
            screen.blit(
                font.render(
                    "Oops, you closed the dialog. Restart app to see it again.",
                    True, (255, 150, 150)), (15, 460))

        pygame.display.update()