Beispiel #1
0
def pull_propagated_buffs(source_buffable, destination_buffable, source_event):
    """ Pull all propagation buffs from a source to a target. Usually when creating a new buffable.

    :param Buffable source_buffable:
    :param Buffable destination_buffable:
    :param BuffEvent source_event:
    :rtype list[EventResult]
    :returns A list of event results containing all added, removed or propagated modifications
    """
    event_results = []
    for buff_id in source_buffable.active_buffs:
        buff_spec = buffspecs.get_buff_spec(buff_id)

        # If the destination contains any buff that targets my buffable type and is auto triggered, propagate
        if buff_spec.auto_triggers and destination_buffable.name in buff_spec.propagates_to:
            propagation_event = BuffPropagatedEvent(destination_buffable,
                                                    source_buffable, buff_id,
                                                    source_event)
            if handle_event_conditions(propagation_event,
                                       buff_spec.conditions):
                event_results.append(
                    add_buff(destination_buffable,
                             buff_spec,
                             propagation_event,
                             propagated=True))
    return event_results
Beispiel #2
0
def create_buff_modifications(buffable, buff_id, source_event, current_stack=1):
    """ Generates a list of buff modifications a buff will have to apply a buffable.
    Buff modifications are changes that can be applied to attributes as a whole.
    This list contains all changes that will update the buffable attributes.

    :param Buffable buffable:
    :param int buff_id:
    :param BuffEvent source_event:
    :param int current-stack:
    :rtype: list[BuffModification]
    """
    modifications = []
    buff_spec = buffspecs.get_buff_spec(buff_id)
    for modifier in buff_spec.modifiers:
        buff_modification = BuffModification(modifier, source_event, buff_id)

        # In case this derivates to another attribute we need to generate the derivation modifier
        # This modifier contains the calculated derivated value as a "flat add" modifier to the derivated attribute.
        if buff_spec.to_attribute:
            buff_modification.derivated_modifier = create_derivation_modifier(
                buffable.attributes, modifier, buff_spec.to_attribute
            )

        # If this buff propagates an derived attribute from a buffable to another, we need to calculate the
        # derived value based on the propagator source and not this buffable
        if buff_spec.propagates_to_attribute:
            source_buffable = get_propagation_source(source_event)
            buff_modification.derivated_modifier = create_derivation_modifier(
                source_buffable.attributes, modifier, buff_spec.propagates_to_attribute
            )

        buff_modification.stack_count = current_stack
        modifications.append(buff_modification)
    return modifications
Beispiel #3
0
def get_expired_buffs(buffable):
    """ Get a generator of all buffs that already have expired and removes them from the expiry list.

    :param Buffable buffable:
    :rtype: generator[BuffSpec]
    """
    expired_buffs = []
    while buffable.expiry_times and get_timestamp() >= _get_next_expiry_time(
            buffable):
        next_expiry_time, buff_id = buffable.expiry_times.pop(0)
        expired_buffs.append(buffspecs.get_buff_spec(buff_id))
    return expired_buffs
Beispiel #4
0
def remove_buff(buffable, buff_id):
    """ Removes a buff from a buffable

    :param Buffable buffable:
    :param int buff_id:
    """
    if buff_id in buffable.active_buffs:

        buff_spec = buffspecs.get_buff_spec(buff_id)
        if buffable.name in buff_spec.propagates_to:
            raise BuffException(BuffErrorCodes.REMOVING_BUFF_NOT_FROM_SOURCE)

        del buffable.active_buffs[buff_id]
        buff_spec = buffspecs.get_buff_spec(buff_id)
        delete_triggers(buff_id, buff_spec.get_triggers(),
                        buffable.activation_triggers)
        delete_triggers(buff_id, buff_spec.get_propagation_triggers(),
                        buffable.propagation_triggers)
        delete_triggers(buff_id, buff_spec.get_remove_triggers(),
                        buffable.deactivation_triggers)
        for target in get_propagation_target_buffables_including_self(
                buffable, buff_spec):
            remove_all_buff_modifications(target, buff_spec)
Beispiel #5
0
def _recalculate_derivated_values_from_attribute(buffable,
                                                 source_attribute_id):
    """ For existing derivated modifications on the buffable that are based on the source attribute ID,
    Recalculate the derivation modifiers by removing and re-appliyng them, updating the derivated values.

    :param Buffable buffable:
    :param int source_attribute_id:  The attribute that changed
    """

    # Get all modifications this attribute we are changing derivates to on this buffable
    for modification in _get_modifications_derived_by_attribute(
            buffable.attributes, source_attribute_id):

        # In case this modification is a derivation from a propagation, we need to calculate the derived value
        # with basis on the source buffable attributes
        buff_spec = buffspecs.get_buff_spec(modification.buff_id)
        buffable_propagator = buffable
        if buff_spec.propagates_to_attribute:
            buffable_propagator = get_propagation_source(
                modification.source_event)

        # Recalculate the derivated value
        new_derivated_modifier = create_derivation_modifier(
            buffable_propagator.attributes, modification.modifier,
            modification.derivated_modifier.attribute_id)

        # Keeping track of old derivated value because we will need to check it changed
        old_derivated_value = modification.derivated_modifier.value

        if old_derivated_value != new_derivated_modifier.value:

            # Undo the changes, just apply inversed
            _apply_modifier_to_attributes(buffable.attributes,
                                          modification.derivated_modifier,
                                          inverse=True)

            # Apply again with updated modifier
            _apply_modifier_to_attributes(buffable.attributes,
                                          new_derivated_modifier)

            # The final modifier of the derivated value is stored in derivated modifier, keeping the original intact
            modification.derivated_modifier = new_derivated_modifier

            # Since we changed an attribute, we need to chain derivation modifiers recalculation
            _recalculate_derivated_values_from_attribute(
                buffable, new_derivated_modifier.attribute_id)
