Smart Simulations: Talent & Trait interactions

Last year I wrote a post on looking at talent interactions to look at how talents interact with each other. With the launch of Battle for Azeroth and my focus change towards more experimental theorycrafting ideas I’ve decided to revisit this subject. One issue I found mid-way through this is that just showing the interaction values, with 5 output related talent rows plus 3 different sources for Azerite Traits, doesn’t actually make it easy to answer the question of which combination is better. To answer that I’ve built a second process to combine the results.

This post is more of a reference document for people who want to replicate this process within their own systems or analysis tools. If others want to replicate this for their own specs I can help with some of the initial setup process.

Step 1: Generating Data

Running sims to evaluate every combination will take a lot of time, even with access to Raidbots Advanced Sim feature. With 5 rows of 3 talents plus 3 slots to use 6 azerite traits this leads to 243 talent combinations & 56 unique trait combinations for a total of 13,608 unique profiles. If we just run each one individually & then with the other talents/traits it could be paired with we end up with 223 profiles (1.64% of the original count).

My approach to this was to set up the profileset details via a spreadsheet to return entries like the following which covers the initial settings, the “default” profile used as a base, and the initial L15 talent profiles & L30 combinations.

target_error=0.05
disable_azerite=items
profileset."Default"+=talents=0000000
profileset."Flashover"+=talents=1000000
profileset."Eradication"+=talents=2000000
profileset."SoulFire"+=talents=3000000
profileset."Flashover_ReverseEntropy"+=talents=1100000
profileset."Flashover_InfernalCombustion"+=talents=1200000
profileset."Flashover_Shadowburn"+=talents=1300000
profileset."Eradication_ReverseEntropy"+=talents=2100000
profileset."Eradication_InfernalCombustion"+=talents=2200000
profileset."Eradication_Shadowburn"+=talents=2300000
profileset."SoulFire_ReverseEntropy"+=talents=3100000
profileset."SoulFire_InfernalCombustion"+=talents=3200000
profileset."SoulFire_Shadowburn"+=talents=3300000

This section outlines the Azerite Trait setup

profileset."Accelerant_BurstingFlare"+=azerite_override=131:345/460:345
profileset."Accelerant_BurstingFlare"+=talents=0000000
profileset."Accelerant_ChaoticInferno"+=azerite_override=131:345/432:345
profileset."Accelerant_ChaoticInferno"+=talents=0000000
profileset."Accelerant_CrashingChaos"+=azerite_override=131:345/444:345
profileset."Accelerant_CrashingChaos"+=talents=0000000

Profile sets are the preferred way of handling this sort of analysis as we’re just interested in the DPS results, but require one line for each override used. The Azerite_Override setting is TraitID:ItemLevel with each trait separated by /.

The spreadsheet I used can be found here and you’ll need to look at the SimSetup tab.

The profile sets are copied in at the end of one of the pre-built profiles in SimCraft before starting the sim process. I’ve used the PR (Pre-Raid) Destruction Warlock profile for this.

Step 2: Converting Data

Once the simulation is complete on Raidbots I download the generated JSON file & run it through a web based JSON converter to get the data into a form I can use in excel to build some insert scripts for SQL for further data analysis. I won’t go into much detail on this, but if you want to run your own copy using a SQL database then contact me on twitter.

Step 3: Processing Data

Warning: this section will contain a lot of SQL query language. I’ll try to make notes & explain it as I go. Destruction has a ClassID & SpecID of 1 as it’s the only spec set up in my local database.

First we need to generate the valid combinations of traits/talents:

SELECT *
FROM (SELECT * FROM Talent WHERE ClassID = 1 AND SpecID = 1 AND Row = 15) AS a
CROSS JOIN (SELECT * FROM Talent WHERE ClassID = 1 AND SpecID = 1 AND Row = 30) AS b
CROSS JOIN (SELECT * FROM Talent WHERE ClassID = 1 AND SpecID = 1 AND Row = 60) AS c
CROSS JOIN (SELECT * FROM Talent WHERE ClassID = 1 AND SpecID = 1 AND Row = 90) AS d
CROSS JOIN (SELECT * FROM Talent WHERE ClassID = 1 AND SpecID = 1 AND Row = 100) AS e
CROSS JOIN (SELECT a.[ID] AS Trait1ID,b.[ID] AS Trait2ID,c.[ID] AS Trait3ID
FROM (SELECT ID FROM Trait WHERE ClassID = 1 AND SpecID = 1) AS a
CROSS JOIN (SELECT ID FROM Trait WHERE ClassID = 1 AND SpecID = 1) AS b
CROSS JOIN (SELECT ID FROM Trait WHERE ClassID = 1 AND SpecID = 1) AS c
WHERE a.[ID] <= b.[ID] AND b.[ID] <= c.[ID]) AS f

