コード例 #1
0
 def from_xml(cls, ele: Element) -> 'XmlSerializable':
     validate_xml_tag(ele, XML_ITEM_LIST)
     categories = {}
     items = {}
     for child in ele:
         if child.tag == XML_CATEGORY:
             validate_xml_attribs(
                 child, [XML_CATEGORY__NAME, XML_CATEGORY__WEIGHT])
             name = child.get(XML_CATEGORY__NAME)
             if not hasattr(MappaItemCategory, name):
                 raise XmlValidateError(f"Unknown item category {name}.")
             weight_str = child.get(XML_CATEGORY__WEIGHT)
             weight = int(
                 weight_str) if weight_str != 'GUARANTEED' else GUARANTEED
             categories[getattr(MappaItemCategory, name)] = weight
         elif child.tag == XML_ITEM:
             validate_xml_attribs(child, [XML_ITEM__ID, XML_ITEM__WEIGHT])
             weight_str = child.get(XML_ITEM__WEIGHT)
             weight = int(
                 weight_str) if weight_str != 'GUARANTEED' else GUARANTEED
             items[Pmd2DungeonItem(int(child.get(XML_ITEM__ID)),
                                   '???')] = weight
         else:
             raise XmlValidateError(
                 f"Unexpected sub-node for {XML_ITEM_LIST}: {child.tag}")
     return cls(categories, items)
コード例 #2
0
 def from_xml(cls, xml: Element, value_to_update: List[Optional[KaoImage]]):
     if len(value_to_update) != len(xml):
         raise XmlValidateError(
             f"Incompatible XML. The number of portraits don't match with the expected value of {len(value_to_update)}"
         )
     for i, xml_portrait in enumerate(xml):
         validate_xml_tag(xml_portrait, XML_PORTRAITS_PORTRAIT)
         if len(xml_portrait) > 0:
             image = None
             palette = None
             for xml_image_or_pal in xml_portrait:
                 if xml_image_or_pal.tag == XML_PORTRAITS_PORTRAIT__IMAGE:
                     image = xml_image_or_pal.text
                 elif xml_image_or_pal.tag == XML_PORTRAITS_PORTRAIT__PALETTE:
                     palette = xml_image_or_pal.text
             if image is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_PORTRAITS_PORTRAIT__IMAGE}' missing for a portrait."
                 )
             if palette is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_PORTRAITS_PORTRAIT__PALETTE}' missing for a portrait."
                 )
             try:
                 value_to_update[i] = KaoImage(
                     b64decode(palette.encode('ascii')) +
                     b64decode(image.encode('ascii')), 0)
             except Exception as err:
                 raise XmlValidateError(
                     f"Invalid XML. The portrait data of one of the portraits is invalid: {err}"
                 ) from err
         else:
             value_to_update[i] = None
コード例 #3
0
 def from_xml(cls, xml: Element, value_to_update: MoveLearnset):
     for xml_type in xml:
         if xml_type.tag == XML_MOVESET_LEVEL_UP:
             new_level_up = []
             for xml_learn in xml_type:
                 validate_xml_tag(xml_learn, XML_MOVESET_LEVEL_UP__LEARN)
                 level = None
                 move_id = None
                 for xml_level_or_move in xml_learn:
                     if xml_level_or_move.tag == XML_MOVESET_LEVEL_UP__LEVEL:
                         level = int(xml_level_or_move.text)
                     elif xml_level_or_move.tag == XML_MOVESET__MOVE_ID:
                         move_id = int(xml_level_or_move.text)
                 if level is None:
                     raise XmlValidateError(
                         f"Invalid XML. '{XML_MOVESET_LEVEL_UP__LEVEL}' missing for a level up moveset entry."
                     )
                 if move_id is None:
                     raise XmlValidateError(
                         f"Invalid XML. '{XML_MOVESET__MOVE_ID}' missing for a level up moveset entry."
                     )
                 new_level_up.append(LevelUpMove(move_id, level))
             value_to_update.level_up_moves = new_level_up
         elif xml_type.tag == XML_MOVESET_EGG:
             new_eggs = []
             for xml_move_id in xml_type:
                 validate_xml_tag(xml_move_id, XML_MOVESET__MOVE_ID)
                 new_eggs.append(int(xml_move_id.text))
             value_to_update.egg_moves = new_eggs
         elif xml_type.tag == XML_MOVESET_HM_TM:
             new_hm_tm = []
             for xml_move_id in xml_type:
                 validate_xml_tag(xml_move_id, XML_MOVESET__MOVE_ID)
                 new_hm_tm.append(int(xml_move_id.text))
             value_to_update.tm_hm_moves = new_hm_tm
