예제 #1
0
 def add_manually(self, handler: AbstractPatchHandler, patch_base_dir: str):
     # Try to find the patch in the config
     if handler.name not in self._config.asm_patches_constants.patches.keys(
     ):
         raise ValueError(
             f(
                 _("No patch for handler '{handler.name}' found in the configuration."
                   )))
     self._loaded_patches[handler.name] = handler
     self._patch_dirs[handler.name] = os.path.realpath(patch_base_dir)
예제 #2
0
    def edit_palette_ani(self, ani_pal_id):
        if not self.parent.dpla.has_for_palette(ani_pal_id):
            md = SkyTempleMessageDialog(
                MainController.window(),
                Gtk.DialogFlags.DESTROY_WITH_PARENT,
                Gtk.MessageType.ERROR,
                Gtk.ButtonsType.OK,
                _("Palette Animation is not enabled for this palette."),
                title=_("Warning!"))
            md.set_position(Gtk.WindowPosition.CENTER)
            md.run()
            md.destroy()
            return
        # This is controlled by a separate controller
        dict_pals = OrderedDict()

        list_of_colors = self.parent.dpla.colors[ani_pal_id *
                                                 16:(ani_pal_id + 1) * 16]
        # We need to transpose the list to instead have a list of frames.
        list_of_frames = list(
            [] for _ in range(0, int(len(list_of_colors[0]) / 3)))
        for color in list_of_colors:
            for frame_idx, c in enumerate(chunks(color, 3)):
                list_of_frames[frame_idx] += c
        for i, pal in enumerate(list_of_frames):
            dict_pals[f'F{i + 1}'] = pal.copy()

        cntrl = PaletteEditorController(MainController.window(), dict_pals,
                                        False, True, False)
        edited_palettes = cntrl.show()
        if edited_palettes:
            # Transpose back
            edited_colors = list(
                [] for _ in range(0, int(len(edited_palettes[0]) / 3)))
            for palette in edited_palettes:
                for color_idx, c in enumerate(chunks(palette, 3)):
                    edited_colors[color_idx] += c

            self.parent.dpla.colors[ani_pal_id * 16:(ani_pal_id + 1) *
                                    16] = edited_colors
            self.parent.reload_all()
            self.parent.mark_as_modified()
        del cntrl
예제 #3
0
 def apply(self, name: str):
     if name not in self._loaded_patches:
         raise ValueError(f(_("The patch '{name}' was not found.")))
     patch = self._loaded_patches[name]
     if isinstance(patch, DependantPatch):
         for patch_name in patch.depends_on():
             try:
                 if not self.is_applied(patch_name):
                     raise PatchDependencyError(
                         f(
                             _("The patch '{patch_name}' needs to be applied before you can "
                               "apply '{name}'.")))
             except ValueError as err:
                 raise PatchDependencyError(
                     f(
                         _("The patch '{patch_name}' needs to be applied before you can "
                           "apply '{name}'. "
                           "This patch could not be found."))) from err
     patch.apply(partial(self._apply_armips, name), self._rom, self._config)
예제 #4
0
 def on_intro_dialog_created_with_clicked(self, *args):
     if RomProject.get_current() is None or self._loaded_map_bg_module is None:
         md = SkyTempleMessageDialog(MainController.window(),
                                     Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.ERROR,
                                     Gtk.ButtonsType.OK, _("A project must be opened to use this."))
         md.set_position(Gtk.WindowPosition.CENTER)
         md.run()
         md.destroy()
         return
     self._loaded_map_bg_module.add_created_with_logo()
