Example #1
0
def clean_monster_behavior(o: MonsterBehavior) -> MonsterBehavior:
    r = MonsterBehavior()
    r.monster_id = o.monster_id
    r.approved = o.approved
    for l in o.levels:
        r.levels.append(clean_level_behavior(l))
    return r
    def load_enemy_data(self, base_dir: str):
        card_files = []
        logger.warning('scanning enemy data for %d cards',
                       len(self.data.all_cards))
        for csc in self.data.all_cards:
            card_file = os.path.join(base_dir,
                                     '{}.textproto'.format(csc.monster_id))
            if not os.path.exists(card_file):
                continue
            card_files.append(card_file)

        logger.warning('loading enemy data for %d cards', len(card_files))
        count_not_approved = 0
        count_approved = 0
        for card_file in card_files:
            mbwo = enemy_skill_proto.load_from_file(card_file)
            mb = MonsterBehavior()
            mb.monster_id = mbwo.monster_id
            if mbwo.status == enemy_skills_pb2.MonsterBehaviorWithOverrides.NOT_APPROVED:
                mb.levels.extend(mbwo.levels)
                mb.approved = False
                count_not_approved += 1
            else:
                mb.levels.extend(mbwo.level_overrides)
                mb.approved = True
                count_approved += 1

            item = EnemyData.from_mb(mb)
            self.db.insert_or_update(item)

        logger.warning('done, %d approved %d not approved', count_approved,
                       count_not_approved)
def process_card(csc: CrossServerCard) -> MonsterBehavior:
    enemy_behavior = [x.na_skill for x in csc.enemy_behavior]
    card = csc.na_card.card
    if not enemy_behavior:
        return None

    inject_implicit_onetime(card, enemy_behavior)

    levels = enemy_skillset_processor.extract_levels(enemy_behavior)
    skill_listings = []
    used_actions = []
    for level in sorted(levels):
        try:
            skillset = enemy_skillset_processor.convert(card, enemy_behavior, level)
            if not skillset.has_actions():
                continue
            flattened = enemy_skill_proto.flatten_skillset(level, skillset)
            used_actions.extend(debug_utils.extract_used_skills(skillset))
            skill_listings.append(flattened)
        except Exception as ex:
            if 'No loop' not in str(ex):
                raise ex
            else:
                # TODO: some monsters have whacked out behavior (they aren't real monsters)
                # Should start ignoring those (e.g. pixel yuna).
                print('\tLoop detection failure for', card.monster_no, card.name)

    if not skill_listings:
        return None

    unused_actions = []
    for b in enemy_behavior:
        try:
            if issubclass(b.btype, ESAction) and b not in used_actions and b not in unused_actions:
                unused_actions.append(b)
        except:
            print('oops')

    # TODO: add unused actions and store them

    result = MonsterBehavior()
    result.monster_id = csc.monster_id
    result.levels.extend(skill_listings)

    return result
Example #4
0
def process_card(csc: CrossServerCard) -> MonsterBehavior:
    enemy_behavior = [x.na_skill for x in csc.enemy_behavior]
    card = csc.na_card.card
    if not enemy_behavior:
        return None

    levels = enemy_skillset_processor.extract_levels(enemy_behavior)
    skill_listings = []  # type: List[LevelBehavior]
    seen_level_behavior = set()  # type: Set[str]
    used_actions = []  # type: List[ESInstance]
    for level in sorted(levels):
        try:
            skillset = enemy_skillset_processor.convert(
                card, enemy_behavior, level)
            if not skillset.has_actions():
                continue
            flattened = enemy_skill_proto.flatten_skillset(level, skillset)

            # Check if we've already seen this level behavior; zero out the level and stick it
            # in a set containing all the levels we've seen. We want the behavior set at the
            # lowest possible level.
            zerod_flattened = LevelBehavior()
            zerod_flattened.CopyFrom(flattened)
            zerod_flattened.level = 0
            zerod_value = zerod_flattened.SerializeToString()
            if zerod_value in seen_level_behavior:
                continue
            else:
                seen_level_behavior.add(zerod_value)

            used_actions.extend(debug_utils.extract_used_skills(skillset))
            skill_listings.append(flattened)
        except Exception as ex:
            if 'No loop' not in str(ex):
                raise ex
            else:
                # TODO: some monsters have whacked out behavior (they aren't real monsters)
                # Should start ignoring those (e.g. pixel yuna).
                print('\tLoop detection failure for', card.monster_no,
                      card.name)
                break
    if not skill_listings:
        return None

    unused_actions = []
    for b in enemy_behavior:
        try:
            is_action = isinstance(b.behavior, ESAction)
            is_used = b not in used_actions
            already_in_unused = b not in unused_actions
            is_death_action = isinstance(b.behavior, ESDeathAction)
            if is_action and is_used and already_in_unused and not is_death_action:
                unused_actions.append(b)
        except:
            print('oops')

    for level_behavior in skill_listings:
        add_unused(unused_actions, level_behavior)

    result = MonsterBehavior()
    result.monster_id = csc.monster_id
    result.levels.extend(skill_listings)

    return result
