def kr_no_to_monster_id(kr_id: MonsterNo) -> MonsterId:
    if kr_id > 99999:
        sub_id = MonsterNo(kr_id % 100000)
        kr_id -= sub_id
        kr_id += _kr_no_to_monster_id(sub_id)
    else:
        kr_id = _kr_no_to_monster_id(kr_id)

    return MonsterId(kr_id)
def na_no_to_monster_id(na_id: MonsterNo) -> MonsterId:
    if na_id > 99999:
        sub_id = MonsterNo(na_id % 100000)
        na_id -= sub_id
        na_id += _na_no_to_monster_id(sub_id)
    else:
        na_id = _na_no_to_monster_id(na_id)

    return MonsterId(na_id)
Пример #3
0
def copy_media(args):
    base_dir = args.base_dir
    output_dir = args.output_dir

    jp_icon_input_dir = os.path.join(base_dir, 'jp', 'portrait', 'local')
    na_icon_input_dir = os.path.join(base_dir, 'na', 'portrait', 'local')

    jp_portrait_input_dir = os.path.join(base_dir, 'jp', 'full',
                                         'corrected_data')
    na_portrait_input_dir = os.path.join(base_dir, 'na', 'full',
                                         'corrected_data')

    hq_portrait_input_dir = os.path.join(base_dir, 'hq_images')
    animated_portrait_input_dir = os.path.join(base_dir, 'animated')

    icon_output_dir = os.path.join(output_dir, 'icons')
    portrait_output_dir = os.path.join(output_dir, 'portraits')
    hq_portrait_output_dir = os.path.join(output_dir, 'hq_portraits')
    animated_portrait_output_dir = os.path.join(output_dir,
                                                'animated_portraits')

    for jp_id in range(1, 9000):
        monster_id = jp_id
        monster_id_filled = str(monster_id).zfill(5)

        do_copy(jp_icon_input_dir, '{}.png'.format(monster_id),
                icon_output_dir, '{}.png'.format(monster_id_filled))

        do_copy(jp_portrait_input_dir, '{}.png'.format(monster_id),
                portrait_output_dir, '{}.png'.format(monster_id_filled))

        do_copy(hq_portrait_input_dir, '{}.png'.format(monster_id),
                hq_portrait_output_dir, '{}.png'.format(monster_id_filled))

        do_copy(animated_portrait_input_dir, '{}.mp4'.format(monster_id),
                animated_portrait_output_dir,
                '{}.mp4'.format(monster_id_filled))

        do_copy(animated_portrait_input_dir, '{}.gif'.format(monster_id),
                animated_portrait_output_dir,
                '{}.gif'.format(monster_id_filled))

    for na_id in range(1, 9000):
        monster_id = monster_id_mapping.na_no_to_monster_id(MonsterNo(na_id))
        monster_id_filled = str(monster_id).zfill(5)

        do_copy(na_icon_input_dir, '{}.png'.format(na_id), icon_output_dir,
                '{}.png'.format(monster_id_filled))

        do_copy(na_portrait_input_dir, '{}.png'.format(na_id),
                portrait_output_dir, '{}.png'.format(monster_id_filled))
