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
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)
def spell(self) -> WowSpell: return WowSpell.get(spell_id=self.spell_id)
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)
async def spells_one(spell_id: int): """Get a single Spell by spell_id.""" spell = WowSpell.get(spell_id=spell_id) if not spell: return "Spell not found", 400 return spell.as_dict()