Example #1
0
    def add_aura(self, aura):
        # Note: This order of applying, removing colliding and then returning might be problematic if cases are added to can_apply_aura.
        # At the moment mount behaviour depends on this order
        can_apply = self.can_apply_aura(aura)
        self.remove_colliding_effects(aura)
        if not can_apply:
            return

        aura.initialize_period_timestamps(
        )  # Initialize periodic spell timestamps on application

        AuraEffectHandler.handle_aura_effect_change(aura)
        aura.index = self.get_next_aura_index(aura)
        self.active_auras[aura.index] = aura

        if not aura.passive:
            self.write_aura_to_unit(aura)
            self.write_aura_flag_to_unit(aura)
            self.send_aura_duration(aura)

        # Aura application threat TODO handle threat elsewhere
        if aura.is_harmful() and aura.source_spell.generates_threat():
            self.unit_mgr.attack(aura.caster)

        self.unit_mgr.set_dirty()
Example #2
0
    def check_aura_procs(self,
                         involved_cast=None,
                         killed_unit=False,
                         damage_info=None,
                         is_melee_swing=False):
        is_receiver = (damage_info and damage_info.target is self.unit_mgr) or \
                      (involved_cast and involved_cast.spell_caster is not self.unit_mgr)

        # Always pass the second unit as the effect target. The handler will choose the target based on the spell.
        if damage_info:
            effect_target = damage_info.attacker if is_receiver else damage_info.target
        elif involved_cast:
            # All targets for the spell could be passed, but this would only matter for ProcFlags.SPELL_CAST
            # SPELL_CAST is only used by one deprecated spell which will have the correct target in initial_target.
            effect_target = involved_cast.spell_caster if is_receiver else involved_cast.initial_target
        else:
            effect_target = self.unit_mgr

        flag_cases = {
            ProcFlags.DEAL_COMBAT_DMG:
            not is_receiver and damage_info
            and damage_info.total_damage > 0,  # -> cast on target.
            ProcFlags.TAKE_COMBAT_DMG:
            is_receiver and damage_info and damage_info.total_damage > 0,
            ProcFlags.KILL:
            killed_unit,
            ProcFlags.HEARTBEAT:
            False,  # Heartbeat effects are handled in their respective places on update - ignore the flag here.
            ProcFlags.DODGE:
            is_receiver and damage_info
            and damage_info.proc_victim & ProcFlags.DODGE,
            ProcFlags.PARRY:
            is_receiver and damage_info
            and damage_info.proc_victim & ProcFlags.PARRY,
            ProcFlags.BLOCK:
            is_receiver and damage_info
            and damage_info.proc_victim & ProcFlags.BLOCK,
            ProcFlags.SWING:
            not is_receiver and is_melee_swing,
            ProcFlags.SPELL_CAST:
            not is_receiver and involved_cast,  # Only used by zzOLDMind Bomb.
            ProcFlags.SPELL_HIT:
            is_receiver and involved_cast,
        }
        for aura in list(self.active_auras.values()):
            flags = aura.source_spell.spell_entry.ProcFlags
            if not flags:
                continue

            for proc_flag, condition in flag_cases.items():
                if proc_flag & flags and condition and aura.proc_charges != 0:  # Proc charges are set to -1 for auras with no charges so check for 0.
                    # Remove charge before trigger to avoid infinite loops with procs.
                    aura.proc_charges -= 1
                    AuraEffectHandler.handle_aura_effect_change(aura,
                                                                effect_target,
                                                                is_proc=True)

                    if aura.proc_charges == 0:
                        self.remove_aura(aura)
Example #3
0
    def update(self, elapsed):
        if self.has_duration():
            self.duration -= int(elapsed * 1000)

        if not self.target:  # Auras that are only tied to effects - ie. persistent area auras
            return
        if self.is_periodic():
            AuraEffectHandler.handle_aura_effect_change(self)
Example #4
0
    def update(self, timestamp):
        if self.has_duration():
            self.spell_effect.update_effect_aura(timestamp)

        if self.is_periodic():
            AuraEffectHandler.handle_aura_effect_change(self, self.target)

        if self.source_spell.cast_state != SpellState.SPELL_STATE_ACTIVE:
            self.spell_effect.remove_old_periodic_effect_ticks()
Example #5
0
    def remove_aura(self, aura):
        # TODO check if aura can be removed (by player)
        AuraEffectHandler.handle_aura_effect_change(aura, True)
        self.active_auras.pop(aura.index)
        if aura.passive:
            return  # Passive auras aren't written to unit

        self.write_aura_to_unit(aura, clear=True)
        self.write_aura_flag_to_unit(aura, clear=True)
        self.unit_mgr.set_dirty()
Example #6
0
    def update(self, timestamp):
        if self.has_duration():
            self.spell_effect.update_effect_aura(timestamp)

        if self.is_periodic():
            AuraEffectHandler.handle_aura_effect_change(self, self.target)

        # Don't remove periodic ticks for channeled spells.
        # Channeled spells have special handling for applied auras because of targeting reasons.
        # See SpellManager::handle_spell_effect_update for more information.
        if self.source_spell.cast_state != SpellState.SPELL_STATE_ACTIVE:
            self.spell_effect.remove_old_periodic_effect_ticks()
