With the help of several excellent people, I manage the the fork of b1ueb1ues' Dragalia DPS (damage per second) simulation chart deployed here as well as the customizable simulator hosted here. Though the DPS chart is pretty looking and moderately useful as a comparison tool, it has a severe limitation of being 1 character only sim and doesn't really show how exactly you achieve the displayed optimal DPS, so I recommend everyone to use the customizable simulator instead.
This post is a quick guide on how to run simulations and interpret the results.
The Various Arbitrary Rules About What We Put on the Chart
Both the DPS chart and the customizable simulator run off the same source code, but the DPS chart is statically deployed and intended for comparing the DPS of adventurers under "generic" conditions. The assumptions are:
- DPS uptime is perfect, i.e. you do not have to move and dodge.
- The adventurer's last offense abilities activate at the start of the fight, and other low HP based abilities activate at various points during the fight.
- Wand/Bow/Dagger and anyone with innate combo based abilities never lose combo, unless their skills force them to (see Delphi s2). Only these adventurers are allowed to use flurry prints/dragons.
- Anyone with full HP or never get hit type passives are assumed to never get hit by anything, so only these adventurers are allowed to use full HP prints and Garland.
- Only people who can inflict their own afflictions get to use affliction punishers, even though affliction punisher can benefit anyone on the same team.
This state of "generic" conditions tend to not exist in actual gameplay, because different elements have different meta team comps and available tools, thus I feel it is much better to simulate an adventurer under different conditions and identify more realistic optimal gear. Cloning the whole repository and editing/running the sim is not exactly user friendly, so I made a small website to do it.
- Adventurer - selects an adventurer sim out of the currently available ones
- Simulation Time - Sets the amount of time to simulate in seconds, 180s (3min) is the default since that is usually how long a HDT fight lasts.
- Team DPS - Sets the base team DPS, which is multiplied by the expected team buff percent to compute team DPS gains (more on that later)
- Affliction Resist - sets the base affliction resist, only available to adventurers that inflicts an affliction
- Weapon / Dragon / Wyrmprint 1 / Wyrmprint 2 - selects adventurer load out, some special load outs that don't exist in game inlude
- Unreleased Weapons - covers Agito weapons for elements other than flame
- Unreleased Dragons - speculative dragon auras that don't exist yet, such as light skill damage
- Non-standard Condition Wyrmprints - includes Dear Diary [dl wp="dear_diary"] at various intervals of RO activation and a generic high dragon wyrmprint with no abilities
- Co-Abilities - sets what co-abilites are active for the simulation, adventurers always have their own co-ability active
- Run Test - runs the test
- Conditions - display the condition checkboxes, used to disable things like hp100 when desired
- Text Display/Visual Display - toggles display mode between a visual one and a markdown based one for copy+paste
- Log - view the sim debug logs
- Clear - clear results
- Reset - clear results, and reset all gear choices to default
- About - show some FAQ messages that no one reads
Simulated Condition Inputs
- Simulate Affliction - simulate the presence of burn/paralysis/poison by inflicting a fake, 0 damage, instance of it at the start of the simulation that exists for (uptime% * simulation time) seconds. This is meant for testing punishers on adventurers that don't inflict any affliction themselves.
- Adventurers that already burn/paralysis/poison can't be simmed properly with the same fake affliction, since it doesn't make a lot of sense to do that.
- The uptime of actual afflictions in a real fight are usually not continuous and is impacted by RNG
- Simulated uptimes are noted on the chart, however the more affliction inflictors you have on an actual team, the faster you build resistance and lose uptime
- Simulate +Str% and Simulate -Def% - simulate team buff/debuff effects with a fake instance of the buff/debuff that lasts for the whole duration of the sim.
Action Condition Language (ACL)
ACL is like a set of logical instructions for the adventurer, describing what actions to perform given the specified condition (if any).
- Each consists of an action, optionally followed by a comma and condition, e.g.
- Lines starting with # is considered comment and not evaluated
- ` is a decorator that is removed from each line, this behavior exists due to historical reasons.
- During the simulation, the ACL is read from top to bottom. When the action is available (e.g. skill is filled) and any specified condition is met, the action is executed. When none of the specified actions are used, the sim will perform the next auto attack (c1 c2 c3 c4 c5 then back to c1)
- You can specify the same action multiple times, to cover different conditions.
- It's also possible to specify blocks of actions under one condition, using python-like if/elif/else syntax:
if <condition> ... elif <condition> ... else ... end
end is required and indentation does not matter.
- The built in actions include skills (s1, s2, s3), force strike (fs), a dodge roll (dodge), and shapeshift (dragon). Force strike fail (fsf) is an action too, but it is assumed to be performed for c5 hit of blade, wand, and lance.
- Some adventurers have extra actions implemented, for example Ramona has s1a for using all hits on her s1.
- The dragon action assumes you are doing the normal full duration optimal combo, but you can change that by using
dragon.act(act string). The act string syntax is:
- Each action is separated by a space, e.g.
dragon.act('c3 s c3 end')
c3) means do c1 to cX of the dragon combo chain. Most dragons go up to 3 combos, some have 5 combos.
smeans use skill (if they have usage left)
dodgemeans do a dodge. Dodge is implicitly added after
cXif dodge is faster than recovery or if the
cXis not the final combo.
endmeans preemptively stop the transform, used to represent dragon tanking.
- Each action is separated by a space, e.g.
- The conditions are essentially python code that is evaluated so they can be just about anything, but the most commonly used ones are:
seq=n: the previous action was combo #n in the attack chain.
fsc: the previous action was force strike
cancel: the previous action was a combo or a force strike, equivalent to
x=1 or x=2 or x=3 or x=4 or x=5 or fsc.
s=n: the previous action was skill #n
s: the previous action was a skill
pin='prep': at the start of the fight if the adventurer has skill prep
s1.chargedis the amount of sp charged on s1, you can combine it with
this.sp_valto make conditions like
s1.charged>=s1.sp-this.sp_val('fs'), aka "do this action when S1 is one FS away from being fully charged. This can be used with s2 and s3 as well.
- ``this.have_buff(buffname)` checks for presence of buff on certain character. The name of buffs is poorly documented with inconsistent naming scheme, but you can look at logs to figure out the specifics for your adventurer.
- You can use any python logical operators in the condition, such as
andto combine 2 conditions
- For Agito weapons,
s3, not this.s3_buffmeans only use S3 if the buff is not on, you can also check for what type of buff is currently active, e.g.
s3, this.s3_buff and this.s3_buff.mod_type = 'defense'
- Special conditions are implemented for some adventurers but unfortunately most aren't well documented nor universal. You most likely have to look at the source code to tell.
[dl adv="gala_cleo"] Example 1: Gala Cleo (HDT2)
`s2, pin='prep' `fs, s1.charged>=s1.sp and this.fsa_charge `s2, x=5 or x=4 or fsc `s1, fsc or s=2 `s3, x=5 or fsc
We can translate the ACL as:
- use s2, at start of the fight
- use fs, when s1 is fully charged AND Gala Cleo's alternate force strike is available (tracked by this.fsa_charge)
- use s2, after c5 or c4 or fs
- use s1, after fs or s2
- use s3, after c5 or fs
If none of the actions are performable, continue doing standard combos
[dl adv="gala_sarisse"] Example 2: Gala Sarisse (Agito, Roll FS)
`s3, not this.s3_buff_on `s1, fsc `s2, fsc `dodge, fsc `fs
We can translate the ACL as:
- use s3, if the Agito s3 buff is not on
- use s1, after fs
- use s2, after fs
- dodge, after fs
- use fs
The 4th and 5th actions together specifices a roll FS rotation, but be aware that the frame data of roll FS is incomplete and the results may be skewed for non-bow charactres.
Reading Simulation Results
[dl adv="gala_luca"] Gala Luca 180s (co-ab: blade) [The_Wyrmclan_Duo+Primal_Crisis][Daikokuten][HDT2]
DPS: 12224 <hit15 & hp70> attack: 4110|skill_1: 6433|skill_3: 1680 DPS: 7220 attack: 2457|skill_1: 3805|skill_3: 957
Gala Luca's rotation is very simple and basically boils down to "use skills when they are up, do c5 otherwise", and it shows that his DPS bar contains just attack, skill 1, and skill 2. However, to actually achieve something close to this advertised amount, you must be always above 70% HP (hp70) and keep 15 or more combo (hit15), also known as flurry. Failing that means your DPS falls closer to the meh 7220 instead of that sexy 12224.
The simulator is limited in that the conditions shown are all or nothing, so you must consider what abilities do these conditions come from and how much impact do they have on DPS. In this case we know that for keeping up 15 hits, Daikokuten [dl d="daikokuten"] gives +25% passive strength and Primal Crisis [dl wp="primal_crisis"] gives +20% passive strength an 10% crit rate. Meanwhile the >70% HP only impacts the 17% critical damage from The Wyrmclan Duo [dl wp="the_wyrmclan_duo"], so losing out on >70% hp is significantly less impactful than losing out on combos.
Another important thing to keep in mind is the lack of team interactions in an adventurer simulation. Since he does not personally have paralysis in his kit, Gala Luca benefits from teammates inflicting paralysis for punisher purposes. You can estimate DPS with team para in effect using the simulated affliction feature. The other team interaction is Gala Luca's inability to fill his buff icon based abilities by himself, so the benefits he gains from additional buff icons (like strength, defense, or shield) is not visible here. It is significant enough that, giving him -1% strength via simulated buff is actually a DPS gain.
[dl adv="elisanne"] Elisanne 180s (co-ab: none) [Beach_Battle+From_Whence_He_Came][Halloween_Maritimus][HDT2]
DPS: 12037 attack: 2316|team_buff: 9721 (+61%)
Elisanne is what is commonly called a "buff bot". Her personal DPS is quite low, but her buffs makes everyone else do more damage. Against a sandbag, she is able to perfect coverage of 3 layers of her 20% S1 strength buff, sometimes hitting 4 stacks. However, buff bots like Elisanne has more to lose when they have to back off and stop attacking, since their buff coverage becomes no longer perfect.
When consolidating a total DPS number, the team buff value is a simply team DPS * buff%. This isn't exactly realistic, since the number of buffs Elisanne varies through out a fight and the amount of DPS her teammates are outputting also varies. I personally prefer to ignore this team buff DPS number and just take the +61% as an upper bound on Elisanne's team buff potency.
Buffs of the same type are additive with each other, so a team full of buff bots don't work as well as teams with high DPS characters in additional to buff bots. The major exception here is defense down, which increases damage by *1/(1-%defdown) instead of *(1+buff%). For example, one 10% def down is 1/0.9 ~= +11% damage increase, but two 10% def downs is 1/0.8 ~= 25%, more than double of what one 10% def down gave (this is a big reason why 4 Gala Cleo is broken).
A Note on RNG Mass Sim Characters
Dragalia's damage formula contains a +-5% damage variance, and many other mechanics like critical hit and afflictions have RNG involved. Sim is meant to compare characters, so we choose to take the expected value whenever possible. Certain mechanics like 80% chance to hit bleed and Ezelith's multiple RNG def downs are difficult to implement accurately as expected values, so we instead perform 1000 runs and take the average for the chart. The web sim isn't fast enough to do 1000 runs in <1s, so instead we only do 25 runs. This can result in getting different values with the same loadout, so keep that in mind when trying to optimize.
Improving Adventurer DPS
There is no algorithmic optimizer implemented for the DPS sim, so all default slot and ACL is selected by hand. Since there are so many adventurers, it's very likely that some of them are not optimal. Changing weapon from HDT2 to (unreleased) Agito weapons may also create unexpected results, as the slots and ACL might be optimized for HDT2 s3 specifically. We will look at Ieyasu (no poison) as an example:
`s1 `s2, seq=5 and this.bleed._static['stacks'] > 0 `s3, seq=4
[dl adv="ieyasu"] Ieyasu 180s (co-ab: blade) [Resounding_Rendition+Jewels_of_the_Sun][Shinobi][HDT2]
DPS: 14631 <hp70> attack: 2172|skill_1: 4932|skill_3: 1216|bleed: 6309 DPS: 11319 attack: 1676|skill_1: 3817|skill_3: 937|bleed: 4887
Unreleased Shadow Agito Blade
`s3, not this.s3_buff_on `s1 `s2, seq=5 and this.bleed._static['stacks'] > 0
[dl adv="ieyasu"] Ieyasu 180s (co-ab: blade) [Resounding_Rendition+Jewels_of_the_Sun][Shinobi][UnreleasedAgito]
DPS: 14288 <hp70> attack: 2769|skill_1: 6345|bleed: 5174 DPS: 11063 attack: 2140|skill_1: 4925|bleed: 3997
Even though the Agito s3 is a big 20% strength buff, we encountered DPS loss. The error lies in the automatically modified ACL. Ieyasu's s1 inflicts bleed, for which there is a cap of 3 stacks and do the most damage at 3 stacks. Without s3 usage interrupting things, he is using s1 too often to keep up 3 stacks all the time. Thus, we should restrict his s1 usage to times where bleed is less than 3 stacks only. Since we are slowing down s1 casts anyways, Jewels of the Sun is not the best second print, so we will try using Beautiful Nothingness in conjunction with c5fs c4 for s1.
New ACL and result:
`s3, not this.s3_buff_on `s1, this.bleed._static['stacks'] < 3 `s2, x=5 and this.bleed._static['stacks'] > 0 `fs, x=5
[dl adv="ieyasu"] Ieyasu 180s (co-ab: blade) [Resounding_Rendition+Beautiful_Nothingness][Shinobi][UnreleasedAgito]
DPS: 16986 <hp70> attack: 2877|force_strike: 145|skill_1: 6298|bleed: 7664 DPS: 13313 attack: 2248|force_strike: 113|skill_1: 4941|bleed: 6009
Our optimizations gave 18% more DPS than the initial ACL + print set up, pretty good eh?
Contributing to the DPS Simulator
The DPS simulator is a open source project originally developed by b1ueb1ues. The custom sim came about because I got tired of friends telling me to sim things for them, and when the original chart had a long period of inactivity I ended up making a fork so we can update it. Much of the core mechanics were implemented by b1ues, and the bulk of the work done by active contributors now is adding new adventurers and optimizing old adventurers as new gear is released. When you see silly default dragons and wyrmprints, please please help us fix it by editing the sim and sending in a pull request.
To do so, you need to:
- Set up git and python3. Note: git command cheatsheet
- Make a github account then fork a copy of the simulator
- Clone the repository to your local.
- Make any changes you need to the files, in particular the adventurer sims are contained in the
- Set up the PYTHONPATH env variable to point to the
dlfolder to run things properly.
- Test your changes by running them with python by running the adv files:
python adv/mikoto.py -2 180 kd. The arguments are optional and represent loglevel (-2, 0, 1), sim duration, and coabilities (k: katana/blade, r: rod/wand, d: dagger, b: bow, m: hmym) respectively.
- Commit and push your changes.
- Send me a pull request via github so I can review and merge the change.
If you have any questions, ping me on discord I'm chu2.718281828459045235360287471#0110. And finally, remember that simulator is merely theory and the best way to gauge a character's strength is to actually run them.