Esempio n. 1
0
    def load_level(self, world: int, level: int, object_data_offset: int,
                   enemy_data_offset: int, object_set_number: int):
        self._internal_level = Level(world, level, object_data_offset,
                                     enemy_data_offset, object_set_number)

        self._internal_level.data_changed.connect(self.data_changed.emit)
        self._internal_level.jumps_changed.connect(self.jumps_changed.emit)

        # actively emit, because we weren't connected yet, when the level sent it out
        self.data_changed.emit()
Esempio n. 2
0
    def _draw_objects(self, painter: QPainter, level: Level):
        for level_object in level.get_all_objects():
            level_object.render()

            if level_object.description.lower() in SPECIAL_BACKGROUND_OBJECTS:
                width = LEVEL_MAX_LENGTH
                height = GROUND - level_object.y_position

                blocks_to_draw = [level_object.blocks[0]] * width * height

                for index, block_index in enumerate(blocks_to_draw):
                    x = level_object.x_position + index % width
                    y = level_object.y_position + index // width

                    level_object._draw_block(painter, block_index, x, y, self.block_length, False)
            else:
                level_object.draw(painter, self.block_length, self.transparency)

            if level_object.selected:
                painter.save()

                painter.setPen(QPen(QColor(0x00, 0x00, 0x00, 0x80), width=1))
                painter.drawRect(level_object.get_rect(self.block_length))

                painter.restore()
Esempio n. 3
0
    def _draw_background(self, painter: QPainter, level: Level):
        painter.save()

        bg_color = bg_color_for_object_set(level.object_set_number, level.header.object_palette_index)

        painter.fillRect(level.get_rect(self.block_length), bg_color)

        painter.restore()
Esempio n. 4
0
    def _draw_objects(self, painter: QPainter, level: Level):
        for level_object in level.get_all_objects():
            level_object.render()
            level_object.draw(painter, self.block_length, self.transparency)

            if level_object.selected:
                painter.save()

                painter.setPen(QPen(QColor(0x00, 0x00, 0x00, 0x80), width=1))
                painter.drawRect(level_object.get_rect(self.block_length))

                painter.restore()
Esempio n. 5
0
    def _draw_background(self, painter: QPainter, level: Level):
        painter.save()

        if level.object_set_number == CLOUDY_OBJECT_SET:
            bg_color = QColor(
                *NESPalette[load_palette_group(level.object_set_number, level.header.object_palette_index)[3][2]]
            )
        else:
            bg_color = bg_color_for_object_set(level.object_set_number, level.header.object_palette_index)

        painter.fillRect(level.get_rect(self.block_length), bg_color)

        painter.restore()
Esempio n. 6
0
    def _draw_grid(self, painter: QPainter, level: Level):
        panel_width, panel_height = level.get_rect(self.block_length).size().toTuple()

        painter.setPen(self.grid_pen)

        for x in range(0, panel_width, self.block_length):
            painter.drawLine(x, 0, x, panel_height)
        for y in range(0, panel_height, self.block_length):
            painter.drawLine(0, y, panel_width, y)

        painter.setPen(self.screen_pen)

        if level.is_vertical:
            for y in range(0, panel_height, self.block_length * SCREEN_HEIGHT):
                painter.drawLine(0, y, panel_width, y)
        else:
            for x in range(0, panel_width, self.block_length * SCREEN_WIDTH):
                painter.drawLine(x, 0, x, panel_height)
Esempio n. 7
0
    def _draw_expansions(self, painter: QPainter, level: Level):
        for level_object in level.get_all_objects():
            if level_object.selected:
                painter.drawRect(level_object.get_rect(self.block_length))

            if self.draw_expansions:
                painter.save()

                painter.setPen(Qt.NoPen)

                if level_object.expands() == EXPANDS_BOTH:
                    painter.setBrush(QColor(0xFF, 0, 0xFF, 0x80))
                elif level_object.expands() == EXPANDS_HORIZ:
                    painter.setBrush(QColor(0xFF, 0, 0, 0x80))
                elif level_object.expands() == EXPANDS_VERT:
                    painter.setBrush(QColor(0, 0, 0xFF, 0x80))

                painter.drawRect(level_object.get_rect(self.block_length))

                painter.restore()