コード例 #4
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)
コード例 #5
0
ファイル: trap_list.py プロジェクト: riiswa/skytemple-files
 def from_xml(cls, ele: Element) -> 'XmlSerializable':
     validate_xml_tag(ele, XML_TRAP_LIST)
     weights = {}
     for child in ele:
         validate_xml_tag(child, XML_TRAP)
         validate_xml_attribs(child, [XML_TRAP__NAME, XML_TRAP__WEIGHT])
         name = child.get(XML_TRAP__NAME)
         if not hasattr(MappaTrapType, name):
             raise XmlValidateError(f(_("Unknown trap {name}.")))
         weights[getattr(MappaTrapType, name)] = int(child.get(XML_TRAP__WEIGHT))
     try:
         return cls(weights)
     except ValueError as ex:
         raise XmlValidateError(_("Trap lists need an entry for all of the 25 traps")) from ex
コード例 #6
0
 def from_xml(cls, xml: Element, value_to_update: Dict[str, Tuple[str, str]]):
     for xml_lang in xml:
         if xml_lang.tag in value_to_update.keys():
             name = None
             category = None
             for xml_sub in xml_lang:
                 if xml_sub.tag == XML_STRINGS__NAME:
                     name = xml_sub.text
                 if xml_sub.tag == XML_STRINGS__CATEGORY:
                     category = xml_sub.text
             if name is None:
                 raise XmlValidateError(f"Invalid XML. '{XML_STRINGS__NAME}' missing for language {xml_lang.tag}.")
             if category is None:
                 raise XmlValidateError(f"Invalid XML. '{XML_STRINGS__CATEGORY}' missing for language {xml_lang.tag}.")
             value_to_update[xml_lang.tag] = (name, category)
