def _fix_error(self, dungeons: List[DungeonDefinition], e: DungeonValidatorError): mappa = self.module.get_mappa() if isinstance(e, DungeonTotalFloorCountInvalidError): dungeons[e.dungeon_id].number_floors_in_group = e.expected_floor_count_in_group elif isinstance(e, InvalidFloorListReferencedError) or isinstance(e, FloorReusedError): dungeons[e.dungeon_id].mappa_index = self.module.mappa_generate_and_insert_new_floor_list() dungeons[e.dungeon_id].start_after = u8(0) dungeons[e.dungeon_id].number_floors = u8(1) dungeons[e.dungeon_id].number_floors_in_group = u8(1) elif isinstance(e, InvalidFloorReferencedError): valid_floors = len(mappa.floor_lists[e.dungeon.mappa_index]) - e.dungeon.start_after if valid_floors > 0: dungeons[e.dungeon_id].number_floors = u8_checked(valid_floors) else: mappa.floor_lists[e.dungeon.mappa_index].append(self.module.mappa_generate_new_floor()) dungeons[e.dungeon_id].number_floors = u8(1) elif isinstance(e, DungeonMissingFloorError): # Special case for Regigigas Chamber if self._is_regigias_special_case(dungeons, e): # Remove additional floors mappa.floor_lists[e.dungeon.mappa_index] = [ f for i, f in enumerate(mappa.floor_lists[e.dungeon.mappa_index]) if i not in e.floors_in_mappa_not_referenced ] else: # Add additional floors # TODO: Raise error or warning if we can't fix it? It should really always be consecutive. if min(e.floors_in_mappa_not_referenced) == e.dungeon.start_after + e.dungeon.number_floors: if check_consecutive(e.floors_in_mappa_not_referenced): max_floor_id = max(e.floors_in_mappa_not_referenced) dungeons[e.dungeon_id].number_floors = u8_checked(max_floor_id - dungeons[e.dungeon_id].start_after + 1)
def _rebuild_stats(self): assert self._level_bin_entry is not None store: Gtk.ListStore = self.builder.get_object('stats_store') for row in store: level, exp, hp, atk, sp_atk, defense, sp_def = (int(x) for x in row) level_entry = self._level_bin_entry.levels[level - 1] level_entry.experience_required = i32(exp) level_entry.hp_growth = u16(hp) level_entry.attack_growth = u8(atk) level_entry.special_attack_growth = u8(sp_atk) level_entry.defense_growth = u8(defense) level_entry.special_defense_growth = u8(sp_def) self.queue_render_graph() self._mark_stats_as_modified()
def kind(self) -> Pmd2ScriptObject: kind_id = self.emu_thread.emu.memory.unsigned.read_short(self.pnt + 0x06) try: return self.rom_data.script_data.objects__by_id[kind_id] except KeyError: return Pmd2ScriptObject(u16(kind_id), u16(0), u16(0), u8(0), 'UNKNOWN')
def on_btn_add_clicked(self, *args): self._list_store.append([len(self._list.list), "NULL", 0, 0, 0, False]) self._list.list.append( Pmd2ScriptObject(id=u16(len(self._list.list)), unk1=u16(0), unk2=u16(0), unk3=u8(0), name="NULL")) self.module.mark_objects_as_modified()
def __init__(self, scriptdata: Pmd2ScriptData, object_id: u16, htibox_w: i16, hitbox_h: i16, pos: SsaPosition, script_id: i16, unk12: i16): try: self.object = scriptdata.objects__by_id[object_id] except KeyError: logger.warning(f"Unknown object id: {object_id}") self.object = Pmd2ScriptObject(object_id, u16(0), u16(0), u8(0), 'UNKNOWN') self.hitbox_w = htibox_w self.hitbox_h = hitbox_h self.pos = pos self.script_id = script_id self.unk12 = unk12
def list_from_mappa(cls, read: 'MappaBinReadContainer', pointer: int) -> List['MappaMonster']: monsters = [] while not cls._is_end_of_entries(read.data, pointer): monsters.append(MappaMonster( u8(read_u16(read.data, pointer + 0) // LEVEL_MULTIPLIER), read_u16(read.data, pointer + 2), read_u16(read.data, pointer + 4), read_u16(read.data, pointer + 6), )) pointer += 8 return monsters
def _save_td(self): self._dungeon_tilesets.clear() for row in self.builder.get_object('dungeon_tileset_store'): self._dungeon_tilesets.append( GroundTilesetMapping( row[1], row[2], u8(int(row[5])), u32(0), )) self.module.save_dungeon_tilesets(self._dungeon_tilesets)
def reset_bma(self, bma): if isinstance(bma, BmaProtocol): self.tiling_width = bma.tiling_width self.tiling_height = bma.tiling_height self.mappings: List[Sequence[int]] = [bma.layer0, bma.layer1] # type: ignore self.width_in_chunks = bma.map_width_chunks self.height_in_chunks = bma.map_height_chunks self.width_in_tiles: Optional[u8] = bma.map_width_camera self.height_in_tiles: Optional[u8] = bma.map_height_camera self.collision1 = bma.collision self.collision2 = bma.collision2 self.data_layer = bma.unknown_data_block else: self.tiling_width = u8(3) self.tiling_height = u8(3) self.mappings = [[], []] self.width_in_chunks = u8(1) self.height_in_chunks = u8(1) self.width_in_tiles = None self.height_in_tiles = None self.collision1 = None self.collision2 = None self.data_layer = None
def on_list_store_row_changed(self, store, path, l_iter): """Propagate changes to list store entries to the lists.""" if self._loading: return a_id, level, location_id, ent_icon, entid, location_name, ent_name = store[ path][:] a_id = int(a_id) self._species[a_id] = u16(int(entid)) self._levels[a_id] = u16(int(level)) self._locations[a_id] = u8(int(location_id)) logger.debug( f"Updated list entry {a_id}: {entid}, {level}, {location_id}") self.module.set_recruitment_list(self._species, self._levels, self._locations)
def _switch_table(self): cb_store: Gtk.ListStore = self.builder.get_object('table_store') cb: Gtk.ComboBoxText = self.builder.get_object('cb_table_select') if cb.get_active_iter() is not None: assert self.font is not None v: int = cb_store[cb.get_active_iter()][0] self.entries = self.font.get_entries_from_table(u8(v)) entry_tree: Gtk.TreeView = self.builder.get_object('entry_tree') store: Gtk.ListStore = entry_tree.get_model() store.clear() for e in self.entries: self._add_property_row(store, e) surface = self.tables[v].resize((self.tables[v].width*IMAGE_ZOOM, self.tables[v].height*IMAGE_ZOOM)) self.surface = pil_to_cairo_surface(surface.convert('RGBA')) self.builder.get_object('draw').queue_draw()
def on_btn_add_clicked(self, widget): dialog: Gtk.Dialog = self.builder.get_object('dialog_choose_char') self.builder.get_object('entry_char_id').set_text(str(0)) self.builder.get_object('entry_char_id').set_increments(1,1) self.builder.get_object('entry_char_id').set_range(0, 255) dialog.set_attached_to(MainController.window()) dialog.set_transient_for(MainController.window()) resp = dialog.run() dialog.hide() if resp == ResponseType.OK: cb_store: Gtk.ListStore = self.builder.get_object('table_store') cb: Gtk.ComboBoxText = self.builder.get_object('cb_table_select') v: int = cb_store[cb.get_active_iter()][0] char = int(self.builder.get_object('entry_char_id').get_text()) try: for e in self.entries: if e.get_properties()["char"] == char: raise ValueError(f(_("Character {char} already exists in the table!"))) assert self.font is not None entry = self.font.create_entry_for_table(u8(v)) entry.set_properties({"char": char}) self.entries.append(entry) entry_tree: Gtk.TreeView = self.builder.get_object('entry_tree') store: Gtk.ListStore = entry_tree.get_model() self._add_property_row(store, entry) self.module.mark_font_as_modified(self.spec) except Exception as err: display_error( sys.exc_info(), str(err), _("Error adding character.") )
def read_u8(data: ByteReadable, start: int = 0) -> u8: """Returns an unsigned 8-bit integer from the bytes-like object at the given position.""" return u8(data[start])
# You should have received a copy of the GNU General Public License # along with SkyTemple. If not, see <https://www.gnu.org/licenses/>. from enum import Enum from range_typed_integers import u8 class FontType(Enum): FONT_DAT = 0x00 FONT_SIR0 = 0x01 BANNER_FONT = 0x02 GRAPHIC_FONT = 0x03 FONT_DEFAULT_BPROW = u8(2) FONT_DEFAULT_CAT = u8(0x02) FONT_DEFAULT_PADDING = u8(0xFF) FONT_VALID_TABLES = [0x00, 0x30, 0x81, 0x82, 0x83, 0x84, 0x87, 0xFF] XML_FONT = "Font" XML_HEADER = "Header" XML_HEADER__UNKNOWN = "unknown" XML_TABLE = "Table" XML_TABLE__ID = "tableid" XML_CHAR = "Char" XML_CHAR__ID = "id" XML_CHAR__WIDTH = "width" XML_CHAR__BPROW = "bprow" XML_CHAR__CAT = "category"