To do this I return the results from the Talent table for each talent row for Destruction in a “sub select” (the bit in brackets which takes a SQL query and presents that as a table to the rest of the query) and then use the CROSS JOIN function to generate one data row for each combination of talents. The trait one is a little different as I need to generate unique combinations of traits rather than listing 1,2,1 as a different row than 1,1,2 or 2,1,1. To do that I ensure that the trait trios returned have the first & second IDs lower or equal to the next ID. That means that 1,1,2 is the only valid entry returned for all combinations of two 1’s and a 2. This is then cross joined in with the talent rows to give us the full talent/trait combination list.

To calculate the value for each combination I first run another cross join to have the “default” result on each row, and then left join the Results table to calculate the individual talent values and its synergy values.

CROSS JOIN (SELECT * FROM [Results]
WHERE [Talent1ID] IS NULL AND [Talent2ID] IS NULL AND [Trait1ID] IS NULL
AND [Trait2ID] IS NULL AND [ClassID] = 1 AND [SpecID] = 1) AS rb
LEFT JOIN [Results] AS r15 ON r15.[Talent1ID] = a.[ID] AND r15.[Talent2ID] IS NULL AND r15.[Trait1ID] IS NULL AND r15.[Trait2ID] IS NULL
LEFT JOIN [Results] AS s1530 ON s1530.[Talent1ID] = a.[ID] AND s1530.[Talent2ID] = b.[ID]
LEFT JOIN [Results] AS s1560 ON s1560.[Talent1ID] = a.[ID] AND s1560.[Talent2ID] = c.[ID]
LEFT JOIN [Results] AS s1590 ON s1590.[Talent1ID] = a.[ID] AND s1590.[Talent2ID] = d.[ID]
LEFT JOIN [Results] AS s15100 ON s15100.[Talent1ID] = a.[ID] AND s15100.[Talent2ID] = e.[ID]
LEFT JOIN [Results] AS s15t1 ON s15t1.[Talent1ID] = a.[ID] AND s15t1.[Trait2ID] = f.[Trait1ID]
LEFT JOIN [Results] AS s15t2 ON s15t2.[Talent1ID] = a.[ID] AND s15t2.[Trait2ID] = f.[Trait2ID]
LEFT JOIN [Results] AS s15t3 ON s15t3.[Talent1ID] = a.[ID] AND s15t3.[Trait2ID] = f.[Trait3ID]

The r15 join for the Results table is just joining in the one result record where the L15 talent is selected without any additional talents or traits. The s15 join series are bringing in the results for the L15 talent and the other talents/traits run with it as a pair, ie: s1530 joins the result where the L15 and L30 talents are selected and there are no traits.

 ,rb.[DPS]
+ (r15.[DPS] - rb.[DPS])
+ (s1530.[DPS] - rb.[DPS] - (r15.[DPS] - rb.[DPS]) - (r30.[DPS] - rb.[DPS]))
+ (s1560.[DPS] - rb.[DPS] - (r15.[DPS] - rb.[DPS]) - (r60.[DPS] - rb.[DPS]))
+ (s1590.[DPS] - rb.[DPS] - (r15.[DPS] - rb.[DPS]) - (r90.[DPS] - rb.[DPS]))
+ (s15100.[DPS] - rb.[DPS] - (r15.[DPS] - rb.[DPS]) - (r100.[DPS] - rb.[DPS]))
+ (s15t1.[DPS] - rb.[DPS] - (r15.[DPS] - rb.[DPS]) - (rt1.[DPS] - rb.[DPS]))
+ (s15t2.[DPS] - rb.[DPS] - (r15.[DPS] - rb.[DPS]) - (rt2.[DPS] - rb.[DPS]))
+ (s15t3.[DPS] - rb.[DPS] - (r15.[DPS] - rb.[DPS]) - (rt3.[DPS] - rb.[DPS]))
AS DPS

The DPS values of each join is then combined after adjusting it to be the net gain of the particular join. For each individual talent/trait it’s the result DPS minus the default DPS, but for each pairing it’s the default DPS and individual talent gains are subtracted from the pair DPS to give the net pair interaction. The net interaction value is positive when there’s a synergy gain and negative when there’s a loss. The left joins and DPS sum get extended out for all the other talent and trait combinations.

The full processing query can be found on pastebin.

Step 4: Show results

Once step 3 completes it’s just a case of copying the results to a spreadsheet, sort by the DPS column and you have your ideal combinations (as seen on the Combination Results tab of my spreadsheet)

 

 

About binkenstein
I'm a geek, living in Christchurch, New Zealand.

Leave a comment