コード例 #7
0
ファイル: model.py プロジェクト: riiswa/skytemple-files
 def import_from_xml(self, xml: Element, tables: Dict[int, Image.Image]):
     self.entries = []
     self.unknown = 0
     pal_table = 256
     validate_xml_tag(xml, XML_FONT)
     for child in xml:
         if child.tag == XML_TABLE:
             validate_xml_attribs(child, [XML_TABLE__ID])
             t = int(child.get(XML_TABLE__ID))
             if t in FONT_VALID_TABLES and t in tables:
                 if pal_table > t:
                     pal_table = t
                     self.set_palette_raw(
                         memoryview(tables[t].palette.palette))
                 for char in child:
                     validate_xml_tag(char, XML_CHAR)
                     validate_xml_attribs(char,
                                          [XML_CHAR__ID, XML_CHAR__WIDTH])
                     charid = int(char.get(XML_CHAR__ID))
                     width = int(char.get(XML_CHAR__WIDTH))
                     x = (charid % 16) * BANNER_FONT_SIZE
                     y = (charid // 16) * BANNER_FONT_SIZE
                     self.entries.append(
                         BannerFontEntry.from_pil(
                             tables[t].crop(box=[
                                 x, y, x + BANNER_FONT_SIZE, y +
                                 BANNER_FONT_SIZE
                             ]), charid, t, width))
         elif child.tag == XML_HEADER:
             validate_xml_attribs(child, [XML_HEADER__UNKNOWN])
             self.unknown = int(child.get(XML_HEADER__UNKNOWN))
         else:
             raise XmlValidateError(
                 f(_('Font parsing: Unexpected {child.tag}')))
コード例 #8
0
def mappa_floor_xml_import(xml: Element, floor: MappaFloor):
    """Imports all data available in the mappa floor XML into the given model."""
    for child in xml:
        if child.tag == XML_FLOOR_LAYOUT:
            floor_number_before = floor.layout.floor_number
            floor.layout = MappaFloorLayout.from_xml(child)
            floor.layout.floor_number = floor_number_before
        elif child.tag == XML_MONSTER_LIST:
            monsters = []
            for monster in child:
                monsters.append(MappaMonster.from_xml(monster))
            floor.monsters = monsters
        elif child.tag == XML_TRAP_LIST:
            floor.traps = MappaTrapList.from_xml(child)
        elif child.tag == XML_ITEM_LIST and child.get(
                XML_ITEM_LIST__TYPE) == XML_ITEM_LIST__TYPE__FLOOR:
            floor.floor_items = MappaItemList.from_xml(child)
        elif child.tag == XML_ITEM_LIST and child.get(
                XML_ITEM_LIST__TYPE) == XML_ITEM_LIST__TYPE__SHOP:
            floor.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:
            floor.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:
            floor.buried_items = MappaItemList.from_xml(child)
        elif child.tag == XML_ITEM_LIST and child.get(
                XML_ITEM_LIST__TYPE) == XML_ITEM_LIST__TYPE__UNK1:
            floor.unk_items1 = MappaItemList.from_xml(child)
        elif child.tag == XML_ITEM_LIST and child.get(
                XML_ITEM_LIST__TYPE) == XML_ITEM_LIST__TYPE__UNK2:
            floor.unk_items2 = MappaItemList.from_xml(child)
        else:
            raise XmlValidateError(
                f(_('Floor parsing: Unexpected {child.tag}')))
コード例 #9
0
 def from_xml(cls, xml: Element, value_to_update: LevelBinEntry):
     if len(xml) != 100:
         raise XmlValidateError(
             "Invalid XML. StatsGrowth must have exactly 100 levels.")
     for i, xml_level in enumerate(xml):
         validate_xml_tag(xml_level, XML_STATS_GROWTH_LEVEL)
         required_exp = None
         hp = None
         attack = None
         sp_attack = None
         defense = None
         sp_defense = None
         for xml_stat in xml_level:
             if xml_stat.tag == XML_STATS_GROWTH_LEVEL__REQUIRED_EXP:
                 required_exp = int(xml_stat.text)
             elif xml_stat.tag == XML_STATS_GROWTH_LEVEL__HP:
                 hp = int(xml_stat.text)
             elif xml_stat.tag == XML_STATS_GROWTH_LEVEL__ATTACK:
                 attack = int(xml_stat.text)
             elif xml_stat.tag == XML_STATS_GROWTH_LEVEL__SP_ATTACK:
                 sp_attack = int(xml_stat.text)
             elif xml_stat.tag == XML_STATS_GROWTH_LEVEL__DEFENSE:
                 defense = int(xml_stat.text)
             elif xml_stat.tag == XML_STATS_GROWTH_LEVEL__SP_DEFENSE:
                 sp_defense = int(xml_stat.text)
         if required_exp is None:
             raise XmlValidateError(
                 f"Invalid XML. '{XML_STATS_GROWTH_LEVEL__REQUIRED_EXP}' missing for a stats growth level entry."
             )
         if hp is None:
             raise XmlValidateError(
                 f"Invalid XML. '{XML_STATS_GROWTH_LEVEL__HP}' missing for a stats growth level entry."
             )
         if attack is None:
             raise XmlValidateError(
                 f"Invalid XML. '{XML_STATS_GROWTH_LEVEL__ATTACK}' missing for a stats growth level entry."
             )
         if sp_attack is None:
             raise XmlValidateError(
                 f"Invalid XML. '{XML_STATS_GROWTH_LEVEL__SP_ATTACK}' missing for a stats growth level entry."
             )
         if defense is None:
             raise XmlValidateError(
                 f"Invalid XML. '{XML_STATS_GROWTH_LEVEL__DEFENSE}' missing for a stats growth level entry."
             )
         if sp_defense is None:
             raise XmlValidateError(
                 f"Invalid XML. '{XML_STATS_GROWTH_LEVEL__SP_DEFENSE}' missing for a stats growth level entry."
             )
         value_to_update.levels[i] = LevelEntry(required_exp, hp, attack,
                                                sp_attack, defense,
                                                sp_defense, 0)
コード例 #10
0
 def from_xml(cls, xml: Element, value_to_update: MdEntry):
     for sub_xml in xml:
         if sub_xml.tag in XML_GENENT__MAP__SIMPLE.keys():
             attr_name = XML_GENENT__MAP__SIMPLE[sub_xml.tag]
             if attr_name in XML_GENENT__MAP__ENUMS.keys():
                 # Enum
                 setattr(
                     value_to_update, attr_name,
                     XML_GENENT__MAP__ENUMS[attr_name](int(sub_xml.text)))
             else:
                 # Simple value
                 setattr(value_to_update, attr_name, int(sub_xml.text))
         if sub_xml.tag == XML_GENENT_EVOLUTION_REQ:
             pre_evo_index = None
             method = None
             param1 = None
             param2 = None
             for value_xml in sub_xml:
                 if value_xml.tag == XML_GENENT_EVOLUTION_REQ__PRE_EVO_INDEX:
                     pre_evo_index = int(value_xml.text)
                 elif value_xml.tag == XML_GENENT_EVOLUTION_REQ__EVO_METHOD:
                     method = EvolutionMethod(int(value_xml.text))
                 elif value_xml.tag == XML_GENENT_EVOLUTION_REQ__EVO_PRAM1:
                     param1 = int(value_xml.text)
                 elif value_xml.tag == XML_GENENT_EVOLUTION_REQ__EVO_PRAM2:
                     param2 = int(value_xml.text)
             if pre_evo_index is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_EVOLUTION_REQ__PRE_EVO_INDEX}' missing for a {XML_GENENT_EVOLUTION_REQ}."
                 )
             if method is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_EVOLUTION_REQ__EVO_METHOD}' missing for a {XML_GENENT_EVOLUTION_REQ}."
                 )
             if param1 is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_EVOLUTION_REQ__EVO_PRAM1}' missing for a {XML_GENENT_EVOLUTION_REQ}."
                 )
             if param2 is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_EVOLUTION_REQ__EVO_PRAM2}' missing for a {XML_GENENT_EVOLUTION_REQ}."
                 )
             value_to_update.pre_evo_index = pre_evo_index
             value_to_update.evo_method = method
             value_to_update.evo_param1 = param1
             value_to_update.evo_param2 = param2
         if sub_xml.tag == XML_GENENT_BASE_STATS:
             hp = None
             attack = None
             sp_attack = None
             defense = None
             sp_defense = None
             for value_xml in sub_xml:
                 if value_xml.tag == XML_GENENT_BASE_STATS__HP:
                     hp = int(value_xml.text)
                 elif value_xml.tag == XML_GENENT_BASE_STATS__ATTACK:
                     attack = int(value_xml.text)
                 elif value_xml.tag == XML_GENENT_BASE_STATS__SP_ATTACK:
                     sp_attack = int(value_xml.text)
                 elif value_xml.tag == XML_GENENT_BASE_STATS__DEFENSE:
                     defense = int(value_xml.text)
                 elif value_xml.tag == XML_GENENT_BASE_STATS__SP_DEFENSE:
                     sp_defense = int(value_xml.text)
             if hp is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BASE_STATS__HP}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if attack is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BASE_STATS__ATTACK}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if sp_attack is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BASE_STATS__SP_ATTACK}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if defense is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BASE_STATS__DEFENSE}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if sp_defense is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_STATS_GROWTH_LEVEL__SP_DEFENSE}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             value_to_update.base_hp = hp
             value_to_update.base_atk = attack
             value_to_update.base_sp_atk = sp_attack
             value_to_update.base_def = defense
             value_to_update.base_sp_def = sp_defense
         if sub_xml.tag == XML_GENENT_EXCLUSIVE_ITEMS:
             if len(sub_xml) != 4:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_EXCLUSIVE_ITEMS}' needs four item IDs."
                 )
             update = ('exclusive_item1', 'exclusive_item2',
                       'exclusive_item3', 'exclusive_item4')
             for item_xml, attr_name in zip(sub_xml, update):
                 validate_xml_tag(item_xml,
                                  XML_GENENT_EXCLUSIVE_ITEMS__ITEM_ID)
                 setattr(value_to_update, attr_name, int(item_xml.text))
         if sub_xml.tag == XML_GENENT_BITFLAG1:
             unk0 = None
             unk1 = None
             unk2 = None
             unk3 = None
             unk4 = None
             unk5 = None
             unk6 = None
             unk7 = None
             for value_xml in sub_xml:
                 if value_xml.tag == XML_GENENT_BITFLAG1__UNK0:
                     unk0 = bool(int(value_xml.text))
                 elif value_xml.tag == XML_GENENT_BITFLAG1__UNK1:
                     unk1 = bool(int(value_xml.text))
                 elif value_xml.tag == XML_GENENT_BITFLAG1__UNK2:
                     unk2 = bool(int(value_xml.text))
                 elif value_xml.tag == XML_GENENT_BITFLAG1__UNK3:
                     unk3 = bool(int(value_xml.text))
                 elif value_xml.tag == XML_GENENT_BITFLAG1__UNK4:
                     unk4 = bool(int(value_xml.text))
                 elif value_xml.tag == XML_GENENT_BITFLAG1__UNK5:
                     unk5 = bool(int(value_xml.text))
                 elif value_xml.tag == XML_GENENT_BITFLAG1__UNK6:
                     unk6 = bool(int(value_xml.text))
                 elif value_xml.tag == XML_GENENT_BITFLAG1__UNK7:
                     unk7 = bool(int(value_xml.text))
             if unk0 is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BITFLAG1__UNK0}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if unk1 is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BITFLAG1__UNK1}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if unk2 is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BITFLAG1__UNK2}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if unk3 is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BITFLAG1__UNK3}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if unk4 is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BITFLAG1__UNK4}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if unk5 is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BITFLAG1__UNK5}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if unk6 is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BITFLAG1__UNK6}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             if unk7 is None:
                 raise XmlValidateError(
                     f"Invalid XML. '{XML_GENENT_BITFLAG1__UNK7}' missing for a {XML_GENENT_BASE_STATS}."
                 )
             value_to_update.bitfield1_0 = unk0
             value_to_update.bitfield1_1 = unk1
             value_to_update.bitfield1_2 = unk2
             value_to_update.bitfield1_3 = unk3
             value_to_update.can_move = unk4
             value_to_update.bitfield1_5 = unk5
             value_to_update.can_evolve = unk6
             value_to_update.item_required_for_spawning = unk7