Example #5
0
def process_card(csc: CrossServerCard) -> MonsterBehavior:
    enemy_behavior = [x.na_skill for x in csc.enemy_behavior]

    # Apply conditional overrides
    cond_overrides = CONDITIONAL_OVERRIDES.get(csc.monster_id,
                                               []) + CONDITIONAL_OVERRIDES[0]
    uncond_overrides = UNCONDITIONAL_OVERRIDES.get(
        csc.monster_id, []) + UNCONDITIONAL_OVERRIDES[0]
    for eb in enemy_behavior:
        if eb.enemy_skill_id in cond_overrides:
            eb.behavior.conditional = True
        if eb.enemy_skill_id in uncond_overrides:
            eb.behavior.conditional = False

    card = csc.na_card.card
    if not enemy_behavior:
        return None

    # Override the NA increment and max counter from the JP version.
    # This can rarely be different, typically when a collab comes to NA/JP
    # in the first run, and then gets updated in JP later.
    # TODO: Possibly this should occur in the merged card
    # card.enemy_skill_max_counter = max(card.enemy_skill_max_counter,
    #                                    csc.jp_card.card.enemy_skill_max_counter)
    # card.enemy_skill_counter_increment = max(card.enemy_skill_counter_increment,
    #                                          csc.jp_card.card.enemy_skill_counter_increment)
    # TODO: That wasn't always correct; probably needs to use the value from whichever ES tree is selected
    card.enemy_skill_max_counter = csc.jp_card.card.enemy_skill_max_counter
    card.enemy_skill_counter_increment = csc.jp_card.card.enemy_skill_counter_increment

    levels = enemy_skillset_processor.extract_levels(enemy_behavior)
    long_loop = csc.monster_id in LONG_LOOP_MONSTERS

    skill_listings = []  # type: List[LevelBehavior]
    previous_level_behavior = ""
    used_actions = []  # type: List[ESInstance]
    for level in sorted(levels):
        try:
            skillset = enemy_skillset_processor.convert(
                card, enemy_behavior, level, long_loop)
            if not skillset.has_actions():
                continue

            skillset_extraction = (csc.monster_id %
                                   100000) in APPLY_SKILLSET_GROUPING
            flattened = enemy_skill_proto.flatten_skillset(
                level, skillset, skillset_extraction=skillset_extraction)

            # Check if we've already seen this level behavior; zero out the level and stick it
            # in a set containing all the levels we've seen. We want the behavior set at the
            # lowest possible level.
            #
            # However, some monsters have a weird alternating ES behavior (1/3/5 are the same,
            # 2/4/6 are the same) so to deal with that we only compare against the last seen.
            zerod_flattened = LevelBehavior()
            zerod_flattened.CopyFrom(flattened)
            zerod_flattened.level = 0
            zerod_value = zerod_flattened.SerializeToString()
            if zerod_value == previous_level_behavior:
                continue
            else:
                previous_level_behavior = zerod_value

            used_actions.extend(debug_utils.extract_used_skills(skillset))
            skill_listings.append(flattened)
        except Exception as ex:
            if 'No loop' not in str(ex):
                raise ex
            else:
                # TODO: some monsters have whacked out behavior (they aren't real monsters)
                # Should start ignoring those (e.g. pixel yuna).
                print('\tLoop detection failure for', card.monster_no,
                      card.name)
                break
    if not skill_listings:
        return None

    unused_actions = []
    for b in enemy_behavior:
        try:
            is_action = isinstance(b.behavior, ESAction)
            is_used = b not in used_actions
            already_in_unused = b not in unused_actions
            is_death_action = isinstance(b.behavior, ESDeathAction)
            if is_action and is_used and already_in_unused and not is_death_action:
                unused_actions.append(b)
        except:
            print('oops')

    for level_behavior in skill_listings:
        add_unused(unused_actions, level_behavior)

    result = MonsterBehavior()
    result.monster_id = csc.monster_id
    result.levels.extend(skill_listings)

    return result
