Example #1
0
    def test_get_cast_query_spells(self):
        #inputs
        spells = [WowSpell(spell_id=101), WowSpell(spell_id=102)]

        # run and test
        q = self.actor.get_cast_query(spells)
        assert q == "type='cast' and ability.id in (101,102)"
Example #2
0
    def test_get_buff_query_spells(self):
        #inputs
        spells = [WowSpell(spell_id=101), WowSpell(spell_id=102)]

        expected = "type in ('applybuff','removebuff','applydebuff','removedebuff') and ability.id in (101,102)"

        # run and test
        q = self.actor.get_buff_query(spells)
        assert q == expected
Example #3
0
    def setUp(self):
        self.boss = warcraftlogs_boss.Boss()

        # setup an example boss
        self.example_boss = mock.MagicMock()
        self.example_boss.spells = [
            WowSpell(spell_id=101),
            WowSpell(spell_id=102)
        ]
        self.example_boss.buffs = [
            WowSpell(spell_id=201),
            WowSpell(spell_id=202)
        ]
    def get_filter(self) -> str:
        """Filter that is applied to the query."""
        filter_healing_cds = self._get_healing_cooldowns()

        raid_cds = self._get_raid_cds()
        raid_cds_str = WowSpell.spell_ids_str(raid_cds)
        raid_cds_filter = f"type='cast' and ability.id in ({raid_cds_str})"

        raid_buffs = self._get_raid_buffs()
        raid_buffs_str = WowSpell.spell_ids_str(raid_buffs)
        raid_buffs_filter = f"type in ('applybuff', 'removebuff') and ability.id in ({raid_buffs_str})"

        return self.combine_queries(filter_healing_cds, raid_cds_filter,
                                    raid_buffs_filter)
Example #5
0
    def get_cast_query(self, spells=typing.List[WowSpell]):
        if not spells:
            return ""

        spell_ids = WowSpell.spell_ids_str(spells)
        cast_filter = f"type='cast' and ability.id in ({spell_ids})"
        return cast_filter
Example #6
0
    def add_buff(self, spell_id, **kwargs) -> WowSpell:

        kwargs.setdefault("spell_type", self.full_name_slug)
        spell = WowSpell(spell_id=spell_id, **kwargs)

        self.buffs.append(spell)
        return spell
Example #7
0
    def add_spell(self, **kwargs):
        kwargs.setdefault("color", self.color)
        kwargs.setdefault("spell_type", self.name_slug)

        spell = WowSpell(**kwargs)
        self.spells.append(spell)
        return spell
Example #8
0
    def has_own_casts(self):
        """Return true if a player has own casts (eg.: exclude raid wide buffs like bloodlust)."""
        for cast in self.casts:
            spell = WowSpell.get(spell_id=cast.spell_id)

            if spell.spell_type != WowSpell.TYPE_BUFFS:
                return True
        return False
Example #9
0
    def add_debuff(self, spell: WowSpell = None, **kwargs):

        if not spell:
            kwargs.setdefault("color", self.color)
            kwargs.setdefault("spell_type", self.name_slug)
            spell = WowSpell(**kwargs)

        self.debuffs.append(spell)
Example #10
0
    def add_spell(self, spell: WowSpell = None, **kwargs):

        if not spell:
            kwargs.setdefault("color", self.wow_class.color)
            kwargs.setdefault("spell_type", self.full_name_slug)
            spell = WowSpell(**kwargs)

        self.spells.append(spell)  # Important to keep a ref in memory
        return spell
Example #11
0
    def add_buff(self, spell: WowSpell = None, **kwargs):

        if not spell:
            kwargs.setdefault("color", self.wow_class.color)
            kwargs.setdefault("spell_type", self.full_name_slug)
            spell = WowSpell(**kwargs)

        self.buffs.append(spell)
        return spell
Example #12
0
    def add_event(
        self, **kwargs
    ):  # event_type, spell_id, name: str, icon: str, duration: int = 0):
        kwargs.setdefault("event_type", "cast")

        # track the event (for query)
        self.events.append(kwargs)

        # dedicated "stop" event, for events with non static timers.. eg: intermissions
        end_event = kwargs.get("until", {})
        if end_event:
            self.events.append(end_event)

        # spell instance used for UI things
        kwargs.setdefault("spell_type", self.full_name_slug)
        spell = WowSpell(**kwargs)

        spell.specs = [self]
        self.event_spells.append(spell)
Example #13
0
    def _build_buff_query(spells: typing.List[WowSpell],
                          event_types: typing.List[str]):
        if not spells:
            return ""
        spell_ids = WowSpell.spell_ids_str(spells)

        event_types = [f"'{event}'" for event in event_types
                       ]  # wrap each into single quotes
        event_types_combined = ",".join(event_types)

        return f"type in ({event_types_combined}) and ability.id in ({spell_ids})"