Пример #4
0
    def __init__(self, raw: List[str]):
        _unflatten(raw, 57, 3, replace=True)
        _unflatten(raw, 58, 1, replace=True)

        self.monster_no = MonsterNo(int(raw[0]))
        self.name = raw[1]
        self.attr_id = AttrId(int(raw[2]))
        self.sub_attr_id = AttrId(int(raw[3]))
        self.is_ult = bool(raw[4])  # True if ultimate, False if normal evo
        self.type_1_id = TypeId(int(raw[5]))
        self.type_2_id = TypeId(int(raw[6]))
        self.rarity = int(raw[7])
        self.cost = int(raw[8])

        # Appears to be related to the size of the monster.
        # If 5, the monster always spawns alone. Needs more research.
        self.unknown_009 = int(raw[9])

        self.max_level = int(raw[10])
        self.feed_xp_per_level = int(raw[11]) // 4
        self.released_status = raw[12] == 100
        self.sell_gold_per_level = int(raw[13]) // 10

        self.min_hp = int(raw[14])
        self.max_hp = int(raw[15])
        self.hp_scale = float(raw[16])

        self.min_atk = int(raw[17])
        self.max_atk = int(raw[18])
        self.atk_scale = float(raw[19])

        self.min_rcv = int(raw[20])
        self.max_rcv = int(raw[21])
        self.rcv_scale = float(raw[22])

        self.xp_max = int(raw[23])
        self.xp_scale = float(raw[24])

        self.active_skill_id = SkillId(int(raw[25]))
        self.leader_skill_id = SkillId(int(raw[26]))

        # Enemy turn timer for normal dungeons, and techs where enemy_turns_alt is not populated.
        self.enemy_turns = int(raw[27])

        # Min = lvl 1 and Max = lvl 10
        self.enemy_hp_min = int(raw[28])
        self.enemy_hp_max = int(raw[29])
        self.enemy_hp_scale = float(raw[30])

        self.enemy_atk_min = int(raw[31])
        self.enemy_atk_max = int(raw[32])
        self.enemy_atk_scale = float(raw[33])

        self.enemy_def_min = int(raw[34])
        self.enemy_def_max = int(raw[35])
        self.enemy_def_scale = float(raw[36])

        self.enemy_max_level = int(raw[37])
        self.enemy_coins_per_level = int(raw[38]) // 2
        self.enemy_xp_per_level = int(raw[39]) // 2

        self.ancestor_id = MonsterNo(int(raw[40]))

        self.evo_mat_id_1 = MonsterNo(int(raw[41]))
        self.evo_mat_id_2 = MonsterNo(int(raw[42]))
        self.evo_mat_id_3 = MonsterNo(int(raw[43]))
        self.evo_mat_id_4 = MonsterNo(int(raw[44]))
        self.evo_mat_id_5 = MonsterNo(int(raw[45]))

        self.un_evo_mat_1 = MonsterNo(int(raw[46]))
        self.un_evo_mat_2 = MonsterNo(int(raw[47]))
        self.un_evo_mat_3 = MonsterNo(int(raw[48]))
        self.un_evo_mat_4 = MonsterNo(int(raw[49]))
        self.un_evo_mat_5 = MonsterNo(int(raw[50]))

        # When >0, the enemy turn timer for technical dungeons.
        self.enemy_turns_alt = int(raw[51])

        # Controls whether the monster uses the 'new' AI or the 'old' AI.
        # Monsters using the old  AI only have support up to some limit of ES values.
        # One main difference between is behavior during preempts; old-AI monsters will
        # attack if they cannot execute a preempt, new-AI monsters will skip to the next.
        # (needs verification).
        self.use_new_ai = bool(raw[52])

        # Each monster has an internal counter which starts at raw[53] and is decremented
        # each time a skill activates. If the counter is less than the action cost, it cannot
        # execute.
        #
        # Turn flow follows this order:
        # 1: pick action (possibly checking counter value)
        # 2: increment the counter up, capped at the max value
        # 3: decrement the counter based on the selected action value
        #
        # The starting and maximum value for the enemy skill action counter.
        self.enemy_skill_max_counter = int(raw[53])

        # The amount to increment the counter each turn.
        #
        # The vast majority of these are 0/1.
        # Deus Ex Machina has 2, Kanna has 7.
        self.enemy_skill_counter_increment = int(raw[54])

        # Boolean, unlikely to be anything useful, only populated for 495 and 111.
        self.unknown_055 = raw[55]

        # Unused
        self.unknown_056 = raw[56]

        self.enemy_skill_refs = []  # type: List[ESRef]
        es_data = list(map(int, raw[57]))
        for i in range(0, len(es_data) - 2, 3):
            self.enemy_skill_refs.append(
                ESRef(es_data[i], es_data[i + 1], es_data[i + 2]))

        self.awakenings = raw[58]  # type: List[int]
        self.super_awakenings = list(
            map(int, filter(str.strip, raw[59].split(','))))  # List[int]

        self.base_id = MonsterNo(int(raw[60]))  # ??
        self.group_id = raw[61]  # ??
        self.type_3_id = TypeId(int(raw[62]))

        self.sell_mp = int(raw[63])
        self.latent_on_feed = int(raw[64])
        self.collab_id = int(raw[65])

        # Bitmap with some random flag values, not sure what they all do.
        self.random_flags = int(raw[66])
        self.inheritable = bool(self.random_flags & 1)
        self.is_collab = bool(self.random_flags & 4)

        self.furigana = str(raw[67])  # JP data only?
        self.limit_mult = int(raw[68])

        # Number of the voice file, 1-indexed, 0 if no voice
        self.voice_id = int(raw[69])

        # Number of the orb skin unlocked, 1-indexed, 0 if no orb skin
        self.orb_skin_id = int(raw[70])

        self.other_fields = raw[71:]
