def __init__(self, parent: Optional[QWidget], jump: Jump): super(JumpEditor, self).__init__(parent, "Jump Editor") self.jump = jump self.screen_spinner = Spinner(parent=self, maximum=MAX_SCREEN_INDEX, base=10) position_layout = QFormLayout() position_layout.addRow("Jump on screen:", self.screen_spinner) level_group_box = QGroupBox("Level position") level_group_box.setLayout(position_layout) self.exit_action = QComboBox(self) self.exit_action.addItems(JUMP_ACTIONS) self.exit_horizontal = Spinner(parent=self, maximum=MAX_HORIZ_POSITION, base=10) self.exit_vertical = QComboBox(self) self.exit_vertical.addItems(VERT_POSITIONS) exit_layout = QFormLayout() exit_layout.addRow("Exit action:", self.exit_action) exit_layout.addRow("Exit position x:", self.exit_horizontal) exit_layout.addRow("Exit position y:", self.exit_vertical) exit_group_box = QGroupBox("Exit options") exit_group_box.setLayout(exit_layout) button_box = QDialogButtonBox() self.ok_button = button_box.addButton(QDialogButtonBox.Ok) self.ok_button.pressed.connect(self.on_ok) button_box.addButton(QDialogButtonBox.Cancel).pressed.connect( self.close) main_layout = QVBoxLayout() main_layout.addWidget(level_group_box) main_layout.addWidget(exit_group_box) main_layout.addWidget(button_box) self.setLayout(main_layout) self._set_widget_values()
def __init__(self, parent): super(BlockViewer, self).__init__(parent, "Block Viewer") self._object_set = 0 self.sprite_bank = BlockBank(parent=self) self.setCentralWidget(self.sprite_bank) self.toolbar = QToolBar(self) self.prev_os_action = self.toolbar.addAction(icon("arrow-left.svg"), "Previous object set") self.prev_os_action.triggered.connect(self.prev_object_set) self.next_os_action = self.toolbar.addAction(icon("arrow-right.svg"), "Next object set") self.next_os_action.triggered.connect(self.next_object_set) self.zoom_out_action = self.toolbar.addAction(icon("zoom-out.svg"), "Zoom Out") self.zoom_out_action.triggered.connect(self.sprite_bank.zoom_out) self.zoom_in_action = self.toolbar.addAction(icon("zoom-in.svg"), "Zoom In") self.zoom_in_action.triggered.connect(self.sprite_bank.zoom_in) self.bank_dropdown = QComboBox(parent=self.toolbar) self.bank_dropdown.addItems(OBJECT_SET_ITEMS) self.bank_dropdown.setCurrentIndex(0) self.bank_dropdown.currentIndexChanged.connect(self.on_combo) self.palette_group_spinner = Spinner(self, maximum=PALETTE_GROUPS_PER_OBJECT_SET - 1, base=10) self.palette_group_spinner.valueChanged.connect(self.on_palette) self.toolbar.addWidget(self.bank_dropdown) self.toolbar.addWidget(QLabel(" Object Palette: ")) self.toolbar.addWidget(self.palette_group_spinner) self.addToolBar(self.toolbar) self.layout().setSizeConstraint(QLayout.SetFixedSize) self.setStatusBar(QStatusBar(self)) return
def __init__(self, parent: Optional[QWidget], level_ref: LevelRef): super(SpinnerPanel, self).__init__(parent) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.level_ref = level_ref self.level_ref.data_changed.connect(self.update) self.spin_domain = Spinner(self, maximum=MAX_DOMAIN) self.spin_domain.setEnabled(False) self.spin_domain.valueChanged.connect(self.object_change.emit) self.spin_type = Spinner(self, maximum=MAX_TYPE) self.spin_type.setEnabled(False) self.spin_type.valueChanged.connect(self.object_change.emit) self.spin_length = Spinner(self, maximum=MAX_LENGTH) self.spin_length.setEnabled(False) self.spin_length.valueChanged.connect(self.object_change.emit) spinner_layout = QFormLayout() spinner_layout.addRow("Bank/Domain:", self.spin_domain) spinner_layout.addRow("Type:", self.spin_type) spinner_layout.addRow("Length:", self.spin_length) self.setLayout(spinner_layout)
def __init__(self, parent, level_ref: LevelRef): super(AutoScrollEditor, self).__init__(parent, title="Autoscroll Editor") self.level_ref = level_ref self.original_autoscroll_item = _get_autoscroll(self.level_ref.enemies) QVBoxLayout(self) self.enabled_checkbox = QCheckBox("Enable Autoscroll in level", self) self.enabled_checkbox.toggled.connect(self._insert_autoscroll_object) self.y_position_spinner = Spinner(self, maximum=0x60 - 1) self.y_position_spinner.valueChanged.connect(self._update_y_position) self.auto_scroll_type_label = QLabel(self) self.layout().addWidget(self.enabled_checkbox) self.layout().addWidget(self.y_position_spinner) self.layout().addWidget(self.auto_scroll_type_label) self.update()
def __init__(self, parent): super(ObjectViewer, self).__init__(parent, title="Object Viewer") self.spin_domain = Spinner(self, MAX_DOMAIN) self.spin_domain.valueChanged.connect(self.on_spin) self.spin_type = Spinner(self, MAX_TYPE) self.spin_type.valueChanged.connect(self.on_spin) self.spin_length = Spinner(self, MAX_LENGTH) self.spin_length.setDisabled(True) self.spin_length.valueChanged.connect(self.on_spin) _toolbar = QToolBar(self) _toolbar.addWidget(self.spin_domain) _toolbar.addWidget(self.spin_type) _toolbar.addWidget(self.spin_length) self.object_set_dropdown = QComboBox(_toolbar) self.object_set_dropdown.addItems(OBJECT_SET_ITEMS[1:]) self.object_set_dropdown.setCurrentIndex(0) self.graphic_set_dropdown = QComboBox(_toolbar) self.graphic_set_dropdown.addItems(GRAPHIC_SET_NAMES) self.graphic_set_dropdown.setCurrentIndex(1) self.object_set_dropdown.currentIndexChanged.connect( self.on_object_set) self.graphic_set_dropdown.currentIndexChanged.connect( self.on_graphic_set) _toolbar.addWidget(self.object_set_dropdown) _toolbar.addWidget(self.graphic_set_dropdown) self.addToolBar(_toolbar) self.drawing_area = ObjectDrawArea(self, 1) self.status_bar = QStatusBar(parent=self) self.status_bar.showMessage(self.drawing_area.current_object.name) self.setStatusBar(self.status_bar) self.drawing_area.update() self.block_list = BlockArray(self, self.drawing_area.current_object) central_widget = QWidget() central_widget.setLayout(QVBoxLayout()) central_widget.layout().addWidget(self.drawing_area) central_widget.layout().addWidget(self.block_list) self.setCentralWidget(central_widget) self.layout().setSizeConstraint(QLayout.SetFixedSize) return
def __init__(self, parent): super(ObjectViewer, self).__init__(parent, title="Object Viewer") self.spin_domain = Spinner(self, MAX_DOMAIN) self.spin_domain.valueChanged.connect(self.on_spin) self.spin_type = Spinner(self, MAX_TYPE) self.spin_type.valueChanged.connect(self.on_spin) self.spin_length = Spinner(self, MAX_LENGTH) self.spin_length.setDisabled(True) self.spin_length.valueChanged.connect(self.on_spin) _toolbar = QToolBar(self) _toolbar.addWidget(self.spin_domain) _toolbar.addWidget(self.spin_type) _toolbar.addWidget(self.spin_length) self.object_set_dropdown = QComboBox(_toolbar) self.object_set_dropdown.addItems(OBJECT_SET_ITEMS[1:]) self.object_set_dropdown.setCurrentIndex(0) self.graphic_set_dropdown = QComboBox(_toolbar) self.graphic_set_dropdown.addItems( [f"Graphics Set {gfx_set}" for gfx_set in range(32)]) self.graphic_set_dropdown.setCurrentIndex(1) self.object_set_dropdown.currentIndexChanged.connect( self.on_object_set) self.graphic_set_dropdown.currentIndexChanged.connect( self.on_graphic_set) _toolbar.addWidget(self.object_set_dropdown) _toolbar.addWidget(self.graphic_set_dropdown) self.addToolBar(_toolbar) self.object_set = 1 self.drawing_area = ObjectDrawArea(self, self.object_set) self.status_bar = QStatusBar(parent=self) self.status_bar.showMessage( self.drawing_area.current_object.description) self.setStatusBar(self.status_bar) self.setCentralWidget(self.drawing_area) self.drawing_area.update() self.layout().setSizeConstraint(QLayout.SetFixedSize) return
def __init__(self, parent: Optional[QWidget], level_ref: LevelRef): super(SpinnerPanel, self).__init__(parent) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.level_ref = level_ref self.level_ref.data_changed.connect(self.update) self.spin_domain = Spinner(self, maximum=MAX_DOMAIN) self.spin_domain.setEnabled(False) self.spin_domain.valueChanged.connect(self.object_change.emit) self.spin_type = Spinner(self, maximum=MAX_TYPE) self.spin_type.setEnabled(False) self.spin_type.valueChanged.connect(self.object_change.emit) self.spin_length = Spinner(self, maximum=MAX_LENGTH) self.spin_length.setEnabled(False) self.spin_length.valueChanged.connect(self.object_change.emit) spinner_layout = QFormLayout() spinner_layout.addRow("Bank/Domain:", self.spin_domain) spinner_layout.addRow("Index:", self.spin_type) spinner_layout.addRow("Length:", self.spin_length) self.setLayout(spinner_layout) self.setWhatsThis( "<b>Spinner Panel</b><br/>" "The Spinner Panel gives raw byte access to objects for advanced users. The values are shown " "in hexadecimal notation.<br/>" "Level objects and enemies/items are categorized using domains and indexes. Which domain an " "object is in, doesn't hold much information about the object, if at all.<br/>" "As for the index, the only important information is, that all objects from 0x00 - 0x0F can " "not be resized. " "They have fixed dimensions, like the background bushes in Level 1-1.<br/>" "All other objects have 16 different iterations, meaning 0x10 - 0x1F, for example, is one " "object, with 16 different sizes, going from smallest to largest. In what way these objects " "expand, depends on their particular expansion type.<br/>" "Some '4-byte' objects can expand in a second way, since they have an additional byte " "holding that information. For example a platform, which can be sized vertically using the " "index and horizontally using the 4th byte.")
def __init__(self, parent: Optional[QWindow], level_ref: LevelRef): super(HeaderEditor, self).__init__(parent, "Level Header Editor") self.level: Level = level_ref.level # enables undo self.header_change.connect(level_ref.save_level_state) main_layout = QVBoxLayout(self) tab_widget = QTabWidget(self) main_layout.addWidget(tab_widget) # level settings self.length_dropdown = QComboBox() self.length_dropdown.addItems(STR_LEVEL_LENGTHS) self.length_dropdown.activated.connect(self.on_combo) self.music_dropdown = QComboBox() self.music_dropdown.addItems(MUSIC_ITEMS) self.music_dropdown.activated.connect(self.on_combo) self.time_dropdown = QComboBox() self.time_dropdown.addItems(TIMES) self.time_dropdown.activated.connect(self.on_combo) self.v_scroll_direction_dropdown = QComboBox() self.v_scroll_direction_dropdown.addItems(SCROLL_DIRECTIONS) self.v_scroll_direction_dropdown.activated.connect(self.on_combo) self.level_is_vertical_cb = QCheckBox("Level is Vertical") self.level_is_vertical_cb.clicked.connect(self.on_check_box) self.pipe_ends_level_cb = QCheckBox("Pipe ends Level") self.pipe_ends_level_cb.clicked.connect(self.on_check_box) check_box_layout = QHBoxLayout() check_box_layout.setContentsMargins(0, 0, 0, 0) check_box_layout.addWidget(self.level_is_vertical_cb) check_box_layout.addWidget(self.pipe_ends_level_cb) check_box_widget = QWidget() check_box_widget.setLayout(check_box_layout) form = QFormLayout() form.setFormAlignment(Qt.AlignCenter) form.addRow("Level length: ", self.length_dropdown) form.addRow("Music: ", self.music_dropdown) form.addRow("Time: ", self.time_dropdown) form.addRow("Scroll direction: ", self.v_scroll_direction_dropdown) form.addWidget(check_box_widget) widget = QWidget() widget.setLayout(form) tab_widget.addTab(widget, "Level") # player settings self.x_position_dropdown = QComboBox() self.x_position_dropdown.addItems(STR_X_POSITIONS) self.x_position_dropdown.activated.connect(self.on_combo) self.y_position_dropdown = QComboBox() self.y_position_dropdown.addItems(STR_Y_POSITIONS) self.y_position_dropdown.activated.connect(self.on_combo) self.action_dropdown = QComboBox() self.action_dropdown.addItems(ACTIONS) self.action_dropdown.activated.connect(self.on_combo) form = QFormLayout() form.setFormAlignment(Qt.AlignCenter) form.addRow("Starting X: ", self.x_position_dropdown) form.addRow("Starting Y: ", self.y_position_dropdown) form.addRow("Action: ", self.action_dropdown) widget = QWidget() widget.setLayout(form) tab_widget.addTab(widget, "Mario") # graphic settings self.object_palette_spinner = Spinner(self, maximum=7) self.object_palette_spinner.valueChanged.connect(self.on_spin) self.enemy_palette_spinner = Spinner(self, maximum=3) self.enemy_palette_spinner.valueChanged.connect(self.on_spin) self.graphic_set_dropdown = QComboBox() self.graphic_set_dropdown.addItems(GRAPHIC_SETS) self.graphic_set_dropdown.activated.connect(self.on_combo) form = QFormLayout() form.setFormAlignment(Qt.AlignCenter) form.addRow("Object Palette: ", self.object_palette_spinner) form.addRow("Enemy Palette: ", self.enemy_palette_spinner) form.addRow("Graphic Set: ", self.graphic_set_dropdown) widget = QWidget() widget.setLayout(form) tab_widget.addTab(widget, "Graphics") # next area settings self.level_pointer_spinner = Spinner(self, maximum=SPINNER_MAX_VALUE) self.level_pointer_spinner.valueChanged.connect(self.on_spin) self.enemy_pointer_spinner = Spinner(self, maximum=SPINNER_MAX_VALUE) self.enemy_pointer_spinner.valueChanged.connect(self.on_spin) self.next_area_object_set_dropdown = QComboBox() self.next_area_object_set_dropdown.addItems(OBJECT_SET_ITEMS) self.next_area_object_set_dropdown.activated.connect(self.on_combo) level_select_button = QPushButton("Set from Level") level_select_button.pressed.connect(self._set_jump_destination) form = QFormLayout() form.setFormAlignment(Qt.AlignCenter) form.addRow("Address of Objects: ", self.level_pointer_spinner) form.addRow("Address of Enemies: ", self.enemy_pointer_spinner) form.addRow("Object Set: ", self.next_area_object_set_dropdown) form.addRow(QLabel("")) form.addRow(level_select_button) widget = QWidget() widget.setLayout(form) tab_widget.addTab(widget, "Jump Destination") self.header_bytes_label = QLabel() main_layout.addWidget(self.header_bytes_label, alignment=Qt.AlignCenter) self.update()
class HeaderEditor(CustomDialog): header_change: SignalInstance = Signal() def __init__(self, parent: Optional[QWindow], level_ref: LevelRef): super(HeaderEditor, self).__init__(parent, "Level Header Editor") self.level: Level = level_ref.level # enables undo self.header_change.connect(level_ref.save_level_state) main_layout = QVBoxLayout(self) tab_widget = QTabWidget(self) main_layout.addWidget(tab_widget) # level settings self.length_dropdown = QComboBox() self.length_dropdown.addItems(STR_LEVEL_LENGTHS) self.length_dropdown.activated.connect(self.on_combo) self.music_dropdown = QComboBox() self.music_dropdown.addItems(MUSIC_ITEMS) self.music_dropdown.activated.connect(self.on_combo) self.time_dropdown = QComboBox() self.time_dropdown.addItems(TIMES) self.time_dropdown.activated.connect(self.on_combo) self.v_scroll_direction_dropdown = QComboBox() self.v_scroll_direction_dropdown.addItems(SCROLL_DIRECTIONS) self.v_scroll_direction_dropdown.activated.connect(self.on_combo) self.level_is_vertical_cb = QCheckBox("Level is Vertical") self.level_is_vertical_cb.clicked.connect(self.on_check_box) self.pipe_ends_level_cb = QCheckBox("Pipe ends Level") self.pipe_ends_level_cb.clicked.connect(self.on_check_box) check_box_layout = QHBoxLayout() check_box_layout.setContentsMargins(0, 0, 0, 0) check_box_layout.addWidget(self.level_is_vertical_cb) check_box_layout.addWidget(self.pipe_ends_level_cb) check_box_widget = QWidget() check_box_widget.setLayout(check_box_layout) form = QFormLayout() form.setFormAlignment(Qt.AlignCenter) form.addRow("Level length: ", self.length_dropdown) form.addRow("Music: ", self.music_dropdown) form.addRow("Time: ", self.time_dropdown) form.addRow("Scroll direction: ", self.v_scroll_direction_dropdown) form.addWidget(check_box_widget) widget = QWidget() widget.setLayout(form) tab_widget.addTab(widget, "Level") # player settings self.x_position_dropdown = QComboBox() self.x_position_dropdown.addItems(STR_X_POSITIONS) self.x_position_dropdown.activated.connect(self.on_combo) self.y_position_dropdown = QComboBox() self.y_position_dropdown.addItems(STR_Y_POSITIONS) self.y_position_dropdown.activated.connect(self.on_combo) self.action_dropdown = QComboBox() self.action_dropdown.addItems(ACTIONS) self.action_dropdown.activated.connect(self.on_combo) form = QFormLayout() form.setFormAlignment(Qt.AlignCenter) form.addRow("Starting X: ", self.x_position_dropdown) form.addRow("Starting Y: ", self.y_position_dropdown) form.addRow("Action: ", self.action_dropdown) widget = QWidget() widget.setLayout(form) tab_widget.addTab(widget, "Mario") # graphic settings self.object_palette_spinner = Spinner(self, maximum=7) self.object_palette_spinner.valueChanged.connect(self.on_spin) self.enemy_palette_spinner = Spinner(self, maximum=3) self.enemy_palette_spinner.valueChanged.connect(self.on_spin) self.graphic_set_dropdown = QComboBox() self.graphic_set_dropdown.addItems(GRAPHIC_SETS) self.graphic_set_dropdown.activated.connect(self.on_combo) form = QFormLayout() form.setFormAlignment(Qt.AlignCenter) form.addRow("Object Palette: ", self.object_palette_spinner) form.addRow("Enemy Palette: ", self.enemy_palette_spinner) form.addRow("Graphic Set: ", self.graphic_set_dropdown) widget = QWidget() widget.setLayout(form) tab_widget.addTab(widget, "Graphics") # next area settings self.level_pointer_spinner = Spinner(self, maximum=SPINNER_MAX_VALUE) self.level_pointer_spinner.valueChanged.connect(self.on_spin) self.enemy_pointer_spinner = Spinner(self, maximum=SPINNER_MAX_VALUE) self.enemy_pointer_spinner.valueChanged.connect(self.on_spin) self.next_area_object_set_dropdown = QComboBox() self.next_area_object_set_dropdown.addItems(OBJECT_SET_ITEMS) self.next_area_object_set_dropdown.activated.connect(self.on_combo) level_select_button = QPushButton("Set from Level") level_select_button.pressed.connect(self._set_jump_destination) form = QFormLayout() form.setFormAlignment(Qt.AlignCenter) form.addRow("Address of Objects: ", self.level_pointer_spinner) form.addRow("Address of Enemies: ", self.enemy_pointer_spinner) form.addRow("Object Set: ", self.next_area_object_set_dropdown) form.addRow(QLabel("")) form.addRow(level_select_button) widget = QWidget() widget.setLayout(form) tab_widget.addTab(widget, "Jump Destination") self.header_bytes_label = QLabel() main_layout.addWidget(self.header_bytes_label, alignment=Qt.AlignCenter) self.update() def update(self): length_index = LEVEL_LENGTHS.index(self.level.length) self.length_dropdown.setCurrentIndex(length_index) self.music_dropdown.setCurrentIndex(self.level.music_index) self.time_dropdown.setCurrentIndex(self.level.time_index) self.v_scroll_direction_dropdown.setCurrentIndex( self.level.scroll_type) self.level_is_vertical_cb.setChecked(self.level.is_vertical) self.pipe_ends_level_cb.setChecked(self.level.pipe_ends_level) self.x_position_dropdown.setCurrentIndex(self.level.start_x_index) self.y_position_dropdown.setCurrentIndex(self.level.start_y_index) self.action_dropdown.setCurrentIndex(self.level.start_action) self.object_palette_spinner.setValue(self.level.object_palette_index) self.enemy_palette_spinner.setValue(self.level.enemy_palette_index) self.graphic_set_dropdown.setCurrentIndex(self.level.graphic_set) self.level_pointer_spinner.setValue(self.level.next_area_objects) self.enemy_pointer_spinner.setValue(self.level.next_area_enemies) self.next_area_object_set_dropdown.setCurrentIndex( self.level.next_area_object_set) self.header_bytes_label.setText(" ".join( f"{number:0=#4X}"[2:] for number in self.level.header_bytes)) def _set_jump_destination(self): level_selector = LevelSelector(self) level_was_selected = level_selector.exec_() == QDialog.Accepted if not level_was_selected: return self.next_area_object_set_dropdown.setCurrentIndex( level_selector.object_set) self.level.next_area_object_set = level_selector.object_set self.level_pointer_spinner.setValue(level_selector.object_data_offset) self.level.next_area_objects = level_selector.object_data_offset self.enemy_pointer_spinner.setValue(level_selector.enemy_data_offset) self.level.next_area_enemies = level_selector.enemy_data_offset - 1 self.header_change.emit() def on_spin(self, _): if self.level is None: return spinner = self.sender() self.level.data_changed.connect(self.header_change.emit) if spinner == self.object_palette_spinner: new_index = self.object_palette_spinner.value() self.level.object_palette_index = new_index elif spinner == self.enemy_palette_spinner: new_index = self.enemy_palette_spinner.value() self.level.enemy_palette_index = new_index elif spinner == self.level_pointer_spinner: new_offset = self.level_pointer_spinner.value() self.level.next_area_objects = new_offset elif spinner == self.enemy_pointer_spinner: new_offset = self.enemy_pointer_spinner.value() self.level.next_area_enemies = new_offset self.level.data_changed.disconnect(self.header_change.emit) self.update() def on_combo(self, _): dropdown = self.sender() self.level.data_changed.connect(self.header_change.emit) if dropdown == self.length_dropdown: new_length = LEVEL_LENGTHS[self.length_dropdown.currentIndex()] self.level.length = new_length elif dropdown == self.music_dropdown: new_music = self.music_dropdown.currentIndex() self.level.music_index = new_music elif dropdown == self.time_dropdown: new_time = self.time_dropdown.currentIndex() self.level.time_index = new_time elif dropdown == self.v_scroll_direction_dropdown: new_scroll = self.v_scroll_direction_dropdown.currentIndex() self.level.scroll_type = new_scroll elif dropdown == self.x_position_dropdown: new_x = self.x_position_dropdown.currentIndex() self.level.start_x_index = new_x elif dropdown == self.y_position_dropdown: new_y = self.y_position_dropdown.currentIndex() self.level.start_y_index = new_y elif dropdown == self.action_dropdown: new_action = self.action_dropdown.currentIndex() self.level.start_action = new_action elif dropdown == self.graphic_set_dropdown: new_gfx_set = self.graphic_set_dropdown.currentIndex() self.level.graphic_set = new_gfx_set elif dropdown == self.next_area_object_set_dropdown: new_object_set = self.next_area_object_set_dropdown.currentIndex() self.level.next_area_object_set = new_object_set self.level.data_changed.disconnect(self.header_change.emit) self.update() def on_check_box(self, _): checkbox = self.sender() self.level.data_changed.connect(self.header_change.emit) if checkbox == self.pipe_ends_level_cb: self.level.pipe_ends_level = self.pipe_ends_level_cb.isChecked() elif checkbox == self.level_is_vertical_cb: self.level.is_vertical = self.level_is_vertical_cb.isChecked() self.level.data_changed.disconnect(self.header_change.emit) self.update()
class LevelSelector(QDialog): def __init__(self, parent): super(LevelSelector, self).__init__(parent) self.setWindowTitle("Level Selector") self.setModal(True) self.level_name = "" self.object_set = 0 self.object_data_offset = 0x0 self.enemy_data_offset = 0x0 self.world_label = QLabel(parent=self, text="World") self.world_list = QListWidget(parent=self) self.world_list.addItems(WORLD_ITEMS) self.world_list.itemDoubleClicked.connect(self.on_ok) self.world_list.itemSelectionChanged.connect(self.on_world_click) self.level_label = QLabel(parent=self, text="Level") self.level_list = QListWidget(parent=self) self.level_list.itemDoubleClicked.connect(self.on_ok) self.level_list.itemSelectionChanged.connect(self.on_level_click) self.enemy_data_label = QLabel(parent=self, text="Enemy Data") self.enemy_data_spinner = Spinner(parent=self) self.object_data_label = QLabel(parent=self, text="Object Data") self.object_data_spinner = Spinner(self) self.object_set_label = QLabel(parent=self, text="Object Set") self.object_set_dropdown = QComboBox(self) self.object_set_dropdown.addItems(OBJECT_SET_ITEMS) self.button_ok = QPushButton("Ok", self) self.button_ok.clicked.connect(self.on_ok) self.button_cancel = QPushButton("Cancel", self) self.button_cancel.clicked.connect(self.close) stock_level_widget = QWidget() stock_level_layout = QGridLayout(stock_level_widget) stock_level_layout.addWidget(self.world_label, 0, 0) stock_level_layout.addWidget(self.level_label, 0, 1) stock_level_layout.addWidget(self.world_list, 1, 0) stock_level_layout.addWidget(self.level_list, 1, 1) self.source_selector = QTabWidget() self.source_selector.addTab(stock_level_widget, "Stock Levels") for world_number in range(WORLD_COUNT): world_number += 1 world_map_select = WorldMapLevelSelect(world_number) world_map_select.level_selected.connect( self._on_level_selected_via_world_map) self.source_selector.addTab(world_map_select, f"World {world_number}") data_layout = QGridLayout() data_layout.addWidget(self.enemy_data_label, 0, 0) data_layout.addWidget(self.object_data_label, 0, 1) data_layout.addWidget(self.enemy_data_spinner, 1, 0) data_layout.addWidget(self.object_data_spinner, 1, 1) data_layout.addWidget(self.object_set_label, 2, 0) data_layout.addWidget(self.object_set_dropdown, 2, 1) data_layout.addWidget(self.button_ok, 3, 0) data_layout.addWidget(self.button_cancel, 3, 1) main_layout = QVBoxLayout() main_layout.addWidget(self.source_selector) main_layout.addLayout(data_layout) self.setLayout(main_layout) self.world_list.setCurrentRow(1) # select Level 1-1 self.on_world_click() def keyPressEvent(self, key_event: QKeyEvent): if key_event.key() == Qt.Key_Escape: self.reject() def on_world_click(self): index = self.world_list.currentRow() assert index >= 0 self.level_list.clear() # skip first meaningless item for level in Level.offsets[1:]: if level.game_world == index: if level.name: self.level_list.addItem(level.name) if self.level_list.count(): self.level_list.setCurrentRow(0) self.on_level_click() def on_level_click(self): index = self.level_list.currentRow() assert index >= 0 level_is_overworld = self.world_list.currentRow( ) == OVERWORLD_MAPS_INDEX if level_is_overworld: level_array_offset = index + 1 self.level_name = "" else: level_array_offset = Level.world_indexes[ self.world_list.currentRow()] + index + 1 self.level_name = f"World {self.world_list.currentRow()}, " self.level_name += f"{Level.offsets[level_array_offset].name}" object_data_for_lvl = Level.offsets[ level_array_offset].rom_level_offset if not level_is_overworld: object_data_for_lvl -= Level.HEADER_LENGTH if not level_is_overworld: enemy_data_for_lvl = Level.offsets[level_array_offset].enemy_offset else: enemy_data_for_lvl = 0 if enemy_data_for_lvl > 0: # data in look up table is off by one, since workshop ignores the first byte enemy_data_for_lvl -= 1 self.enemy_data_spinner.setEnabled(not level_is_overworld) # if self.world_list.currentRow() >= WORLD_1_INDEX: object_set_index = Level.offsets[level_array_offset].real_obj_set self.button_ok.setDisabled(level_is_overworld) self._fill_in_data(object_set_index, object_data_for_lvl, enemy_data_for_lvl) def _fill_in_data(self, object_set: int, layout_address: int, enemy_address: int): self.object_set_dropdown.setCurrentIndex(object_set) self.object_data_spinner.setValue(layout_address) self.enemy_data_spinner.setValue(enemy_address) def _on_level_selected_via_world_map(self, level_name: str, object_set: int, layout_address: int, enemy_address: int): self.level_name = level_name self._fill_in_data(object_set, layout_address, enemy_address) self.on_ok() def on_ok(self, _=None): self.object_set = self.object_set_dropdown.currentIndex() self.object_data_offset = self.object_data_spinner.value() # skip the first byte, because it seems useless self.enemy_data_offset = self.enemy_data_spinner.value() + 1 self.accept() def closeEvent(self, _close_event: QCloseEvent): self.reject()
class SpinnerPanel(QWidget): object_change: SignalInstance = Signal(int) zoom_in_triggered: SignalInstance = Signal() zoom_out_triggered: SignalInstance = Signal() def __init__(self, parent: Optional[QWidget], level_ref: LevelRef): super(SpinnerPanel, self).__init__(parent) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.level_ref = level_ref self.level_ref.data_changed.connect(self.update) self.spin_domain = Spinner(self, maximum=MAX_DOMAIN) self.spin_domain.setEnabled(False) self.spin_domain.valueChanged.connect(self.object_change.emit) self.spin_type = Spinner(self, maximum=MAX_TYPE) self.spin_type.setEnabled(False) self.spin_type.valueChanged.connect(self.object_change.emit) self.spin_length = Spinner(self, maximum=MAX_LENGTH) self.spin_length.setEnabled(False) self.spin_length.valueChanged.connect(self.object_change.emit) spinner_layout = QFormLayout() spinner_layout.addRow("Bank/Domain:", self.spin_domain) spinner_layout.addRow("Type:", self.spin_type) spinner_layout.addRow("Length:", self.spin_length) self.setLayout(spinner_layout) def update(self): if len(self.level_ref.selected_objects) == 1: selected_object = self.level_ref.selected_objects[0] if isinstance(selected_object, ObjectLike): self._populate_spinners(selected_object) else: self.disable_all() super(SpinnerPanel, self).update() def _populate_spinners(self, obj: ObjectLike): self.blockSignals(True) self.set_type(obj.obj_index) self.enable_domain(isinstance(obj, LevelObject), obj.domain) if isinstance(obj, LevelObject) and obj.is_4byte: self.set_length(obj.length) else: self.enable_length(False) self.blockSignals(False) def get_type(self): return self.spin_type.value() def set_type(self, object_type: int): self.spin_type.setValue(object_type) self.spin_type.setEnabled(True) def get_domain(self): return self.spin_domain.value() def set_domain(self, domain: int): self.spin_domain.setValue(domain) self.spin_domain.setEnabled(True) def get_length(self) -> int: return self.spin_length.value() def set_length(self, length: int): self.spin_length.setValue(length) self.spin_length.setEnabled(True) def enable_type(self, enable: bool, value: int = 0): self.spin_type.setValue(value) self.spin_type.setEnabled(enable) def enable_domain(self, enable: bool, value: int = 0): self.spin_domain.setValue(value) self.spin_domain.setEnabled(enable) def enable_length(self, enable: bool, value: int = 0): self.spin_length.setValue(value) self.spin_length.setEnabled(enable) def clear_spinners(self): self.set_type(0x00) self.set_domain(0x00) self.set_length(0x00) def disable_all(self): self.blockSignals(True) self.clear_spinners() self.enable_type(False) self.enable_domain(False) self.enable_length(False) self.blockSignals(False)
class SpinnerPanel(QWidget): object_change: SignalInstance = Signal(int) zoom_in_triggered: SignalInstance = Signal() zoom_out_triggered: SignalInstance = Signal() def __init__(self, parent: Optional[QWidget], level_ref: LevelRef): super(SpinnerPanel, self).__init__(parent) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.level_ref = level_ref self.level_ref.data_changed.connect(self.update) self.spin_domain = Spinner(self, maximum=MAX_DOMAIN) self.spin_domain.setEnabled(False) self.spin_domain.valueChanged.connect(self.object_change.emit) self.spin_type = Spinner(self, maximum=MAX_TYPE) self.spin_type.setEnabled(False) self.spin_type.valueChanged.connect(self.object_change.emit) self.spin_length = Spinner(self, maximum=MAX_LENGTH) self.spin_length.setEnabled(False) self.spin_length.valueChanged.connect(self.object_change.emit) spinner_layout = QFormLayout() spinner_layout.addRow("Bank/Domain:", self.spin_domain) spinner_layout.addRow("Index:", self.spin_type) spinner_layout.addRow("Length:", self.spin_length) self.setLayout(spinner_layout) self.setWhatsThis( "<b>Spinner Panel</b><br/>" "The Spinner Panel gives raw byte access to objects for advanced users. The values are shown " "in hexadecimal notation.<br/>" "Level objects and enemies/items are categorized using domains and indexes. Which domain an " "object is in, doesn't hold much information about the object, if at all.<br/>" "As for the index, the only important information is, that all objects from 0x00 - 0x0F can " "not be resized. " "They have fixed dimensions, like the background bushes in Level 1-1.<br/>" "All other objects have 16 different iterations, meaning 0x10 - 0x1F, for example, is one " "object, with 16 different sizes, going from smallest to largest. In what way these objects " "expand, depends on their particular expansion type.<br/>" "Some '4-byte' objects can expand in a second way, since they have an additional byte " "holding that information. For example a platform, which can be sized vertically using the " "index and horizontally using the 4th byte.") def update(self): if len(self.level_ref.selected_objects) == 1: selected_object = self.level_ref.selected_objects[0] if isinstance(selected_object, ObjectLike): self._populate_spinners(selected_object) else: self.disable_all() super(SpinnerPanel, self).update() def _populate_spinners(self, obj: ObjectLike): self.blockSignals(True) self.set_type(obj.obj_index) self.enable_domain(isinstance(obj, LevelObject), obj.domain) if isinstance(obj, LevelObject) and obj.is_4byte: self.set_length(obj.length) else: self.enable_length(False) self.blockSignals(False) def get_type(self): return self.spin_type.value() def set_type(self, object_type: int): self.spin_type.setValue(object_type) self.spin_type.setEnabled(True) def get_domain(self): return self.spin_domain.value() def set_domain(self, domain: int): self.spin_domain.setValue(domain) self.spin_domain.setEnabled(True) def get_length(self) -> int: return self.spin_length.value() def set_length(self, length: int): self.spin_length.setValue(length) self.spin_length.setEnabled(True) def enable_type(self, enable: bool, value: int = 0): self.spin_type.setValue(value) self.spin_type.setEnabled(enable) def enable_domain(self, enable: bool, value: int = 0): self.spin_domain.setValue(value) self.spin_domain.setEnabled(enable) def enable_length(self, enable: bool, value: int = 0): self.spin_length.setValue(value) self.spin_length.setEnabled(enable) def clear_spinners(self): self.set_type(0x00) self.set_domain(0x00) self.set_length(0x00) def disable_all(self): self.blockSignals(True) self.clear_spinners() self.enable_type(False) self.enable_domain(False) self.enable_length(False) self.blockSignals(False)
def __init__(self, parent): super(LevelSelector, self).__init__(parent) self.setWindowTitle("Level Selector") self.setModal(True) self.selected_world = 1 self.selected_level = 1 self.object_set = 0 self.object_data_offset = 0x0 self.enemy_data_offset = 0x0 self.world_label = QLabel(parent=self, text="World") self.world_list = QListWidget(parent=self) self.world_list.addItems(WORLD_ITEMS) self.world_list.itemDoubleClicked.connect(self.on_ok) self.world_list.itemSelectionChanged.connect(self.on_world_click) self.level_label = QLabel(parent=self, text="Level") self.level_list = QListWidget(parent=self) self.level_list.itemDoubleClicked.connect(self.on_ok) self.level_list.itemSelectionChanged.connect(self.on_level_click) self.enemy_data_label = QLabel(parent=self, text="Enemy Data") self.enemy_data_spinner = Spinner(parent=self) self.object_data_label = QLabel(parent=self, text="Object Data") self.object_data_spinner = Spinner(self) self.object_set_label = QLabel(parent=self, text="Object Set") self.object_set_dropdown = QComboBox(self) self.object_set_dropdown.addItems(OBJECT_SET_ITEMS) self.button_ok = QPushButton("Ok", self) self.button_ok.clicked.connect(self.on_ok) self.button_cancel = QPushButton("Cancel", self) self.button_cancel.clicked.connect(self.close) self.window_layout = QGridLayout(self) self.window_layout.addWidget(self.world_label, 0, 0) self.window_layout.addWidget(self.level_label, 0, 1) self.window_layout.addWidget(self.world_list, 1, 0) self.window_layout.addWidget(self.level_list, 1, 1) self.window_layout.addWidget(self.enemy_data_label, 2, 0) self.window_layout.addWidget(self.object_data_label, 2, 1) self.window_layout.addWidget(self.enemy_data_spinner, 3, 0) self.window_layout.addWidget(self.object_data_spinner, 3, 1) self.window_layout.addWidget(self.object_set_label, 4, 0) self.window_layout.addWidget(self.object_set_dropdown, 4, 1) self.window_layout.addWidget(self.button_ok, 5, 0) self.window_layout.addWidget(self.button_cancel, 5, 1) self.setLayout(self.window_layout) self.world_list.setCurrentRow(1) # select Level 1-1 self.on_world_click()
def __init__(self, parent): super(LevelSelector, self).__init__(parent) self.setWindowTitle("Level Selector") self.setModal(True) self.level_name = "" self.object_set = 0 self.object_data_offset = 0x0 self.enemy_data_offset = 0x0 self.world_label = QLabel(parent=self, text="World") self.world_list = QListWidget(parent=self) self.world_list.addItems(WORLD_ITEMS) self.world_list.itemDoubleClicked.connect(self.on_ok) self.world_list.itemSelectionChanged.connect(self.on_world_click) self.level_label = QLabel(parent=self, text="Level") self.level_list = QListWidget(parent=self) self.level_list.itemDoubleClicked.connect(self.on_ok) self.level_list.itemSelectionChanged.connect(self.on_level_click) self.enemy_data_label = QLabel(parent=self, text="Enemy Data") self.enemy_data_spinner = Spinner(parent=self) self.object_data_label = QLabel(parent=self, text="Object Data") self.object_data_spinner = Spinner(self) self.object_set_label = QLabel(parent=self, text="Object Set") self.object_set_dropdown = QComboBox(self) self.object_set_dropdown.addItems(OBJECT_SET_ITEMS) self.button_ok = QPushButton("Ok", self) self.button_ok.clicked.connect(self.on_ok) self.button_cancel = QPushButton("Cancel", self) self.button_cancel.clicked.connect(self.close) stock_level_widget = QWidget() stock_level_layout = QGridLayout(stock_level_widget) stock_level_layout.addWidget(self.world_label, 0, 0) stock_level_layout.addWidget(self.level_label, 0, 1) stock_level_layout.addWidget(self.world_list, 1, 0) stock_level_layout.addWidget(self.level_list, 1, 1) self.source_selector = QTabWidget() self.source_selector.addTab(stock_level_widget, "Stock Levels") for world_number in range(WORLD_COUNT): world_number += 1 world_map_select = WorldMapLevelSelect(world_number) world_map_select.level_selected.connect( self._on_level_selected_via_world_map) self.source_selector.addTab(world_map_select, f"World {world_number}") data_layout = QGridLayout() data_layout.addWidget(self.enemy_data_label, 0, 0) data_layout.addWidget(self.object_data_label, 0, 1) data_layout.addWidget(self.enemy_data_spinner, 1, 0) data_layout.addWidget(self.object_data_spinner, 1, 1) data_layout.addWidget(self.object_set_label, 2, 0) data_layout.addWidget(self.object_set_dropdown, 2, 1) data_layout.addWidget(self.button_ok, 3, 0) data_layout.addWidget(self.button_cancel, 3, 1) main_layout = QVBoxLayout() main_layout.addWidget(self.source_selector) main_layout.addLayout(data_layout) self.setLayout(main_layout) self.world_list.setCurrentRow(1) # select Level 1-1 self.on_world_click()
class JumpEditor(CustomDialog): def __init__(self, parent: Optional[QWidget], jump: Jump): super(JumpEditor, self).__init__(parent, "Jump Editor") self.jump = jump self.screen_spinner = Spinner(parent=self, maximum=MAX_SCREEN_INDEX, base=10) position_layout = QFormLayout() position_layout.addRow("Jump on screen:", self.screen_spinner) level_group_box = QGroupBox("Level position") level_group_box.setLayout(position_layout) self.exit_action = QComboBox(self) self.exit_action.addItems(JUMP_ACTIONS) self.exit_horizontal = Spinner(parent=self, maximum=MAX_HORIZ_POSITION, base=10) self.exit_vertical = QComboBox(self) self.exit_vertical.addItems(VERT_POSITIONS) exit_layout = QFormLayout() exit_layout.addRow("Exit action:", self.exit_action) exit_layout.addRow("Exit position x:", self.exit_horizontal) exit_layout.addRow("Exit position y:", self.exit_vertical) exit_group_box = QGroupBox("Exit options") exit_group_box.setLayout(exit_layout) button_box = QDialogButtonBox() self.ok_button = button_box.addButton(QDialogButtonBox.Ok) self.ok_button.pressed.connect(self.on_ok) button_box.addButton(QDialogButtonBox.Cancel).pressed.connect( self.close) main_layout = QVBoxLayout() main_layout.addWidget(level_group_box) main_layout.addWidget(exit_group_box) main_layout.addWidget(button_box) self.setLayout(main_layout) self._set_widget_values() def _set_widget_values(self): self.screen_spinner.setValue(self.jump.screen_index) self.exit_action.setCurrentIndex(self.jump.exit_action) self.exit_horizontal.setValue(self.jump.exit_horizontal) self.exit_vertical.setCurrentIndex(self.jump.exit_vertical) @staticmethod def edit_jump(parent: Optional[QWidget], jump: Jump): jump_editor = JumpEditor(parent, jump) jump_editor.exec_() return jump_editor.jump def on_ok(self): self.jump = Jump.from_properties( self.screen_spinner.value(), self.exit_action.currentIndex(), self.exit_horizontal.value(), self.exit_vertical.currentIndex(), ) self.close()
class ObjectViewer(CustomChildWindow): def __init__(self, parent): super(ObjectViewer, self).__init__(parent, title="Object Viewer") self.spin_domain = Spinner(self, MAX_DOMAIN) self.spin_domain.valueChanged.connect(self.on_spin) self.spin_type = Spinner(self, MAX_TYPE) self.spin_type.valueChanged.connect(self.on_spin) self.spin_length = Spinner(self, MAX_LENGTH) self.spin_length.setDisabled(True) self.spin_length.valueChanged.connect(self.on_spin) _toolbar = QToolBar(self) _toolbar.addWidget(self.spin_domain) _toolbar.addWidget(self.spin_type) _toolbar.addWidget(self.spin_length) self.object_set_dropdown = QComboBox(_toolbar) self.object_set_dropdown.addItems(OBJECT_SET_ITEMS[1:]) self.object_set_dropdown.setCurrentIndex(0) self.graphic_set_dropdown = QComboBox(_toolbar) self.graphic_set_dropdown.addItems(GRAPHIC_SET_NAMES) self.graphic_set_dropdown.setCurrentIndex(1) self.object_set_dropdown.currentIndexChanged.connect( self.on_object_set) self.graphic_set_dropdown.currentIndexChanged.connect( self.on_graphic_set) _toolbar.addWidget(self.object_set_dropdown) _toolbar.addWidget(self.graphic_set_dropdown) self.addToolBar(_toolbar) self.drawing_area = ObjectDrawArea(self, 1) self.status_bar = QStatusBar(parent=self) self.status_bar.showMessage(self.drawing_area.current_object.name) self.setStatusBar(self.status_bar) self.drawing_area.update() self.block_list = BlockArray(self, self.drawing_area.current_object) central_widget = QWidget() central_widget.setLayout(QVBoxLayout()) central_widget.layout().addWidget(self.drawing_area) central_widget.layout().addWidget(self.block_list) self.setCentralWidget(central_widget) self.layout().setSizeConstraint(QLayout.SetFixedSize) return def set_object_and_graphic_set(self, object_set: int, graphics_set: int): self.object_set_dropdown.setCurrentIndex(object_set - 1) self.graphic_set_dropdown.setCurrentIndex(graphics_set) self.drawing_area.change_object_set(object_set) self.drawing_area.change_graphic_set(graphics_set) self.block_list.update_object(self.drawing_area.current_object) self.status_bar.showMessage(self.drawing_area.current_object.name) def on_object_set(self): object_set = self.object_set_dropdown.currentIndex() + 1 graphics_set = object_set self.set_object_and_graphic_set(object_set, graphics_set) def on_graphic_set(self): object_set = self.object_set_dropdown.currentIndex() + 1 graphics_set = self.graphic_set_dropdown.currentIndex() self.set_object_and_graphic_set(object_set, graphics_set) def set_object(self, domain: int, obj_index: int, secondary_length: int): object_data = bytearray(4) object_data[0] = domain << 5 object_data[1] = 0 object_data[2] = obj_index object_data[3] = secondary_length self.spin_domain.setValue(domain) self.spin_type.setValue(obj_index) self.spin_length.setValue(secondary_length) self.drawing_area.update_object(object_data) self.block_list.update_object(self.drawing_area.current_object) if self.drawing_area.current_object.is_4byte: self.spin_length.setEnabled(True) else: self.spin_length.setValue(0) self.spin_length.setEnabled(False) self.drawing_area.update() self.status_bar.showMessage(self.drawing_area.current_object.name) def on_spin(self, _): domain = self.spin_domain.value() obj_index = self.spin_type.value() secondary_length = self.spin_length.value() self.set_object(domain, obj_index, secondary_length)
class ObjectViewer(CustomChildWindow): def __init__(self, parent): super(ObjectViewer, self).__init__(parent, title="Object Viewer") self.spin_domain = Spinner(self, MAX_DOMAIN) self.spin_domain.valueChanged.connect(self.on_spin) self.spin_type = Spinner(self, MAX_TYPE) self.spin_type.valueChanged.connect(self.on_spin) self.spin_length = Spinner(self, MAX_LENGTH) self.spin_length.setDisabled(True) self.spin_length.valueChanged.connect(self.on_spin) _toolbar = QToolBar(self) _toolbar.addWidget(self.spin_domain) _toolbar.addWidget(self.spin_type) _toolbar.addWidget(self.spin_length) self.object_set_dropdown = QComboBox(_toolbar) self.object_set_dropdown.addItems(OBJECT_SET_ITEMS[1:]) self.object_set_dropdown.setCurrentIndex(0) self.graphic_set_dropdown = QComboBox(_toolbar) self.graphic_set_dropdown.addItems( [f"Graphics Set {gfx_set}" for gfx_set in range(32)]) self.graphic_set_dropdown.setCurrentIndex(1) self.object_set_dropdown.currentIndexChanged.connect( self.on_object_set) self.graphic_set_dropdown.currentIndexChanged.connect( self.on_graphic_set) _toolbar.addWidget(self.object_set_dropdown) _toolbar.addWidget(self.graphic_set_dropdown) self.addToolBar(_toolbar) self.object_set = 1 self.drawing_area = ObjectDrawArea(self, self.object_set) self.status_bar = QStatusBar(parent=self) self.status_bar.showMessage( self.drawing_area.current_object.description) self.setStatusBar(self.status_bar) self.setCentralWidget(self.drawing_area) self.drawing_area.update() self.layout().setSizeConstraint(QLayout.SetFixedSize) return def on_object_set(self): self.object_set = self.object_set_dropdown.currentIndex() + 1 gfx_set = self.object_set self.graphic_set_dropdown.setCurrentIndex(gfx_set) self.drawing_area.change_object_set(self.object_set) self.drawing_area.change_graphic_set(gfx_set) self.status_bar.showMessage( self.drawing_area.current_object.description) def on_graphic_set(self): gfx_set = self.graphic_set_dropdown.currentIndex() self.drawing_area.change_graphic_set(gfx_set) self.status_bar.showMessage( self.drawing_area.current_object.description) def on_spin(self, _): object_data = bytearray(4) object_data[0] = self.spin_domain.value() << 5 object_data[1] = 0 object_data[2] = self.spin_type.value() object_data[3] = self.spin_length.value() self.drawing_area.update_object(object_data) if self.drawing_area.current_object.is_4byte: self.spin_length.setEnabled(True) else: self.spin_length.setValue(0) self.spin_length.setEnabled(False) self.drawing_area.update() self.status_bar.showMessage( self.drawing_area.current_object.description)
class BlockViewer(CustomChildWindow): def __init__(self, parent): super(BlockViewer, self).__init__(parent, "Block Viewer") self._object_set = 0 self.sprite_bank = BlockBank(parent=self) self.setCentralWidget(self.sprite_bank) self.toolbar = QToolBar(self) self.prev_os_action = self.toolbar.addAction(icon("arrow-left.svg"), "Previous object set") self.prev_os_action.triggered.connect(self.prev_object_set) self.next_os_action = self.toolbar.addAction(icon("arrow-right.svg"), "Next object set") self.next_os_action.triggered.connect(self.next_object_set) self.zoom_out_action = self.toolbar.addAction(icon("zoom-out.svg"), "Zoom Out") self.zoom_out_action.triggered.connect(self.sprite_bank.zoom_out) self.zoom_in_action = self.toolbar.addAction(icon("zoom-in.svg"), "Zoom In") self.zoom_in_action.triggered.connect(self.sprite_bank.zoom_in) self.bank_dropdown = QComboBox(parent=self.toolbar) self.bank_dropdown.addItems(OBJECT_SET_ITEMS) self.bank_dropdown.setCurrentIndex(0) self.bank_dropdown.currentIndexChanged.connect(self.on_combo) self.palette_group_spinner = Spinner(self, maximum=PALETTE_GROUPS_PER_OBJECT_SET - 1, base=10) self.palette_group_spinner.valueChanged.connect(self.on_palette) self.toolbar.addWidget(self.bank_dropdown) self.toolbar.addWidget(QLabel(" Object Palette: ")) self.toolbar.addWidget(self.palette_group_spinner) self.addToolBar(self.toolbar) self.layout().setSizeConstraint(QLayout.SetFixedSize) self.setStatusBar(QStatusBar(self)) return @property def object_set(self): return self._object_set @object_set.setter def object_set(self, value): self._object_set = value self._after_object_set() @property def palette_group(self): return self.palette_group_spinner.value() @palette_group.setter def palette_group(self, value): self.palette_group_spinner.setValue(value) def prev_object_set(self): self.object_set = max(self.object_set - 1, 0) def next_object_set(self): self.object_set = min(self.object_set + 1, 0xE) def _after_object_set(self): self.sprite_bank.object_set = self.object_set self.bank_dropdown.setCurrentIndex(self.object_set) self.sprite_bank.update() def on_combo(self, _): self.object_set = self.bank_dropdown.currentIndex() self.sprite_bank.object_set = self.object_set self.sprite_bank.update() def on_palette(self, value): self.sprite_bank.palette_group = value self.sprite_bank.update()
class LevelSelector(QDialog): def __init__(self, parent): super(LevelSelector, self).__init__(parent) self.setWindowTitle("Level Selector") self.setModal(True) self.selected_world = 1 self.selected_level = 1 self.object_set = 0 self.object_data_offset = 0x0 self.enemy_data_offset = 0x0 self.world_label = QLabel(parent=self, text="World") self.world_list = QListWidget(parent=self) self.world_list.addItems(WORLD_ITEMS) self.world_list.itemDoubleClicked.connect(self.on_ok) self.world_list.itemSelectionChanged.connect(self.on_world_click) self.level_label = QLabel(parent=self, text="Level") self.level_list = QListWidget(parent=self) self.level_list.itemDoubleClicked.connect(self.on_ok) self.level_list.itemSelectionChanged.connect(self.on_level_click) self.enemy_data_label = QLabel(parent=self, text="Enemy Data") self.enemy_data_spinner = Spinner(parent=self) self.object_data_label = QLabel(parent=self, text="Object Data") self.object_data_spinner = Spinner(self) self.object_set_label = QLabel(parent=self, text="Object Set") self.object_set_dropdown = QComboBox(self) self.object_set_dropdown.addItems(OBJECT_SET_ITEMS) self.button_ok = QPushButton("Ok", self) self.button_ok.clicked.connect(self.on_ok) self.button_cancel = QPushButton("Cancel", self) self.button_cancel.clicked.connect(self.close) self.window_layout = QGridLayout(self) self.window_layout.addWidget(self.world_label, 0, 0) self.window_layout.addWidget(self.level_label, 0, 1) self.window_layout.addWidget(self.world_list, 1, 0) self.window_layout.addWidget(self.level_list, 1, 1) self.window_layout.addWidget(self.enemy_data_label, 2, 0) self.window_layout.addWidget(self.object_data_label, 2, 1) self.window_layout.addWidget(self.enemy_data_spinner, 3, 0) self.window_layout.addWidget(self.object_data_spinner, 3, 1) self.window_layout.addWidget(self.object_set_label, 4, 0) self.window_layout.addWidget(self.object_set_dropdown, 4, 1) self.window_layout.addWidget(self.button_ok, 5, 0) self.window_layout.addWidget(self.button_cancel, 5, 1) self.setLayout(self.window_layout) self.world_list.setCurrentRow(1) # select Level 1-1 self.on_world_click() def keyPressEvent(self, key_event: QKeyEvent): if key_event.key() == Qt.Key_Escape: self.reject() def on_world_click(self): index = self.world_list.currentRow() assert index >= 0 self.level_list.clear() # skip first meaningless item for level in Level.offsets[1:]: if level.game_world == index: if level.name: self.level_list.addItem(level.name) if self.level_list.count(): self.level_list.setCurrentRow(0) self.on_level_click() def on_level_click(self): index = self.level_list.currentRow() assert index >= 0 self.selected_world = self.world_list.currentRow() self.selected_level = index + 1 level_is_overworld = self.selected_world == OVERWORLD_MAPS_INDEX if level_is_overworld: level_array_offset = self.selected_level else: level_array_offset = Level.world_indexes[self.selected_world] + self.selected_level object_data_for_lvl = Level.offsets[level_array_offset].rom_level_offset if not level_is_overworld: object_data_for_lvl -= Level.HEADER_LENGTH self.object_data_spinner.setValue(object_data_for_lvl) if not level_is_overworld: enemy_data_for_lvl = Level.offsets[level_array_offset].enemy_offset else: enemy_data_for_lvl = 0 if enemy_data_for_lvl > 0: # data in look up table is off by one, since workshop ignores the first byte enemy_data_for_lvl -= 1 self.enemy_data_spinner.setValue(enemy_data_for_lvl) self.enemy_data_spinner.setEnabled(not level_is_overworld) # if self.selected_world >= WORLD_1_INDEX: object_set_index = Level.offsets[level_array_offset].real_obj_set self.object_set_dropdown.setCurrentIndex(object_set_index) self.button_ok.setDisabled(self.selected_world == 0) def on_ok(self, _): if self.selected_world == 0: return self.object_set = self.object_set_dropdown.currentIndex() self.object_data_offset = self.object_data_spinner.value() # skip the first byte, because it seems useless self.enemy_data_offset = self.enemy_data_spinner.value() + 1 self.accept() def closeEvent(self, _close_event: QCloseEvent): self.reject()
class AutoScrollEditor(CustomDialog): def __init__(self, parent, level_ref: LevelRef): super(AutoScrollEditor, self).__init__(parent, title="Autoscroll Editor") self.level_ref = level_ref self.original_autoscroll_item = _get_autoscroll(self.level_ref.enemies) QVBoxLayout(self) self.enabled_checkbox = QCheckBox("Enable Autoscroll in level", self) self.enabled_checkbox.toggled.connect(self._insert_autoscroll_object) self.y_position_spinner = Spinner(self, maximum=0x60 - 1) self.y_position_spinner.valueChanged.connect(self._update_y_position) self.auto_scroll_type_label = QLabel(self) self.layout().addWidget(self.enabled_checkbox) self.layout().addWidget(self.y_position_spinner) self.layout().addWidget(self.auto_scroll_type_label) self.update() def update(self): autoscroll_item = _get_autoscroll(self.level_ref.enemies) self.enabled_checkbox.setChecked(autoscroll_item is not None) self.y_position_spinner.setEnabled(autoscroll_item is not None) if autoscroll_item is None: self.auto_scroll_type_label.setText(AUTOSCROLL_LABELS[-1]) else: self.y_position_spinner.setValue(autoscroll_item.y_position) self.auto_scroll_type_label.setText( AUTOSCROLL_LABELS[autoscroll_item.y_position >> 4]) def _update_y_position(self, _): autoscroll_item = _get_autoscroll(self.level_ref.enemies) autoscroll_item.y_position = self.y_position_spinner.value() self.level_ref.data_changed.emit() self.update() def _insert_autoscroll_object(self, should_insert: bool): autoscroll_item = _get_autoscroll(self.level_ref.enemies) if autoscroll_item is not None: self.level_ref.enemies.remove(autoscroll_item) if should_insert: self.level_ref.enemies.insert(0, self._create_autoscroll_object()) self.level_ref.data_changed.emit() self.update() def _create_autoscroll_object(self): return self.level_ref.level.enemy_item_factory.from_properties( OBJ_AUTOSCROLL, 0, self.y_position_spinner.value()) def closeEvent(self, event): current_autoscroll_item = _get_autoscroll(self.level_ref.enemies) if not (self.original_autoscroll_item is None and current_autoscroll_item is None): added_or_removed_autoscroll = self.original_autoscroll_item is None or current_autoscroll_item is None if (added_or_removed_autoscroll or self.original_autoscroll_item.y_position != current_autoscroll_item.y_position): self.level_ref.save_level_state() super(AutoScrollEditor, self).closeEvent(event)