Skip to content
Snippets Groups Projects
gui.py 91.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • Dominik Battefeld's avatar
    Dominik Battefeld committed
    import logging
    
    import signal
    import subprocess
    
    import uuid
    
    from enum import Enum
    
    from subprocess import Popen
    
    import numpy as np
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
    import pygame
    
    import yaml
    
    from minerl.env.test_fake_env import color
    
    from pygame import mixer
    
    from websockets.sync.client import connect
    
    from cooperative_cuisine import ROOT_DIR
    
    from cooperative_cuisine.action import ActionType, InterActionData, Action
    
    from cooperative_cuisine.argument_parser import create_gui_parser
    
    from cooperative_cuisine.environment import Environment
    
    from cooperative_cuisine.game_server import (
        CreateEnvironmentConfig,
        WebsocketMessage,
        PlayerRequestType,
    )
    
    from cooperative_cuisine.items import ItemInfo
    
    from cooperative_cuisine.pygame_2d_vis.drawing import Visualizer, CacheFlags
    
    from cooperative_cuisine.pygame_2d_vis.game_colors import colors
    
    from cooperative_cuisine.server_results import PlayerInfo
    
    from cooperative_cuisine.state_representation import StateRepresentation
    from cooperative_cuisine.utils import (
    
        setup_logging, load_config_files,
    
    from cooperative_cuisine.pygame_2d_vis.grid import layout_thumbnail
    
    class MenuStates(Enum):
    
        """Enumeration of "Page" types in the 2D pygame vis."""
    
    
        PreGame = "PreGame"
    
        PostGame = "PostGame"
    
    Dominik Battefeld's avatar
    Dominik Battefeld committed
    log = logging.getLogger(__name__)
    
    """The logger for this module."""
    
    class PlayerKeySet:
    
        """Set of keyboard keys for controlling a player.
    
        First four keys are for movement. Order: Down, Up, Left, Right.
        5th key is for interacting with counters.
        6th key ist for picking up things or dropping them.
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            self,
            move_keys: list[pygame.key],
            interact_key: pygame.key,
            pickup_key: pygame.key,
            switch_key: pygame.key,
    
            players: list[str],
    
            joystick: int | None,
    
            """Creates a player key set which contains information about which keyboard keys control the player.
    
            Movement keys in the following order: Down, Up, Left, Right
    
            Args:
    
                move_keys: The keys which control this players movement in the following order: Down, Up, Left, Right.
                interact_key: The key to interact with objects in the game.
                pickup_key: The key to pick items up or put them down.
                switch_key: The key for switching through controllable players.
                players: The player indices which this keyset can control.
    
                joystick: number of joystick (later check if available)
    
            self.move_vectors: list[list[int]] = [[-1, 0], [1, 0], [0, -1], [0, 1]]
            self.key_to_movement: dict[pygame.key, list[int]] = {
                key: vec for (key, vec) in zip(move_keys, self.move_vectors)
    
            self.move_keys: list[pygame.key] = move_keys
            self.interact_key: pygame.key = interact_key
            self.pickup_key: pygame.key = pickup_key
            self.switch_key: pygame.key = switch_key
    
            self.controlled_players: list[str] = players
            self.current_player: str = players[0] if players else "0"
    
            self.current_idx = 0
            self.other_keyset: list[PlayerKeySet] = []
    
        def set_controlled_players(self, controlled_players: list[str]) -> None:
    
            """Sets the controlled players for this keyset.
            Args:
                controlled_players: The players controlled by this keyset.
            """
    
            self.controlled_players = controlled_players
            self.current_player = self.controlled_players[0]
    
            """Switches to the next player in the list of controlled players."""
    
            self.current_idx = (self.current_idx + 1) % len(self.controlled_players)
            if self.other_keyset:
                for ok in self.other_keyset:
                    if ok.current_idx == self.current_idx:
                        self.next_player()
                        return
            self.current_player = self.controlled_players[self.current_idx]
    
        def __repr__(self) -> str:
            return f"Keyset(current={self.current_player}, players={self.controlled_players}, joy={self.joystick})"
    
    class PyGameGUI:
    
        """Visualisation of the overcooked environment and reading keyboard inputs using pygame."""
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            self,
    
            study_host: str,
            study_port: int,
            game_host: str,
            game_port: int,
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            manager_ids: list[str],
    
            do_study: bool,
            use_ssl: bool,
    
            self.show_debug_elements = not do_study
            self.CONNECT_WITH_STUDY_SERVER = not debug
    
            pygame.init()
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            pygame.display.set_icon(
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                pygame.image.load(ROOT_DIR / "pygame_2d_vis" / "images" / "brain_icon.png")
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            )
    
            self.game_screen: pygame.Surface | None = None
    
            self.key_sets: list[PlayerKeySet] = []
    
            if self.CONNECT_WITH_STUDY_SERVER:
                self.request_url = (
                    f"http{'s' if use_ssl else ''}://{study_host}:{study_port}"
                )
    
                self.request_url = f"http{'s' if use_ssl else ''}://{game_host}:{game_port}"
    
            self.manager_id = random.choice(manager_ids)
    
            with open(ROOT_DIR / "pygame_2d_vis" / "visualization.yaml", "r") as file:
    
                self.visualization_config = yaml.safe_load(file)
    
    
            self.language = self.visualization_config["Gui"]["language"]
            # self.fluent_bundle: FluentBundle = create_bundle(
            #     self.visualization_config["Gui"]["language"],
            #     ROOT_DIR
            #     / "pygame_2d_vis"
            #     / "locales"
            #     / f"gui_messages_{self.language}.ftl",
            # )
    
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            self.FPS = self.visualization_config["GameWindow"]["FPS"]
    
    
            self.min_width = self.visualization_config["GameWindow"]["min_width"]
            self.min_height = self.visualization_config["GameWindow"]["min_height"]
            self.buttons_width = self.visualization_config["GameWindow"]["buttons_width"]
            self.buttons_height = self.visualization_config["GameWindow"]["buttons_height"]
    
            self.order_bar_height = self.visualization_config["GameWindow"][
                "order_bar_height"
            ]
    
            (
                self.window_width_fullscreen,
                self.window_height_fullscreen,
            ) = pygame.display.get_desktop_sizes()[0]
    
            # if (
            #     self.window_width_fullscreen >= 3840
            #     and self.window_height_fullscreen >= 2160
            # ):
            #     self.window_width_fullscreen /= 2
            #     self.window_height_fullscreen /= 2
    
            self.game_width = 0
            self.game_height = 0
    
            self.window_width_windowed = self.min_width
            self.window_height_windowed = self.min_height
            self.kitchen_width = 1
            self.kitchen_height = 1
            self.kitchen_aspect_ratio = 1
    
            self.images_path = ROOT_DIR / "pygame_gui" / "images"
    
            self.vis = Visualizer(self.visualization_config)
    
            self.last_score: float = 0
            self.switch_score_color: bool = False
            self.count_frames_score_label: int = 0
    
    
            self.menu_state = MenuStates.Start
            self.manager: pygame_gui.UIManager
    
    
            self.layout_file_paths_dict = {
                p.name: p for p in (ROOT_DIR / "configs" / "layouts").rglob("*.layout")
            }
            self.layout_file_paths = sorted(list(self.layout_file_paths_dict.keys()))
    
            self.current_layout_idx = 0
    
            self.selected_layout = "basic.layout"
    
            self.last_state: StateRepresentation
    
            self.player_info = {"0": {"name": "0"}}
    
            self.level_info = {
                "name": "Level",
                "recipe_graphs": [],
                "number_players": -1,
                "kitchen_size": (0, 0),
            }
    
            self.last_level = False
    
            self.all_completed_meals = []
            self.last_completed_meals = []
            self.all_recipes_labels = []
            self.last_recipes_labels = []
    
        def setup_player_keys(self, players: list[str], number_key_sets=1, disjunct=False):
    
    Annika Österdiekhoff's avatar
    Annika Österdiekhoff committed
            # First four keys are for movement. Order: Down, Up, Left, Right.
            # 5th key is for interacting with counters.
            # 6th key ist for picking up things or dropping them.
    
                key_set1 = PlayerKeySet(
                    move_keys=[pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s],
                    interact_key=pygame.K_f,
                    pickup_key=pygame.K_e,
                    switch_key=pygame.K_SPACE,
    
                    joystick=None,
    
                )
                key_set2 = PlayerKeySet(
                    move_keys=[pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN],
                    interact_key=pygame.K_i,
                    pickup_key=pygame.K_o,
                    switch_key=pygame.K_p,
    
                    joystick=None,
    
                key_sets = [key_set1, key_set2]
    
    
                if self.joysticks:
                    for idx, key in enumerate(self.joysticks.keys()):
                        if idx >= len(key_sets):
                            break
                        key_sets[idx].joystick = key
    
    
                    key_set1.set_controlled_players(players[::2])
                    key_set2.set_controlled_players(players[1::2])
    
                    key_set1.set_controlled_players(players)
                    key_set2.set_controlled_players(players)
                    key_set1.other_keyset = [key_set2]
                    key_set2.other_keyset = [key_set1]
                    key_set2.next_player()
    
            """Handles keyboard inputs. Sends action for the respective players. When a key is held down, every frame
            an action is sent in this function.
            """
    
            keys = pygame.key.get_pressed()
    
            for key_set in self.key_sets:
                current_player_name = str(key_set.current_player)
                relevant_keys = [keys[k] for k in key_set.move_keys]
                if any(relevant_keys):
    
                    move_vec = np.zeros(2)
    
                    for idx, pressed in enumerate(relevant_keys):
    
                        if pressed:
    
                            move_vec += key_set.move_vectors[idx]
    
                    if np.linalg.norm(move_vec) != 0:
                        move_vec = move_vec / np.linalg.norm(move_vec)
    
    
                        ActionType.MOVEMENT.value,
    
                        duration=self.time_delta,
    
                    self.send_action(action)
    
        def handle_joy_stick_input(self, joysticks: dict[int, pygame.joystick.Joystick]):
    
            """Handles joystick inputs for movement every frame
            Args:
                joysticks: list of joysticks
    
            # Axis 0: joy stick left: -1 = left, ~0 = center, 1 = right
            # Axis 1: joy stick left: -1 = up, ~0 = center, 1 = down
    
            # see control stuff here (at the end of the page): https://www.pygame.org/docs/ref/joystick.html
    
            for key_set in self.key_sets:
    
                current_player_name = str(key_set.current_player)
    
                # if a joystick is connected for current player
    
                if key_set.joystick in joysticks:
    
                    # Usually axis run in pairs, up/down for one, and left/right for the other. Triggers count as axes.
                    # You may want to take into account some tolerance to handle jitter, and
                    # joystick drift may keep the joystick from centering at 0 or using the full range of position values.
    
                    tolerance_threshold = 0.22
    
                    # axis 0 = joy stick left --> left & right
                    axis_left_right = joysticks[key_set.joystick].get_axis(0)
                    axis_up_down = joysticks[key_set.joystick].get_axis(1)
    
    
                    if np.linalg.norm([axis_left_right, axis_up_down]) > tolerance_threshold:
                        move_vec = np.array([axis_left_right, axis_up_down])
    
    fheinrich's avatar
    fheinrich committed
                        # if np.linalg.norm(move_vec) != 0:
                        #     move_vec = move_vec / np.linalg.norm(move_vec)
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                            current_player_name,
    
                            ActionType.MOVEMENT.value,
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                            move_vec,
                            duration=self.time_delta,
    
        def handle_key_event(self, event: pygame.event.Event):
    
            """Handles key events for the pickup and interaction keys. Pickup is a single action,
            for interaction keydown and keyup is necessary, because the player has to be able to hold
            the key down.
    
    
            for key_set in self.key_sets:
                current_player_name = str(key_set.current_player)
    
                if event.key == key_set.pickup_key and event.type == pygame.KEYDOWN:
    
                    action = Action(current_player_name, ActionType.PICK_UP_DROP, None)
    
                    self.send_action(action)
    
                if event.key == key_set.interact_key:
    
                            current_player_name, ActionType.INTERACT, InterActionData.START
    
                        self.send_action(action)
    
                            current_player_name, ActionType.INTERACT, InterActionData.STOP
    
                        self.send_action(action)
    
                if event.key == key_set.switch_key:
    
                    if event.type == pygame.KEYDOWN:
                        key_set.next_player()
    
        def handle_joy_stick_event(
            self, event: pygame.event.Event, joysticks: dict[int, pygame.joystick.Joystick]
        ):
    
            """Handles joy stick events for the pickup and interaction keys. Pickup is a single action,
            for interaction buttondown and buttonup is necessary, because the player has to be able to hold
            the button down.
    
            Args:
                event: Pygame event for extracting the button action.
    
                joysticks: list of joysticks
    
            for key_set in self.key_sets:
    
                current_player_name = str(key_set.current_player)
    
                # if a joystick is connected for current player
    
                if key_set.joystick in joysticks:
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                    if (
                        joysticks[key_set.joystick].get_button(0)
                        and event.type == pygame.JOYBUTTONDOWN
                    ):
    
                        action = Action(current_player_name, ActionType.PICK_UP_DROP, None)
    
                    # interact = Button X <-> 2
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                    if (
                        joysticks[key_set.joystick].get_button(2)
                        and event.type == pygame.JOYBUTTONDOWN
                    ):
    
                        action = Action(
                            current_player_name, ActionType.INTERACT, InterActionData.START
                        )
                        self.send_action(action)
    
                        # stop interaction if last pressed button was X <-> 2
    
                    if event.button == 2 and event.type == pygame.JOYBUTTONUP:
                        action = Action(
                            current_player_name, ActionType.INTERACT, InterActionData.STOP
                        )
                        self.send_action(action)
    
                    # switch button Y <-> 3
    
                    if joysticks[key_set.joystick].get_button(3):
    
                        if event.type == pygame.JOYBUTTONDOWN:
                            key_set.next_player()
    
            """Sets the window size based on fullscreen or not."""
    
            if self.fullscreen:
                flags = pygame.FULLSCREEN
                self.window_width = self.window_width_fullscreen
                self.window_height = self.window_height_fullscreen
            else:
                flags = 0
                self.window_width = self.window_width_windowed
                self.window_height = self.window_height_windowed
    
            self.screen_margin = self.visualization_config["GameWindow"][
    
                                     "screen_margin_proportion"
                                 ] * min(self.window_width, self.window_height)
    
            self.main_window = pygame.display.set_mode(
    
        def set_game_size(self, max_width: float = None, max_height: float = None):
            """Sets the game size based on the kitchen size and the current window size.
    
            Args:
                max_width: Maximum width of the game screen.
                max_height: Maximum height of the game screen.
            """
    
            if max_width is None:
                max_width = self.window_width - (2 * self.screen_margin)
            if max_height is None:
                max_height = self.window_height - (2 * self.screen_margin)
    
            self.kitchen_aspect_ratio = self.kitchen_height / self.kitchen_width
            if self.kitchen_width > self.kitchen_height:
                self.game_width = max_width
                self.game_height = self.game_width * self.kitchen_aspect_ratio
    
                if self.game_height > max_height:
                    self.game_height = max_height
                    self.game_width = self.game_height / self.kitchen_aspect_ratio
            else:
                self.game_height = max_height
                self.game_width = self.game_height / self.kitchen_aspect_ratio
    
                if self.game_width > max_width:
                    self.game_width = max_width
                    self.game_height = self.game_width * self.kitchen_aspect_ratio
    
            self.grid_size = int(self.game_width / self.kitchen_width)
    
            self.game_width = max(self.game_width, 100)
            self.game_height = max(self.game_height, 100)
            self.grid_size = max(self.grid_size, 1)
    
    
            self.vis.set_grid_size(self.grid_size)
    
    
            residual_x = self.game_width - (self.kitchen_width * self.grid_size)
            residual_y = self.game_height - (self.kitchen_height * self.grid_size)
            self.game_width -= residual_x
            self.game_height -= residual_y
    
    
            self.game_screen = pygame.Surface(
                (
                    self.game_width,
                    self.game_height,
                )
    
            """Creates all UI elements. Creates lists of which elements belong on which screen."""
    
    
            self.manager = pygame_gui.UIManager(
                (self.window_width, self.window_height),
                starting_language=self.language,
                translation_directory_paths=[ROOT_DIR / "pygame_2d_vis" / "locales"],
            )
    
            self.manager.get_theme().load_theme(
                ROOT_DIR / "pygame_2d_vis" / "gui_theme.json"
            )
    
            self.elements_margin = self.window_height * 0.02
    
    
            ########################################################################
            # All screens
            ########################################################################
    
            fullscreen_button_rect = pygame.Rect(
                (0, 0), (self.buttons_width * 0.7, self.buttons_height)
            )
            fullscreen_button_rect.topright = (-self.buttons_width, 0)
            self.fullscreen_button = pygame_gui.elements.UIButton(
                relative_rect=fullscreen_button_rect,
    
                text="translations.fullscreen",
    
                manager=self.manager,
                object_id="#fullscreen_button",
                anchors={"right": "right", "top": "top"},
            )
    
            rect = pygame.Rect((0, 0), (self.buttons_width, self.buttons_height))
            rect.topright = (0, 0)
            self.quit_button = pygame_gui.elements.UIButton(
                relative_rect=rect,
    
                text="translations.quit_game",
    
                manager=self.manager,
                object_id="#quit_button",
                anchors={"right": "right", "top": "top"},
            )
    
    
            ########################################################################
            # Start screen
            ########################################################################
    
            self.start_button = pygame_gui.elements.UIButton(
    
                relative_rect=pygame.Rect(
    
                    (0, 0), (self.buttons_width, self.buttons_height)
    
                text="translations.start_game",
                text_kwargs={},
    
                manager=self.manager,
    
                object_id="#start_button",
    
            if self.visualization_config["Gui"]["press_button_to_continue"]:
                img = pygame.image.load(
                    ROOT_DIR
                    / "pygame_2d_vis"
                    / "gui_images"
                    / f"continue_{self.language}.png"
                ).convert_alpha()
    
                image_rect = img.get_rect()
                img_width = self.buttons_width * 1.5
                img_height = img_width * (image_rect.height / image_rect.width)
                new_dims = (img_width, img_height)
                img = pygame.transform.smoothscale(img, new_dims)
                image_rect = img.get_rect()
    
                image_rect.centery += 80
                self.press_a_image = pygame_gui.elements.UIImage(
                    image_rect,
                    img,
                    manager=self.manager,
                    anchors={"centerx": "centerx", "centery": "centery"},
                )
            else:
                self.press_a_image = None
    
    
            # self.press_a_image.set_dimensions(new_dims)
    
            if not self.CONNECT_WITH_STUDY_SERVER:
                assert len(self.layout_file_paths) != 0, "No layout files."
            dropdown_width, dropdown_height = 200, 40
            self.layout_selection = pygame_gui.elements.UIDropDownMenu(
                relative_rect=pygame.Rect(
                    (
                        0,
                        0,
                    ),
                    (dropdown_width, dropdown_height),
                ),
                manager=self.manager,
                options_list=self.layout_file_paths,
                starting_option="basic.layout"
                if "basic.layout" in self.layout_file_paths
                else random.choice(self.layout_file_paths),
            )
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                    self.window_width * 0.9,
    
            player_selection_rect.bottom = -self.elements_margin
    
            self.player_selection_container = pygame_gui.elements.UIPanel(
                player_selection_rect,
                manager=self.manager,
                object_id="#players",
                anchors={"bottom": "bottom", "centerx": "centerx"},
            )
    
            rect = pygame.Rect((0, 0), (190, 50))
    
            self.multiple_keysets_button = pygame_gui.elements.UIButton(
    
                relative_rect=rect,
    
                manager=self.manager,
                container=self.player_selection_container,
                text="not set",
    
                anchors={"centerx": "centerx", "centery": "centery"},
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                object_id="#multiple_keysets_button",
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            split_players_button_rect = pygame.Rect((0, 0), (190, 50))
    
            self.split_players_button = pygame_gui.elements.UIButton(
                relative_rect=split_players_button_rect,
                manager=self.manager,
                container=self.player_selection_container,
                text="not set",
    
                anchors={"centery": "centery", "left_target": self.multiple_keysets_button},
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                object_id="#split_players_button",
    
            rect = pygame.Rect(
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                (
                    self.window_width * 0.6,
    
                    self.player_selection_container.get_abs_rect().height * 0.35,
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            self.player_number_container = pygame_gui.elements.UIPanel(
    
                relative_rect=rect,
    
                manager=self.manager,
                object_id="#players_players",
                container=self.player_selection_container,
                anchors={"top": "top", "centerx": "centerx"},
            )
    
    
            rect = pygame.Rect(
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                (
                    self.window_width * 0.6,
    
                    self.player_selection_container.get_abs_rect().height * 0.35,
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            self.bot_number_container = pygame_gui.elements.UIPanel(
    
                relative_rect=rect,
    
                manager=self.manager,
                object_id="#players_bots",
                container=self.player_selection_container,
                anchors={"bottom": "bottom", "centerx": "centerx"},
            )
    
            number_players_rect = pygame.Rect((0, 0), (200, 200))
            self.added_players_label = pygame_gui.elements.UILabel(
                number_players_rect,
                manager=self.manager,
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                object_id="#number_players_label",
                container=self.player_number_container,
    
                text=f"not set: -",
    
                anchors={"center": "center"},
            )
    
            number_bots_rect = pygame.Rect((0, 0), (200, 200))
            self.added_bots_label = pygame_gui.elements.UILabel(
                number_bots_rect,
                manager=self.manager,
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                object_id="#number_bots_label",
                container=self.bot_number_container,
    
                text=f"not set: -",
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            size = 50
    
            self.add_human_player_button = pygame_gui.elements.UIButton(
    
                relative_rect=pygame.Rect((0, 0), (size, size)),
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                object_id="#quantity_button",
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                container=self.player_number_container,
    
                anchors={"left_target": self.added_bots_label, "centery": "centery"},
    
            rect = pygame.Rect((0, 0), (size, size))
            rect.right = 0
    
            self.remove_human_button = pygame_gui.elements.UIButton(
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                object_id="#quantity_button",
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                container=self.player_number_container,
    
                anchors={
                    "right": "right",
                    "right_target": self.added_bots_label,
                    "centery": "centery",
                },
    
            )
    
            self.add_bot_button = pygame_gui.elements.UIButton(
    
                relative_rect=pygame.Rect((0, 0), (size, size)),
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                object_id="#quantity_button",
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                container=self.bot_number_container,
    
                anchors={"left_target": self.added_bots_label, "centery": "centery"},
    
            rect = pygame.Rect((0, 0), (size, size))
            rect.right = 0
    
            self.remove_bot_button = pygame_gui.elements.UIButton(
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                object_id="#quantity_button",
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                container=self.bot_number_container,
    
                anchors={
                    "right": "right",
                    "right_target": self.added_bots_label,
                    "centery": "centery",
                },
    
            self.scroll_space_layouts = pygame_gui.elements.UIScrollingContainer(
                relative_rect=pygame.Rect((0, 0), (self.buttons_width * 1.2, self.window_height)),
                manager=self.manager,
                anchors={"top": "top", "left": "left"},
            )
            self.setup_layout_selection()
    
            rect = pygame.Rect(
                (0, 0),
                (
                    self.window_width * 0.5,
                    self.buttons_height,
                ),
            )
            self.selected_layout_label = pygame_gui.elements.UILabel(
                text="translations.selected_layout",
                text_kwargs={"layout": "basic.layout"},
                relative_rect=rect,
                manager=self.manager,
                object_id="#selected_layout",
                anchors={"centerx": "centerx", "bottom_target": self.start_button},
            )
    
    
            ########################################################################
            # Tutorial screen
            ########################################################################
    
            button_rect.bottom = -self.elements_margin
    
            self.continue_button = pygame_gui.elements.UIButton(
                relative_rect=button_rect,
    
                text="translations.continue",
    
                manager=self.manager,
                anchors={"centerx": "centerx", "bottom": "bottom"},
            )
    
            # TODO update on pregame
    
            button_rect = pygame.Rect((0, 0), (220, 80))
            button_rect.bottom = -self.elements_margin
            button_rect.centerx += 250
            self.continue_button_two = pygame_gui.elements.UIButton(
                relative_rect=button_rect,
                text="translations.continue",
                manager=self.manager,
                anchors={"centerx": "centerx", "bottom": "bottom"},
            )
    
    
            image = pygame.image.load(
    
                ROOT_DIR / "pygame_2d_vis" / "gui_images" / f"controls_{self.language}.png"
    
            ).convert_alpha()
            image_rect = image.get_rect()
    
    
            # img_width = self.window_width * 0.68
            # img_height = img_width * (image_rect.height / image_rect.width)
            img_height = self.window_height * 0.95
            img_width = img_height * (image_rect.width / image_rect.height)
    
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            image = pygame.transform.smoothscale(image, new_dims)
    
            image_rect.left = self.elements_margin
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            image_rect.top = self.elements_margin
    
            self.tutorial_image = pygame_gui.elements.UIImage(
                image_rect,
                image,
                manager=self.manager,
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
                anchors={"top": "top", "left": "left"},
    
            arrow_img = pygame.image.load(
    
                ROOT_DIR / "pygame_2d_vis" / "gui_images" / f"try_{self.language}.png"
    
            ).convert_alpha()
            image_rect = arrow_img.get_rect()
            img_width = self.window_width * 0.2
            img_height = img_width * (image_rect.height / image_rect.width)
            new_dims = (img_width, img_height)
    
    Fabian Heinrich's avatar
    Fabian Heinrich committed
            arrow_img = pygame.transform.smoothscale(arrow_img, new_dims)
    
            rect = arrow_img.get_rect()
            rect.left = self.window_width * 0.55
            rect.top = self.window_height * 0.7
            self.arrow_img = pygame_gui.elements.UIImage(
                relative_rect=rect,
                image_surface=arrow_img,
                manager=self.manager,
                anchors={
                    "left": "left",
                    "top": "top",
                },
            )
    
    
                (self.window_width * 0.25, self.window_height * 0.4),
    
            rect.right = -self.elements_margin
    
            self.tutorial_recipe_container = pygame_gui.elements.UIPanel(
                relative_rect=rect,
    
                manager=self.manager,
    
                anchors={"right": "right", "top": "top", "top_target": self.quit_button},
    
            self.tutorial_recipe_graph_rect = pygame.Rect(
                (0, 0), (self.window_width * 0.25, self.window_height * 0.2)
    
            self.tutorial_recipe_graph_rect.bottom = 0
    
            self.tutorial_graph_image = pygame_gui.elements.UIImage(
                relative_rect=self.tutorial_recipe_graph_rect,
                image_surface=pygame.Surface(self.tutorial_recipe_graph_rect.size),
    
                manager=self.manager,
    
                object_id="#recipe_graph",
                container=self.tutorial_recipe_container,
    
                anchors={"centerx": "centerx", "bottom": "bottom"},
    
    
            r = pygame.Rect((0, 0), (self.window_width * 0.25, self.window_height * 0.05))
    
                text="translations.salad_recipe",
    
                relative_rect=r,
                manager=self.manager,
                container=self.tutorial_recipe_container,
    
                object_id="#recipe_name",
    
                    "bottom_target": self.tutorial_graph_image,
    
            ########################################################################
            # PreGame screen
            ########################################################################
    
            rect = pygame.Rect(
                (0, 0),
                (self.window_width, 50),
            )
            rect.top = 20
    
            self.level_name_label = pygame_gui.elements.UILabel(
                text=f"not set",
    
                relative_rect=rect,
    
                manager=self.manager,
    
                object_id="#level_name",
    
                anchors={"centerx": "centerx", "top": "top"},
    
            self.text_recipes_label = pygame_gui.elements.UILabel(
    
                text="translations.recipes_in_this_level",
    
                relative_rect=pygame.Rect(
                    (0, 0),
    
                    (self.window_width * 0.5, 50),
    
                ),
                manager=self.manager,
                anchors={"centerx": "centerx", "top_target": self.level_name_label},
            )
    
    
            self.scroll_height = (
    
                self.continue_button.get_abs_rect().top
                - self.text_recipes_label.get_abs_rect().bottom
            )
    
            self.scroll_space_recipes = pygame_gui.elements.UIScrollingContainer(
    
                relative_rect=pygame.Rect((0, 0), (self.window_width, self.scroll_height)),
    
                manager=self.manager,
                anchors={"centerx": "centerx", "top_target": self.text_recipes_label},
            )
    
            ########################################################################
            # Game screen
            ########################################################################
    
    
            self.orders_label = pygame_gui.elements.UILabel(
    
                text="translations.orders",
    
                relative_rect=pygame.Rect(0, 0, self.buttons_width, self.screen_margin),
    
                manager=self.manager,
                object_id="#orders_label",
            )
    
    
            self.orders_container_width = (
                self.window_width - (2 * self.buttons_width) - (self.buttons_width * 0.7)
            )
    
            self.orders_image = pygame_gui.elements.UIImage(
                relative_rect=pygame.Rect(
                    0, 0, self.orders_container_width, self.screen_margin
                ),
                image_surface=pygame.Surface(
                    (self.orders_container_width, self.screen_margin)
                ),
                manager=self.manager,
                object_id="#recipe_graph",
                anchors={"top": "top", "left_target": self.orders_label},
            )
    
    
                (self.window_width * 0.3, self.buttons_height),
    
            self.score_label = pygame_gui.elements.UILabel(
    
                manager=self.manager,
                object_id="#score_label",
    
                anchors={"bottom": "bottom", "left": "left"},
    
            rect = pygame.Rect(
                (0, 0),
                (self.window_width * 0.4, self.buttons_height),
            )
            rect.bottom = 0
    
            self.timer_label = pygame_gui.elements.UILabel(
    
                manager=self.manager,
                object_id="#timer_label",
    
                anchors={"bottom": "bottom", "centerx": "centerx"},
            )
    
            rect = pygame.Rect(
                (0, 0),
                (self.window_width, self.screen_margin),
            )
            rect.right = 20
            self.wait_players_label = pygame_gui.elements.UILabel(
    
                text="translations.waiting_for_players",
    
                relative_rect=rect,
                manager=self.manager,
                object_id="#wait_players_label",
                anchors={"centery": "centery", "right": "right"},
    
            rect = pygame.Rect((0, 0), (self.buttons_width, self.buttons_height))
            rect.bottomright = (0, 0)
            self.return_to_main_button = pygame_gui.elements.UIButton(
                relative_rect=rect,
                text="translations.return_to_main_menu",
                manager=self.manager,
                object_id="#main_menu_button",
                anchors={"right": "right", "bottom": "bottom"},
            )
    
    
            ########################################################################
            # PostGame screen
            ########################################################################
    
            rect = pygame.Rect((0, 0), (220, 80))
    
            rect.bottom = -self.elements_margin
    
            self.next_game_button = pygame_gui.elements.UIButton(
    
                relative_rect=rect,
    
                manager=self.manager,
    
                text="translations.next_game",
    
                anchors={"centerx": "centerx", "bottom": "bottom"},
    
                object_id="#split_players_button",
            )
    
    
            rect = pygame.Rect(
                (0, 0),
    
                (self.window_width, self.window_height * 0.07),
    
            )
            self.score_conclusion = pygame_gui.elements.UILabel(
                text=f"not set",
                relative_rect=rect,
                manager=self.manager,
    
                object_id="#score_conclusion",
    
                anchors={"centerx": "centerx", "top_target": self.level_name_label},
            )
    
            self.completed_meals_text_label = pygame_gui.elements.UILabel(
    
                text="translations.completed_meals",
    
                relative_rect=pygame.Rect(
                    (0, 0),
    
                    (self.window_width, self.window_height * 0.05),
    
                ),
                manager=self.manager,
    
                object_id="#completed_meals_label",
    
                anchors={"centerx": "centerx", "top_target": self.score_conclusion},
            )
    
    
            scroll_height = (
                self.continue_button.get_abs_rect().top
                - self.completed_meals_text_label.get_abs_rect().bottom
                - 10