Пример #5
0
def copy_media(args):
    base_dir = args.base_dir
    alt_base_dir = args.alt_base_dir
    output_dir = args.output_dir

    jp_icon_input_dir = os.path.join(base_dir, 'jp', 'portrait', 'local')
    na_icon_input_dir = os.path.join(base_dir, 'na', 'portrait', 'local')

    jp_portrait_input_dir = os.path.join(base_dir, 'jp', 'full',
                                         'corrected_data')
    na_portrait_input_dir = os.path.join(base_dir, 'na', 'full',
                                         'corrected_data')

    hq_portrait_input_dir = os.path.join(base_dir, 'hq_images')
    animated_portrait_input_dir = os.path.join(base_dir, 'animated')

    orb_skins_input_dir = os.path.join(alt_base_dir, 'orb_styles', 'extract',
                                       'jp')
    jp_voice_input_dir = os.path.join(alt_base_dir, 'voices', 'fixed', 'jp')
    na_voice_input_dir = os.path.join(alt_base_dir, 'voices', 'fixed', 'na')

    icon_output_dir = os.path.join(output_dir, 'icons')
    portrait_output_dir = os.path.join(output_dir, 'portraits')
    hq_portrait_output_dir = os.path.join(output_dir, 'hq_portraits')
    animated_portrait_output_dir = os.path.join(output_dir,
                                                'animated_portraits')
    orb_skins_output_dir = os.path.join(output_dir, 'orb_skins')
    jp_voice_output_dir = os.path.join(output_dir, 'voices', 'jp')
    na_voice_output_dir = os.path.join(output_dir, 'voices', 'na')

    for jp_id in range(1, 9000):
        monster_id = jp_id
        monster_id_filled = str(monster_id).zfill(5)

        do_copy(jp_icon_input_dir, '{}.png'.format(monster_id),
                icon_output_dir, '{}.png'.format(monster_id_filled))

        do_copy(jp_portrait_input_dir, '{}.png'.format(monster_id),
                portrait_output_dir, '{}.png'.format(monster_id_filled))

        do_copy(hq_portrait_input_dir, '{}.png'.format(monster_id),
                hq_portrait_output_dir, '{}.png'.format(monster_id_filled))

        do_copy(animated_portrait_input_dir, '{}.mp4'.format(monster_id),
                animated_portrait_output_dir,
                '{}.mp4'.format(monster_id_filled))

        do_copy(animated_portrait_input_dir, '{}.gif'.format(monster_id),
                animated_portrait_output_dir,
                '{}.gif'.format(monster_id_filled))

        do_copy(jp_voice_input_dir, '{}.wav'.format(monster_id),
                jp_voice_output_dir, '{}.wav'.format(monster_id_filled))

    for na_id in range(1, 9000):
        monster_id = monster_id_mapping.nakr_no_to_monster_id(MonsterNo(na_id))
        monster_id_filled = str(monster_id).zfill(5)

        do_copy(na_icon_input_dir, '{}.png'.format(na_id), icon_output_dir,
                '{}.png'.format(monster_id_filled))

        do_copy(na_portrait_input_dir, '{}.png'.format(na_id),
                portrait_output_dir, '{}.png'.format(monster_id_filled))

        do_copy(na_voice_input_dir, '{}.wav'.format(na_id),
                na_voice_output_dir, '{}.wav'.format(monster_id_filled))

    for file_name in os.listdir(orb_skins_input_dir):
        clean_file_name = file_name.lower().lstrip('block')
        do_copy(orb_skins_input_dir, file_name, orb_skins_output_dir,
                clean_file_name)
