Ejemplo n.º 1
0
class ColourPicker:
    pick_colour_callback: Callable[[Tuple[float, float, float, float]], None]

    __base: ShowBase

    __palette_img: PNMImage
    __palette_size: Tuple[int, int]
    __palette_frame: DirectFrame

    __marker: DirectFrame
    __marker_center: DirectFrame

    enabled: bool

    def __init__(self, base: ShowBase, pick_colour_callback: Callable[
        [Tuple[float, float, float, float]], None], **kwargs) -> None:
        self.__base = base
        self.pick_colour_callback = pick_colour_callback
        self.enabled = True

        # PALETTE #
        palette_filename = os.path.join(GUI_DATA_PATH, "colour_palette.png")
        self.__palette_img = PNMImage(
            Filename.fromOsSpecific(palette_filename))
        self.__palette_size = (self.__palette_img.getReadXSize(),
                               self.__palette_img.getReadYSize())
        self.__palette_frame = DirectFrame(image=palette_filename, **kwargs)
        self.__palette_frame['state'] = DGG.NORMAL
        self.__palette_frame.bind(DGG.B1PRESS, command=self.__pick)

        # MARKER #
        self.__marker = DirectFrame(parent=self.__palette_frame,
                                    frameColor=(0.0, 0.0, 0.0, 1.0),
                                    frameSize=(-0.08, .08, -.08, .08),
                                    pos=(0.0, 0.0, 0.0))

        self.__marker_center = DirectFrame(parent=self.__marker,
                                           frameSize=(-0.03, 0.03, -0.03,
                                                      0.03))
        self.__marker.hide()

    def __colour_at(
            self, x: float,
            y: float) -> Union[Tuple[float, float, float, float], None]:
        w, h = self.__palette_size
        screen = self.__base.pixel2d

        img_scale = self.__palette_frame['image_scale']
        sx = self.__palette_frame.getSx(screen) * img_scale[0]
        sy = self.__palette_frame.getSz(screen) * img_scale[2]

        x -= self.__palette_frame.getX(screen)
        y -= self.__palette_frame.getZ(screen)
        x = (0.5 + x / (2.0 * sx)) * w
        y = (0.5 - y / (2.0 * sy)) * h

        if 0 <= x < w and 0 <= y < h:
            return (*self.__palette_img.getXel(int(x), int(y)), 1.0)
        else:
            return None

    def __update_marker_colour(self) -> Tuple[float, float, float, float]:
        c = self.colour_under_marker()
        if c is None:
            c = self.__marker_center['frameColor']
        else:
            self.__marker_center['frameColor'] = c
        return c

    def __update_marker_pos(self) -> None:
        if not self.__base.mouseWatcherNode.hasMouse():
            return None

        pointer = self.__base.win.get_pointer(0)
        x, y = pointer.getX(), -pointer.getY()

        w, h = self.__palette_size
        screen = self.__base.pixel2d

        img_scale = self.__palette_frame['image_scale']
        sx = self.__palette_frame.getSx(screen) * img_scale[0]
        sy = self.__palette_frame.getSz(screen) * img_scale[2]

        x -= self.__palette_frame.getX(screen)
        y -= self.__palette_frame.getZ(screen)
        x /= sx
        y /= sy

        x = max(-0.92, min(0.92, x))
        y = max(-0.92, min(0.92, y))

        self.__marker.set_pos(x, 0.0, y)
        self.__marker.show()

    def colour_under_marker(
            self) -> Union[Tuple[float, float, float, float], None]:
        x, _, y = self.__marker.get_pos()

        w, h = self.__palette_size
        screen = self.__base.pixel2d

        img_scale = self.__palette_frame['image_scale']
        sx = self.__palette_frame.getSx(screen) * img_scale[0]
        sy = self.__palette_frame.getSz(screen) * img_scale[2]

        x *= sx
        y *= sy
        x += self.__palette_frame.getX(screen)
        y += self.__palette_frame.getZ(screen)

        return self.__colour_at(x, y)

    def colour_under_mouse(
            self) -> Union[Tuple[float, float, float, float], None]:
        if not self.__base.mouseWatcherNode.hasMouse():
            return None

        pointer = self.__base.win.get_pointer(0)
        return self.__colour_at(pointer.getX(), -pointer.getY())

    def __pick(self, *args):
        if self.enabled:
            self.__update_marker_pos()
            self.pick_colour_callback(self.__update_marker_colour())

    @property
    def frame(self) -> DirectFrame:
        return self.__palette_frame

    @property
    def marker(self) -> DirectFrame:
        return self.__marker
