Intro to Expressions
Quick Links
- Join us on Discord
- Follow Us on Twitter
- Support the Project
This article aims to explain and go through the expression language used on Warcraft Logs Season of Discovery. Please join us on Discord if you have any questions, as we're happy to help and provide answers if you have any queries.
What are expressions?
Expressions are built using the WCL Expression Language and are intended for experts and programmers who need to build more complex queries that can't be handled by the query UI. Expression Pins can still be shared with others, however, so you don't have to be an expert to use them!
The way to think about expressions is that every fight is broken up into a series of events. Those events are damage events, healing events, casts, buffs, debuffs etc. All of these events have three components. An event has a source, an ability and a target.
Take for example this event from a log:
Velynn is the source of this event, the ability is Shadow Bolt and the target is Gruul the Dragonslayer.
You can also be both the source and the target of an event:
Velynn gains Blessing of the Silver Crescent from Velynn.
Here Velynn is both the source and the target. The ability is Blessing of the Silver Crescent from the Icon of the Silver Crescent trinket.
Expressions are queries that filter through all these events to get the information you want to see. A query expression is built through various logical operators and strings to filter through the data.
Filter Expression
Every log report has a Filter Expression you can type in. This is where your queries should go if you write them from scratch or copy paste from someone else.
Warcraft Logs Season of Discovery uses an SQL-like language for constructing expressions. When creating an expression, you can use various operators, such as the ones listed below.
Logical Operators
A logical operator is a symbol or word used to connect two or more expressions. You can use the logical operator keywords AND, OR, or NOT to connect multiple conditions together.
"A AND B" means that both A and B must be true.
"A OR B" means that either A or B can be true.
"NOT A" is true when A is false.
The AND and OR operators do short-circuit evaluation. In other words, for A AND B, if A turns out to be false, then B will not be evaluated, so construct your queries accordingly.
Comparison Operators
Comparison operators are used to compare The following comparison operators are supported:
- < means 'Less than'
- It will filter out all the data that doesn't match. It returns true if the value on the left is less than the value on the right, otherwise it returns false.
- > means 'Greater than'
- It returns true if the value on the left is greater than the value on the right, otherwise it returns false.
- <= means 'Less than or equal to'
- It returns true if the value on the left is less than or equal to the value on the right, otherwise it returns false.
- >= means 'Greater than or equal to'
- It returns true if the value on the left is greater than or equal to the value on the right, otherwise it returns false.
- = means 'Equal to'
- It returns true if the value on the left is equal to the value on the right, otherwise it returns false.
- != means 'Not equal to'
- It returns true if the value on the left is not equal to the value on the right, otherwise it returns false.
In addition, the BETWEEN construct can be used to ask if a number or string is between two other values (inclusive).
For example:
is true if A is >= 5 and A <= 20.
Arithmetic Operators
The following arithmetic operators are supported:
→ + is addition
→ - is subtraction or negation
→ * is multiplication
→ / is division
→ % is mod
IN and NOT IN
You can ask if an object is a member of a set (or not a member of a set) using the IN and NOT IN keywords.
For example:
returns true if A is = to any of the three strings.
Case Statements
You can use case statements. Their syntax matches SQL usage, i.e., you can use either a simple case or a full case statement.
The full case statement above has conditions specified with a WHEN statement. If the condition is true (going in order) then the expression under that WHEN block is returned. The ELSE statement holds a default value to return if none of the WHEN conditions are satisfied.
The simple case statement specifies a case value that can then be compared with when values. This is useful when you are always testing equality.
Numbers
All numbers are Numbers. No floating point numbers/decimals are allowed.
Strings
Strings can be represented using either single or double quotes, i.e., both "Kihra" and 'Kihra' are valid strings. All string comparisons are case-insensitive, so "Kihra" and "KIHRA" are equivalent.
Identifiers
Some event fields are just simple identifiers, e.g., type
Certain fields have their own subfields. Access to subfields uses a "." notation. For example, you can query for the name of the source actor in an event by typing:
Function Calls
Functions look like objects except they have arguments attached in a parentheses-enclosed comma-separated list. Specific functions below document how many arguments they take and what those arguments should look like.
Built-in Identifiers
Every expression is evaluated on all of the events within the specified time range. The following built-in identifiers are supported:
- encounterID
EncounterIDs can be used to look at a specific encounter or to exclude encounters. If you want to look at a whole raid night except for one fight, you can use encounterID to exclude this fight from the overview. Trash fights have a value of 0.
For example:
You can find encounterIDs either on the DungeonEncounterID Wowpedia page or you can find it at the top of the Summary/Events view in a report, as shown in the image below.
- encounterSize
- The raid size of the encounter. 10-man vs. 25-man, etc.
- encounterDifficulty
- The difficulty of the encounter. 1 = LFR, 2 = Flex, 3 = Normal, 4 = Heroic, 5 = Mythic, 10 = Dungeon (Mythic+, CMs, FFXIV), 100 = FF/WildStar raids.
- encounterEnd
- How the encounter ended. Possible values are "wipe" and "kill".
- encounterDuration
- How long the encounter lasted in milliseconds.
- encounterBossHealthPercentage
- The percentage health of the boss at the end of the pull. A number between 0 and 100.
- encounterFightPercentage
- How far into the fight you were (corresponds to the colored bars that show up in the wipes display). A number between 0 and 100.
- encounterPhase
The phase an event belongs to. Phases are numbered starting from 1. If a fight has no phases, this number will be 0.
- encounterStartTime
- The start time of the fight relative to the beginning of the report.
- encounterEndTime
- The end time of the fight relative to the beginning of the report.
- timestamp
- The timestamp of the event in milliseconds relative to the start of the fight.
- type
- The type of the event. Warcraft Logs supports the following event types:
PLEASE NOTE: Note that Warcraft Logs does not consider a full absorb to be a miss. It will be represented with a damage event.
- inCategory
The inCategory function can be used to take advantage of WCL's smart categorization. For example if you want to look at healing events and also implicitly include absorbs, you can use inCategory("healing") = true instead of type = "heal" (which would not catch absorb events).
The following categories are supported (and more or less match the Query Pin UI):
- rawDamage
- The raw damage for a damage event. This includes absorbs and overkill damage.
- effectiveDamage
- The effective damage for a damage event. This excludes absorbs and overkill, and it represents how much damage the actor actually took.
- absorbedDamage
- The amount absorbed for a damage event.
- blocked
- The amount blocked for a damage event.
- overkill
- The amount of overkill for a damage event.
- rawHealing
- The raw healing for a healing/absorb event. This includes absorbs and overheal.
- effectiveHealing
- The effective healing for a healing/absorb event. This excludes overheal but still includes absorbed healing (e.g., Veil of Darkness on Sylvanas Windrunner)
- absorbedHealing
- The amount absorbed for a healing event. For non-absorb heals, it represents the amount absorbed (e.g., Veil of Darkness on Sylvanas Windrunner), but for absorb abilities it is equivalent to effectiveHealing.
- isCritical
True or False - checks whether or not a damage or heal event crit.
- isTick
True or False - checks whether or not a damage or heal event is periodic, i.e., a DoT or HoT.
- isUnpairedCalculation
- isGlancing
- True or False - checks whether or not a melee damage event is a glancing blow
- isMultistrike
- True or False - checks whether or not a damage or heal event was a multistrike.
- missType For a miss, indicates what happened.
- stack
- The stack count for buff and debuff stack events.
- extraAttacks
- The number of extra attacks for an extra attacks event.
- source
- The source of the event. A special Environment actor is returned if no source exists.
- target
- The target of the event. A special Environment actor is returned if no target exists.
- ability
- The primary ability for the event.
- supportedActor
- To get back to the original buffed player in cases of Augmentation Evoker augmented damage events
- stoppedAbility
- For steals, breaks and dispels, represents the spell that was dispelled. For interrupts, it represents the spell that was interrupted.
- resources
- Returns a resources object that can be used to obtain information like Hit Points, Spell Power, map positions, etc.
- feign
True or false - Returns true if a death event is actually a hunter feign.
- killer
- Will match death events if the killing blow that caused the death came from this actor.
- killingAbility
- Will match death events if the killing blow that caused the death was from this ability.
- absorbedAttacker
- Will match absorbed events if the attacker whose blow was absorbed is this actor
- absorbedAttackerAbility
- Will match absorbed events if the attack that was absorbed came from this ability.
- absorbedHealer
- Will match heal absorbed events if the healer whose heal was absorbed is this actor.
- absorbedHealerAbility
- Will match absorbed events if the healer whose heal was absorbed came from this ability.
True or False - checks whether an ability ghosted or not. i.e., it will display as "true" if a prepares event has ghosted.
Possible values are:
Actor Fields
Actors have the following subfields:
Ability Fields
Abilities have the following subfields:
The school of the ability. The value matches the Number of the raw event, with bits from 1 up to 64. The list for WoW parameters can be found on Wowpedia.
Resources Fields
Resources have the following subfields:
The X position in game of the resource actor. WCL stores this position as the original position multiplied by 100. For example an X position of 32.56 is represented by WCL as 3256.
Range Testing
With range testing, you can define arbitrary range boundaries and test if an event is inside (or not inside) that range.
Example:
Details:
The WHEN clause is just an initial condition that has to be matched before you even check the range boundaries. IN RANGE conditions can not be nested, so this lets you specify conditions if needed.
The FROM clause is a condition that if matched will cause you to begin a new range. If omitted, FROM will be the beginning of the fight.
The TO clause is a condition that if matched will cause you to end a range. If omitted, TO will be the end of the fight.
GROUP BY is how you link the FROM and TO together. For example with buffs and debuffs you typically would pair on the target of both events. If you want to pair on the source of the FROM and the target of the TO, that's allowed by adding an optional AND to specify something different for the TO.
The ON clause is a way to further filter the events by requiring that the expression in the ON for the event you're testing matches the GROUP BY for the from/to boundaries. If omitted, the expression in GROUP BY will be used.
Match Against Indices
MATCHED condition IN tuple expression END
With the MATCHED expression, you can test for the n-th time something happened, for example the second time a player gets a specific debuff. The first part is the condition whose matches you want to count and the second part is a tuple of indices (starting from 1) of which matches you want to include.
MATCHED type = "applydebuff" and ability.name = "Dark Herald" IN (1,3) END
The above example will match events for the first and third Dark Herald debuffs that go out during the fight.
Contact Us
As always, we love to hear your feedback. Please join us on Discord to share any feedback and suggestions, or to ask any questions.
Follow our Twitter for updates!
If you have any support questions, please reach out to our support team at [email protected].