Risk of Rain 2 Engineer Exponential Build Optimization

In Risk of Rain 2, a character’s DPS can be decomposed into the product of several factors, such as base damage, attack speed, and critical strike chance. As a result, linearly stacking items that increase attack speed, critical chance, and similar stats can produce exponential DPS growth. Similarly, survivability can be decomposed into total health multiplied by armor. Because item resources are limited, marginal returns are huge, and the costs of improving different stats are inconsistent, it is worth computing the optimal build in advance under an item-count constraint so that DPS and effective health are maximized. This matters most for the Engineer, because turrets deal damage in a pure stationary-output style.

Maximum DPS

Core Mechanics

base damage the character’s base attack power

total damage the actual total damage dealt on hit

On-hit proc damage is based on base damage or actual damage.

proc coefficient the coefficient used for triggering on-hit effects. For example, a missile has a proc coefficient of 1 and can normally trigger Ukulele, but Ukulele only has a proc coefficient of 0.2, so each bounce has a \(10%*0.2=2%\) chance to trigger a missile.

drop rate
Common : Uncommon : Legendary = 63 : 27 : 1

Item Analysis

Ignoring on-kill effects such as Berserker’s Pauldron, items that are completely outclassed by others of the same rarity, items whose ceiling is too low because they scale only from base damage, and some high-tier items with unusually specific effects:

  • Attack speed: Soldier’s Syringe, Predatory Instincts, War Horn (assuming it triggers), Irradiant Pearl

  • Critical chance: Lens-Maker’s Glasses, Predatory Instincts, Irradiant Pearl

  • Critical damage multiplier: Laser Scope

  • Proc damage: AtG Missile Mk. 1, Charged Perforator, Molten Perforator, Ukulele, Sticky Bomb, Brilliant Behemoth

  • Damage multipliers: Delicate Watch (with risk), Focus Crystal, Armor-Piercing Rounds, Irradiant Pearl. Based on Amdahl’s law, Crowbar, Old Guillotine, and similar items are discarded

Mathematical Model

$$ DPS = Coeff \cdot BaseDamage \cdot AttackSpeed \cdot (1 + CritRate \cdot (CritDamage-1)) \cdot TriggerDamage $$

The first five terms are relatively simple:

$$ BaseDamage = 14 + 2.8lvl\\ Coeff = 1 + 0.1N_{focus} \\ CritDamage = 2 + N_{laser} \\ CritRate = min(1, 0.01 + 0.1N_{Red} + \min{(0.05,N_{instinct})} + 0.1N_{pearl})\\ AttackSpeed = 1 + 0.15N_{yellow} + 0.24N_{instinct} + 0.1N_{pearl} + min(0.7, N_{horn})\\ $$

The main difficulty lies in the damage caused by proc effects. These effects can trigger one another recursively, and their trigger probabilities and proc coefficients differ. Suppose we have one missile, one Ukulele, and one Sticky Bomb. For a single shot, we first sample three Bernoulli distributions. The probability vector for the three effects is \(P_1=(0.1,0.25,0.05)\). Future triggers must also take proc coefficients into account, which produces a transition to the next state. For example, the probability that missiles trigger again is \(P_{2,1} = 0.1 * (1 * 0.1 + 0.2 * 2 * 0.25 + 0 * 0.05 ) = 0.02\). In practice, this is the intrinsic trigger probability 0.1 multiplied by the effective attack count 0.2 from the previous stage.

Let the level-\(n\) trigger probabilities of all effects be a k-dimensional vector \(P_n\), let the proc coefficient matrix be \(C\), and let the original trigger probability vector be \(P_1\). Then the recursion is

$$ P_n^{T}=C \cdot P_{n-1}^{T} \cdot P_1^T $$

$$ \sum_i { P_{n,i} \rightarrow 0 }, n \rightarrow \infin $$

The decay is exponential, so it is enough to calculate only the first five levels.