Ejemplo n.º 2
0
class RailsScheme:
    """Rails scheme GUI.

    Represents the railways map, which can be used by
    players to choose the right way across the game world.

    Args:
        world_map (list): All the world blocks.
    """
    def __init__(self, world_map):
        self.is_shown = False
        self._temp_wids = []

        self._open_snd = loader.loadSfx("sounds/GUI/paper1.ogg")  # noqa: F821
        self._close_snd = loader.loadSfx("sounds/GUI/paper2.ogg")  # noqa: F821
        self._world_map = world_map

        self._list = DirectFrame(
            frameSize=(-1.2, 1.2, -0.6, 0.6),
            frameTexture="gui/tex/paper2.png",
            state=DGG.NORMAL,
        )
        self._list.setDepthTest(False)
        self._list.setTransparency(TransparencyAttrib.MAlpha)
        self._list.hide()

        DirectLabel(  # Silewer Railways Scheme
            parent=self._list,
            text=base.labels.SCHEME[0],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            frameSize=(0.2, 0.2, 0.2, 0.2),
            text_scale=0.035,
            pos=(0, 0, 0.5),
        )
        self._scheme = DirectFrame(
            parent=self._list,
            frameSize=(-1.1, 1.1, -0.3, 0.3),
            frameTexture="gui/tex/world_scheme.png",
        )
        self._scheme.setTransparency(TransparencyAttrib.MAlpha)

        self._arrow = DirectFrame(
            parent=self._scheme,
            frameSize=(-0.02, 0.02, -0.02, 0.02),
            frameTexture="gui/tex/train_dir.png",
            pos=(-0.96, 0, 0.07),
        )
        self._build_legend()

    def _build_legend(self):
        """Build the scheme legend GUI."""
        lab_opts = {
            "parent": self._list,
            "text_scale": 0.033,
            "frameColor": (0, 0, 0, 0),
            "frameSize": (-0.1, 0.1, -0.1, 0.1),
        }
        DirectLabel(  # Legend
            text=base.labels.SCHEME[1],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            text_align=TextNode.ALeft,
            pos=(-1, 0, -0.35),
            **lab_opts,
        )
        DirectFrame(
            parent=self._scheme,
            frameTexture="gui/tex/city.png",
            frameSize=(-0.04, 0.04, -0.04, 0.04),
            pos=(-0.39, 0, -0.41),
        )
        DirectLabel(  # city
            text=base.labels.SCHEME[2],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            pos=(-0.3, 0, -0.42),
            **lab_opts,
        )
        DirectFrame(
            parent=self._scheme,
            frameTexture="gui/tex/dash.png",
            frameSize=(-0.004, 0.004, -0.06, 0.06),
            frameColor=(0, 0, 0, 0.2),
            pos=(0.09, 0, -0.37),
        ).setR(90)

        DirectLabel(
            text=base.labels.SCHEME[3],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            pos=(0.29, 0, -0.38),
            **lab_opts,
        )
        DirectFrame(
            parent=self._scheme,
            frameColor=(0.71, 0.25, 0.05, 0.2),
            frameSize=(-0.06, 0.06, -0.02, 0.02),
            pos=(0.09, 0, -0.45),
        )
        DirectLabel(
            text=base.labels.SCHEME[4],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            pos=(0.26, 0, -0.46),
            **lab_opts,
        )

    def _fill_branches(self):
        """Paint railway branches on the railways scheme."""
        for branch in base.world.branches:  # noqa: F821
            start = -0.96 + self._world_map[branch["start"]].id * 0.0032
            self._temp_wids.append(
                DirectFrame(
                    parent=self._scheme,
                    frameTexture="gui/tex/dash.png",
                    frameSize=(-0.004, 0.004, -0.1, 0.1),
                    frameColor=(0, 0, 0, 0.2),
                    pos=(start, 0, 0.1 if branch["side"] == "l" else -0.1),
                ))
            end = -0.96 + self._world_map[branch["end"]].id * 0.0032
            self._temp_wids.append(
                DirectFrame(
                    parent=self._scheme,
                    frameTexture="gui/tex/dash.png",
                    frameSize=(-0.004, 0.004, -0.1, 0.1),
                    frameColor=(0, 0, 0, 0.2),
                    pos=(end, 0, 0.1 if branch["side"] == "l" else -0.1),
                ))

            x_coor = (start + end) / 2

            horiz = DirectFrame(
                parent=self._scheme,
                frameTexture="gui/tex/dash.png",
                frameSize=(-0.004, 0.004, -(x_coor - start), end - x_coor),
                frameColor=(0, 0, 0, 0.2),
                pos=(x_coor, 0, 0.2 if branch["side"] == "l" else -0.2),
            )
            horiz.setR(90)
            self._temp_wids.append(horiz)

            outs = ""
            for block in branch["blocks"][1:-1]:
                if block.outing_available:
                    outs += block.outing_available[0]

                if block.is_station:
                    outs += "i"

            if outs:
                outs = outs.lower()
                self._temp_wids.append(
                    DirectLabel(
                        parent=self._scheme,
                        text=outs,
                        text_scale=0.035,
                        text_bg=(0, 0, 0, 0),
                        text_fg=(0, 0, 0, 0.5),
                        frameColor=(0, 0, 0, 0),
                        pos=(x_coor, 0,
                             0.25 if branch["side"] == "l" else -0.27),
                    ))

    def _fill_scheme(self):
        """Fill the railways scheme with the world data.

        Shows cities, outings and railway branches on the scheme.
        """
        self._fill_branches()

        outs = None
        cities = 0
        for block in self._world_map[:601]:
            if block.id % 100 == 0:
                if outs:
                    self._temp_wids.append(
                        DirectLabel(
                            parent=self._scheme,
                            text=outs,
                            text_scale=0.035,
                            text_bg=(0, 0, 0, 0),
                            frameColor=(0, 0, 0, 0),
                            pos=(-0.96 + (block.id - 50) * 0.0032, 0, -0.1),
                        ))
                outs = ""

            if block.outing_available:
                outs += block.outing_available[0].lower()

            if block.is_station:
                outs += "i"

            if block.is_city:
                self._temp_wids.append(
                    DirectFrame(
                        parent=self._scheme,
                        frameTexture="gui/tex/city.png",
                        frameSize=(-0.04, 0.04, -0.04, 0.04),
                        pos=(-0.96 + block.id * 0.0032, 0, 0),
                    ))
                self._temp_wids.append(
                    DirectLabel(
                        parent=self._scheme,
                        text=base.labels.CITY_NAMES[cities],  # noqa: F821
                        text_font=base.main_font,  # noqa: F821
                        text_scale=0.032,
                        text_bg=(0, 0, 0, 0),
                        frameColor=(0, 0, 0, 0),
                        pos=(-0.96 + block.id * 0.0032, 0, 0.1),
                    ))
                cities += 1

        self._temp_wids.append(
            DirectFrame(
                parent=self._scheme,
                frameColor=(0.71, 0.25, 0.05, 0.2),
                frameSize=(
                    0,
                    base.world.stench_step * 0.0032,  # noqa: F821
                    -0.22,
                    0.22,
                ),
                pos=(-0.96, 0, 0),
            ))

    def _update_arrow(self, task):
        """Update the Train position on the scheme."""
        blocks = base.world.current_blocks  # noqa: F821
        if blocks and blocks[0] != -1:

            z_shift = 0
            if not base.world.is_near_fork:  # noqa: F821
                if base.world.current_block.branch == "l":  # noqa: F821
                    z_shift = 0.155
                elif base.world.current_block.branch == "r":  # noqa: F821
                    z_shift = -0.295

            if blocks[0] < 600:
                x = -0.96 + blocks[0] * 0.0032
            else:
                x = self._arrow.getX()

            self._arrow.setPos(x, 0, 0.07 + z_shift)

            if blocks[0] < blocks[1]:
                self._arrow["frameTexture"] = "gui/tex/train_dir.png"
            else:
                self._arrow["frameTexture"] = "gui/tex/train_dir_op.png"

        task.delayTime = 5
        return task.again

    def show(self):
        """Show/hide railways scheme GUI."""
        if (self.is_shown or base.world.outings_mgr.gui_is_shown  # noqa: F821
                or base.traits_gui.is_shown  # noqa: F821
            ):
            self._close_snd.play()
            self._list.hide()
            taskMgr.remove("update_scheme_arrow")  # noqa: F821

            clear_wids(self._temp_wids)
        else:
            if base.world.is_on_et:  # noqa: F821
                return

            self._open_snd.play()
            taskMgr.doMethodLater(  # noqa: F821
                0.2, self._update_arrow, "update_scheme_arrow")
            self._fill_scheme()
            self._list.show()
            base.char_gui.clear_char_info(True)  # noqa: F821

        self.is_shown = not self.is_shown