Example #7
0
    def add_aura(self, aura):
        can_apply = self.can_apply_aura(
            aura) and self.remove_colliding_effects(aura)
        if not can_apply:
            return

        # Application threat and negative aura application interrupts.
        if aura.harmful:
            if aura.caster.object_type_mask & ObjectTypeFlags.TYPE_UNIT and \
                    aura.source_spell.generates_threat():
                # TODO Replace once threat is handled properly.
                self.unit_mgr.attack(aura.caster)

            self.check_aura_interrupts(negative_aura_applied=True)

        applied_similar_auras = self.get_similar_applied_auras(
            aura, accept_all_ranks=False, accept_all_sources=False)
        is_refresh = len(applied_similar_auras) > 0
        if is_refresh > 0:
            # Only one similar aura from the same source can be applied.
            # Lower ranks are removed by remove_colliding_effects.
            similar_aura = applied_similar_auras[0]

            if aura.can_stack and similar_aura.applied_stacks < similar_aura.max_stacks:
                similar_aura.applied_stacks += 1  # Add a stack if the aura isn't at max already

            similar_aura.spell_effect.start_aura_duration(
                overwrite=True)  # Refresh duration

            # Note that this aura will not be actually applied.
            # Index and stacks are copied for sending information and updating effect points.
            aura.applied_stacks = similar_aura.applied_stacks
            aura.index = similar_aura.index
        else:
            aura.index = self.get_next_aura_index(aura)
            self.active_auras[aura.index] = aura

        # Handle effects after possible stack increase/refresh to update stats properly.
        AuraEffectHandler.handle_aura_effect_change(aura, aura.target)

        # TODO Some aura applications appear twice in the combat log.
        # For example, the proc effect from frost armor appears twice.
        # Gouge seems to appear twice against players (tested in duels), but not against NPCs.
        if not aura.passive:
            if not is_refresh:
                self.write_aura_to_unit(aura)
                self.write_aura_flag_to_unit(aura)
            self.send_aura_duration(aura)
Example #8
0
    def remove_aura(self, aura, canceled=False):
        AuraEffectHandler.handle_aura_effect_change(aura,
                                                    aura.target,
                                                    remove=True)
        if not self.active_auras.pop(aura.index, None):
            return
        # Some area effect auras (paladin auras, tranq etc.) are tied to spell effects. Cancel cast on aura cancel, canceling the auras as well.
        self.unit_mgr.spell_manager.remove_cast(aura.source_spell,
                                                interrupted=canceled)

        # Some spells start cooldown on aura remove, handle that case here.
        if aura.source_spell.trigger_cooldown_on_aura_remove():
            self.unit_mgr.spell_manager.set_on_cooldown(
                aura.source_spell, start_locked_cooldown=True)

        self.write_aura_to_unit(aura, clear=True)
Example #9
0
    def add_aura(self, aura):
        can_apply = self.can_apply_aura(
            aura) and self.remove_colliding_effects(aura)
        if not can_apply:
            return

        # Application threat and negative aura application interrupts.
        if aura.harmful:
            # Add threat for non-player targets against unit casters.
            if aura.caster.object_type_mask & ObjectTypeFlags.TYPE_UNIT and \
                    self.unit_mgr.get_type_id() == ObjectTypeIds.ID_UNIT and aura.source_spell.generates_threat():
                # TODO: Threat calculation.
                self.unit_mgr.threat_manager.add_threat(aura.caster, 10)

            self.check_aura_interrupts(negative_aura_applied=True)

        applied_similar_auras = self.get_similar_applied_auras(
            aura, accept_all_ranks=False, accept_all_sources=False)
        is_refresh = len(applied_similar_auras) > 0
        if is_refresh > 0:
            # Only one similar aura from the same source can be applied.
            # Lower ranks are removed by remove_colliding_effects.
            similar_aura = applied_similar_auras[0]

            if aura.can_stack and similar_aura.applied_stacks < similar_aura.max_stacks:
                similar_aura.applied_stacks += 1  # Add a stack if the aura isn't at max already

            similar_aura.spell_effect.start_aura_duration(
                overwrite=True)  # Refresh duration

            # Note that this aura will not be actually applied.
            # Index and stacks are copied for sending information and updating effect points.
            aura.applied_stacks = similar_aura.applied_stacks
            aura.index = similar_aura.index
        else:
            aura.index = self.get_next_aura_index(aura)
            self.active_auras[aura.index] = aura

        # Handle effects after possible stack increase/refresh to update stats properly.
        AuraEffectHandler.handle_aura_effect_change(aura, aura.target)

        self.write_aura_to_unit(aura, is_refresh=is_refresh)
Example #10
0
                aura.spell_id)) > 0:
            if existing_auras[0].applied_stacks < existing_auras[0].max_stacks:
                existing_auras[
                    0].applied_stacks += 1  # Add a stack if the aura isn't at max already
            existing_auras[0].spell_effect.start_aura_duration(
                overwrite=True)  # Refresh duration

            # Note that this aura will not be actually applied. Index and stacks are copied for sending information and updating effect points.
            aura.applied_stacks = existing_auras[0].applied_stacks
            aura.index = existing_auras[0].index
        else:
            aura.index = self.get_next_aura_index(aura)
            self.active_auras[aura.index] = aura

        # Handle effects after possible stack increase to update stats properly
        AuraEffectHandler.handle_aura_effect_change(aura, aura.target)

        if not aura.passive:
            self.write_aura_to_unit(aura)
            self.write_aura_flag_to_unit(aura)
            self.send_aura_duration(aura)

        # Aura application threat TODO handle threat elsewhere
        if aura.harmful:
            if aura.source_spell.generates_threat():
                self.unit_mgr.attack(aura.caster)
            self.check_aura_interrupts(negative_aura_applied=True)

        self.unit_mgr.set_dirty()

    has_moved = False  # Set from SpellManager - TODO pass movement info from unit update instead