As for damage, missile-triggered missile damage can reach \(3^n\). With four missiles, the mathematical expectation of single-shot missile damage can diverge to infinity, but in practice the trigger probability is very low and damage overflow is also likely, especially on bosses where there may be a forced cap. Therefore, when calculating proc-effect damage, this article uses multiples of the initial total damage as a conservative estimate.

Finally, we solve an equality-constrained optimization problem.

For the case with only common and uncommon items:

$$ \max _ N DPS \\ s.t. \forall N_i \in N \\ N_{focus}+N_{red}+N_{yellow}+N_{bomb} = 20 \\ N_{missle}+N_{ukulele}+N_{instinct} = 10 $$

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def loss(w):
focus, red, yellow, bomb, missle, ukulele, instinct = w
coeff = 1 + 0.1*focus
crit_damage = 2
crit_chance = min(1, 0.01 + 0.1*red + min(0.05, instinct))
attack_speed = 1 + 0.15*yellow + 0.24*instinct

P_1 = np.array([0.1, 0.25*0.8, min(1, 0.05*bomb)*1.8])
C = np.array([1, min(1, 0.2*ukulele), 0])

P_2 = C.dot(P_1.T)*(P_1.T)
P_3 = C.dot(P_2.T)*(P_1.T)
P_4 = C.dot(P_3.T)*(P_1.T)
P_5 = C.dot(P_4.T)*(P_1.T)

missle_times, ukulele_times, bomb_times = sum([P_1, P_2, P_3, P_4, P_5])
missle_damage = 3*missle*missle_times
ukulele_damage = 0.8*ukulele_times
bomb_damage = 1.8*bomb_times

dps = coeff * (1 + crit_chance*(crit_damage-1)) * attack_speed * (1 + missle_damage + ukulele_damage + bomb_damage)
return -dps

cons = [{'type': 'eq', 'fun': lambda w: sum(w[:4]) - 20},
{'type': 'eq', 'fun': lambda w: sum(w[4:]) - 10}]
bnds = [(0, 200)]*7

ret = minimize(loss, [1, 1, 1, 1, 1, 1, 1], method='SLSQP', bounds=bnds, constraints=cons)

Compute how the optimal solution changes as the total item count increases:

Result analysis: Among common items, take Soldier’s Syringe and Lens-Maker’s Glasses in a 1:1 ratio early on. Once the number of glasses reaches 9, start taking Focus Crystal. The target count ratio of crystal to syringe is 1:1. Sticky Bomb is useless. Among uncommon items, missiles are strong throughout the entire game. Predatory Instincts becomes useful later, and its count is roughly one fifth of missiles. Ukulele is sensitive to hyperparameters, but the rule is simple: take it aggressively until the bounce count reaches the needed upper bound. Its main value comes from triggering other effects.

DPS growth: as the number of items increases, DPS grows exponentially, with each extra item adding roughly 13.2%.

Thanks to the power of exponential growth, common and uncommon items alone are enough to overflow damage. In the same way, we can compute the optimal build after adding boss items.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
def loss(w, lvl=10):
(
# common
focus,
red,
yellow,
bomb,
steak,
psg,
slug,
fungus,
tough,
# uncommon
missle,
ukulele,
instinct,
# legendary
clover,
# boss
charged_perforator,
molten_perforator,
ir_pearl,
) = w

coeff = 1 + 0.05 * focus + 0.1 * ir_pearl
crit_damage = 2
crit_chance = min(1, 0.01 + 0.1 * red + min(0.05, instinct) + 0.1 * ir_pearl)
attack_speed = 1 + 0.15 * yellow + 0.24 * instinct + 0.1 * ir_pearl

P_1 = np.array([0.1, 0.25 * 0.8, min(1, 0.05 * bomb) * 1.8, 0.1, 0.1])
C = np.array([1, min(1, 0.2 * ukulele), 0, 1, 2.1])