Example #14
0
    def setUp(self):
        self.player = warcraftlogs_actor.Player(
            spec_slug=MOCK_SPEC.full_name_slug
        )
        self.spells = [WowSpell(spell_id=101)]

        self.cast_query_patch = mock.patch("lorgs.models.warcraftlogs_actor.BaseActor.get_cast_query")
        self.cast_query_mock = self.cast_query_patch.start()
        self.cast_query_mock.return_value = "CAST_QUERY"
        self.buff_query_patch = mock.patch("lorgs.models.warcraftlogs_actor.BaseActor.get_buff_query")
        self.buff_query_mock = self.buff_query_patch.start()
        self.buff_query_mock.return_value = "BUFF_QUERY"
    def _get_healing_cooldowns(self) -> str:  # typing.List[WowSpell]:
        """All Spells that are considered Healing-Cooldowns.

        Right now, this simply returns every spell healers have

        TODO:
            share logic with <BaseActor> ?

        """
        def join(*parts: str):
            return " and ".join(parts)

        queries: typing.List[str] = []
        healers: typing.List[WowSpec] = [
            spec for spec in WowSpec.all if spec.role.code == "heal"
        ]

        # Casts
        casts: typing.List[WowSpell] = utils.flatten(spec.all_spells
                                                     for spec in healers)
        casts = [cast for cast in casts if cast.is_healing_cooldown()]
        if casts:
            cast_ids = WowSpell.spell_ids_str(casts)
            buffs_q = join("source.role='healer'", "type='cast'",
                           f"ability.id in ({cast_ids})")
            queries.append(buffs_q)

        # Buffs
        buffs: typing.List[WowSpell] = utils.flatten(spec.all_buffs
                                                     for spec in healers)
        buffs = [buff for buff in buffs if buff.is_healing_cooldown()]
        if buffs:
            buffs_ids = WowSpell.spell_ids_str(buffs)
            buffs_q = join("target.role='healer'",
                           "type in ('applybuff', 'removebuff')",
                           f"ability.id in ({buffs_ids})")
            queries.append(buffs_q)

        return self.combine_queries(*queries)
Example #16
0
    def get_event_query(self, spells=typing.List[WowSpell]):
        if not spells:
            return ""

        # TODO: group spells by event_type

        spell_ids = WowSpell.spell_ids_str(spells)

        parts = []
        for spell in spells:
            part = f"(type='{spell.event_type.value}' and ability.id in ({spell_ids}))"
            parts.append(part)

        return " or ".join(parts)
Example #17
0
    def process_event_resurrect(self, event):
        fight_start = self.fight.start_time_rel if self.fight else 0

        data = {}
        data["ts"] = event.get("timestamp", 0) - fight_start

        spell_id = event.get("abilityGameID", -1)
        spell = WowSpell.get(spell_id=spell_id)
        if spell:
            data["spell_name"] = spell.name
            data["spell_icon"] = spell.icon

        source_id = event.get("sourceID", 0)
        source_player: Player = self.fight.report.players.get(str(source_id))
        if source_player:
            data["source_name"] = source_player.name
            data["source_class"] = source_player.class_slug

        self.resurrects.append(data)
Example #18
0
def test_is_healing_cooldown__other():
    spell = WowSpell(spell_id=5)
    assert spell.is_healing_cooldown() == True
Example #19
0
                             icon="spell_shadow_summonfelguard.jpg")
WARLOCK_DEMONOLOGY.add_spell(spell_id=264119,
                             cooldown=45,
                             duration=15,
                             color="#69b851",
                             name="Summon Vilefiend",
                             icon="inv_argusfelstalkermount.jpg")
WARLOCK_DEMONOLOGY.add_spell(spell_id=267217,
                             cooldown=180,
                             duration=15,
                             name="Nether Portal",
                             icon="inv_netherportal.jpg")

WARLOCK_DESTRUCTION.add_spell(spell_id=1122,
                              cooldown=180,
                              duration=30,
                              color="#91c45a",
                              name="Summon Infernal",
                              icon="spell_shadow_summoninfernal.jpg")
WARLOCK_DESTRUCTION.add_spell(spell_id=113858,
                              cooldown=120,
                              duration=20,
                              color="#c35ec4",
                              name="Dark Soul: Instability",
                              icon="spell_warlock_soulburn.jpg")

# Additional Spells (not tracked)
SOULSTONE_RESURRECTION = WowSpell(spell_id=95750,
                                  name="Soulstone",
                                  icon="spell_shadow_soulgem.jpg")
