Esempio n. 1
0
def get_actions_for_names(names):
    """Returns a list of actions granted by the list of feature names. Will filter out any duplicates."""
    actions = []
    seen_action_names = set()

    for name in names:
        g_actions = get_actions_for_name(name)
        # in some cases, a very generic feature name (e.g. "Channel Divinity") will grant far more actions than we want
        # code snippet to determine this threshold:
        # bleps = [(name, len(actions), actions) for name, actions in discoverer.actions_granted_by_name.items()]
        # bleps = sorted(bleps, key=lambda blep: blep[1], reverse=True)
        if len(g_actions) > 20:
            continue

        for g_action in g_actions:
            if g_action.name in seen_action_names:
                continue
            seen_action_names.add(g_action.name)
            actions.append(
                Action(name=g_action.name,
                       uid=g_action.uid,
                       id=g_action.id,
                       type_id=g_action.type_id,
                       activation_type=g_action.activation_type))

    return actions
Esempio n. 2
0
        def add_action_from_gamedata(d_action, g_action):
            name = g_action.name
            if d_action.get(
                    'isCustomized') and d_action['name'] != g_action.name:
                # custom name handler: steal any parenthetical from the canonical name and tack it on to the custom name
                name = d_action['name']
                g_name_parenthetical = re.search(r'\(.+\)$', g_action.name)
                if g_name_parenthetical:
                    name = f"{name} {g_name_parenthetical.group(0)}"

            actions.append(
                Action(name=name,
                       uid=g_action.uid,
                       id=g_action.id,
                       type_id=g_action.type_id,
                       activation_type=g_action.activation_type,
                       snippet=html_to_md(d_action['snippet'])))
Esempio n. 3
0
    def get_actions(self):
        # iterate over features and look for actions with the same name, snippet is the feature description?
        actions = []
        g_actions_by_name = {a.name: a for a in compendium.actions}

        for f in self.character_data.get('features', []):
            if not f.get('enabled'):
                continue
            if f.get('removed'):
                continue
            name = f.get('name')
            if name not in g_actions_by_name:
                continue
            g_action = g_actions_by_name[name]
            actions.append(Action(
                name=g_action.name, uid=g_action.uid, id=g_action.id, type_id=g_action.type_id,
                activation_type=g_action.activation_type, snippet=f.get('description')
            ))

        return Actions(actions)
Esempio n. 4
0
    def get_actions(self):
        # iterate over features and look for actions with the same name
        actions = []
        g_actions_by_name = {a.name: a for a in compendium.actions}

        # v1: Z45:AH56
        # v2: C59:AC84
        if self.version >= (2, 0):
            feature_names = self.character_data.value_range("C59:AC84")
        else:
            feature_names = self.character_data.value_range("Z45:AH56")

        for name in feature_names:
            if name not in g_actions_by_name:
                continue
            g_action = g_actions_by_name[name]
            actions.append(
                Action(name=g_action.name,
                       uid=g_action.uid,
                       id=g_action.id,
                       type_id=g_action.type_id,
                       activation_type=g_action.activation_type))

        return Actions(actions)
Esempio n. 5
0
    def _process_actions(self):
        """
        :return: a pair (actions, action ids that granted valid actions (id, typeid))
        :rtype: tuple[Actions, set[tuple[str, str]]]
        """
        character_actions = self.character_data['actions']
        character_features = self.character_data['features']
        actions = []
        seen_feature_ids = set()  # set of tuples (typeid, id)
        action_ids_with_valid_actions = set()  # set of tuples (id, typeid)

        def add_action_from_gamedata(d_action, g_action):
            name = g_action.name
            if d_action.get(
                    'isCustomized') and d_action['name'] != g_action.name:
                # custom name handler: steal any parenthetical from the canonical name and tack it on to the custom name
                name = d_action['name']
                g_name_parenthetical = re.search(r'\(.+\)$', g_action.name)
                if g_name_parenthetical:
                    name = f"{name} {g_name_parenthetical.group(0)}"

            actions.append(
                Action(name=name,
                       uid=g_action.uid,
                       id=g_action.id,
                       type_id=g_action.type_id,
                       activation_type=g_action.activation_type,
                       snippet=html_to_md(d_action['snippet'])))

        # actions: save all, regardless of gamedata presence
        for d_action in character_actions:
            # Unarmed Strike - already in attacks
            if d_action['typeId'] == '1120657896' and d_action['id'] == '1':
                continue
            # display as attack override - fall back to attack system
            if d_action['isCustomized'] and d_action['displayAsAttack']:
                continue
            # racial feature affected by martial arts - fall back to attack system
            if (d_action['isMartialArts'] and d_action['displayAsAttack']
                    and int(d_action['componentTypeId'])
                    == gamedata.race.RaceFeature.type_id):
                continue

            # gamedata for limiteduse
            try:
                g_actions = compendium.lookup_actions_for_entity(
                    int(d_action['typeId']), int(d_action['id']))
            except (
                    TypeError, ValueError
            ):  # weird null typeid/uuid id action, maybe artificer infused item?
                continue

            # gamedata for component (parent feature)
            # data might have been entered for the parent feature instead
            try:
                parent_type_id, parent_id = int(
                    d_action['componentTypeId']), int(d_action['componentId'])
                parent_g_actions = compendium.lookup_actions_for_entity(
                    parent_type_id, parent_id)
                seen_feature_ids.add((parent_type_id, parent_id))
            except (TypeError, ValueError):
                parent_g_actions = []

            # if the lu itself has action data, save a reference to each gamedata action by UID
            for g_action in itertools.chain(g_actions, parent_g_actions):
                add_action_from_gamedata(d_action, g_action)

            # just save the action w/ its snippet if there is no gamedata
            if not (g_actions or parent_g_actions):
                activation_type = (enums.ActivationType(
                    d_action['activationType']) if d_action['activationType']
                                   is not None else None)
                actions.append(
                    Action(name=d_action['name'],
                           uid=None,
                           id=int(d_action['id']),
                           type_id=int(d_action['typeId']),
                           activation_type=activation_type,
                           snippet=html_to_md(d_action['snippet'])))
            else:
                # otherwise, either it or its parent successfully added something, so we can save its id
                # for attack filtering
                action_ids_with_valid_actions.add(
                    (str(d_action['id']), str(d_action['typeId'])))

        # features: save only if gamedata references them
        for d_feature in character_features:
            d_type_id, d_id = int(d_feature['typeId']), int(d_feature['id'])
            if (d_type_id, d_id) in seen_feature_ids:
                continue
            g_actions = compendium.lookup_actions_for_entity(d_type_id, d_id)
            for g_action in g_actions:
                add_action_from_gamedata(d_feature, g_action)

        return Actions(actions), action_ids_with_valid_actions