P_2 = C.dot(P_1.T) * (P_1.T)
P_3 = C.dot(P_2.T) * (P_1.T)
P_4 = C.dot(P_3.T) * (P_1.T)
P_5 = C.dot(P_4.T) * (P_1.T)

(
missle_times,
ukulele_times,
bomb_times,
charged_perforator_times,
molten_perforator_times,
) = sum([P_1, P_2, P_3, P_4, P_5])
missle_damage = 3 * missle * missle_times
ukulele_damage = 0.8 * ukulele_times
bomb_damage = 1.8 * bomb_times
charged_perforator_damage = (
5 * charged_perforator * charged_perforator * charged_perforator_times
)
molten_perforator_damage = (
3 * 3 * molten_perforator * molten_perforator * molten_perforator_times
)

dps = (
coeff
* (1 + crit_chance * (crit_damage - 1))
* attack_speed
* (
1
+ missle_damage
+ ukulele_damage
+ bomb_damage
+ charged_perforator_damage
+ molten_perforator_damage
)
)

hp = (130 + 39 * lvl) * (1 + 0.1 * ir_pearl) + 25 * steak
shield = 0.08 * hp * psg
regen = 0.6 + 0.2 * lvl + 3 * slug + 0.045 * 2 * fungus * hp + 0.1 * ir_pearl

Q = (1 + 0.15 * tough) ** (1 + clover)

R1 = regen * Q
R2 = (hp + shield) * Q
R = np.log(R1)*np.log(R2)

score = dps

return -score


bnds = [(0, 50)] * 16

Maximum Tankiness

Mechanics

In the game, total HP consists of Health, Shield, and Barrier.
Health mainly comes from leveling up and Bison Steak. Personal Shield Generator, or PSG, provides shield. Bustling Fungus and Cautious Slug stack healing.

The quality of the health bar depends on armor and block chance.

Armor formula

$$ DamageDealt = \frac{100}{100+Armor},Armor>0 $$

$$ \frac{HP_{adjusted}}{HP} = 1 + Armor/100 $$

Block chance

$$ BlockChance = 1-\frac{1}{1+0.15x} $$

Here \(x\) is the number of Tougher Times.

$$ \frac{HP_{adjusted}}{HP} = 1 + 0.15x $$

We can see that the increase in effective HP from any single attribute is linear. Combining all three would yield exponential growth, but the problem is that there is no item that grants permanent armor, so at first glance only total HP and block chance can be increased, which seems underwhelming.

Fortunately, the legendary item 57 Leaf Clover fundamentally changes the block check. Suppose you have \(y\) copies of 57 Leaf Clover. Then the single-hit block probability becomes

$$ BlockChance' = 1-(\frac{1}{1+0.15x})^{1+y} $$

Differentiate effective HP with respect to \(x\):