Example #20
0
    def process_query_result(self, query_result):
        """Process the result of a casts-query to create Cast objects."""

        # save unwrap the data
        query_result = query_result.get("reportData") or query_result
        query_result = query_result.get("report") or query_result
        query_result = query_result.get("events") or query_result

        casts_data = query_result.get("data") or []
        if not casts_data:
            logger.warning("casts_data is empty")
            return

        # track buffs/debuff: spell id -> start cast
        active_buffs: typing.Dict[int, Cast] = {}

        fight_start = self.fight.start_time_rel if self.fight else 0

        for cast_data in casts_data:
            self.process_event(cast_data)

            cast_type: str = cast_data.get("type") or "unknown"

            cast_actor_id = cast_data.get("sourceID")
            if cast_type in ("applybuff", "removebuff", "resurrect"):
                cast_actor_id = cast_data.get("targetID")

            if self._has_source_id and (cast_actor_id != self.source_id):
                continue

            # resurrect are dealt with in `process_event`
            if cast_type == "resurrect":
                continue

            # Create the Cast Object
            cast = Cast()
            cast.spell_id = cast_data.get("abilityGameID")
            cast.spell_id = WowSpell.resolve_spell_id(cast.spell_id)
            cast.timestamp = cast_data.get("timestamp", 0) - fight_start
            cast.duration = cast_data.get("duration")

            if cast_type in ("cast", "damage"):
                cast.stacks = 1

            # new buff, or buff stack
            if cast_type in ("applybuff", "applydebuff"):
                # check if the buff/debuff is already active.
                cast = active_buffs.get(cast.spell_id) or cast
                cast.stacks += 1

            if cast_type in ("removebuff", "removedebuff"):

                start_cast = active_buffs.get(cast.spell_id)

                # special case for buffs that are applied pre pull
                # meaning.. the buff was already present at the start of the fight,
                if not start_cast:
                    start_cast = cast
                    spell = WowSpell.get(
                        spell_id=cast.spell_id
                    )  # get the duration from the spell defintion
                    start_cast.timestamp -= (
                        spell.duration * 1000
                    )  # and calculate back the start time
                    continue

                start_cast.stacks -= 1

                # no stacks left --> buff/debuff ends
                if start_cast.stacks == 0:
                    start_cast.duration = (cast.timestamp -
                                           start_cast.timestamp)
                    start_cast.duration *= 0.001
                    active_buffs[cast.spell_id] = None

            if cast.stacks == 1:  # only add new buffs on their first application
                # track applied buffs
                active_buffs[cast.spell_id] = cast
                self.casts.append(cast)

        # Filter out same event at the same time (eg.: raid wide debuff apply)
        self.casts = utils.uniqify(
            self.casts,
            key=lambda cast:
            (cast.spell_id, math.floor(cast.timestamp / 1000)))
        self.casts = list(
            self.casts
        )  # `utils.uniqify` returns dict values, which mongoengine doesn't like

        # make sure casts are sorted correctly
        # avoids weird UI overlaps, and just feels cleaner
        self.casts = sorted(self.casts, key=lambda cast: cast.timestamp)
Example #21
0
 def spell(self) -> WowSpell:
     return WowSpell.get(spell_id=self.spell_id)
Example #22
0
def test_spell_ids_str():

    spells = [WowSpell(spell_id=5), WowSpell(spell_id=3), WowSpell(spell_id=10)]

    result = WowSpell.spell_ids_str(spells)
    assert result == "3,5,10"
Example #23
0
def test_is_item_spell__true():
    spell = WowSpell(spell_id=5, spell_type=WowSpell.TYPE_TRINKET)
    assert spell.is_item_spell() == True
Example #24
0
def test_is_healing_cooldown__personal():
    spell = WowSpell(spell_id=5, spell_type=WowSpell.TYPE_PERSONAL)
    assert spell.is_healing_cooldown() == False
Example #25
0
def test_is_healing_cooldown__item_spell():
    spell = WowSpell(spell_id=5, spell_type=WowSpell.TYPE_TRINKET)
    assert spell.is_healing_cooldown() == False
Example #26
0
def test_is_item_spell__false():
    spell = WowSpell(spell_id=5)
    assert spell.is_item_spell() == False
Example #27
0
                            icon="ability_deathknight_pillaroffrost.jpg",
                            show=False)
DEATHKNIGHT_FROST.add_spell(spell_id=46585,
                            cooldown=120,
                            duration=60,
                            color="#c7ba28",
                            name="Raise Dead",
                            icon="inv_pet_ghoul.jpg",
                            show=False)