Esempio n. 8
0
    def _draw_overlays(self, painter: QPainter, level: Level):
        painter.save()

        for level_object in level.get_all_objects():
            name = level_object.description.lower()

            # only handle this specific enemy item for now
            if isinstance(level_object, EnemyObject) and "invisible door" not in name:
                continue

            pos = level_object.get_rect(self.block_length).topLeft()
            rect = level_object.get_rect(self.block_length)

            # invisible coins, for example, expand and need to have multiple overlays drawn onto them
            # set true by default, since for most overlays it doesn't matter
            fill_object = True

            # pipe entries
            if "pipe" in name and "can go" in name:
                if not self.draw_jumps_on_objects:
                    continue

                fill_object = False

                # center() is one pixel off for some reason
                pos = rect.topLeft() + QPoint(*(rect.size() / 2).toTuple())

                if "left" in name:
                    image = LEFT_ARROW

                    pos.setX(rect.right())
                    pos.setY(pos.y() - self.block_length / 2)

                elif "right" in name:
                    image = RIGHT_ARROW
                    pos.setX(rect.left() - self.block_length)
                    pos.setY(pos.y() - self.block_length / 2)

                elif "down" in name:
                    image = DOWN_ARROW

                    pos.setX(pos.x() - self.block_length / 2)
                    pos.setY(rect.top() - self.block_length)
                else:
                    image = UP_ARROW

                    pos.setX(pos.x() - self.block_length / 2)
                    pos.setY(rect.bottom())

                if not self._object_in_jump_area(level, level_object):
                    image = NO_JUMP

            elif "door" == name or "door (can go" in name or "invisible door" in name:
                fill_object = False

                image = DOWN_ARROW

                pos.setY(rect.top() - self.block_length)

                if not self._object_in_jump_area(level, level_object):
                    image = NO_JUMP

            # "?" - blocks, note blocks, wooden blocks and bricks
            elif "'?' with" in name or "brick with" in name or "bricks with" in name or "block with" in name:
                if not self.draw_items_in_blocks:
                    continue

                pos.setY(pos.y() - self.block_length)

                if "flower" in name:
                    image = FIRE_FLOWER
                elif "leaf" in name:
                    image = LEAF
                elif "continuous star" in name:
                    image = CONTINUOUS_STAR
                elif "star" in name:
                    image = NORMAL_STAR
                elif "multi-coin" in name:
                    image = MULTI_COIN
                elif "coin" in name:
                    image = COIN
                elif "1-up" in name:
                    image = ONE_UP
                elif "vine" in name:
                    image = VINE
                elif "p-switch" in name:
                    image = P_SWITCH
                else:
                    image = EMPTY_IMAGE

                # draw little arrow for the offset item overlay
                arrow_pos = QPoint(pos)
                arrow_pos.setY(arrow_pos.y() + self.block_length / 4)
                painter.drawImage(arrow_pos, ITEM_ARROW.scaled(self.block_length, self.block_length))

            elif "invisible" in name:
                if not self.draw_invisible_items:
                    continue

                if "coin" in name:
                    image = INVISIBLE_COIN
                elif "1-up" in name:
                    image = INVISIBLE_1_UP
                else:
                    image = EMPTY_IMAGE

            elif "silver coins" in name:
                if not self.draw_invisible_items:
                    continue

                image = SILVER_COIN
            else:
                continue

            if fill_object:
                for x in range(level_object.rendered_width):
                    adapted_pos = QPoint(pos)
                    adapted_pos.setX(pos.x() + x * self.block_length)

                    image = image.scaled(self.block_length, self.block_length)
                    painter.drawImage(adapted_pos, image)

                    if level_object.selected:
                        painter.drawImage(adapted_pos, _make_image_selected(image))

            else:
                image = image.scaled(self.block_length, self.block_length)
                painter.drawImage(pos, image)

        painter.restore()
Esempio n. 9
0
def level(rom, qtbot):
    return Level(1, 1, level_1_1_object_address, level_1_1_enemy_address, PLAINS_OBJECT_SET)
