@axiapps/bridge-metrics 0.1.0
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/dist/aggregationTypes.cjs +18 -0
- package/dist/aggregationTypes.d.cts +21 -0
- package/dist/aggregationTypes.d.ts +21 -0
- package/dist/aggregationTypes.js +1 -0
- package/dist/boonGeneration.cjs +308 -0
- package/dist/boonGeneration.d.cts +65 -0
- package/dist/boonGeneration.d.ts +65 -0
- package/dist/boonGeneration.js +16 -0
- package/dist/chunk-42DVJJLC.js +106 -0
- package/dist/chunk-4F55Q6K2.js +0 -0
- package/dist/chunk-ELKDB763.js +349 -0
- package/dist/chunk-FU74LJEM.js +77 -0
- package/dist/chunk-J3YCFY3C.js +37 -0
- package/dist/chunk-JP2ZL44R.js +18 -0
- package/dist/chunk-K2SRAMGC.js +0 -0
- package/dist/chunk-KRHODGVU.js +48 -0
- package/dist/chunk-LIGIXSSA.js +1383 -0
- package/dist/chunk-M2WR3JBQ.js +0 -0
- package/dist/chunk-PMVLNDZZ.js +279 -0
- package/dist/chunk-R5EJF5AW.js +147 -0
- package/dist/chunk-RGXSI3AI.js +298 -0
- package/dist/chunk-UFJJ6WLD.js +197 -0
- package/dist/chunk-WW5XFXGC.js +234 -0
- package/dist/chunk-ZFZS7JFU.js +10 -0
- package/dist/combatMetrics.cjs +251 -0
- package/dist/combatMetrics.d.cts +26 -0
- package/dist/combatMetrics.d.ts +26 -0
- package/dist/combatMetrics.js +21 -0
- package/dist/computePlayerAggregation.cjs +2042 -0
- package/dist/computePlayerAggregation.d.cts +249 -0
- package/dist/computePlayerAggregation.d.ts +249 -0
- package/dist/computePlayerAggregation.js +30 -0
- package/dist/conditionsMetrics.cjs +328 -0
- package/dist/conditionsMetrics.d.cts +67 -0
- package/dist/conditionsMetrics.d.ts +67 -0
- package/dist/conditionsMetrics.js +18 -0
- package/dist/constants.cjs +36 -0
- package/dist/constants.d.cts +18 -0
- package/dist/constants.d.ts +18 -0
- package/dist/constants.js +10 -0
- package/dist/dashboardMetrics.cjs +226 -0
- package/dist/dashboardMetrics.d.cts +29 -0
- package/dist/dashboardMetrics.d.ts +29 -0
- package/dist/dashboardMetrics.js +42 -0
- package/dist/dpsReportTypes.cjs +18 -0
- package/dist/dpsReportTypes.d.cts +294 -0
- package/dist/dpsReportTypes.d.ts +294 -0
- package/dist/dpsReportTypes.js +1 -0
- package/dist/index.cjs +2902 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +152 -0
- package/dist/metrics-methods.json +38 -0
- package/dist/metricsSettings.cjs +75 -0
- package/dist/metricsSettings.d.cts +23 -0
- package/dist/metricsSettings.d.ts +23 -0
- package/dist/metricsSettings.js +8 -0
- package/dist/professionUtils.cjs +265 -0
- package/dist/professionUtils.d.cts +10 -0
- package/dist/professionUtils.d.ts +10 -0
- package/dist/professionUtils.js +20 -0
- package/dist/reportMetrics.cjs +224 -0
- package/dist/reportMetrics.d.cts +85 -0
- package/dist/reportMetrics.d.ts +85 -0
- package/dist/reportMetrics.js +12 -0
- package/dist/resUtility.cjs +52 -0
- package/dist/resUtility.d.cts +5 -0
- package/dist/resUtility.d.ts +5 -0
- package/dist/resUtility.js +8 -0
- package/dist/roles.cjs +18 -0
- package/dist/roles.d.cts +17 -0
- package/dist/roles.d.ts +17 -0
- package/dist/roles.js +1 -0
- package/dist/rollup.cjs +378 -0
- package/dist/rollup.d.cts +103 -0
- package/dist/rollup.d.ts +103 -0
- package/dist/rollup.js +16 -0
- package/dist/statsMetrics.cjs +153 -0
- package/dist/statsMetrics.d.cts +39 -0
- package/dist/statsMetrics.d.ts +39 -0
- package/dist/statsMetrics.js +22 -0
- package/dist/timestampUtils.cjs +63 -0
- package/dist/timestampUtils.d.cts +12 -0
- package/dist/timestampUtils.d.ts +12 -0
- package/dist/timestampUtils.js +9 -0
- package/package.json +44 -0
|
File without changes
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
// src/boonGeneration.ts
|
|
2
|
+
var BOON_CATEGORIES = ["selfBuffs", "groupBuffs", "squadBuffs"];
|
|
3
|
+
var CATEGORY_COUNT = {
|
|
4
|
+
selfBuffs: () => 1,
|
|
5
|
+
groupBuffs: (groupCount) => Math.max(groupCount - 1, 0),
|
|
6
|
+
squadBuffs: (_groupCount, squadCount) => Math.max(squadCount - 1, 0)
|
|
7
|
+
};
|
|
8
|
+
var safeDiv = (a, b, fallback = 0) => b ? a / b : fallback;
|
|
9
|
+
var isBoon = (meta) => {
|
|
10
|
+
if (!meta?.classification) return true;
|
|
11
|
+
return meta.classification === "Boon";
|
|
12
|
+
};
|
|
13
|
+
var toBoonId = (id) => `b${id}`;
|
|
14
|
+
var getActiveTimeMs = (player, fallbackMs) => {
|
|
15
|
+
const activeTimes = Array.isArray(player?.activeTimes) ? player.activeTimes : [];
|
|
16
|
+
const activeMs = typeof activeTimes[0] === "number" ? activeTimes[0] : 0;
|
|
17
|
+
return activeMs > 0 ? activeMs : fallbackMs;
|
|
18
|
+
};
|
|
19
|
+
var computeGenerationMs = (category, stacking, generation, wasted, durationMs, groupCount, squadCount) => {
|
|
20
|
+
const count = CATEGORY_COUNT[category](groupCount, squadCount);
|
|
21
|
+
if (!count || !durationMs) {
|
|
22
|
+
return { generationMs: 0, wastedMs: 0 };
|
|
23
|
+
}
|
|
24
|
+
if (stacking) {
|
|
25
|
+
return {
|
|
26
|
+
generationMs: generation * durationMs * count,
|
|
27
|
+
wastedMs: wasted * durationMs * count
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
generationMs: generation / 100 * durationMs * count,
|
|
32
|
+
wastedMs: wasted / 100 * durationMs * count
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
var computeBoonMetrics = (row, category, stacking) => {
|
|
36
|
+
const activeTimeMs = row.activeTimeMs || 1;
|
|
37
|
+
const numFights = row.numFights || 1;
|
|
38
|
+
const groupSupported = row.groupSupported || 1;
|
|
39
|
+
const squadSupported = row.squadSupported || 1;
|
|
40
|
+
const selfData = row.categories.selfBuffs;
|
|
41
|
+
const squadData = row.categories.squadBuffs;
|
|
42
|
+
const sourceData = category === "totalBuffs" ? {
|
|
43
|
+
generationMs: selfData.generationMs + squadData.generationMs,
|
|
44
|
+
wastedMs: selfData.wastedMs + squadData.wastedMs
|
|
45
|
+
} : row.categories[category];
|
|
46
|
+
const generationMs = sourceData.generationMs;
|
|
47
|
+
const wastedMs = sourceData.wastedMs;
|
|
48
|
+
let denom = 1;
|
|
49
|
+
if (category === "groupBuffs") {
|
|
50
|
+
denom = safeDiv(groupSupported - numFights, numFights, 1);
|
|
51
|
+
} else if (category === "squadBuffs") {
|
|
52
|
+
denom = safeDiv(squadSupported - numFights, numFights, 1);
|
|
53
|
+
} else if (category === "totalBuffs") {
|
|
54
|
+
denom = squadSupported || 1;
|
|
55
|
+
}
|
|
56
|
+
let uptimeRaw = 0;
|
|
57
|
+
let wastedRaw = 0;
|
|
58
|
+
if (category === "selfBuffs") {
|
|
59
|
+
uptimeRaw = stacking ? safeDiv(generationMs, activeTimeMs) : safeDiv(generationMs, activeTimeMs) * 100;
|
|
60
|
+
wastedRaw = stacking ? safeDiv(wastedMs, activeTimeMs) : safeDiv(wastedMs, activeTimeMs) * 100;
|
|
61
|
+
} else {
|
|
62
|
+
const base = safeDiv(generationMs, activeTimeMs) / (denom || 1);
|
|
63
|
+
const wastedBase = safeDiv(wastedMs, activeTimeMs) / (denom || 1);
|
|
64
|
+
uptimeRaw = stacking ? base : base * 100;
|
|
65
|
+
wastedRaw = stacking ? wastedBase : wastedBase * 100;
|
|
66
|
+
}
|
|
67
|
+
return { generationMs, wastedMs, uptimeRaw, wastedRaw };
|
|
68
|
+
};
|
|
69
|
+
var getBoonMetricValue = (row, category, stacking, metric) => {
|
|
70
|
+
const { generationMs, uptimeRaw } = computeBoonMetrics(row, category, stacking);
|
|
71
|
+
const activeTimeMs = row.activeTimeMs || 1;
|
|
72
|
+
if (metric === "total") {
|
|
73
|
+
return generationMs / 1e3;
|
|
74
|
+
}
|
|
75
|
+
if (metric === "average") {
|
|
76
|
+
return safeDiv(generationMs, activeTimeMs);
|
|
77
|
+
}
|
|
78
|
+
return uptimeRaw;
|
|
79
|
+
};
|
|
80
|
+
var formatBoonMetricDisplay = (row, category, stacking, metric, options) => {
|
|
81
|
+
const value = getBoonMetricValue(row, category, stacking, metric);
|
|
82
|
+
const isPercent = metric === "uptime" && !stacking;
|
|
83
|
+
const isRate = metric === "average";
|
|
84
|
+
const decimals = options?.roundCountStats && !isPercent && !isRate ? 0 : 2;
|
|
85
|
+
const formatted = value.toLocaleString(void 0, {
|
|
86
|
+
minimumFractionDigits: decimals,
|
|
87
|
+
maximumFractionDigits: decimals
|
|
88
|
+
});
|
|
89
|
+
if (isPercent) {
|
|
90
|
+
return `${formatted}%`;
|
|
91
|
+
}
|
|
92
|
+
return formatted;
|
|
93
|
+
};
|
|
94
|
+
var buildBoonTables = (logs, splitPlayersByClass = false) => {
|
|
95
|
+
const boonMeta = /* @__PURE__ */ new Map();
|
|
96
|
+
const playerAgg = /* @__PURE__ */ new Map();
|
|
97
|
+
logs.forEach((log) => {
|
|
98
|
+
const details = log.details;
|
|
99
|
+
if (!details) return;
|
|
100
|
+
const durationMs = details.durationMS || 0;
|
|
101
|
+
const buffMap = details.buffMap || {};
|
|
102
|
+
Object.entries(buffMap).forEach(([id, meta]) => {
|
|
103
|
+
if (!boonMeta.has(id)) {
|
|
104
|
+
boonMeta.set(id, meta);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const existing = boonMeta.get(id) || {};
|
|
108
|
+
const merged = {
|
|
109
|
+
name: existing.name || meta.name,
|
|
110
|
+
stacking: existing.stacking ?? meta.stacking,
|
|
111
|
+
icon: existing.icon || meta.icon,
|
|
112
|
+
classification: existing.classification || meta.classification
|
|
113
|
+
};
|
|
114
|
+
boonMeta.set(id, merged);
|
|
115
|
+
});
|
|
116
|
+
const players = details.players || [];
|
|
117
|
+
const squadPlayers = players.filter((p) => !p.notInSquad);
|
|
118
|
+
const squadCount = squadPlayers.length;
|
|
119
|
+
const groupCounts = /* @__PURE__ */ new Map();
|
|
120
|
+
squadPlayers.forEach((player) => {
|
|
121
|
+
const group = player.group ?? 0;
|
|
122
|
+
groupCounts.set(group, (groupCounts.get(group) || 0) + 1);
|
|
123
|
+
});
|
|
124
|
+
squadPlayers.forEach((player) => {
|
|
125
|
+
const account = player.account || player.name || player.character_name || "Unknown";
|
|
126
|
+
const profession = player.profession || "Unknown";
|
|
127
|
+
const group = player.group ?? 0;
|
|
128
|
+
const groupCount = groupCounts.get(group) || 1;
|
|
129
|
+
const activeTimeMs = getActiveTimeMs(player, durationMs);
|
|
130
|
+
const key = splitPlayersByClass && profession !== "Unknown" ? `${account}::${profession}` : account;
|
|
131
|
+
if (!playerAgg.has(key)) {
|
|
132
|
+
playerAgg.set(key, {
|
|
133
|
+
account,
|
|
134
|
+
profession,
|
|
135
|
+
professions: /* @__PURE__ */ new Set(),
|
|
136
|
+
professionTimeMs: {},
|
|
137
|
+
activeTimeMs: 0,
|
|
138
|
+
numFights: 0,
|
|
139
|
+
groupSupported: 0,
|
|
140
|
+
squadSupported: 0,
|
|
141
|
+
boons: {}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
const agg = playerAgg.get(key);
|
|
145
|
+
agg.profession = profession;
|
|
146
|
+
if (profession && profession !== "Unknown") {
|
|
147
|
+
agg.professions.add(profession);
|
|
148
|
+
agg.professionTimeMs[profession] = (agg.professionTimeMs[profession] || 0) + activeTimeMs;
|
|
149
|
+
}
|
|
150
|
+
agg.activeTimeMs += activeTimeMs;
|
|
151
|
+
agg.numFights += 1;
|
|
152
|
+
agg.groupSupported += groupCount;
|
|
153
|
+
agg.squadSupported += squadCount;
|
|
154
|
+
BOON_CATEGORIES.forEach((category) => {
|
|
155
|
+
const buffs = player[category] || [];
|
|
156
|
+
buffs.forEach((buff) => {
|
|
157
|
+
if (typeof buff?.id !== "number") return;
|
|
158
|
+
const boonId = toBoonId(buff.id);
|
|
159
|
+
const meta = buffMap[boonId];
|
|
160
|
+
if (!isBoon(meta)) return;
|
|
161
|
+
const stacking = meta?.stacking ?? false;
|
|
162
|
+
const generation = buff.buffData?.[0]?.generation ?? 0;
|
|
163
|
+
const wasted = buff.buffData?.[0]?.wasted ?? 0;
|
|
164
|
+
const { generationMs, wastedMs } = computeGenerationMs(
|
|
165
|
+
category,
|
|
166
|
+
stacking,
|
|
167
|
+
generation,
|
|
168
|
+
wasted,
|
|
169
|
+
durationMs,
|
|
170
|
+
groupCount,
|
|
171
|
+
squadCount
|
|
172
|
+
);
|
|
173
|
+
if (!generationMs && !wastedMs) return;
|
|
174
|
+
if (!boonMeta.has(boonId)) {
|
|
175
|
+
boonMeta.set(boonId, meta || {});
|
|
176
|
+
}
|
|
177
|
+
if (!agg.boons[boonId]) {
|
|
178
|
+
agg.boons[boonId] = {
|
|
179
|
+
selfBuffs: { generationMs: 0, wastedMs: 0 },
|
|
180
|
+
groupBuffs: { generationMs: 0, wastedMs: 0 },
|
|
181
|
+
squadBuffs: { generationMs: 0, wastedMs: 0 }
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
agg.boons[boonId][category].generationMs += generationMs;
|
|
185
|
+
agg.boons[boonId][category].wastedMs += wastedMs;
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
const boonIds = Array.from(boonMeta.keys()).filter((id) => isBoon(boonMeta.get(id)));
|
|
191
|
+
const boonTables = boonIds.map((boonId) => {
|
|
192
|
+
const meta = boonMeta.get(boonId) || {};
|
|
193
|
+
const rows = [];
|
|
194
|
+
playerAgg.forEach((agg) => {
|
|
195
|
+
const boonData = agg.boons[boonId];
|
|
196
|
+
if (!boonData) return;
|
|
197
|
+
const hasData = BOON_CATEGORIES.some((category) => boonData[category].generationMs > 0 || boonData[category].wastedMs > 0);
|
|
198
|
+
if (!hasData) return;
|
|
199
|
+
const professionList = Array.from(agg.professions || []).filter((prof) => prof && prof !== "Unknown");
|
|
200
|
+
let primaryProfession = agg.profession;
|
|
201
|
+
if (professionList.length > 0) {
|
|
202
|
+
primaryProfession = professionList[0];
|
|
203
|
+
let maxTime = agg.professionTimeMs?.[primaryProfession] || 0;
|
|
204
|
+
professionList.forEach((prof) => {
|
|
205
|
+
const time = agg.professionTimeMs?.[prof] || 0;
|
|
206
|
+
if (time > maxTime) {
|
|
207
|
+
maxTime = time;
|
|
208
|
+
primaryProfession = prof;
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
rows.push({
|
|
213
|
+
account: agg.account,
|
|
214
|
+
profession: primaryProfession || "Unknown",
|
|
215
|
+
professionList,
|
|
216
|
+
activeTimeMs: agg.activeTimeMs || 1,
|
|
217
|
+
numFights: agg.numFights || 1,
|
|
218
|
+
groupSupported: agg.groupSupported || 1,
|
|
219
|
+
squadSupported: agg.squadSupported || 1,
|
|
220
|
+
categories: {
|
|
221
|
+
selfBuffs: { ...boonData.selfBuffs },
|
|
222
|
+
groupBuffs: { ...boonData.groupBuffs },
|
|
223
|
+
squadBuffs: { ...boonData.squadBuffs }
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
id: boonId,
|
|
229
|
+
name: meta.name || boonId,
|
|
230
|
+
icon: meta.icon,
|
|
231
|
+
stacking: meta.stacking ?? false,
|
|
232
|
+
rows
|
|
233
|
+
};
|
|
234
|
+
}).filter((boon) => boon.rows.length > 0);
|
|
235
|
+
return { boonTables };
|
|
236
|
+
};
|
|
237
|
+
var buildBoonLeaderboards = (tables, metric = "uptime") => {
|
|
238
|
+
const result = {};
|
|
239
|
+
for (const table of tables) {
|
|
240
|
+
const ranked = table.rows.map((row) => ({
|
|
241
|
+
account: row.account,
|
|
242
|
+
profession: row.profession,
|
|
243
|
+
professionList: row.professionList,
|
|
244
|
+
value: getBoonMetricValue(row, "squadBuffs", table.stacking, metric),
|
|
245
|
+
count: row.numFights
|
|
246
|
+
})).filter((r) => Number.isFinite(r.value) && r.value > 0).sort((a, b) => b.value - a.value || a.account.localeCompare(b.account));
|
|
247
|
+
let lastValue = null;
|
|
248
|
+
let lastRank = 0;
|
|
249
|
+
result[table.id] = ranked.map((row, index) => {
|
|
250
|
+
if (lastValue === null || row.value !== lastValue) {
|
|
251
|
+
lastRank = index + 1;
|
|
252
|
+
lastValue = row.value;
|
|
253
|
+
}
|
|
254
|
+
return { ...row, rank: lastRank };
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
return result;
|
|
258
|
+
};
|
|
259
|
+
var getPlayerBoonGenerationMs = (player, category, boonId, durationMs, groupCount, squadCount, buffMap = {}) => {
|
|
260
|
+
const buffs = player?.[category] || [];
|
|
261
|
+
const target = buffs.find((buff) => buff.id === boonId);
|
|
262
|
+
if (!target) {
|
|
263
|
+
return { generationMs: 0, wastedMs: 0 };
|
|
264
|
+
}
|
|
265
|
+
const meta = buffMap[toBoonId(boonId)];
|
|
266
|
+
const stacking = meta?.stacking ?? false;
|
|
267
|
+
const generation = target.buffData?.[0]?.generation ?? 0;
|
|
268
|
+
const wasted = target.buffData?.[0]?.wasted ?? 0;
|
|
269
|
+
return computeGenerationMs(category, stacking, generation, wasted, durationMs, groupCount, squadCount);
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
export {
|
|
273
|
+
computeBoonMetrics,
|
|
274
|
+
getBoonMetricValue,
|
|
275
|
+
formatBoonMetricDisplay,
|
|
276
|
+
buildBoonTables,
|
|
277
|
+
buildBoonLeaderboards,
|
|
278
|
+
getPlayerBoonGenerationMs
|
|
279
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
STABILITY_BOON_ID
|
|
3
|
+
} from "./chunk-ZFZS7JFU.js";
|
|
4
|
+
import {
|
|
5
|
+
getPlayerBoonGenerationMs
|
|
6
|
+
} from "./chunk-PMVLNDZZ.js";
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_DISRUPTION_METHOD,
|
|
9
|
+
METRICS_SPEC
|
|
10
|
+
} from "./chunk-KRHODGVU.js";
|
|
11
|
+
|
|
12
|
+
// src/combatMetrics.ts
|
|
13
|
+
var toSeconds = (ms) => (ms || 0) / 1e3;
|
|
14
|
+
var applyTierWeight = (count, durationMs) => {
|
|
15
|
+
if (!count) return 0;
|
|
16
|
+
const tiers = METRICS_SPEC.methods.tiered?.tiers;
|
|
17
|
+
if (!tiers) return count;
|
|
18
|
+
const avg = durationMs / Math.max(count, 1);
|
|
19
|
+
if (avg <= tiers.shortMs) return count * tiers.weights.short;
|
|
20
|
+
if (avg <= tiers.mediumMs) return count * tiers.weights.medium;
|
|
21
|
+
return count * tiers.weights.long;
|
|
22
|
+
};
|
|
23
|
+
var resolveDisruptionValue = (count, durationMs, method) => {
|
|
24
|
+
if (method === "duration") return toSeconds(durationMs);
|
|
25
|
+
if (method === "tiered") return applyTierWeight(count, durationMs);
|
|
26
|
+
return count;
|
|
27
|
+
};
|
|
28
|
+
function computeOutgoingCrowdControl(player, method = DEFAULT_DISRUPTION_METHOD) {
|
|
29
|
+
const stats = player.statsAll?.[0];
|
|
30
|
+
const count = Number(stats?.appliedCrowdControl ?? 0);
|
|
31
|
+
const durationMs = Number(stats?.appliedCrowdControlDuration ?? 0);
|
|
32
|
+
return resolveDisruptionValue(count, durationMs, method);
|
|
33
|
+
}
|
|
34
|
+
function computeIncomingDisruptions(player, method = DEFAULT_DISRUPTION_METHOD) {
|
|
35
|
+
const defenses = player.defenses?.[0];
|
|
36
|
+
const incomingCcCount = Number(defenses?.receivedCrowdControl ?? 0);
|
|
37
|
+
const incomingCcDurationMs = Number(defenses?.receivedCrowdControlDuration ?? 0);
|
|
38
|
+
const incomingStripCount = Number(defenses?.boonStrips ?? 0);
|
|
39
|
+
const incomingStripDurationMs = Number(defenses?.boonStripsTime ?? 0);
|
|
40
|
+
const resolveValue = (count, durationMs) => resolveDisruptionValue(count, durationMs, method);
|
|
41
|
+
return {
|
|
42
|
+
strips: {
|
|
43
|
+
total: resolveValue(incomingStripCount, incomingStripDurationMs),
|
|
44
|
+
missed: 0,
|
|
45
|
+
blocked: 0
|
|
46
|
+
},
|
|
47
|
+
cc: {
|
|
48
|
+
total: resolveValue(incomingCcCount, incomingCcDurationMs),
|
|
49
|
+
missed: 0,
|
|
50
|
+
blocked: 0
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function applySquadStabilityGeneration(players, context) {
|
|
55
|
+
const durationMs = context?.durationMS || 0;
|
|
56
|
+
const buffMap = context?.buffMap || {};
|
|
57
|
+
const squadPlayers = players.filter((p) => !p.notInSquad);
|
|
58
|
+
const squadCount = squadPlayers.length;
|
|
59
|
+
const groupCounts = /* @__PURE__ */ new Map();
|
|
60
|
+
squadPlayers.forEach((player) => {
|
|
61
|
+
const group = player.group ?? 0;
|
|
62
|
+
groupCounts.set(group, (groupCounts.get(group) || 0) + 1);
|
|
63
|
+
});
|
|
64
|
+
squadPlayers.forEach((player) => {
|
|
65
|
+
const groupCount = groupCounts.get(player.group ?? 0) || 1;
|
|
66
|
+
const self = getPlayerBoonGenerationMs(
|
|
67
|
+
player,
|
|
68
|
+
"selfBuffs",
|
|
69
|
+
STABILITY_BOON_ID,
|
|
70
|
+
durationMs,
|
|
71
|
+
groupCount,
|
|
72
|
+
squadCount,
|
|
73
|
+
buffMap
|
|
74
|
+
);
|
|
75
|
+
const squad = getPlayerBoonGenerationMs(
|
|
76
|
+
player,
|
|
77
|
+
"squadBuffs",
|
|
78
|
+
STABILITY_BOON_ID,
|
|
79
|
+
durationMs,
|
|
80
|
+
groupCount,
|
|
81
|
+
squadCount,
|
|
82
|
+
buffMap
|
|
83
|
+
);
|
|
84
|
+
player.stabGeneration = (self.generationMs + squad.generationMs) / 1e3;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function computeDownContribution(player) {
|
|
88
|
+
if (player.statsAll && player.statsAll.length > 0) {
|
|
89
|
+
const val = player.statsAll[0].downContribution;
|
|
90
|
+
if (typeof val === "number" && val > 0) return val;
|
|
91
|
+
}
|
|
92
|
+
let total = 0;
|
|
93
|
+
if (player.totalDamageDist) {
|
|
94
|
+
for (const targetList of player.totalDamageDist) {
|
|
95
|
+
if (targetList) {
|
|
96
|
+
for (const entry of targetList) {
|
|
97
|
+
total += entry.downContribution || 0;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (total > 0) return total;
|
|
103
|
+
if (player.statsTargets) {
|
|
104
|
+
for (const targetStats of player.statsTargets) {
|
|
105
|
+
if (targetStats && targetStats.length > 0) {
|
|
106
|
+
total += targetStats[0].downContribution || 0;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return total;
|
|
111
|
+
}
|
|
112
|
+
function computeSquadBarrier(player) {
|
|
113
|
+
if (!player.extBarrierStats || !player.extBarrierStats.outgoingBarrierAllies) return 0;
|
|
114
|
+
let total = 0;
|
|
115
|
+
for (const squadMember of player.extBarrierStats.outgoingBarrierAllies) {
|
|
116
|
+
if (!squadMember) continue;
|
|
117
|
+
for (const phaseData of squadMember) {
|
|
118
|
+
if (phaseData) {
|
|
119
|
+
total += phaseData.barrier || 0;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return total;
|
|
124
|
+
}
|
|
125
|
+
function computeSquadHealing(player) {
|
|
126
|
+
if (!player.extHealingStats || !player.extHealingStats.outgoingHealingAllies) return 0;
|
|
127
|
+
let total = 0;
|
|
128
|
+
for (const squadMember of player.extHealingStats.outgoingHealingAllies) {
|
|
129
|
+
if (!squadMember) continue;
|
|
130
|
+
for (const phaseData of squadMember) {
|
|
131
|
+
if (phaseData) {
|
|
132
|
+
total += phaseData.healing || 0;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return total;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export {
|
|
140
|
+
resolveDisruptionValue,
|
|
141
|
+
computeOutgoingCrowdControl,
|
|
142
|
+
computeIncomingDisruptions,
|
|
143
|
+
applySquadStabilityGeneration,
|
|
144
|
+
computeDownContribution,
|
|
145
|
+
computeSquadBarrier,
|
|
146
|
+
computeSquadHealing
|
|
147
|
+
};
|