Пример #6
0
    def __init__(self, raw: List):
        _unflatten(raw, 57, 3)
        _unflatten(raw, 58, 1)

        self.monster_no = MonsterNo(raw[0])
        self.name: str = raw[1]
        self.attr_id = AttrId(raw[2])
        self.sub_attr_id = AttrId(raw[3])
        self.is_ult: bool = bool(
            raw[4])  # True if ultimate, False if normal evo
        self.type_1_id = TypeId(raw[5])
        self.type_2_id = TypeId(raw[6])
        self.rarity: int = raw[7]
        self.cost: int = raw[8]

        # Appears to be related to the size of the monster.
        # If 5, the monster always spawns alone. Needs more research.
        self.unknown_009: int = raw[9]

        self.max_level: int = raw[10]
        self.feed_xp_per_level = raw[11] / 4
        self.released_status = raw[12] == 100
        self.sell_gold_per_level = raw[13] / 10

        self.min_hp: int = raw[14]
        self.max_hp: int = raw[15]
        self.hp_scale = float(raw[16])

        self.min_atk: int = raw[17]
        self.max_atk: int = raw[18]
        self.atk_scale = float(raw[19])

        self.min_rcv: int = raw[20]
        self.max_rcv: int = raw[21]
        self.rcv_scale = float(raw[22])

        self.xp_max: int = raw[23]
        self.xp_scale = float(raw[24])

        self.active_skill_id = SkillId(raw[25])
        self.leader_skill_id = SkillId(raw[26])

        # Enemy turn timer for normal dungeons, and techs where enemy_turns_alt is not populated.
        self.enemy_turns: int = raw[27]

        # Min = lvl 1 and Max = lvl 10
        self.enemy_hp_min: int = raw[28]
        self.enemy_hp_max: int = raw[29]
        self.enemy_hp_scale = float(raw[30])

        self.enemy_atk_min: int = raw[31]
        self.enemy_atk_max: int = raw[32]
        self.enemy_atk_scale = float(raw[33])

        self.enemy_def_min: int = raw[34]
        self.enemy_def_max: int = raw[35]
        self.enemy_def_scale = float(raw[36])

        self.enemy_max_level: int = raw[37]
        self.enemy_coins_per_level = raw[38] / 2
        self.enemy_xp_per_level = raw[39] / 2

        self.ancestor_id = MonsterNo(raw[40])

        self.evo_mat_id_1 = MonsterNo(raw[41])
        self.evo_mat_id_2 = MonsterNo(raw[42])
        self.evo_mat_id_3 = MonsterNo(raw[43])
        self.evo_mat_id_4 = MonsterNo(raw[44])
        self.evo_mat_id_5 = MonsterNo(raw[45])

        self.un_evo_mat_1 = MonsterNo(raw[46])
        self.un_evo_mat_2 = MonsterNo(raw[47])
        self.un_evo_mat_3 = MonsterNo(raw[48])
        self.un_evo_mat_4 = MonsterNo(raw[49])
        self.un_evo_mat_5 = MonsterNo(raw[50])

        # When >0, the enemy turn timer for technical dungeons.
        self.enemy_turns_alt: int = raw[51]

        # Controls whether the monster uses the 'new' AI or the 'old' AI.
        # Monsters using the old  AI only have support up to some limit of ES values.
        # One main difference between is behavior during preempts; old-AI monsters will
        # attack if they cannot execute a preempt, new-AI monsters will skip to the next.
        # (needs verification).
        self.use_new_ai = bool(raw[52])

        # Each monster has an internal counter which starts at raw[53] and is decremented
        # each time a skill activates. If the counter is less than the action cost, it cannot
        # execute.
        #
        # Turn flow follows this order:
        # 1: pick action (possibly checking counter value)
        # 2: increment the counter up, capped at the max value
        # 3: decrement the counter based on the selected action value
        #
        # The starting and maximum value for the enemy skill action counter.
        self.enemy_skill_max_counter: int = raw[53]

        # The amount to increment the counter each turn.
        #
        # The vast majority of these are 0/1.
        # Deus Ex Machina has 2, Kanna has 7.
        self.enemy_skill_counter_increment: int = raw[54]

        # Boolean, unlikely to be anything useful, only populated for 495 (1) and 111 (1000).
        self.unknown_055: int = raw[55]

        # Unused
        self.unknown_056: Any = raw[56]

        self.enemy_skill_refs: List[ESRef] = []
        es_data: List[int] = raw[57]
        for i in range(0, len(es_data) - 2, 3):
            self.enemy_skill_refs.append(
                ESRef(es_data[i], es_data[i + 1], es_data[i + 2]))

        self.awakenings: List[int] = raw[58]
        self.super_awakenings: List[int] = list(
            map(int, filter(str.strip, raw[59].split(','))))

        self.base_id = MonsterNo(int(raw[60]))
        self.group_id: int = raw[61]
        self.type_3_id = TypeId(int(raw[62]))

        self.sell_mp: int = raw[63]
        self.latent_on_feed: int = raw[64]
        self.collab_id: int = raw[65]

        # Bitmap with some non-random flag values
        self.flags: int = raw[66]
        self.inheritable_flag = bool(self.flags & 1)
        self.take_assists_flag = bool(self.flags & 2)
        self.is_collab_flag = bool(self.flags & 4)
        self.unstackable_flag = bool(self.flags & 8)
        self.assist_only_flag = bool(self.flags & 16)
        self.latent_slot_unlock_flag = bool(self.flags & 32)

        # Composed with flags and other monster attributes
        self.inheritable = bool(self.inheritable_flag and self.active_skill_id)
        self.take_assists = bool(self.take_assists_flag
                                 and self.active_skill_id)
        self.is_stackable = bool(not self.unstackable_flag
                                 and self.type_1_id in [0, 12, 14])
        self.ownable = self.monster_no < 100000
        self.usable = bool(not self.assist_only_flag and self.ownable)

        self.search_strings: List[str] = raw[67].split('|')
        self.limit_mult: int = raw[68]

        # Number of the voice file, 1-indexed, 0 if no voice
        self.voice_id: int = raw[69]

        # Number of the orb skin unlocked, 1-indexed, 0 if no orb skin
        self.orb_skin_id: int = raw[70]

        # Seems like this could have multiple values.
        self.tags: str = raw[71]
        self.linked_monster_no: Optional[MonsterNo] = None  # No longer used
        if self.tags:
            if 'link:' in self.tags:
                self.linked_monster_no = MonsterNo(
                    int(self.tags[len('link:'):]))
            else:
                human_fix_logger.error('Unexpected tag value: %s', self.tags)

        # Remove this condition once it comes to NA
        self.ls_bitflag: int = raw[72] + (raw[73] << 32)

        self.other_fields: List = raw[74:]

        if self.other_fields:
            human_fix_logger.error('Unused monster values found.')