Example #6
0
 def from_mb(o: MonsterBehavior, status: int) -> 'EnemyData':
     return EnemyData(enemy_id=o.monster_id,
                      status=status,
                      behavior=o.SerializeToString())
Example #7
0
def process_card(csc: CrossServerCard) -> MonsterBehavior:
    enemy_behavior = [x.na_skill for x in csc.enemy_behavior]
    card = csc.na_card.card
    if not enemy_behavior:
        return None

    # Override the NA increment and max counter from the JP version.
    # This can rarely be different, typically when a collab comes to NA/JP
    # in the first run, and then gets updated in JP later.
    # TODO: Possibly this should occur in the merged card
    card.enemy_skill_max_counter = max(
        card.enemy_skill_max_counter, csc.jp_card.card.enemy_skill_max_counter)
    card.enemy_skill_counter_increment = max(
        card.enemy_skill_counter_increment,
        csc.jp_card.card.enemy_skill_counter_increment)

    levels = enemy_skillset_processor.extract_levels(enemy_behavior)
    long_loop = csc.monster_id in LONG_LOOP_MONSTERS

    skill_listings = []  # type: List[LevelBehavior]
    seen_level_behavior = set()  # type: Set[str]
    used_actions = []  # type: List[ESInstance]
    for level in sorted(levels):
        try:
            skillset = enemy_skillset_processor.convert(
                card, enemy_behavior, level, long_loop)
            if not skillset.has_actions():
                continue
            flattened = enemy_skill_proto.flatten_skillset(level, skillset)

            # Check if we've already seen this level behavior; zero out the level and stick it
            # in a set containing all the levels we've seen. We want the behavior set at the
            # lowest possible level.
            zerod_flattened = LevelBehavior()
            zerod_flattened.CopyFrom(flattened)
            zerod_flattened.level = 0
            zerod_value = zerod_flattened.SerializeToString()
            if zerod_value in seen_level_behavior:
                continue
            else:
                seen_level_behavior.add(zerod_value)

            used_actions.extend(debug_utils.extract_used_skills(skillset))
            skill_listings.append(flattened)
        except Exception as ex:
            if 'No loop' not in str(ex):
                raise ex
            else:
                # TODO: some monsters have whacked out behavior (they aren't real monsters)
                # Should start ignoring those (e.g. pixel yuna).
                print('\tLoop detection failure for', card.monster_no,
                      card.name)
                break
    if not skill_listings:
        return None

    unused_actions = []
    for b in enemy_behavior:
        try:
            is_action = isinstance(b.behavior, ESAction)
            is_used = b not in used_actions
            already_in_unused = b not in unused_actions
            is_death_action = isinstance(b.behavior, ESDeathAction)
            if is_action and is_used and already_in_unused and not is_death_action:
                unused_actions.append(b)
        except:
            print('oops')

    for level_behavior in skill_listings:
        add_unused(unused_actions, level_behavior)

    result = MonsterBehavior()
    result.monster_id = csc.monster_id
    result.levels.extend(skill_listings)

    return result
Example #8
0
 def from_mb(o: MonsterBehavior) -> 'EnemyData':
     return EnemyData(enemy_id=o.monster_id, behavior=o.SerializeToString())