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_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_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
Esempio n. 7
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()