예제 #5
0
    def on_import_minimized_activate(self, *args):
        md = SkyTempleMessageDialog(
            MainController.window(),
            Gtk.DialogFlags.DESTROY_WITH_PARENT,
            Gtk.MessageType.INFO,
            Gtk.ButtonsType.OK,
            _("To import, select a folder containing all the image files that were created when exporting the minimized version.\n"
              "IMPORTANT: All image files must be indexed PNGs and use the same palette!"
              ),
            title=_("Import Minimized Version"))
        md.run()
        md.destroy()
        dialog = Gtk.FileChooserNative.new(
            _("Import zmappat minimized from folder..."),
            MainController.window(), Gtk.FileChooserAction.SELECT_FOLDER, None,
            None)

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            try:
                imgs: List[Image.Image] = [
                    None
                ] * ZMAPPAT_NB_VARIATIONS  # type: ignore
                masks: List[Image.Image] = [
                    None
                ] * ZMAPPAT_NB_VARIATIONS  # type: ignore
                for v in ZMappaTVariation:
                    fn_tiles = os.path.join(
                        fn, f'zmappat-{v.filename}-tiles.min.png')
                    fn_masks = os.path.join(
                        fn, f'zmappat-{v.filename}-masks.min.png')
                    imgs[v.value] = Image.open(fn_tiles, 'r')
                    masks[v.value] = Image.open(fn_masks, 'r')
                self.zmappat.from_pil_minimized(imgs, masks)
                self.module.mark_zmappat_as_modified(self.zmappat,
                                                     self.filename)
            except Exception as err:
                display_error(sys.exc_info(), str(err),
                              _("Error importing minimized zmappat."))
            self._reinit_image()