Beispiel #6
0
def call_event(event):
    """ Calls an event and try to trigger any remaining triggers on the event buffable.

    :param BuffEvent event:
    :rtype EventResult
    :returns An event result with all added, removed and propagated modifications.
    """
    buffable = event.buffable
    result = EventResult()

    # Activation Triggers
    for triggered_buff_spec in get_buff_specs_triggered_by_event(
            event, buffable.activation_triggers):
        result.added_modifications = activate_buff(buffable,
                                                   triggered_buff_spec, event)

    # Deactivation Triggers
    for triggered_buff_spec in get_buff_specs_triggered_by_event(
            event, buffable.deactivation_triggers, condition_inverse=True):
        result.removed_modifications = inactivate_buff(buffable,
                                                       triggered_buff_spec,
                                                       event)

    # Propagation Triggers
    for triggered_buff_spec in get_buff_specs_triggered_by_event(
            event, buffable.propagation_triggers, propagation=True):
        for propagation_event in get_buff_propagation_events(
                buffable, triggered_buff_spec, event):
            buff_spec = buffspecs.get_buff_spec(propagation_event.buff_id)
            result.propagated_modifications[
                propagation_event.buffable.id].append(
                    add_buff(propagation_event.buffable,
                             buff_spec,
                             propagation_event,
                             propagated=True))
            # In case this buff spec has no propagation triggers and was just propagated by "AddBuffEvent"
            # means this buff wont be able to re-propagate ever again.
            if not buff_spec.propagation_triggers:
                delete_triggers(propagation_event.buff_id, ["AddBuffEvent"],
                                buffable.propagation_triggers)

    return result
Beispiel #7
0
def get_all_buff_modifications(buffable_attributes, buff_id):
    """ Gets all buff_modifications that buff is causing to attributes

    :param BuffableAttributes buffable_attributes:
    :param int buff_id:
    :rtype: list[BuffModification]
    """
    modifications = []
    buff = buffspecs.get_buff_spec(buff_id)
    for modifier in buff.modifiers:

        # The changed attribute we looking for can be the derivated attribute or the modifier itself
        # TODO: Make propagates_to_attribute works with to_attribute, could it be useful ?
        affected_attribute_id = buff.to_attribute or buff.propagates_to_attribute or modifier.attribute_id

        attr_data = buffable_attributes.attribute_data[affected_attribute_id]
        for buff_modification in attr_data.history.values():
            if buff_modification.buff_id == buff_id:
                modifications.append(buff_modification)
    return modifications
Beispiel #8
0
def get_buff_specs_triggered_by_event(event,
                                      possible_trigger_list,
                                      condition_inverse=False,
                                      propagation=False):
    """ Obtains all triggered buffs by a given possible trigger list and conditions.
    The buffs are triggered from the newest to the oldest, and its a very important aspect
    of this function is that is a generator - because this allow the code to process the older buffs only after the
    first one is processed to evaluate possible condition changes, allowing buff dependency out of the box.

    :param BuffEvent event:
    :param dict[str, list [ int ]] possible_trigger_list:  A dictionary of triggers to a list of buffs ids to trigger
    :param bool condition_inverse:
    :param bool propagation:
    :rtype: generator[BuffSpec]
    """
    for buff_id in reversed(possible_trigger_list[event.get_name()]):
        buff_spec = buffspecs.get_buff_spec(buff_id)
        conditions = buff_spec.conditions if not propagation else buff_spec.propagation_conditions
        if handle_event_conditions(event, conditions) is not condition_inverse:
            yield buff_spec
Beispiel #9
0
def get_propagated_targets_of_given_attribute(buffable, attribute_id):
    """ Obtain a lists of targets that are affected by a propagator attribute, for instance in a derivation.

    :param Buffable buffable:
    :param int attribute_id:
    :rtype: generator[Buffable]
    """
    for active_buff_id in buffable.active_buffs:
        buff_spec = buffspecs.get_buff_spec(active_buff_id)

        # If i have a buff that propagates to an attribute
        if buff_spec.propagates_to_attribute:
            targets = get_propagation_target_buffables(buffable, buff_spec)
            for source_modifier in buff_spec.modifiers:

                # In case the target attribute i propagate comes from this attribute that im changing
                if source_modifier.attribute_id == attribute_id:
                    for target in targets:

                        # Need to track that for that target because he will be affected
                        yield target