aminus 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -10
- package/dist/src/core/artifact-builder.d.ts +3 -0
- package/dist/src/core/artifact-builder.js +41 -25
- package/dist/src/core/artifacts.d.ts +1 -2
- package/dist/src/core/artifacts.js +1 -2
- package/dist/src/core/formulas.d.ts +1 -1
- package/dist/src/core/formulas.js +1 -1
- package/dist/src/core/optimizer.d.ts +7 -1
- package/dist/src/core/optimizer.js +87 -35
- package/dist/src/core/stat.d.ts +2 -1
- package/dist/src/core/stat.js +10 -4
- package/package.json +1 -1
- package/src/core/formulas.ts +1 -1
- package/tests/int/damage-calculation.test.ts +7 -10
package/README.md
CHANGED
|
@@ -21,17 +21,14 @@ let ayaka = new StatTable(
|
|
|
21
21
|
);
|
|
22
22
|
|
|
23
23
|
const rotation = new Rotation(
|
|
24
|
-
["n1", dmg_formula("Cryo", "Normal", 0.84,
|
|
25
|
-
["n2", dmg_formula("Cryo", "Normal", 0.894,
|
|
26
|
-
["ca", dmg_formula("Cryo", "Charged", 3.039,
|
|
27
|
-
["skill", dmg_formula("Cryo", "Skill", 4.07,
|
|
28
|
-
["burstcuts", dmg_formula("Cryo", "Burst", 1.91,
|
|
29
|
-
["burstexplosion", dmg_formula("Cryo", "Burst", 2.86
|
|
24
|
+
["n1", dmg_formula("Cryo", "Normal", 0.84, 3)],
|
|
25
|
+
["n2", dmg_formula("Cryo", "Normal", 0.894, 2)],
|
|
26
|
+
["ca", dmg_formula("Cryo", "Charged", 3.039, 2)],
|
|
27
|
+
["skill", dmg_formula("Cryo", "Skill", 4.07, 2)],
|
|
28
|
+
["burstcuts", dmg_formula("Cryo", "Burst", 1.91, 19)],
|
|
29
|
+
["burstexplosion", dmg_formula("Cryo", "Burst", 2.86)],
|
|
30
30
|
);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
ayaka = ayaka.merge(optimalKqmc5ArtifactsStats(ayaka, rotation, energyRechargeRequirement));
|
|
34
|
-
|
|
31
|
+
ayaka = ayaka.merge(optimalKqmc5ArtifactsStats(ayaka, rotation, 1.30));
|
|
35
32
|
const dps = rotation.execute(ayaka) / 21.0;
|
|
36
33
|
```
|
|
37
34
|
|
|
@@ -13,6 +13,9 @@ export declare class ArtifactBuilder {
|
|
|
13
13
|
rolls: Map<[StatType, ArtifactRollQuality, number], number>;
|
|
14
14
|
constraints: Map<[StatType, number], number>;
|
|
15
15
|
rollLimit?: number;
|
|
16
|
+
private findRollKey;
|
|
17
|
+
private getConstraint;
|
|
18
|
+
private addConstraint;
|
|
16
19
|
constructor(flower?: Artifact, feather?: Artifact, sands?: Artifact, goblet?: Artifact, circlet?: Artifact);
|
|
17
20
|
private initConstraints;
|
|
18
21
|
static kqmc(flower?: Artifact, feather?: Artifact, sands?: Artifact, goblet?: Artifact, circlet?: Artifact): ArtifactBuilder;
|
|
@@ -4,6 +4,27 @@ import { POSSIBLE_SUB_STATS, rollQualityMultiplier, maxRollsFor, maxRollsForGive
|
|
|
4
4
|
* Way to build 1-5 artifact and distrubte substats accordingly
|
|
5
5
|
*/
|
|
6
6
|
export class ArtifactBuilder {
|
|
7
|
+
findRollKey(statType, quality, rarity) {
|
|
8
|
+
for (const key of this.rolls.keys()) {
|
|
9
|
+
if (key[0] === statType && key[1] === quality && key[2] === rarity) {
|
|
10
|
+
return key;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
getConstraint(statType, rarity) {
|
|
16
|
+
let sum = 0;
|
|
17
|
+
for (const [[stat, r], count] of this.constraints.entries()) {
|
|
18
|
+
if (stat === statType && r === rarity) {
|
|
19
|
+
sum += count;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return sum;
|
|
23
|
+
}
|
|
24
|
+
addConstraint(statType, rarity, amount) {
|
|
25
|
+
const key = [statType, rarity];
|
|
26
|
+
this.constraints.set(key, amount);
|
|
27
|
+
}
|
|
7
28
|
//general constructor to building any set of artifacts
|
|
8
29
|
constructor(flower, feather, sands, goblet, circlet) {
|
|
9
30
|
this.rolls = new Map();
|
|
@@ -27,9 +48,8 @@ export class ArtifactBuilder {
|
|
|
27
48
|
].filter((p) => p !== undefined);
|
|
28
49
|
for (const piece of pieces) {
|
|
29
50
|
if (piece.main_stat !== stat) {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
this.constraints.set(key, current + maxRollsForGiven(piece, stat));
|
|
51
|
+
const current = this.getConstraint(stat, piece.rarity);
|
|
52
|
+
this.addConstraint(stat, piece.rarity, current + maxRollsForGiven(piece, stat));
|
|
33
53
|
}
|
|
34
54
|
}
|
|
35
55
|
}
|
|
@@ -54,8 +74,8 @@ export class ArtifactBuilder {
|
|
|
54
74
|
for (const stat of POSSIBLE_SUB_STATS) {
|
|
55
75
|
for (const piece of pieces) {
|
|
56
76
|
if (piece.main_stat !== stat) {
|
|
57
|
-
const
|
|
58
|
-
builder.
|
|
77
|
+
const current = builder.getConstraint(stat, piece.rarity);
|
|
78
|
+
builder.addConstraint(stat, piece.rarity, current + 2);
|
|
59
79
|
}
|
|
60
80
|
}
|
|
61
81
|
}
|
|
@@ -65,8 +85,8 @@ export class ArtifactBuilder {
|
|
|
65
85
|
// Roll 2 of each substat at AVG quality and rollRarity
|
|
66
86
|
for (const stat of POSSIBLE_SUB_STATS) {
|
|
67
87
|
builder.roll(stat, "AVG", rollRarity, 2);
|
|
68
|
-
const
|
|
69
|
-
builder.
|
|
88
|
+
const current = builder.getConstraint(stat, rollRarity);
|
|
89
|
+
builder.addConstraint(stat, rollRarity, current + 2);
|
|
70
90
|
}
|
|
71
91
|
return builder;
|
|
72
92
|
}
|
|
@@ -172,21 +192,20 @@ export class ArtifactBuilder {
|
|
|
172
192
|
const current = this.currentRollsForGiven(substatValue, quality, rarity);
|
|
173
193
|
if (current + num > this.substatConstraint(substatValue, rarity))
|
|
174
194
|
throw new Error("Exceeds constraint");
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
195
|
+
const existingKey = this.findRollKey(substatValue, quality, rarity);
|
|
196
|
+
if (existingKey) {
|
|
197
|
+
this.rolls.set(existingKey, (this.rolls.get(existingKey) || 0) + num);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const key = [substatValue, quality, rarity];
|
|
201
|
+
this.rolls.set(key, num);
|
|
181
202
|
}
|
|
182
203
|
unroll(substatValue, quality, rarity, num) {
|
|
183
204
|
if (!isValidSubstatType(substatValue))
|
|
184
205
|
throw new Error("Invalid substat type");
|
|
185
|
-
const key =
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
rarity,
|
|
189
|
-
];
|
|
206
|
+
const key = this.findRollKey(substatValue, quality, rarity);
|
|
207
|
+
if (!key)
|
|
208
|
+
return;
|
|
190
209
|
const current = this.rolls.get(key) || 0;
|
|
191
210
|
if (current >= num) {
|
|
192
211
|
const newValue = current - num;
|
|
@@ -202,11 +221,9 @@ export class ArtifactBuilder {
|
|
|
202
221
|
return Array.from(this.rolls.values()).reduce((sum, v) => sum + v, 0);
|
|
203
222
|
}
|
|
204
223
|
currentRollsForGiven(statType, quality, rarity) {
|
|
205
|
-
const key =
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
rarity,
|
|
209
|
-
];
|
|
224
|
+
const key = this.findRollKey(statType, quality, rarity);
|
|
225
|
+
if (!key)
|
|
226
|
+
return 0;
|
|
210
227
|
return this.rolls.get(key) || 0;
|
|
211
228
|
}
|
|
212
229
|
maxRolls() {
|
|
@@ -222,8 +239,7 @@ export class ArtifactBuilder {
|
|
|
222
239
|
return pieces.reduce((sum, p) => sum + maxRollsFor(p), 0);
|
|
223
240
|
}
|
|
224
241
|
substatConstraint(statType, rarity) {
|
|
225
|
-
|
|
226
|
-
return this.constraints.get(key) || 0;
|
|
242
|
+
return this.getConstraint(statType, rarity);
|
|
227
243
|
}
|
|
228
244
|
rollsLeft() {
|
|
229
245
|
return this.maxRolls() - this.currentRolls();
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ArtifactBuilder } from "./artifact-builder";
|
|
2
|
-
import { ArtifactFactory } from "./artifact-factory";
|
|
3
2
|
import { Artifact, ArtifactType } from "./artifact-constants";
|
|
4
3
|
type ArtifactRollQuality = "MAX" | "HIGH" | "MID" | "LOW" | "AVG";
|
|
5
|
-
export { ArtifactBuilder
|
|
4
|
+
export { ArtifactBuilder };
|
|
6
5
|
export type { Artifact, ArtifactType, ArtifactRollQuality };
|
|
@@ -8,5 +8,5 @@ declare const def_multiplier: (character_level: number, enemy_level: number, def
|
|
|
8
8
|
declare const res_multiplier: (enemy_base_resistance: number, resistance_reduction: number) => number;
|
|
9
9
|
declare const amplifier_multiplier: (amplifier: number, elemental_mastery: number, reaction_bonus: number) => number;
|
|
10
10
|
declare const calculate_damage: (element: Element, damage_type: DamageType, scaling: BaseScaling, amplifier: Amplifier, instances: number, motion_value: number, character: StatTable, buffs: StatTable | undefined) => number;
|
|
11
|
-
declare const dmg_formula: (element: Element, damage_type: DamageType, motion_value: number,
|
|
11
|
+
declare const dmg_formula: (element: Element, damage_type: DamageType, motion_value: number, instances?: number, buffs?: StatTable, scaling?: BaseScaling, amplifier?: Amplifier) => (s: StatTable) => number;
|
|
12
12
|
export { default_damage_formula, avg_crit_multiplier, def_multiplier, res_multiplier, amplifier_multiplier, calculate_damage, total_attack, total_defense, total_health, dmg_formula, };
|
|
@@ -196,7 +196,7 @@ const calculate_damage = (element, damage_type, scaling, amplifier, instances, m
|
|
|
196
196
|
}
|
|
197
197
|
return default_damage_formula(instances, total_base_scaling_stat, motion_value, 1.0, 0.0, avg_crit_multiplier(total), total_dmg_bonus, 0.0, def_multiplier(90, 100, def_reduction, def_ignore), res_multiplier(0.1, resistance_reduction), amp_multiplier);
|
|
198
198
|
};
|
|
199
|
-
const dmg_formula = (element, damage_type, motion_value, buffs = new StatTable(),
|
|
199
|
+
const dmg_formula = (element, damage_type, motion_value, instances = 1, buffs = new StatTable(), scaling = "ATK", amplifier = "None") => (s) => {
|
|
200
200
|
const total = s.clone();
|
|
201
201
|
if (buffs) {
|
|
202
202
|
for (const [key, value] of buffs) {
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import { StatType, StatTable, Rotation } from "./stat";
|
|
2
|
-
|
|
2
|
+
import { Artifact } from "./artifact-constants";
|
|
3
|
+
/** Public API */
|
|
4
|
+
type SubstatDistribution = Map<StatType, number>;
|
|
5
|
+
export declare function optimalMainStats(stats: StatTable, rotation: Rotation): [StatType, StatType, StatType];
|
|
6
|
+
export declare function gradient5StarKqmcArtifactSubstatOptimizer(stats: StatTable, target: Rotation, flower: Artifact | undefined, feather: Artifact | undefined, sands: Artifact | undefined, goblet: Artifact | undefined, circlet: Artifact | undefined, energyRechargeRequirement: number): SubstatDistribution;
|
|
7
|
+
export declare function optimalKqmc5ArtifactsStats(stats: StatTable, target: Rotation, energyRechargeRequirement: number): StatTable;
|
|
8
|
+
export {};
|
|
@@ -1,35 +1,90 @@
|
|
|
1
1
|
import { StatTable } from "./stat";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
2
|
+
import { POSSIBLE_SANDS_STATS, POSSIBLE_GOBLET_STATS, POSSIBLE_CIRCLE_STATS, POSSIBLE_SUB_STATS, getMainStatValue, } from "./artifact-constants";
|
|
3
|
+
import { ArtifactBuilder } from "./artifact-builder";
|
|
4
|
+
export function optimalMainStats(stats, rotation) {
|
|
5
|
+
return globalKqmcArtifactMainStatOptimizer(stats, rotation);
|
|
6
|
+
}
|
|
7
|
+
export function gradient5StarKqmcArtifactSubstatOptimizer(stats, target, flower, feather, sands, goblet, circlet, energyRechargeRequirement) {
|
|
8
|
+
const builder = ArtifactBuilder.kqmc(flower, feather, sands, goblet, circlet);
|
|
9
|
+
while (true) {
|
|
10
|
+
const combinedStats = stats.merge(builder.build());
|
|
11
|
+
if (combinedStats.get("EnergyRecharge") >= energyRechargeRequirement) {
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
if (builder.rollsLeft() <= 0 ||
|
|
15
|
+
builder.rollsLeftForGiven("EnergyRecharge", "AVG", 5) <= 0) {
|
|
16
|
+
throw new Error("Energy Recharge requirements cannot be met with substats alone");
|
|
17
|
+
}
|
|
18
|
+
builder.roll("EnergyRecharge", "AVG", 5, 1);
|
|
19
|
+
}
|
|
20
|
+
const possibleSubsToRoll = new Set(POSSIBLE_SUB_STATS);
|
|
21
|
+
while (builder.rollsLeft() > 0 && possibleSubsToRoll.size > 0) {
|
|
22
|
+
let bestSub = "None";
|
|
23
|
+
let bestValue = Number.NEGATIVE_INFINITY;
|
|
24
|
+
for (const substat of possibleSubsToRoll) {
|
|
25
|
+
if (builder.currentRollsForGiven(substat, "AVG", 5) >=
|
|
26
|
+
builder.substatConstraint(substat, 5)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
builder.roll(substat, "AVG", 5, 1);
|
|
30
|
+
const value = target.execute(stats.merge(builder.build()));
|
|
31
|
+
builder.unroll(substat, "AVG", 5, 1);
|
|
32
|
+
if (value > bestValue) {
|
|
33
|
+
bestValue = value;
|
|
34
|
+
bestSub = substat;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (bestSub === "None") {
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
builder.roll(bestSub, "AVG", 5, 1);
|
|
41
|
+
}
|
|
42
|
+
const distribution = new Map();
|
|
43
|
+
for (const [[stat], count] of builder.rolls.entries()) {
|
|
44
|
+
distribution.set(stat, (distribution.get(stat) || 0) + count);
|
|
45
|
+
}
|
|
46
|
+
return distribution;
|
|
47
|
+
}
|
|
48
|
+
export function optimalKqmc5ArtifactsStats(stats, target, energyRechargeRequirement) {
|
|
49
|
+
const [sandsMain, gobletMain, circletMain] = globalKqmcArtifactMainStatOptimizer(stats, target);
|
|
50
|
+
const flower = {
|
|
51
|
+
type: "flower",
|
|
52
|
+
rarity: 5,
|
|
53
|
+
level: 20,
|
|
54
|
+
main_stat: "FlatHP",
|
|
55
|
+
};
|
|
56
|
+
const feather = {
|
|
57
|
+
type: "feather",
|
|
58
|
+
rarity: 5,
|
|
59
|
+
level: 20,
|
|
60
|
+
main_stat: "FlatATK",
|
|
61
|
+
};
|
|
62
|
+
const sands = {
|
|
63
|
+
type: "sands",
|
|
64
|
+
rarity: 5,
|
|
65
|
+
level: 20,
|
|
66
|
+
main_stat: sandsMain,
|
|
67
|
+
};
|
|
68
|
+
const goblet = {
|
|
69
|
+
type: "goblet",
|
|
70
|
+
rarity: 5,
|
|
71
|
+
level: 20,
|
|
72
|
+
main_stat: gobletMain,
|
|
73
|
+
};
|
|
74
|
+
const circlet = {
|
|
75
|
+
type: "circlet",
|
|
76
|
+
rarity: 5,
|
|
77
|
+
level: 20,
|
|
78
|
+
main_stat: circletMain,
|
|
79
|
+
};
|
|
80
|
+
const builder = new ArtifactBuilder(flower, feather, sands, goblet, circlet);
|
|
81
|
+
const optimalSubstats = gradient5StarKqmcArtifactSubstatOptimizer(stats, target, flower, feather, sands, goblet, circlet, energyRechargeRequirement);
|
|
82
|
+
for (const [stat, count] of optimalSubstats.entries()) {
|
|
83
|
+
builder.roll(stat, "AVG", 5, count);
|
|
84
|
+
}
|
|
85
|
+
return stats.merge(builder.build());
|
|
86
|
+
}
|
|
87
|
+
/** Ecapsulated implementation */
|
|
33
88
|
// Computes gradients of stats based on slopes
|
|
34
89
|
function statGradients(base, target, slopes) {
|
|
35
90
|
const gradients = new Map();
|
|
@@ -58,7 +113,7 @@ function reluHeuristic(base, target, slopes) {
|
|
|
58
113
|
return effectiveSet;
|
|
59
114
|
}
|
|
60
115
|
// Finds best artifact main stat combo for given stats and rotation
|
|
61
|
-
function globalKqmcArtifactMainStatOptimizer(stats, target
|
|
116
|
+
function globalKqmcArtifactMainStatOptimizer(stats, target) {
|
|
62
117
|
const sandsStats = new Set(POSSIBLE_SANDS_STATS);
|
|
63
118
|
const gobletStats = new Set(POSSIBLE_GOBLET_STATS);
|
|
64
119
|
const circletStats = new Set(POSSIBLE_CIRCLE_STATS);
|
|
@@ -95,6 +150,3 @@ function globalKqmcArtifactMainStatOptimizer(stats, target, getMainStatValue) {
|
|
|
95
150
|
}
|
|
96
151
|
return bestCombo;
|
|
97
152
|
}
|
|
98
|
-
export function optimalMainStats(stats, rotation, getMainStatValue) {
|
|
99
|
-
return globalKqmcArtifactMainStatOptimizer(stats, rotation, getMainStatValue);
|
|
100
|
-
}
|
package/dist/src/core/stat.d.ts
CHANGED
|
@@ -22,7 +22,8 @@ type DamageCompute = (s: StatTable) => number;
|
|
|
22
22
|
declare const compose: (...funcs: DamageCompute[]) => DamageCompute;
|
|
23
23
|
declare class Rotation {
|
|
24
24
|
actions: [string, DamageCompute][];
|
|
25
|
-
constructor(actions: [string, DamageCompute]
|
|
25
|
+
constructor(actions: ([string, DamageCompute] | DamageCompute)[]);
|
|
26
|
+
constructor(...actions: ([string, DamageCompute] | DamageCompute)[]);
|
|
26
27
|
add(action: [string, DamageCompute]): void;
|
|
27
28
|
execute(s: StatTable): number;
|
|
28
29
|
}
|
package/dist/src/core/stat.js
CHANGED
|
@@ -148,15 +148,21 @@ const compose = (...funcs) => {
|
|
|
148
148
|
return (s) => funcs.reduce((acc, fn) => acc + fn(s), 0);
|
|
149
149
|
};
|
|
150
150
|
class Rotation {
|
|
151
|
-
constructor(
|
|
151
|
+
constructor(...args) {
|
|
152
152
|
this.actions = [];
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
// Support both `new Rotation([...])` and `new Rotation(a, b, c)`.
|
|
154
|
+
const first = args[0];
|
|
155
|
+
const isSingleArrayArg = args.length === 1 && Array.isArray(first);
|
|
156
|
+
const normalized = isSingleArrayArg
|
|
157
|
+
? first
|
|
158
|
+
: args;
|
|
159
|
+
if (normalized.length > 0 && typeof normalized[0] === "function") {
|
|
160
|
+
for (let compute of normalized) {
|
|
155
161
|
this.actions.push(["", compute]);
|
|
156
162
|
}
|
|
157
163
|
}
|
|
158
164
|
else {
|
|
159
|
-
this.actions =
|
|
165
|
+
this.actions = normalized;
|
|
160
166
|
}
|
|
161
167
|
}
|
|
162
168
|
add(action) {
|
package/package.json
CHANGED
package/src/core/formulas.ts
CHANGED
|
@@ -286,8 +286,8 @@ const dmg_formula =
|
|
|
286
286
|
element: Element,
|
|
287
287
|
damage_type: DamageType,
|
|
288
288
|
motion_value: number,
|
|
289
|
-
buffs: StatTable = new StatTable(),
|
|
290
289
|
instances = 1,
|
|
290
|
+
buffs: StatTable = new StatTable(),
|
|
291
291
|
scaling: BaseScaling = "ATK",
|
|
292
292
|
amplifier: Amplifier = "None",
|
|
293
293
|
) =>
|
|
@@ -19,17 +19,14 @@ describe("Damage Calculation Integration", () => {
|
|
|
19
19
|
);
|
|
20
20
|
|
|
21
21
|
const rotation = new Rotation(
|
|
22
|
-
["n1", dmg_formula("Cryo", "Normal", 0.84,
|
|
23
|
-
["n2", dmg_formula("Cryo", "Normal", 0.894,
|
|
24
|
-
["ca", dmg_formula("Cryo", "Charged", 3.039,
|
|
25
|
-
["skill", dmg_formula("Cryo", "Skill", 4.07,
|
|
26
|
-
["burstcuts", dmg_formula("Cryo", "Burst", 1.91,
|
|
27
|
-
["burstexplosion", dmg_formula("Cryo", "Burst", 2.86
|
|
22
|
+
["n1", dmg_formula("Cryo", "Normal", 0.84, 3)],
|
|
23
|
+
["n2", dmg_formula("Cryo", "Normal", 0.894, 2)],
|
|
24
|
+
["ca", dmg_formula("Cryo", "Charged", 3.039, 2)],
|
|
25
|
+
["skill", dmg_formula("Cryo", "Skill", 4.07, 2)],
|
|
26
|
+
["burstcuts", dmg_formula("Cryo", "Burst", 1.91, 19)],
|
|
27
|
+
["burstexplosion", dmg_formula("Cryo", "Burst", 2.86)],
|
|
28
28
|
);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
ayaka = ayaka.merge(optimalKqmc5ArtifactsStats(ayaka, rotation, energyRechargeRequirement));
|
|
32
|
-
|
|
29
|
+
ayaka = ayaka.merge(optimalKqmc5ArtifactsStats(ayaka, rotation, 1.30));
|
|
33
30
|
const dps = rotation.execute(ayaka) / 21.0;
|
|
34
31
|
|
|
35
32
|
expect(dps).toBeGreaterThan(0);
|