예제 #6
0
 def from_pil(self, img: Image.Image):
     if img.mode != 'P':
         raise AttributeError(
             _('Cannot convert PIL image to CHR: Must be indexed image (=using a palette)'
               ))
     if img.width % CHR_TILE_WIDTH != 0 or img.height % CHR_TILE_WIDTH != 0:
         raise AttributeError(
             f(
                 _('Cannot convert PIL image to CHR: width and height must be a multiple of {CHR_TILE_WIDTH}'
                   )))
     self.tiles = []
     for y in range(img.height // CHR_TILE_WIDTH):
         for x in range(img.width // CHR_TILE_WIDTH):
             self.tiles.append(
                 img.crop([
                     x * CHR_TILE_WIDTH, y * CHR_TILE_WIDTH,
                     (x + 1) * CHR_TILE_WIDTH, (y + 1) * CHR_TILE_WIDTH
                 ]))
     self.set_palette_raw(list(img.palette.palette))
예제 #7
0
 def on_import_new_clicked(self, w: Gtk.MenuToolButton):
     md = SkyTempleMessageDialog(MainController.window(),
                                 Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO,
                                 Gtk.ButtonsType.OK_CANCEL,
                                 _("This will insert a completely new sprite into the game's sprite file and "
                                   "assign the new ID to the Pokémon.\n"
                                   "If you want to instead replace the currently assigned sprite, choose 'Import'.\n")
                                 +
                                 _("To import select the archive that contains the spritesheets.")
                                 if self._zip_is_active()
                                 else _("To import select the directory of the spritesheets. If it "
                                        "is still zipped, unzip it first."),
                                 title="SkyTemple")
     response = md.run()
     md.destroy()
     if response == Gtk.ResponseType.OK:
         new_item_id = self.module.get_monster_sprite_count()
         if new_item_id > -1:
             self.do_import(new_item_id, lambda: self._assign_new_sprite_id_cb(new_item_id))
예제 #8
0
 def _done(self, return_code):
     self._update_status(GfxcrunchStatus.SUCCESS if return_code ==
                         0 else GfxcrunchStatus.ERROR)
     if return_code != 0:
         self._stderr(
             f(
                 _('!! Process exited with error. Exit code: {return_code} !!'
                   )))
     self.builder.get_object('spinner').stop()
     self.builder.get_object('close').set_sensitive(True)
예제 #9
0
 def export_sprite(self, wan: bytes, dir_fn: str):
     with tempfile.TemporaryDirectory() as tmp_path:
         tmp_path = os.path.join(tmp_path, 'tmp.wan')
         with open(tmp_path, 'wb') as f:
             f.write(wan)
         AsyncTaskRunner.instance().run_task(
             self._run_gfxcrunch([tmp_path, dir_fn]))
         self._run_window()
         if self.status != GfxcrunchStatus.SUCCESS:
             raise RuntimeError(_("The gfxcrunch process failed."))
예제 #10
0
 def on_colvec_info_clicked(self, *args):
     md = SkyTempleMessageDialog(
         MainController.window(), Gtk.DialogFlags.DESTROY_WITH_PARENT,
         Gtk.MessageType.INFO, Gtk.ButtonsType.OK,
         _("This colormap defines color palette transformations used by the game during dungeons (for weather effects).\n"
           "Each color color component (RGB) is changed to the corresponding color component of the n-th color map entry (where n is the old color component value).\n"
           "This transformation also applies to monsters and items sprites."
           ))
     md.run()
     md.destroy()
예제 #11
0
    def export_a_sprite__wan(self, sprite: bytes):
        dialog = Gtk.FileChooserNative.new(_("Export WAN sprite..."),
                                           MainController.window(),
                                           Gtk.FileChooserAction.SAVE, None,
                                           None)
        filter = Gtk.FileFilter()
        filter.set_name(_("WAN sprite (*.wan)"))
        filter.add_pattern("*.wan")
        dialog.add_filter(filter)

        response = dialog.run()
        fn = dialog.get_filename()

        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            fn = add_extension_if_missing(fn, 'wan')
            with open(fn, 'wb') as f:
                f.write(sprite)
예제 #12
0
파일: ssb.py 프로젝트: tech-ticks/skytemple
    def get_content(self) -> Gtk.Widget:
        box: Gtk.Box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 20)
        label = self.generate_content_label(
            _('Each of the scenes has at least one script assigned to them, which is run when the scene is loaded.\n'
              'In addition to that, there is also "COMMON/unionall.ssb", which contains the game\'s coroutines '
              '(main scripts).\n\n'
              'To edit the game\'s scripts, open the Script Engine Debugger. You can also do this by clicking the bug '
              'icon in the top right.\n'))
        button_box = Gtk.ButtonBox.new(Gtk.Orientation.VERTICAL)
        button: Gtk.Button = Gtk.Button.new_with_label(
            _('Open Script Engine Debugger'))
        button.connect(
            'clicked', lambda *args: MainController.debugger_manager().open(
                MainController.window()))
        button_box.pack_start(button, False, False, 0)

        box.pack_start(label, False, False, 0)
        box.pack_start(button_box, False, False, 0)
        return box
예제 #13
0
    def get_view(self) -> Gtk.Widget:
        if self.item_id < 0:
            return Gtk.Label.new(_('Invalid Sprite ID.'))
        self.builder = self._get_builder(__file__, 'monster_sprite.glade')
        self._draw_area = self.builder.get_object('draw_sprite')
        if self.module.get_gfxcrunch().is_available():
            self.builder.get_object('explanation_text2').set_markup(
                _("""Alternatively you can export the sprite files 
in the gfxcrunch format and edit them manually.
Warning: SkyTemple does not validate the files you import."""))
        self.builder.connect_signals(self)

        try:
            self._load_frames()
            self.start_sprite_drawing()
        except BaseException as ex:
            logger.error("Failed rendering sprite preview", exc_info=ex)

        return self.builder.get_object('main_box')
예제 #14
0
 def create_for(cls, string):
     if string == 'CLOSED':
         return cls.CLOSED
     if string == 'OPEN':
         return cls.OPEN
     if string == 'REQUEST':
         return cls.REQUEST
     if string == 'OPEN_AND_REQUEST':
         return cls.OPEN_AND_REQUEST
     raise UserValueError(f(_("Invalid DungeonMode: {string}")))
예제 #15
0
파일: map.py 프로젝트: SkyTemple/skytemple
 def get_view(self) -> Gtk.Widget:
     self.builder = self._get_builder(__file__, 'map.glade')
     self.builder.connect_signals(self)
     self.builder.get_object('title').set_text(
         f(_('Script Scenes for "{}"').format(self.name)))
     self.builder.get_object('desc').set_text(
         f(
             _('This section contains all scenes for the map {self.name}.\n\n'
               '"Enter (sse)" contains the scene that is loaded when the map is entered\n'
               'by the player by "walking into it" (if applicable).\n\n'
               '"Acting (ssa)" contains the scenes used for cutscenes.\n'
               'The player can usually not move the character in these scenes.\n\n'
               '"Sub (sss)" contains scenes that can be loaded on on top of the "Enter" scene,\n'
               'depending on the current story progress.')))
     self._sub_enter, self._sub_acting, self._sub_sub = self.module.get_subnodes(
         self.name)
     if self._sub_enter:
         self.builder.get_object('btn_add_enter').set_sensitive(False)
     return self.builder.get_object('box_list')
예제 #16
0
    def on_edit_groups_clicked(self, *args):
        if not self.module.get_validator().validate(
                self.module.get_dungeon_list()):
            display_error(
                None,
                _("The game currently contains invalid dungeons. Please click 'Fix Dungeon Errors' first."
                  ))
            return
        dialog: Gtk.Dialog = self.builder.get_object('dialog_groups')
        dialog.set_attached_to(SkyTempleMainController.window())
        dialog.set_transient_for(SkyTempleMainController.window())

        expected_dungeon_ids = self._load_dungeons()

        resp = dialog.run()
        dialog.hide()
        if resp == Gtk.ResponseType.APPLY:
            try:
                # Collect new dungeon groupings and tell module to re-group dungeons
                new_groups: List[Union['DungeonGroup', int]] = sorted(
                    self._collect_new_groups_from_dialog(), key=int)
                dungeon_ids_from_dialog = set(
                    chain.from_iterable(
                        [x] if isinstance(x, int) else x.dungeon_ids
                        for x in new_groups))

                # Sanity check
                if expected_dungeon_ids != dungeon_ids_from_dialog:
                    display_error(
                        None,
                        _("Dungeons were missing in the list. This is a bug in SkyTemple! "
                          "Please try again and report this!"),
                        _("Failed regrouping the dungeons."))
                    return

                self.module.regroup_dungeons(new_groups)
            except BaseException as ex:
                display_error(sys.exc_info(),
                              _("An internal error occurred: ") + str(ex),
                              _("Failed regrouping the dungeons."))
                return

        dialog.hide()
예제 #17
0
 def on_tv_paste_import_buffer_paste_done(self, buff: Gtk.TextBuffer,
                                          *args):
     text = buff.get_text(buff.get_start_iter(), buff.get_end_iter(), False)
     buff.delete(buff.get_start_iter(), buff.get_end_iter())
     try:
         self.move_effects.import_armips_effect_code(
             self._get_current_effect(), text)  # type: ignore
         self.module.mark_move_effects_as_modified()
         md = SkyTempleMessageDialog(MainController.window(),
                                     Gtk.DialogFlags.DESTROY_WITH_PARENT,
                                     Gtk.MessageType.INFO,
                                     Gtk.ButtonsType.OK,
                                     _("Patch successfully imported."),
                                     is_success=True)
         md.run()
         md.destroy()
     except Exception as err:
         display_error(sys.exc_info(), str(err),
                       _("Error importing ASM code."))
예제 #18
0
    def load_tree_items(self, item_store: TreeStore, root_node):
        if self._errored:
            display_error(
                self._errored,
                _("The dungeon floor data of this ROM is corrupt. SkyTemple will still try to open it, "
                  "but dungeon editing will not be available. Expect other bugs. Please fix your ROM."),
                _("SkyTemple")
            )
            return
        self._validator = DungeonValidator(self.get_mappa().floor_lists)
        root = item_store.append(root_node, [
            ICON_ROOT, DUNGEONS_NAME, self, MainController, 0, False, '', True
        ])
        self._tree_model = item_store
        self._root_iter = root

        static_data = self.project.get_rom_module().get_static_data()
        self._fixed_floor_data = self.project.open_file_in_rom(
            FIXED_PATH, FileType.FIXED_BIN,
            static_data=static_data
        )
        self._dungeon_bin_context = self.project.open_file_in_rom(
            DUNGEON_BIN, FileType.DUNGEON_BIN,
            static_data=static_data,
            threadsafe=True
        )

        self._validator.validate(self.get_dungeon_list())

        self._fill_dungeon_tree()

        # Fixed rooms
        self._fixed_floor_root_iter = item_store.append(root_node, [
            ICON_FIXED_ROOMS, FIXED_ROOMS_NAME, self, FixedRoomsController, 0, False, '', True
        ])
        for i in range(0, len(self._fixed_floor_data.fixed_floors)):
            self._fixed_floor_iters.append(item_store.append(self._fixed_floor_root_iter, [
                ICON_FIXED_ROOMS, f(_('Fixed Room {i}')), self, FixedController,
                i, False, '', True
            ]))

        recursive_generate_item_store_row_label(self._tree_model[root])
        recursive_generate_item_store_row_label(self._tree_model[self._fixed_floor_root_iter])
예제 #19
0
 def _init_combos(self):
     # Init available menus
     cb_store: Gtk.ListStore = self.builder.get_object('move_filter')
     cb: Gtk.ComboBoxText = self.builder.get_object('cb_filter_move')
     # Init combobox
     cb_store.clear()
     cb_store.append([-1, _("Show All")])
     for i,v in enumerate(self.animations.move_table):
         cb_store.append([i, f'{i}: {self._string_provider.get_value(StringType.MOVE_NAMES, i)}'])
     cb.set_active(0)
예제 #20
0
    def on_btn_help_clicked(self, *args):
        md = SkyTempleMessageDialog(
            MainController.window(), Gtk.DialogFlags.DESTROY_WITH_PARENT,
            Gtk.MessageType.INFO, Gtk.ButtonsType.OK,
            _("""Sort keys are used to sort items in your inventory when using the sort feature in game.
The game sorts items starting from the one with the lowest key to the highest.
Several items can have the same key; this means they will be mixed together while sorting (e.g. Lookalike items).
Only keys from 0 to 2047 should be used."""))
        md.run()
        md.destroy()
예제 #21
0
 def set_tile_mappings(self, tile_mappings):
     self.tile_mappings = tile_mappings
     if len(self.tile_mappings) == 1:
         self.width = BPC_TILE_DIM
         self.height = BPC_TILE_DIM
     elif len(self.tile_mappings) == self.tiling_width * self.tiling_height:
         self.width = BPC_TILE_DIM * self.tiling_width
         self.height = BPC_TILE_DIM * self.tiling_height
     else:
         raise ValueError(_("Only 1x1 or 3x3 supported."))
예제 #22
0
 def _init_graph(self):
     if self._level_bin_entry is None:
         # No valid entry
         graph_box: Gtk.Box = self.builder.get_object('graph_box')
         for child in graph_box:
             graph_box.remove(child)
         graph_box.pack_start(
             Gtk.Label.new(_('This Pokémon has no stats.')), True, True, 0)
     else:
         self.queue_render_graph()
예제 #23
0
    def load_tree_items(self, item_store: TreeStore, root_node):
        self.dungeon_bin_context: ModelContext[
            DungeonBinPack] = self.project.open_file_in_rom(
                DUNGEON_BIN,
                FileType.DUNGEON_BIN,
                static_data=self.project.get_rom_module().get_static_data(),
                threadsafe=True)

        root = self._root_node = item_store.append(root_node, [
            'skytemple-e-dungeon-tileset-symbolic', DUNGEON_GRAPHICS_NAME,
            self, MainController, 0, False, '', True
        ])
        tileset_root = item_store.append(root, [
            'skytemple-e-dungeon-tileset-symbolic', TILESETS_NAME, self,
            TilesetMainController, 0, False, '', True
        ])
        bg_root = item_store.append(root, [
            'skytemple-e-mapbg-symbolic', BACKGROUNDS_NAMES, self,
            DungeonBgMainController, 0, False, '', True
        ])
        self._tree_model = item_store
        self._tree_level_iter = []
        for i in range(0, NUMBER_OF_TILESETS):
            self._tree_level_iter.append(
                item_store.append(tileset_root, [
                    'skytemple-e-dungeon-tileset-symbolic',
                    f"{_('Tileset')} {i}", self, TilesetController, i, False,
                    '', True
                ]))
        for i in range(0, NUMBER_OF_BACKGROUNDS):
            self._tree_level_iter.append(
                item_store.append(bg_root, [
                    'skytemple-e-mapbg-symbolic',
                    f"{_('Background')} {i + NUMBER_OF_TILESETS}", self,
                    DungeonBgController, i, False, '', True
                ]))
        self._tree_level_iter.append(
            item_store.append(root, [
                'skytemple-e-graphics-symbolic', f"Traps", self,
                TrpItmImgController, ImgType.TRP, False, '', True
            ]))
        self._traps_pos = len(self._tree_level_iter) - 1
        self._tree_level_iter.append(
            item_store.append(root, [
                'skytemple-e-graphics-symbolic', f"Items", self,
                TrpItmImgController, ImgType.ITM, False, '', True
            ]))
        self._items_pos = len(self._tree_level_iter) - 1
        self._tree_level_iter.append(
            item_store.append(root, [
                'skytemple-e-dungeon-tileset-symbolic',
                _("Color Map"), self, ColvecController, i, False, '', True
            ]))
        self._colvec_pos = len(self._tree_level_iter) - 1
        recursive_generate_item_store_row_label(self._tree_model[root])
예제 #24
0
    def on_spritebot_import_activate(self, *args):
        dialog = Gtk.FileChooserNative.new(
            _("Import portraits from PNG sheet..."), MainController.window(),
            Gtk.FileChooserAction.OPEN, None, None)

        add_dialog_png_filter(dialog)

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            try:
                for subindex, image in SpriteBotSheet.load(
                        fn, self._get_portrait_name):
                    try:
                        kao = self.kao.get(self.item_id, subindex)
                        if kao:
                            # Replace
                            kao.set(image)
                        else:
                            # New
                            self.kao.set(self.item_id, subindex,
                                         KaoImage.new(image))
                    except Exception as err:
                        name = self._get_portrait_name(subindex)
                        logger.error(f"Failed importing image '{name}'.",
                                     exc_info=err)
                        display_error(
                            sys.exc_info(),
                            f(_('Failed importing image "{name}":\n{err}')),
                            f(_("Error for '{name}'.")))
            except Exception as err:
                logger.error(f"Failed importing portraits sheet: {err}",
                             exc_info=err)
                display_error(sys.exc_info(),
                              f(_('Failed importing portraits sheet:\n{err}')),
                              _("Could not import."))
            self.re_render()
            # Mark as modified
            self.module.mark_as_modified()
            self._mark_as_modified_cb()
예제 #25
0
    def on_btn_import_code_clicked(self, *args):
        dialog = Gtk.FileChooserNative.new(
            _("Import Special Process Effect ASM Code..."),
            MainController.window(),
            Gtk.FileChooserAction.OPEN,
            None, None
        )

        filter = Gtk.FileFilter()
        filter.set_name(_("Any Files"))
        filter.add_pattern("*")
        dialog.add_filter(filter)

        filter = Gtk.FileFilter()
        filter.set_name(_("armips ASM patches (*.asm)"))
        filter.add_pattern("*.asm")
        dialog.add_filter(filter)

        filter = Gtk.FileFilter()
        filter.set_name(_("Raw code (*.bin)"))
        filter.add_pattern("*.bin")
        dialog.add_filter(filter)

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            try:
                if fn.split('.')[-1].lower() == 'asm':
                    with open_utf8(fn, 'r') as file:
                        self.sp_effects.import_armips_effect_code(self._get_current_effect(), file.read())
                else:
                    with open(fn, 'rb') as file:
                        self.sp_effects.set_effect_code(self._get_current_effect(), file.read())
                self.module.mark_sp_effects_as_modified()
            except Exception as err:
                display_error(
                    sys.exc_info(),
                    str(err),
                    _("Error importing ASM code.")
                )
예제 #26
0
    def from_xml(cls, ele: Element) -> 'MappaFloor':
        data = {
            'layout': None,
            'monsters': None,
            'traps': None,
            'floor_items': None,
            'shop_items': None,
            'monster_house_items': None,
            'buried_items': None,
            'unk_items1': None,
            'unk_items2': None
        }
        for child in ele:
            if child.tag == XML_FLOOR_LAYOUT and data['layout'] is None:
                data['layout'] = MappaFloorLayout.from_xml(child)
            elif child.tag == XML_MONSTER_LIST and data['monsters'] is None:
                monsters = []
                for monster in child:
                    monsters.append(MappaMonster.from_xml(monster))
                data['monsters'] = monsters
            elif child.tag == XML_TRAP_LIST and data['traps'] is None:
                data['traps'] = MappaTrapList.from_xml(child)
            elif child.tag == XML_ITEM_LIST and child.get(XML_ITEM_LIST__TYPE) == XML_ITEM_LIST__TYPE__FLOOR and data['floor_items'] is None:
                data['floor_items'] = MappaItemList.from_xml(child)
            elif child.tag == XML_ITEM_LIST and child.get(XML_ITEM_LIST__TYPE) == XML_ITEM_LIST__TYPE__SHOP and data['shop_items'] is None:
                data['shop_items'] = MappaItemList.from_xml(child)
            elif child.tag == XML_ITEM_LIST and child.get(XML_ITEM_LIST__TYPE) == XML_ITEM_LIST__TYPE__MONSTER_HOUSE and data['monster_house_items'] is None:
                data['monster_house_items'] = MappaItemList.from_xml(child)
            elif child.tag == XML_ITEM_LIST and child.get(XML_ITEM_LIST__TYPE) == XML_ITEM_LIST__TYPE__BURIED and data['buried_items'] is None:
                data['buried_items'] = MappaItemList.from_xml(child)
            elif child.tag == XML_ITEM_LIST and child.get(XML_ITEM_LIST__TYPE) == XML_ITEM_LIST__TYPE__UNK1 and data['unk_items1'] is None:
                data['unk_items1'] = MappaItemList.from_xml(child)
            elif child.tag == XML_ITEM_LIST and child.get(XML_ITEM_LIST__TYPE) == XML_ITEM_LIST__TYPE__UNK2 and data['unk_items2'] is None:
                data['unk_items2'] = MappaItemList.from_xml(child)
            else:
                raise XmlValidateError(f(_('Floor parsing: Unexpected {child.tag}')))

        for k, v in data.items():
            if v is None:
                raise XmlValidateError(f(_('Missing {k} for Floor data.')))

        return cls(**data)
예제 #27
0
    def load_tree_items(self, item_store: TreeStore, root_node):
        root = item_store.append(root_node, [
            'skytemple-e-mapbg-symbolic', MAPBG_NAME, self, MainController, 0, False, '', True
        ])
        self._sub_nodes = {
            'S': item_store.append(root, [
                'skytemple-folder-symbolic', _('S - System'), self, FolderController, 'S - System', False, '', True
            ]),
            'T': item_store.append(root, [
                'skytemple-folder-symbolic', _('T - Town'), self, FolderController, 'T - Town', False, '', True
            ]),
            'D': item_store.append(root, [
                'skytemple-folder-symbolic', _('D - Dungeon'), self, FolderController, 'D - Dungeon', False, '', True
            ]),
            'G': item_store.append(root, [
                'skytemple-folder-symbolic', _('G - Guild'), self, FolderController, 'G - Guild', False, '', True
            ]),
            'H': item_store.append(root, [
                'skytemple-folder-symbolic', _('H - Habitat'), self, FolderController, 'H - Habitat', False, '', True
            ]),
            'P': item_store.append(root, [
                'skytemple-folder-symbolic', _('P - Places'), self, FolderController, 'P - Places', False, '', True
            ]),
            'V': item_store.append(root, [
                'skytemple-folder-symbolic', _('V - Visual'), self, FolderController, 'V - Visual', False, '', True
            ]),
            'W': item_store.append(root, [
                'skytemple-folder-symbolic', _('W - Weather'), self, FolderController, 'W - Weather', False, '', True
            ])
        }
        # Other
        self._other_node = item_store.append(root, [
            'skytemple-folder-symbolic', _('Others'), self, FolderController, None, False, '', True
        ])
        self._tree_model = item_store
        self._tree_level_iter = []
        for i, level in enumerate(self.bgs.level):
            parent = self._other_node
            if level.bma_name[0] in self._sub_nodes.keys():
                parent = self._sub_nodes[level.bma_name[0]]
            self._tree_level_iter.append(
                item_store.append(parent, [
                    'skytemple-e-mapbg-symbolic', level.bma_name, self,  BgController, i, False, '', True
                ])
            )

        recursive_generate_item_store_row_label(self._tree_model[root])
예제 #28
0
    def on_import_clicked(self, w: Gtk.MenuToolButton):
        md = SkyTempleMessageDialog(
            MainController.window(),
            Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO,
            Gtk.ButtonsType.OK,
            _("To import, select a folder containing all the files that were created when exporting the font.\n"
              "IMPORTANT: All image files must be indexed PNGs!\n"
              "For banner fonts, all images must have the same palette."),
            title=_("Import Font")
        )
        md.run()
        md.destroy()
        dialog = Gtk.FileChooserNative.new(
            _("Import font from folder..."),
            MainController.window(),
            Gtk.FileChooserAction.SELECT_FOLDER,
            None, None
        )

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()
        
        if response == Gtk.ResponseType.ACCEPT:
            try:
                xml = ElementTree().parse(os.path.join(fn, f'char_tables.xml'))
                tables = dict()
                for i in range(256):
                    path = os.path.join(fn, f'table-{i}.png')
                    if os.path.exists(path):
                        tables[i] = Image.open(path, 'r')

                assert self.font
                self.font.import_from_xml(xml, tables)
                self.module.mark_font_as_modified(self.spec)
            except Exception as err:
                display_error(
                    sys.exc_info(),
                    str(err),
                    _("Error importing font.")
                )
            self._init_font()
예제 #29
0
def handle_exception(exc_type, exc_value, exc_traceback):
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return

    logger.critical("Uncaught exception",
                    exc_info=(exc_type, exc_value, exc_traceback))
    try:
        # noinspection PyUnusedLocal
        traceback_str = ''.join(
            traceback.format_exception(exc_type, exc_value, exc_traceback))
        GLib.idle_add(lambda: display_error(
            (exc_type, exc_value, exc_traceback),
            f(
                _("An uncaught exception occurred! This shouldn't happen, please report it!\n\n"
                  "{traceback_str}")),
            _("SkyTemple - Uncaught error!"),
            log=False))
    except:
        pass
예제 #30
0
 def desc_fixed_floor_monster(monster_id,
                              enemy_settings,
                              monster_names,
                              enemy_settings_names,
                              short=False):
     if monster_id == 0:
         return _("Nothing")
     if short:
         return monster_names[monster_id]
     return monster_names[monster_id] + " (" + enemy_settings_names[
         enemy_settings] + ")"