DEATHKNIGHT_FROST.add_spell(spell_id=47568,
                            cooldown=120,
                            duration=20,
                            color="#88e8f2",
                            name="Empower Rune Weapon",
                            icon="inv_sword_62.jpg")
DEATHKNIGHT_FROST.add_spell(spell_id=152279,
                            cooldown=120,
                            duration=30,
                            color="#52abff",
                            name="Breath of Sindragosa",
                            icon="spell_deathknight_breathofsindragosa.jpg")
DEATHKNIGHT_FROST.add_spell(spell_id=279302,
                            cooldown=180,
                            name="Frostwyrm's Fury",
                            icon="achievement_boss_sindragosa.jpg")

# Additional Spells (not tracked)
RAISE_ALLY = WowSpell(spell_id=61999,
                      name="Raise Ally",
                      icon="spell_shadow_deadofnight.jpg")
Example #28
0
def test_spell_ids():

    spells = [WowSpell(spell_id=5), WowSpell(spell_id=3), WowSpell(spell_id=10)]

    result = WowSpell.spell_ids(spells)
    assert result == [3, 5, 10]
Example #29
0
               show=False)

# Defensive
MONK.add_spell(spell_id=122278,
               cooldown=120,
               duration=10,
               color="#fcba03",
               name="Dampen Harm",
               icon="ability_monk_dampenharm.jpg",
               show=False)

# MW and WW get a reduced CD with rank2
FORT_BREW = WowSpell(spell_type=MONK.name_slug,
                     spell_id=243435,
                     cooldown=180,
                     duration=15,
                     color="#ffb145",
                     name="Fortifying Brew",
                     icon="ability_monk_fortifyingale_new.jpg",
                     show=False)
DIFFUSE = WowSpell(spell_type=MONK.name_slug,
                   spell_id=122783,
                   cooldown=90,
                   duration=6,
                   color=MONK.color,
                   name="Diffuse Magic",
                   icon="spell_monk_diffusemagic.jpg",
                   show=False)

MONK_MISTWEAVER.add_spells(FORT_BREW, DIFFUSE)
MONK_WINDWALKER.add_spells(FORT_BREW, DIFFUSE)
Example #30
0
#
DRUID_BALANCE     = WowSpec(role=RDPS, wow_class=DRUID, name="Balance")
DRUID_FERAL       = WowSpec(role=MDPS, wow_class=DRUID, name="Feral")
DRUID_GUARDIAN    = WowSpec(role=TANK, wow_class=DRUID, name="Guardian")
DRUID_RESTORATION = WowSpec(role=HEAL, wow_class=DRUID, name="Restoration", short_name="Resto")

################################################################################
# Spells
#
DRUID.add_spell(             spell_id=323764, cooldown=60,  duration=4,  color=COL_NF,    name="Convoke the Spirits",            icon="ability_ardenweald_druid.jpg")
DRUID.add_spell(             spell_id=323546, cooldown=180, duration=20, color=COL_VENTR, name="Ravenous Frenzy",                icon="ability_revendreth_druid.jpg",              show=False)

# Defensives
DRUID.add_spell(             spell_id=22812, cooldown=60, duration=12, name="Barkskin",                icon="spell_nature_stoneclawtotem.jpg",              show=False)

BEAR_FORM = WowSpell(spell_id=5487, name="Bear Form", icon="ability_racial_bearform.jpg", show=False)
BEAR_FORM.spell_type = DRUID.name_slug
BEAR_FORM.color = DRUID.color
DRUID_BALANCE.add_buff(BEAR_FORM)
DRUID_FERAL.add_buff(BEAR_FORM)
DRUID_RESTORATION.add_buff(BEAR_FORM)


# Offensive
DRUID_BALANCE.add_spell(     spell_id=194223, cooldown=180, duration=20,                  name="Celestial Alignment",            icon="spell_nature_natureguardian.jpg")
DRUID_BALANCE.add_spell(     spell_id=102560, cooldown=180, duration=30,                  name="Incarnation: Chosen of Elune",   icon="spell_druid_incarnation.jpg")
DRUID_BALANCE.add_spell(     spell_id=205636, cooldown=60,  duration=10,                  name="Force of Nature",                icon="ability_druid_forceofnature.jpg",           show=False)
DRUID_BALANCE.add_spell(     spell_id=202770, cooldown=60,  duration=8,                   name="Fury of Elune",                  icon="ability_druid_dreamstate.jpg",              show=False)

DRUID_FERAL.add_spell(       spell_id=106951, cooldown=180, duration=15,                  name="Berserk",                        icon="ability_druid_berserk.jpg")
DRUID_FERAL.add_spell(       spell_id=58984,  cooldown=120,              color="#999999", name="Shadowmeld ",                    icon="ability_ambush.jpg",                        show=False)