Esempio n. 10
0
class LevelRef(QObject):
    data_changed: SignalInstance = Signal()
    jumps_changed: SignalInstance = Signal()

    def __init__(self):
        super(LevelRef, self).__init__()
        self._internal_level: Optional[Level] = None

    def load_level(self, world: int, level: int, object_data_offset: int,
                   enemy_data_offset: int, object_set_number: int):
        self._internal_level = Level(world, level, object_data_offset,
                                     enemy_data_offset, object_set_number)

        self._internal_level.data_changed.connect(self.data_changed.emit)
        self._internal_level.jumps_changed.connect(self.jumps_changed.emit)

        # actively emit, because we weren't connected yet, when the level sent it out
        self.data_changed.emit()

    @property
    def level(self):
        return self._internal_level

    @property
    def selected_objects(self):
        return [
            obj for obj in self._internal_level.get_all_objects()
            if obj.selected
        ]

    @selected_objects.setter
    def selected_objects(self, selected_objects):
        if selected_objects == self.selected_objects:
            return

        for obj in self._internal_level.get_all_objects():
            obj.selected = obj in selected_objects

        self.data_changed.emit()

    def __getattr__(self, item: str):
        if self._internal_level is None:
            return None
        else:
            return getattr(self._internal_level, item)

    def undo(self):
        if not self.undo_stack.undo_available:
            return

        self._internal_level.from_bytes(*self.undo_stack.undo(),
                                        new_level=False)

        self.data_changed.emit()

    def redo(self):
        if not self.undo_stack.redo_available:
            return

        self.level.from_bytes(*self.undo_stack.redo(), new_level=False)

        self.data_changed.emit()

    def save_level_state(self):
        self.undo_stack.save_level_state(self._internal_level.to_bytes())

        self.data_changed.emit()

    def __bool__(self):
        return self._internal_level is not None
Esempio n. 11
0
class LevelRef(QObject):
    data_changed: SignalInstance = Signal()
    jumps_changed: SignalInstance = Signal()

    def __init__(self):
        super(LevelRef, self).__init__()
        self._internal_level: Optional[Level] = Level()

    def load_level(self, level_name: str, object_data_offset: int, enemy_data_offset: int, object_set_number: int):
        self.level = Level(level_name, object_data_offset, enemy_data_offset, object_set_number)

        # actively emit, because we weren't connected yet, when the level sent it out
        self.data_changed.emit()

    @property
    def level(self):
        return self._internal_level

    @level.setter
    def level(self, level):
        self._internal_level = level

        self._internal_level.data_changed.connect(self.data_changed.emit)
        self._internal_level.jumps_changed.connect(self.jumps_changed.emit)

    @property
    def selected_objects(self):
        return [obj for obj in self._internal_level.get_all_objects() if obj.selected]

    @selected_objects.setter
    def selected_objects(self, selected_objects):
        if selected_objects == self.selected_objects:
            return

        for obj in self._internal_level.get_all_objects():
            obj.selected = obj in selected_objects

        self.data_changed.emit()

    def __getattr__(self, item: str):
        if self._internal_level is None:
            return None
        else:
            return getattr(self._internal_level, item)

    def undo(self):
        if not self.undo_stack.undo_available:
            return

        self.set_level_state(*self.undo_stack.undo())

    def redo(self):
        if not self.undo_stack.redo_available:
            return

        self.set_level_state(*self.undo_stack.redo())

    def set_level_state(self, object_data, enemy_data):
        self.level.from_bytes(object_data, enemy_data, new_level=False)
        self.level.changed = True

        self.data_changed.emit()

    def import_undo_stack_data(self, undo_index, byte_data):
        self.level.undo_stack.import_data(undo_index, byte_data)

        if byte_data:
            self.set_level_state(*byte_data[undo_index])

    def save_level_state(self):
        self.undo_stack.save_level_state(self._internal_level.to_bytes())
        self.level.changed = True

        self.data_changed.emit()

    def __bool__(self):
        return self._internal_level.fully_loaded
Esempio n. 12
0
    def load_level(self, level_name: str, object_data_offset: int, enemy_data_offset: int, object_set_number: int):
        self.level = Level(level_name, object_data_offset, enemy_data_offset, object_set_number)

        # actively emit, because we weren't connected yet, when the level sent it out
        self.data_changed.emit()
Esempio n. 13
0
 def __init__(self):
     super(LevelRef, self).__init__()
     self._internal_level: Optional[Level] = Level()