$$ \frac{d\frac{HP_{adjusted}'}{HP}}{dx} = (1+y)(1+0.15x)^{y} $$

Now the effective HP gained from Tougher Times grows exponentially.
For example, with 20 Tougher Times and 5 clovers, the block chance reaches 99.976%, and effective HP becomes more than 4000 times the base HP. Even with fewer items, 10 Tougher Times plus 2 clovers already provide a 16x multiplier in effective HP. In fact, if you equip 200 Tougher Times and 25 clovers, hit probability drops to \(2^{-128}\), which exceeds the range of single-precision floating point and may enter truly invincible territory.

But that is only a theoretical expectation. Could one unblocked hit still get you killed instantly? The answer is yes in the early game, but no in the late game. First, because One-Shot Protection, OSP, exists, at least 10% HP will remain. So we only need to consider how many hits can still be survived after that point.
Assume the character then suffers 10 consecutive lethal hits. The block events follow a binomial distribution \(X \sim B(10, p’)\).
The probability that all of them are blocked is given by the probability mass function:

$$ f(k,n,p')=C_n^kp'^k(1-p')^{n-k}=(1-(\frac{1}{1+0.15x})^{1+y})^{10} $$

With 15 Tougher Times and 2 clovers, the success probability is 74.4%.

With 20 Tougher Times and 5 clovers, the success probability is 99.8%.

Mathematical Modeling

“Building tankiness” actually has two optimization targets: the ability to stand still and absorb sustained damage, and the ability to survive burst damage.

Define sustained survivability as how much DPS can be endured per second:

$$ R_1 = Regen * Q $$

Burst survivability = health bar thickness * health bar quality

$$ R_2=(health+barrier+shield)*Q $$

Define the combined tankiness score as

$$ R=\sqrt{R_1R_2} $$

Taking Engineer on Monsoon difficulty as the object of discussion, the problem we want to solve is

$$ \max R $$

Health bar length and healing:

$$ health = 130 + 39lvl + 25N_{steak} \\ shield = 0.08*health*N_{psg} \\ regen = 0.6 + 0.2lvl + 3N_{slug} + 0.045N_{fungus} \cdot health \\ $$

Health bar quality without stacking armor:

$$ Q = (1+0.15N_{tough})^{1+N_{clover}} $$

The numerical result is that items with flat value additions, such as Bison Steak and Personal Shield Generator, are all bad, even early on. Tougher Times plus clover is effectively invincible, and two mushrooms are enough.

Summary

Combined build after adding boss items and legendary items:

Common items For offense, take Soldier’s Syringe and Lens-Maker’s Glasses at 1:1 early on, then start adding Focus Crystal once glasses reach 9. The target count is Syringe = Focus Crystal. For defense, take two or three Bustling Fungus, and use the rest on Tougher Times.

Uncommon items Early on, keep missiles, Ukulele, and Predatory Instincts at 1:1:1. After Ukulele is sufficient, keep missiles and instincts at 2:1.

Legendary items Clover, always the best.

Boss items Molten Perforator, the strongest offensive item.

Appendix

A. Common and uncommon offensive build table

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
focus	red	yellow	bomb	missle	ukulele	instinct
1 0 0 1 0 0 0 0
2 0 0 3 0 1 0 0
3 0 0 5 0 2 0 0
4 0 1 5 0 3 0 0
5 0 3 6 0 4 0 0
6 0 4 7 0 5 0 0
7 0 5 8 0 6 0 0
8 0 6 9 0 7 0 0
9 0 7 10 0 7 0 1
10 0 9 10 0 8 0 1
11 0 9 11 0 9 0 1
12 3 9 6 4 6 0 5
13 3 9 13 0 10 0 2
14 4 9 14 0 11 0 2
15 5 9 14 0 12 0 2
16 6 9 15 0 13 0 2
17 8 9 16 0 13 0 3
18 9 9 17 0 14 0 3
19 10 9 18 0 15 0 3
20 11 9 18 0 16 0 3
21 12 9 19 0 16 0 4
22 14 9 20 0 17 0 4
23 15 9 21 0 18 0 4
24 16 9 22 0 19 0 4
25 14 9 25 0 18 4 1
26 15 9 14 12 11 4 9
27 17 9 27 0 20 4 1
28 18 9 28 0 21 4 1
29 19 9 29 0 21 4 2
30 20 9 29 0 22 4 2
31 21 9 30 0 23 4 2
32 23 9 31 0 24 4 2
33 24 9 32 0 24 4 3
34 25 9 33 0 25 5 3
35 26 9 33 0 26 4 3
36 27 9 34 0 27 5 3
37 29 9 35 0 27 5 4
38 30 9 36 0 28 4 4
39 31 9 37 0 29 4 4
40 32 9 37 0 30 5 4
41 33 9 38 0 30 4 5
42 35 9 39 0 31 4 5
43 36 9 40 0 32 4 5
44 37 9 41 0 33 4 5
45 38 9 41 0 33 4 6
46 39 9 42 0 34 5 6
47 41 9 43 0 35 4 6
48 42 9 44 0 36 4 6
49 43 9 45 0 36 5 7
50 44 9 45 0 37 4 7
51 45 9 47 0 38 4 7
52 47 9 47 0 39 4 7
53 48 9 48 0 39 4 8
54 49 9 49 0 40 5 8
55 50 9 49 0 41 5 8
56 51 9 50 0 42 5 8
57 53 9 51 0 42 5 9
58 54 9 52 0 43 4 9
59 55 9 53 0 44 4 9

B. Common, uncommon, and boss offensive build table

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
	focus	red	yellow	bomb	steak	psg	slug	fungus	tough	missle	ukulele	instinct	clover	charged_perforator	molten_perforator	ir_pearl
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0
2 0 0 3 0 0 0 0 0 0 1 0 0 0 0 0 0
3 0 1 3 0 0 0 0 0 0 2 0 1 0 0 1 0
4 0 2 4 0 0 0 0 0 0 3 0 1 0 0 1 0
5 0 3 4 0 0 0 0 0 0 3 0 1 0 0 1 0
6 0 4 5 0 0 0 0 0 0 4 0 1 0 0 1 0
7 0 5 5 0 0 0 0 0 0 2 2 2 0 0 1 0
8 0 6 6 0 0 0 0 0 0 0 4 2 0 0 2 0
9 0 6 6 0 0 0 0 0 0 1 4 2 0 0 2 0
10 0 7 7 0 0 0 0 0 0 1 4 2 0 0 2 0
11 0 8 7 0 0 0 0 0 0 2 5 3 0 0 2 0
12 0 9 8 0 0 0 0 0 0 3 4 3 0 0 3 0
13 0 9 8 0 0 0 0 0 0 3 4 3 0 0 3 0
14 1 9 9 0 0 0 0 0 0 4 5 3 0 0 3 0
15 2 9 9 0 0 0 0 0 0 4 5 4 0 0 3 0
16 3 9 10 0 0 0 0 0 0 5 5 4 0 0 4 0
17 4 9 10 0 0 0 0 0 0 6 5 4 0 0 4 0
18 5 9 11 0 0 0 0 0 0 6 5 4 0 0 4 0
19 6 9 11 0 0 0 0 0 0 7 5 5 0 0 4 0
20 7 9 12 0 0 0 0 0 0 8 4 5 0 0 5 0
21 8 9 12 0 0 0 0 0 0 8 5 5 0 0 5 0
22 9 9 12 0 0 0 0 0 0 9 5 5 0 0 5 0
23 9 9 13 0 0 0 0 0 0 9 5 6 0 0 6 0
24 10 9 14 0 0 0 0 0 0 10 5 6 0 0 6 0
25 11 9 14 0 0 0 0 0 0 11 5 6 0 0 6 0
26 12 9 15 0 0 0 0 0 0 11 5 6 0 0 6 0
27 13 9 15 0 0 0 0 0 0 12 5 7 0 0 6 0
28 14 9 16 0 0 0 0 0 0 13 5 7 0 0 7 0
29 15 9 16 0 0 0 0 0 0 13 5 7 0 0 7 0
30 16 9 17 0 0 0 0 0 0 14 5 7 0 0 7 0
31 17 9 17 0 0 0 0 0 0 14 5 8 0 0 7 0
32 17 9 18 0 0 0 0 0 0 15 5 8 0 0 8 0
33 18 9 18 0 0 0 0 0 0 16 5 8 0 0 8 0
34 20 9 18 0 0 0 0 0 0 16 5 8 0 0 8 0
35 20 9 19 0 0 0 0 0 0 17 5 9 0 0 8 0
36 21 9 20 0 0 0 0 0 0 18 5 9 0 0 9 0
37 22 9 20 0 0 0 0 0 0 18 5 9 0 0 9 0
38 23 9 20 0 0 0 0 0 0 19 5 9 0 0 9 0

Risk of Rain 2 Engineer Exponential Build Optimization

https://en.heth.ink/Risk-of-Rain-2-ngin/

Author

YK

Posted on

2022-03-30

Updated on

2022-03-30

Licensed under