コード例 #11
0
    def from_xml(cls, ele: Element) -> 'MappaFloorLayout':
        validate_xml_tag(ele, XML_FLOOR_LAYOUT)
        generator_settings = None
        chances = None
        terrain_settings = None
        misc = None
        for child in ele:
            if child.tag == XML_FLOOR_LAYOUT__GENSET:
                generator_settings = child
            elif child.tag == XML_FLOOR_LAYOUT__CHANCES:
                chances = child
            elif child.tag == XML_FLOOR_LAYOUT__TERRAINSET:
                terrain_settings = child
            elif child.tag == XML_FLOOR_LAYOUT__MISCSET:
                misc = child
            else:
                raise XmlValidateError(
                    f(
                        _("Unexpected sub-node for {XML_FLOOR_LAYOUT}: {child.tag}"
                          )))

        if generator_settings is None:
            raise XmlValidateError(
                f(
                    _("{XML_FLOOR_LAYOUT__GENSET} missing for {XML_FLOOR_LAYOUT}."
                      )))

        if chances is None:
            raise XmlValidateError(
                f(
                    _("{XML_FLOOR_LAYOUT__CHANCES} missing for {XML_FLOOR_LAYOUT}."
                      )))

        if terrain_settings is None:
            raise XmlValidateError(
                f(
                    _("{XML_FLOOR_LAYOUT__TERRAINSET} missing for {XML_FLOOR_LAYOUT}."
                      )))

        if misc is None:
            raise XmlValidateError(
                f(
                    _("{XML_FLOOR_LAYOUT__MISCSET} missing for {XML_FLOOR_LAYOUT}."
                      )))

        validate_xml_attribs(ele, [
            XML_FLOOR_LAYOUT__STRUCTURE, XML_FLOOR_LAYOUT__TILESET,
            XML_FLOOR_LAYOUT__BGM, XML_FLOOR_LAYOUT__WEATHER,
            XML_FLOOR_LAYOUT__NUMBER, XML_FLOOR_LAYOUT__FIXED_FLOOR_ID,
            XML_FLOOR_LAYOUT__DARKNESS_LEVEL
        ])

        validate_xml_attribs(generator_settings, [
            XML_FLOOR_LAYOUT__GENSET__ROOM_DENSITY,
            XML_FLOOR_LAYOUT__GENSET__FLOOR_CONNECTIVITY,
            XML_FLOOR_LAYOUT__GENSET__INITIAL_ENEMY_DENSITY,
            XML_FLOOR_LAYOUT__GENSET__DEAD_ENDS,
            XML_FLOOR_LAYOUT__GENSET__ITEM_DENSITY,
            XML_FLOOR_LAYOUT__GENSET__TRAP_DENSITY,
            XML_FLOOR_LAYOUT__GENSET__EXTRA_HALLWAY_DENSITY,
            XML_FLOOR_LAYOUT__GENSET__BURIED_ITEM_DENSITY,
            XML_FLOOR_LAYOUT__GENSET__WATER_DENSITY,
            XML_FLOOR_LAYOUT__GENSET__MAX_COIN_AMOUNT
        ])

        validate_xml_attribs(chances, [
            XML_FLOOR_LAYOUT__CHANCES__SHOP,
            XML_FLOOR_LAYOUT__CHANCES__MONSTER_HOUSE,
            XML_FLOOR_LAYOUT__CHANCES__UNUSED,
            XML_FLOOR_LAYOUT__CHANCES__STICKY_ITEM,
            XML_FLOOR_LAYOUT__CHANCES__EMPTY_MONSTER_HOUSE,
            XML_FLOOR_LAYOUT__CHANCES__HIDDEN_STAIRS
        ])

        validate_xml_attribs(terrain_settings, [
            XML_FLOOR_LAYOUT__TERRAINSET__SECONDARY_USED,
            XML_FLOOR_LAYOUT__TERRAINSET__SECONDARY_TYPE,
            XML_FLOOR_LAYOUT__TERRAINSET__IMPERFECT_ROOMS,
            XML_FLOOR_LAYOUT__TERRAINSET__UNK1,
            XML_FLOOR_LAYOUT__TERRAINSET__UNK3,
            XML_FLOOR_LAYOUT__TERRAINSET__UNK4,
            XML_FLOOR_LAYOUT__TERRAINSET__UNK5,
            XML_FLOOR_LAYOUT__TERRAINSET__UNK6,
            XML_FLOOR_LAYOUT__TERRAINSET__UNK7
        ])

        validate_xml_attribs(misc, [
            XML_FLOOR_LAYOUT__MISCSET__UNKE,
            XML_FLOOR_LAYOUT__MISCSET__KECLEON_SHOP_ITEM_POSITIONS,
            XML_FLOOR_LAYOUT__MISCSET__UNK_HIDDEN_STAIRS,
            XML_FLOOR_LAYOUT__MISCSET__ENEMY_IQ,
            XML_FLOOR_LAYOUT__MISCSET__IQ_BOOSTER_BOOST
        ])

        if not hasattr(MappaFloorStructureType,
                       ele.get(XML_FLOOR_LAYOUT__STRUCTURE)):
            raise XmlValidateError(
                f(
                    _("Invalid structure type {ele.get(XML_FLOOR_LAYOUT__STRUCTURE)}"
                      )))
        structure = getattr(MappaFloorStructureType,
                            ele.get(XML_FLOOR_LAYOUT__STRUCTURE))

        if not hasattr(MappaFloorWeather, ele.get(XML_FLOOR_LAYOUT__WEATHER)):
            raise XmlValidateError(
                f(
                    _("Invalid weather type {ele.get(XML_FLOOR_LAYOUT__WEATHER)}"
                      )))
        weather = getattr(MappaFloorWeather,
                          ele.get(XML_FLOOR_LAYOUT__WEATHER))

        if not hasattr(MappaFloorDarknessLevel,
                       ele.get(XML_FLOOR_LAYOUT__DARKNESS_LEVEL)):
            raise XmlValidateError(
                f(
                    _("Invalid darkness level type {ele.get(XML_FLOOR_LAYOUT__DARKNESS_LEVEL)}"
                      )))
        darkness_level = getattr(MappaFloorDarknessLevel,
                                 ele.get(XML_FLOOR_LAYOUT__DARKNESS_LEVEL))

        return cls(
            structure=structure,
            room_density=i8_checked(
                int(
                    generator_settings.get(
                        XML_FLOOR_LAYOUT__GENSET__ROOM_DENSITY))),
            tileset_id=u8_checked(int(ele.get(XML_FLOOR_LAYOUT__TILESET))),
            music_id=u8_checked(int(ele.get(XML_FLOOR_LAYOUT__BGM))),
            weather=weather,
            floor_connectivity=u8_checked(
                int(
                    generator_settings.get(
                        XML_FLOOR_LAYOUT__GENSET__FLOOR_CONNECTIVITY))),
            initial_enemy_density=i8_checked(
                int(
                    generator_settings.get(
                        XML_FLOOR_LAYOUT__GENSET__INITIAL_ENEMY_DENSITY))),
            kecleon_shop_chance=u8_checked(
                int(chances.get(XML_FLOOR_LAYOUT__CHANCES__SHOP))),
            monster_house_chance=u8_checked(
                int(chances.get(XML_FLOOR_LAYOUT__CHANCES__MONSTER_HOUSE))),
            unusued_chance=u8_checked(
                int(chances.get(XML_FLOOR_LAYOUT__CHANCES__UNUSED))),
            sticky_item_chance=u8_checked(
                int(chances.get(XML_FLOOR_LAYOUT__CHANCES__STICKY_ITEM))),
            dead_ends=bool(
                int(generator_settings.get(
                    XML_FLOOR_LAYOUT__GENSET__DEAD_ENDS))),
            secondary_terrain=u8_checked(
                int(
                    terrain_settings.get(
                        XML_FLOOR_LAYOUT__TERRAINSET__SECONDARY_TYPE))),
            terrain_settings=MappaFloorTerrainSettings(
                has_secondary_terrain=bool(
                    int(
                        terrain_settings.get(
                            XML_FLOOR_LAYOUT__TERRAINSET__SECONDARY_USED))),
                unk1=bool(
                    int(
                        terrain_settings.get(
                            XML_FLOOR_LAYOUT__TERRAINSET__UNK1))),
                generate_imperfect_rooms=bool(
                    int(
                        terrain_settings.get(
                            XML_FLOOR_LAYOUT__TERRAINSET__IMPERFECT_ROOMS))),
                unk3=bool(
                    int(
                        terrain_settings.get(
                            XML_FLOOR_LAYOUT__TERRAINSET__UNK3))),
                unk4=bool(
                    int(
                        terrain_settings.get(
                            XML_FLOOR_LAYOUT__TERRAINSET__UNK4))),
                unk5=bool(
                    int(
                        terrain_settings.get(
                            XML_FLOOR_LAYOUT__TERRAINSET__UNK5))),
                unk6=bool(
                    int(
                        terrain_settings.get(
                            XML_FLOOR_LAYOUT__TERRAINSET__UNK6))),
                unk7=bool(
                    int(
                        terrain_settings.get(
                            XML_FLOOR_LAYOUT__TERRAINSET__UNK7))),
            ),
            unk_e=bool(int(misc.get(XML_FLOOR_LAYOUT__MISCSET__UNKE))),
            item_density=u8_checked(
                int(
                    generator_settings.get(
                        XML_FLOOR_LAYOUT__GENSET__ITEM_DENSITY))),
            trap_density=u8_checked(
                int(
                    generator_settings.get(
                        XML_FLOOR_LAYOUT__GENSET__TRAP_DENSITY))),
            floor_number=u8_checked(int(ele.get(XML_FLOOR_LAYOUT__NUMBER))),
            fixed_floor_id=u8_checked(
                int(ele.get(XML_FLOOR_LAYOUT__FIXED_FLOOR_ID))),
            extra_hallway_density=u8_checked(
                int(
                    generator_settings.get(
                        XML_FLOOR_LAYOUT__GENSET__EXTRA_HALLWAY_DENSITY))),
            buried_item_density=u8_checked(
                int(
                    generator_settings.get(
                        XML_FLOOR_LAYOUT__GENSET__BURIED_ITEM_DENSITY))),
            water_density=u8_checked(
                int(
                    generator_settings.get(
                        XML_FLOOR_LAYOUT__GENSET__WATER_DENSITY))),
            darkness_level=darkness_level,
            max_coin_amount=int(
                generator_settings.get(
                    XML_FLOOR_LAYOUT__GENSET__MAX_COIN_AMOUNT)),
            kecleon_shop_item_positions=u8_checked(
                int(
                    misc.get(
                        XML_FLOOR_LAYOUT__MISCSET__KECLEON_SHOP_ITEM_POSITIONS)
                )),
            empty_monster_house_chance=u8_checked(
                int(chances.get(
                    XML_FLOOR_LAYOUT__CHANCES__EMPTY_MONSTER_HOUSE))),
            unk_hidden_stairs=u8_checked(
                int(misc.get(XML_FLOOR_LAYOUT__MISCSET__UNK_HIDDEN_STAIRS))),
            hidden_stairs_spawn_chance=u8_checked(
                int(chances.get(XML_FLOOR_LAYOUT__CHANCES__HIDDEN_STAIRS))),
            enemy_iq=u16_checked(
                int(misc.get(XML_FLOOR_LAYOUT__MISCSET__ENEMY_IQ))),
            iq_booster_boost=i16_checked(
                int(misc.get(XML_FLOOR_LAYOUT__MISCSET__IQ_BOOSTER_BOOST))),
        )