sekai-calculator 0.1.1 → 0.2.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/index.cjs +189 -104
- package/dist/index.d.ts +49 -19
- package/dist/index.mjs +190 -104
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -27,35 +27,93 @@ function duplicateObj(obj, times) {
|
|
|
27
27
|
ret.push(obj);
|
|
28
28
|
return ret;
|
|
29
29
|
}
|
|
30
|
-
function mapOrUndefined(arr, fun) {
|
|
31
|
-
if (arr === undefined)
|
|
32
|
-
return undefined;
|
|
33
|
-
return arr.map(fun);
|
|
34
|
-
}
|
|
35
30
|
|
|
36
31
|
class DeckService {
|
|
37
32
|
dataProvider;
|
|
38
33
|
constructor(dataProvider) {
|
|
39
34
|
this.dataProvider = dataProvider;
|
|
40
35
|
}
|
|
36
|
+
async getUserCard(cardId) {
|
|
37
|
+
const userCards = await this.dataProvider.getUserData('userCards');
|
|
38
|
+
return findOrThrow(userCards, it => it.cardId === cardId);
|
|
39
|
+
}
|
|
41
40
|
async getDeck(deckId) {
|
|
42
41
|
const userDecks = await this.dataProvider.getUserData('userDecks');
|
|
43
42
|
return findOrThrow(userDecks, it => it.deckId === deckId);
|
|
44
43
|
}
|
|
45
44
|
async getDeckCards(userDeck) {
|
|
46
|
-
const userCards = await this.dataProvider.getUserData('userCards');
|
|
47
45
|
const cardIds = [userDeck.member1, userDeck.member2, userDeck.member3, userDeck.member4, userDeck.member5];
|
|
48
|
-
return cardIds.map(id =>
|
|
46
|
+
return await Promise.all(cardIds.map(async (id) => await this.getUserCard(id)));
|
|
47
|
+
}
|
|
48
|
+
static toUserDeck(userCards, deckId = 1, name = 'ユニット01') {
|
|
49
|
+
if (userCards.length !== 5)
|
|
50
|
+
throw new Error('deck card should be 5');
|
|
51
|
+
return {
|
|
52
|
+
userId: userCards[0].userId,
|
|
53
|
+
deckId,
|
|
54
|
+
name,
|
|
55
|
+
leader: userCards[0].cardId,
|
|
56
|
+
subLeader: userCards[1].cardId,
|
|
57
|
+
member1: userCards[0].cardId,
|
|
58
|
+
member2: userCards[1].cardId,
|
|
59
|
+
member3: userCards[2].cardId,
|
|
60
|
+
member4: userCards[3].cardId,
|
|
61
|
+
member5: userCards[4].cardId
|
|
62
|
+
};
|
|
49
63
|
}
|
|
50
64
|
async getChallengeLiveSoloDeck(characterId) {
|
|
51
65
|
const userChallengeLiveSoloDecks = await this.dataProvider.getUserData('userChallengeLiveSoloDecks');
|
|
52
66
|
return findOrThrow(userChallengeLiveSoloDecks, it => it.characterId === characterId);
|
|
53
67
|
}
|
|
54
68
|
async getChallengeLiveSoloDeckCards(deck) {
|
|
55
|
-
const userCards = await this.dataProvider.getUserData('userCards');
|
|
56
69
|
const cardIds = [deck.leader, deck.support1, deck.support2, deck.support3, deck.support4];
|
|
57
|
-
return cardIds.filter(it => it !== undefined && it !== null)
|
|
58
|
-
.map(id =>
|
|
70
|
+
return await Promise.all(cardIds.filter(it => it !== undefined && it !== null)
|
|
71
|
+
.map(async (id) => await this.getUserCard(id === null ? 0 : id)));
|
|
72
|
+
}
|
|
73
|
+
static toUserChallengeLiveSoloDeck(userCards, characterId) {
|
|
74
|
+
if (userCards.length !== 5)
|
|
75
|
+
throw new Error('deck card should be 5');
|
|
76
|
+
return {
|
|
77
|
+
characterId,
|
|
78
|
+
leader: userCards[0].cardId,
|
|
79
|
+
support1: userCards[1].cardId,
|
|
80
|
+
support2: userCards[2].cardId,
|
|
81
|
+
support3: userCards[3].cardId,
|
|
82
|
+
support4: userCards[4].cardId
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
class CardDetailMap {
|
|
88
|
+
min = Number.MAX_SAFE_INTEGER;
|
|
89
|
+
max = Number.MIN_SAFE_INTEGER;
|
|
90
|
+
values = new Map();
|
|
91
|
+
set(unit, unitMember, attrMember, value) {
|
|
92
|
+
this.min = Math.min(this.min, value);
|
|
93
|
+
this.max = Math.max(this.max, value);
|
|
94
|
+
this.values.set(CardDetailMap.getKey(unit, unitMember, attrMember), value);
|
|
95
|
+
}
|
|
96
|
+
get(unit, unitMember, attrMember) {
|
|
97
|
+
const attrMember0 = attrMember === 5 ? 5 : 1;
|
|
98
|
+
let best = this.getInternal(unit, unitMember, attrMember0);
|
|
99
|
+
if (best !== undefined)
|
|
100
|
+
return best;
|
|
101
|
+
best = this.getInternal(unit, unitMember === 5 ? 5 : 1, attrMember0);
|
|
102
|
+
if (best !== undefined)
|
|
103
|
+
return best;
|
|
104
|
+
best = this.getInternal('any', 1, 1);
|
|
105
|
+
if (best !== undefined)
|
|
106
|
+
return best;
|
|
107
|
+
throw new Error('case not found');
|
|
108
|
+
}
|
|
109
|
+
getInternal(unit, unitMember, attrMember) {
|
|
110
|
+
return this.values.get(CardDetailMap.getKey(unit, unitMember, attrMember));
|
|
111
|
+
}
|
|
112
|
+
static getKey(unit, unitMember, attrMember) {
|
|
113
|
+
return `${unit}-${unitMember}-${attrMember}`;
|
|
114
|
+
}
|
|
115
|
+
isCertainlyLessThen(another) {
|
|
116
|
+
return this.max < another.min;
|
|
59
117
|
}
|
|
60
118
|
}
|
|
61
119
|
|
|
@@ -175,14 +233,55 @@ class CardSkillCalculator {
|
|
|
175
233
|
}
|
|
176
234
|
}
|
|
177
235
|
|
|
236
|
+
class CardEventCalculator {
|
|
237
|
+
dataProvider;
|
|
238
|
+
constructor(dataProvider) {
|
|
239
|
+
this.dataProvider = dataProvider;
|
|
240
|
+
}
|
|
241
|
+
async getEventDeckBonus(eventId, card) {
|
|
242
|
+
const eventDeckBonuses = await this.dataProvider.getMasterData('eventDeckBonuses');
|
|
243
|
+
const gameCharacterUnits = await this.dataProvider.getMasterData('gameCharacterUnits');
|
|
244
|
+
return eventDeckBonuses.filter(it => it.eventId === eventId &&
|
|
245
|
+
(it.cardAttr === undefined || it.cardAttr === card.attr))
|
|
246
|
+
.reduce((v, eventDeckBonus) => {
|
|
247
|
+
if (eventDeckBonus.gameCharacterUnitId === undefined)
|
|
248
|
+
return Math.max(v, eventDeckBonus.bonusRate);
|
|
249
|
+
const gameCharacterUnit = findOrThrow(gameCharacterUnits, unit => unit.id === eventDeckBonus.gameCharacterUnitId);
|
|
250
|
+
if (gameCharacterUnit.gameCharacterId !== card.characterId)
|
|
251
|
+
return v;
|
|
252
|
+
if (card.characterId < 21 || card.supportUnit === gameCharacterUnit.unit) {
|
|
253
|
+
return Math.max(v, eventDeckBonus.bonusRate);
|
|
254
|
+
}
|
|
255
|
+
return Math.max(v, card.supportUnit === 'none' ? eventDeckBonus.bonusRate - 10 : 0);
|
|
256
|
+
}, 0);
|
|
257
|
+
}
|
|
258
|
+
async getCardEventBonus(userCard, eventId) {
|
|
259
|
+
const cards = await this.dataProvider.getMasterData('cards');
|
|
260
|
+
const eventCards = await this.dataProvider.getMasterData('eventCards');
|
|
261
|
+
const eventRarityBonusRates = await this.dataProvider.getMasterData('eventRarityBonusRates');
|
|
262
|
+
let eventBonus = 0;
|
|
263
|
+
const card = findOrThrow(cards, it => it.id === userCard.cardId);
|
|
264
|
+
eventBonus += await this.getEventDeckBonus(eventId, card);
|
|
265
|
+
const cardBonus = eventCards.find((it) => it.eventId === eventId && it.cardId === card.id);
|
|
266
|
+
if (cardBonus != null) {
|
|
267
|
+
eventBonus += cardBonus.bonusRate;
|
|
268
|
+
}
|
|
269
|
+
const masterRankBonus = findOrThrow(eventRarityBonusRates, it => it.cardRarityType === card.cardRarityType && it.masterRank === userCard.masterRank);
|
|
270
|
+
eventBonus += masterRankBonus.bonusRate;
|
|
271
|
+
return eventBonus;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
178
275
|
class CardCalculator {
|
|
179
276
|
dataProvider;
|
|
180
277
|
powerCalculator;
|
|
181
278
|
skillCalculator;
|
|
279
|
+
eventCalculator;
|
|
182
280
|
constructor(dataProvider) {
|
|
183
281
|
this.dataProvider = dataProvider;
|
|
184
282
|
this.powerCalculator = new CardPowerCalculator(dataProvider);
|
|
185
283
|
this.skillCalculator = new CardSkillCalculator(dataProvider);
|
|
284
|
+
this.eventCalculator = new CardEventCalculator(dataProvider);
|
|
186
285
|
}
|
|
187
286
|
async getCardUnits(card) {
|
|
188
287
|
const gameCharacters = await this.dataProvider.getMasterData('gameCharacters');
|
|
@@ -192,52 +291,35 @@ class CardCalculator {
|
|
|
192
291
|
units.push(findOrThrow(gameCharacters, it => it.id === card.characterId).unit);
|
|
193
292
|
return units;
|
|
194
293
|
}
|
|
195
|
-
async getCardDetail(userCard, userAreaItemLevels) {
|
|
294
|
+
async getCardDetail(userCard, userAreaItemLevels, eventId = 0) {
|
|
196
295
|
const cards = await this.dataProvider.getMasterData('cards');
|
|
197
296
|
const card = findOrThrow(cards, it => it.id === userCard.cardId);
|
|
198
297
|
const units = await this.getCardUnits(card);
|
|
199
298
|
const skill = await this.skillCalculator.getCardSkill(userCard, card);
|
|
200
299
|
const power = await this.powerCalculator.getCardPower(userCard, card, units, userAreaItemLevels);
|
|
300
|
+
const eventBonus = eventId === 0 ? undefined : await this.eventCalculator.getCardEventBonus(userCard, eventId);
|
|
201
301
|
return {
|
|
202
302
|
cardId: card.id,
|
|
303
|
+
characterId: card.characterId,
|
|
203
304
|
units,
|
|
204
305
|
attr: card.attr,
|
|
205
306
|
power,
|
|
206
307
|
scoreSkill: skill.scoreUp,
|
|
207
|
-
lifeSkill: skill.lifeRecovery
|
|
308
|
+
lifeSkill: skill.lifeRecovery,
|
|
309
|
+
eventBonus
|
|
208
310
|
};
|
|
209
311
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
set(unit, unitMember, attrMember, value) {
|
|
216
|
-
this.min = Math.min(this.min, value);
|
|
217
|
-
this.max = Math.max(this.max, value);
|
|
218
|
-
this.values.set(CardDetailMap.getKey(unit, unitMember, attrMember), value);
|
|
219
|
-
}
|
|
220
|
-
get(unit, unitMember, attrMember) {
|
|
221
|
-
const attrMember0 = attrMember === 5 ? 5 : 1;
|
|
222
|
-
let best = this.getInternal(unit, unitMember, attrMember0);
|
|
223
|
-
if (best !== undefined)
|
|
224
|
-
return best;
|
|
225
|
-
best = this.getInternal(unit, unitMember === 5 ? 5 : 1, attrMember0);
|
|
226
|
-
if (best !== undefined)
|
|
227
|
-
return best;
|
|
228
|
-
best = this.getInternal('any', 1, 1);
|
|
229
|
-
if (best !== undefined)
|
|
230
|
-
return best;
|
|
231
|
-
throw new Error('case not found');
|
|
232
|
-
}
|
|
233
|
-
getInternal(unit, unitMember, attrMember) {
|
|
234
|
-
return this.values.get(CardDetailMap.getKey(unit, unitMember, attrMember));
|
|
312
|
+
async batchGetCardDetail(userCards, eventId = 0) {
|
|
313
|
+
const areaItemLevels = await this.dataProvider.getMasterData('areaItemLevels');
|
|
314
|
+
const userAreas = await this.dataProvider.getUserData('userAreas');
|
|
315
|
+
const userItemLevels = userAreas.flatMap(it => it.areaItems).map(areaItem => findOrThrow(areaItemLevels, it => it.areaItemId === areaItem.areaItemId && it.level === areaItem.level));
|
|
316
|
+
return await Promise.all(userCards.map(async (it) => await this.getCardDetail(it, userItemLevels, eventId)));
|
|
235
317
|
}
|
|
236
|
-
static
|
|
237
|
-
return
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
318
|
+
static isCertainlyLessThan(cardDetail0, cardDetail1) {
|
|
319
|
+
return cardDetail0.power.isCertainlyLessThen(cardDetail1.power) &&
|
|
320
|
+
cardDetail0.scoreSkill.isCertainlyLessThen(cardDetail1.scoreSkill) &&
|
|
321
|
+
(cardDetail0.eventBonus === undefined || cardDetail1.eventBonus === undefined ||
|
|
322
|
+
cardDetail0.eventBonus < cardDetail1.eventBonus);
|
|
241
323
|
}
|
|
242
324
|
}
|
|
243
325
|
|
|
@@ -258,7 +340,7 @@ class DeckCalculator {
|
|
|
258
340
|
})
|
|
259
341
|
.reduce((v, it) => v + it.bonus, 0);
|
|
260
342
|
}
|
|
261
|
-
|
|
343
|
+
static getDeckDetailByCards(cardDetails, honorBonus) {
|
|
262
344
|
const map = new Map();
|
|
263
345
|
for (const cardDetail of cardDetails) {
|
|
264
346
|
computeWithDefault(map, cardDetail.attr, 0, it => it + 1);
|
|
@@ -276,50 +358,7 @@ class DeckCalculator {
|
|
|
276
358
|
return { power, skill };
|
|
277
359
|
}
|
|
278
360
|
async getDeckDetail(deckCards) {
|
|
279
|
-
|
|
280
|
-
const userAreas = await this.dataProvider.getUserData('userAreas');
|
|
281
|
-
const userItemLevels = userAreas.flatMap(it => it.areaItems).map(areaItem => findOrThrow(areaItemLevels, it => it.areaItemId === areaItem.areaItemId && it.level === areaItem.level));
|
|
282
|
-
const cardDetails = await Promise.all(deckCards.map(async (it) => await this.cardCalculator.getCardDetail(it, userItemLevels)));
|
|
283
|
-
return await this.getDeckDetailByCards(cardDetails, await this.getHonorBonusPower());
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
class CardEventCalculator {
|
|
288
|
-
dataProvider;
|
|
289
|
-
constructor(dataProvider) {
|
|
290
|
-
this.dataProvider = dataProvider;
|
|
291
|
-
}
|
|
292
|
-
async getEventDeckBonus(eventId, card) {
|
|
293
|
-
const eventDeckBonuses = await this.dataProvider.getMasterData('eventDeckBonuses');
|
|
294
|
-
const gameCharacterUnits = await this.dataProvider.getMasterData('gameCharacterUnits');
|
|
295
|
-
return eventDeckBonuses.filter(it => it.eventId === eventId &&
|
|
296
|
-
(it.cardAttr === undefined || it.cardAttr === card.attr))
|
|
297
|
-
.reduce((v, eventDeckBonus) => {
|
|
298
|
-
if (eventDeckBonus.gameCharacterUnitId === undefined)
|
|
299
|
-
return Math.max(v, eventDeckBonus.bonusRate);
|
|
300
|
-
const gameCharacterUnit = findOrThrow(gameCharacterUnits, unit => unit.id === eventDeckBonus.gameCharacterUnitId);
|
|
301
|
-
if (gameCharacterUnit.gameCharacterId !== card.characterId)
|
|
302
|
-
return v;
|
|
303
|
-
if (card.characterId < 21 || card.supportUnit === gameCharacterUnit.unit) {
|
|
304
|
-
return Math.max(v, eventDeckBonus.bonusRate);
|
|
305
|
-
}
|
|
306
|
-
return Math.max(v, card.supportUnit === 'none' ? eventDeckBonus.bonusRate - 10 : 0);
|
|
307
|
-
}, 0);
|
|
308
|
-
}
|
|
309
|
-
async getCardEventBonus(userCard, eventId) {
|
|
310
|
-
const cards = await this.dataProvider.getMasterData('cards');
|
|
311
|
-
const eventCards = await this.dataProvider.getMasterData('eventCards');
|
|
312
|
-
const eventRarityBonusRates = await this.dataProvider.getMasterData('eventRarityBonusRates');
|
|
313
|
-
let eventBonus = 0;
|
|
314
|
-
const card = findOrThrow(cards, it => it.id === userCard.cardId);
|
|
315
|
-
eventBonus += await this.getEventDeckBonus(eventId, card);
|
|
316
|
-
const cardBonus = eventCards.find((it) => it.eventId === eventId && it.cardId === card.id);
|
|
317
|
-
if (cardBonus != null) {
|
|
318
|
-
eventBonus += cardBonus.bonusRate;
|
|
319
|
-
}
|
|
320
|
-
const masterRankBonus = findOrThrow(eventRarityBonusRates, it => it.cardRarityType === card.cardRarityType && it.masterRank === userCard.masterRank);
|
|
321
|
-
eventBonus += masterRankBonus.bonusRate;
|
|
322
|
-
return eventBonus;
|
|
361
|
+
return DeckCalculator.getDeckDetailByCards(await this.cardCalculator.batchGetCardDetail(deckCards), await this.getHonorBonusPower());
|
|
323
362
|
}
|
|
324
363
|
}
|
|
325
364
|
|
|
@@ -333,7 +372,31 @@ class EventCalculator {
|
|
|
333
372
|
async getDeckEventBonus(deckCards, eventId) {
|
|
334
373
|
return await deckCards.reduce(async (v, it) => await v + await this.cardEventCalculator.getCardEventBonus(it, eventId), Promise.resolve(0));
|
|
335
374
|
}
|
|
375
|
+
static getEventPoint(type, selfScore, musicRate = 100, deckBonus = 0, boostRate = 1, otherScore = 0, life = 1000) {
|
|
376
|
+
const musicRate0 = musicRate / 100;
|
|
377
|
+
const deckRate = deckBonus / 100 + 1;
|
|
378
|
+
switch (type) {
|
|
379
|
+
case exports.EventLiveType.SOLO:
|
|
380
|
+
return Math.floor((100 + Math.floor(selfScore / 20000)) * musicRate0 * deckRate) * boostRate;
|
|
381
|
+
case exports.EventLiveType.CHALLENGE:
|
|
382
|
+
return (100 + Math.floor(selfScore / 20000)) * 120;
|
|
383
|
+
case exports.EventLiveType.MULTI:
|
|
384
|
+
return Math.floor((110 + Math.floor(selfScore / 17000) +
|
|
385
|
+
Math.floor(Math.min(otherScore, 5200000) / 400000)) * musicRate0 * deckRate) * boostRate;
|
|
386
|
+
case exports.EventLiveType.CHEERFUL:
|
|
387
|
+
return Math.floor((114 + Math.floor(selfScore / 12500) +
|
|
388
|
+
Math.floor(Math.min(otherScore, 4400000) / 400000) + Math.floor(Math.min(life, 1000) / 25)) *
|
|
389
|
+
musicRate0 * deckRate) * boostRate;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
336
392
|
}
|
|
393
|
+
exports.EventLiveType = void 0;
|
|
394
|
+
(function (EventLiveType) {
|
|
395
|
+
EventLiveType["SOLO"] = "solo";
|
|
396
|
+
EventLiveType["CHALLENGE"] = "challenge";
|
|
397
|
+
EventLiveType["MULTI"] = "multi";
|
|
398
|
+
EventLiveType["CHEERFUL"] = "cheerful";
|
|
399
|
+
})(exports.EventLiveType || (exports.EventLiveType = {}));
|
|
337
400
|
|
|
338
401
|
class LiveCalculator {
|
|
339
402
|
dataProvider;
|
|
@@ -342,7 +405,7 @@ class LiveCalculator {
|
|
|
342
405
|
this.dataProvider = dataProvider;
|
|
343
406
|
this.deckCalculator = new DeckCalculator(dataProvider);
|
|
344
407
|
}
|
|
345
|
-
getBaseScore(musicMeta, liveType) {
|
|
408
|
+
static getBaseScore(musicMeta, liveType) {
|
|
346
409
|
switch (liveType) {
|
|
347
410
|
case exports.LiveType.SOLO:
|
|
348
411
|
return musicMeta.base_score;
|
|
@@ -352,7 +415,7 @@ class LiveCalculator {
|
|
|
352
415
|
return musicMeta.base_score_auto;
|
|
353
416
|
}
|
|
354
417
|
}
|
|
355
|
-
getSkillScore(musicMeta, liveType) {
|
|
418
|
+
static getSkillScore(musicMeta, liveType) {
|
|
356
419
|
switch (liveType) {
|
|
357
420
|
case exports.LiveType.SOLO:
|
|
358
421
|
return musicMeta.skill_score_solo;
|
|
@@ -362,15 +425,18 @@ class LiveCalculator {
|
|
|
362
425
|
return musicMeta.skill_score_auto;
|
|
363
426
|
}
|
|
364
427
|
}
|
|
365
|
-
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
428
|
+
static getLiveDetailByDeck(deckDetail, musicMeta, liveType, skillDetails = undefined, multiPowerSum = 0) {
|
|
429
|
+
const skills = skillDetails !== undefined
|
|
430
|
+
? skillDetails
|
|
431
|
+
: (liveType === exports.LiveType.MULTI
|
|
432
|
+
? duplicateObj(LiveCalculator.getMultiLiveSkill(deckDetail), 6)
|
|
433
|
+
: [...[...deckDetail.skill].sort((a, b) => a.scoreUp - b.scoreUp),
|
|
434
|
+
deckDetail.skill[0]]);
|
|
435
|
+
const baseRate = LiveCalculator.getBaseScore(musicMeta, liveType);
|
|
436
|
+
const skillScores = [...LiveCalculator.getSkillScore(musicMeta, liveType)];
|
|
437
|
+
const skillRate = skillDetails === undefined
|
|
438
|
+
? [...skillScores.slice(0, 5).sort((a, b) => a - b), skillScores[5]]
|
|
439
|
+
: skillScores;
|
|
374
440
|
const rate = baseRate + skills.reduce((v, it, i) => v + it.scoreUp * skillRate[i] / 100, 0);
|
|
375
441
|
const life = skills.reduce((v, it) => v + it.lifeRecovery, 0);
|
|
376
442
|
const powerSum = multiPowerSum === 0 ? 5 * deckDetail.power : multiPowerSum;
|
|
@@ -382,19 +448,39 @@ class LiveCalculator {
|
|
|
382
448
|
tap: musicMeta.tap_count
|
|
383
449
|
};
|
|
384
450
|
}
|
|
385
|
-
getMultiLiveSkill(deckDetail) {
|
|
451
|
+
static getMultiLiveSkill(deckDetail) {
|
|
386
452
|
const scoreUp = deckDetail.skill.reduce((v, it, i) => v + (i === 0 ? it.scoreUp : (it.scoreUp / 5)), 0);
|
|
387
453
|
const lifeRecovery = deckDetail.skill[0].lifeRecovery;
|
|
388
|
-
return {
|
|
454
|
+
return {
|
|
455
|
+
scoreUp,
|
|
456
|
+
lifeRecovery
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
static getSoloLiveSkill(liveSkills, skillDetails) {
|
|
460
|
+
if (liveSkills === undefined)
|
|
461
|
+
return undefined;
|
|
462
|
+
const skills = liveSkills.map(liveSkill => findOrThrow(skillDetails, it => it.cardId === liveSkill.cardId));
|
|
463
|
+
const ret = [];
|
|
464
|
+
for (let i = 0; i < 6; ++i) {
|
|
465
|
+
ret.push({
|
|
466
|
+
scoreUp: 0,
|
|
467
|
+
lifeRecovery: 0
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
for (let i = 0; i < skills.length - 1; ++i) {
|
|
471
|
+
ret[i] = skills[i];
|
|
472
|
+
}
|
|
473
|
+
ret[5] = skills[skills.length - 1];
|
|
474
|
+
return ret;
|
|
389
475
|
}
|
|
390
476
|
async getLiveDetail(deckCards, musicId, musicDiff, liveType, liveSkills = undefined) {
|
|
391
477
|
const musicMetas = await this.dataProvider.getMusicMeta();
|
|
392
478
|
const musicMeta = findOrThrow(musicMetas, it => it.music_id === musicId && it.difficulty === musicDiff);
|
|
393
479
|
const deckDetail = await this.deckCalculator.getDeckDetail(deckCards);
|
|
394
480
|
const skills = liveType === exports.LiveType.MULTI
|
|
395
|
-
?
|
|
396
|
-
: (
|
|
397
|
-
return
|
|
481
|
+
? undefined
|
|
482
|
+
: LiveCalculator.getSoloLiveSkill(liveSkills, deckDetail.skill);
|
|
483
|
+
return LiveCalculator.getLiveDetailByDeck(deckDetail, musicMeta, liveType, skills);
|
|
398
484
|
}
|
|
399
485
|
}
|
|
400
486
|
exports.LiveType = void 0;
|
|
@@ -405,7 +491,6 @@ exports.LiveType = void 0;
|
|
|
405
491
|
})(exports.LiveType || (exports.LiveType = {}));
|
|
406
492
|
|
|
407
493
|
exports.CardCalculator = CardCalculator;
|
|
408
|
-
exports.CardDetailMap = CardDetailMap;
|
|
409
494
|
exports.CardEventCalculator = CardEventCalculator;
|
|
410
495
|
exports.CardPowerCalculator = CardPowerCalculator;
|
|
411
496
|
exports.CardSkillCalculator = CardSkillCalculator;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,11 @@ interface DataProvider {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
interface UserDeck {
|
|
8
|
+
userId: number;
|
|
8
9
|
deckId: number;
|
|
10
|
+
name: string;
|
|
11
|
+
leader: number;
|
|
12
|
+
subLeader: number;
|
|
9
13
|
member1: number;
|
|
10
14
|
member2: number;
|
|
11
15
|
member3: number;
|
|
@@ -14,14 +18,24 @@ interface UserDeck {
|
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
interface UserCard {
|
|
21
|
+
userId: number;
|
|
17
22
|
cardId: number;
|
|
18
23
|
level: number;
|
|
24
|
+
exp?: number;
|
|
25
|
+
totalExp: number;
|
|
19
26
|
skillLevel: number;
|
|
27
|
+
skillExp: number;
|
|
28
|
+
totalSkillExp: number;
|
|
20
29
|
masterRank: number;
|
|
21
|
-
specialTrainingStatus
|
|
30
|
+
specialTrainingStatus: string;
|
|
31
|
+
defaultImage: string;
|
|
32
|
+
duplicateCount: number;
|
|
33
|
+
createdAt: number;
|
|
22
34
|
episodes: Array<{
|
|
23
35
|
cardEpisodeId: number;
|
|
24
36
|
scenarioStatus: string;
|
|
37
|
+
scenarioStatusReasons: string[];
|
|
38
|
+
isNotSkipped: boolean;
|
|
25
39
|
}>;
|
|
26
40
|
}
|
|
27
41
|
|
|
@@ -37,10 +51,13 @@ interface UserChallengeLiveSoloDeck {
|
|
|
37
51
|
declare class DeckService {
|
|
38
52
|
private readonly dataProvider;
|
|
39
53
|
constructor(dataProvider: DataProvider);
|
|
54
|
+
getUserCard(cardId: number): Promise<UserCard>;
|
|
40
55
|
getDeck(deckId: number): Promise<UserDeck>;
|
|
41
56
|
getDeckCards(userDeck: UserDeck): Promise<UserCard[]>;
|
|
57
|
+
static toUserDeck(userCards: UserCard[], deckId?: number, name?: string): UserDeck;
|
|
42
58
|
getChallengeLiveSoloDeck(characterId: number): Promise<UserChallengeLiveSoloDeck>;
|
|
43
59
|
getChallengeLiveSoloDeckCards(deck: UserChallengeLiveSoloDeck): Promise<UserCard[]>;
|
|
60
|
+
static toUserChallengeLiveSoloDeck(userCards: UserCard[], characterId: number): UserChallengeLiveSoloDeck;
|
|
44
61
|
}
|
|
45
62
|
|
|
46
63
|
interface AreaItemLevel {
|
|
@@ -58,16 +75,31 @@ interface AreaItemLevel {
|
|
|
58
75
|
sentence: string;
|
|
59
76
|
}
|
|
60
77
|
|
|
78
|
+
declare class CardDetailMap {
|
|
79
|
+
min: number;
|
|
80
|
+
max: number;
|
|
81
|
+
values: Map<string, number>;
|
|
82
|
+
set(unit: string, unitMember: number, attrMember: number, value: number): void;
|
|
83
|
+
get(unit: string, unitMember: number, attrMember: number): number;
|
|
84
|
+
private getInternal;
|
|
85
|
+
static getKey(unit: string, unitMember: number, attrMember: number): string;
|
|
86
|
+
isCertainlyLessThen(another: CardDetailMap): boolean;
|
|
87
|
+
}
|
|
88
|
+
|
|
61
89
|
declare class CardCalculator {
|
|
62
90
|
private readonly dataProvider;
|
|
63
91
|
private readonly powerCalculator;
|
|
64
92
|
private readonly skillCalculator;
|
|
93
|
+
private readonly eventCalculator;
|
|
65
94
|
constructor(dataProvider: DataProvider);
|
|
66
95
|
private getCardUnits;
|
|
67
|
-
getCardDetail(userCard: UserCard, userAreaItemLevels: AreaItemLevel[]): Promise<CardDetail>;
|
|
96
|
+
getCardDetail(userCard: UserCard, userAreaItemLevels: AreaItemLevel[], eventId?: number): Promise<CardDetail>;
|
|
97
|
+
batchGetCardDetail(userCards: UserCard[], eventId?: number): Promise<CardDetail[]>;
|
|
98
|
+
static isCertainlyLessThan(cardDetail0: CardDetail, cardDetail1: CardDetail): boolean;
|
|
68
99
|
}
|
|
69
100
|
interface CardDetail {
|
|
70
101
|
cardId: number;
|
|
102
|
+
characterId: number;
|
|
71
103
|
units: string[];
|
|
72
104
|
attr: string;
|
|
73
105
|
power: CardDetailMap;
|
|
@@ -75,16 +107,6 @@ interface CardDetail {
|
|
|
75
107
|
lifeSkill: number;
|
|
76
108
|
eventBonus?: number;
|
|
77
109
|
}
|
|
78
|
-
declare class CardDetailMap {
|
|
79
|
-
min: number;
|
|
80
|
-
max: number;
|
|
81
|
-
values: Map<string, number>;
|
|
82
|
-
set(unit: string, unitMember: number, attrMember: number, value: number): void;
|
|
83
|
-
get(unit: string, unitMember: number, attrMember: number): number;
|
|
84
|
-
private getInternal;
|
|
85
|
-
static getKey(unit: string, unitMember: number, attrMember: number): string;
|
|
86
|
-
isCertainlyLessThen(another: CardDetailMap): boolean;
|
|
87
|
-
}
|
|
88
110
|
|
|
89
111
|
interface CommonResource {
|
|
90
112
|
resourceId?: number;
|
|
@@ -150,8 +172,8 @@ declare class DeckCalculator {
|
|
|
150
172
|
private readonly dataProvider;
|
|
151
173
|
private readonly cardCalculator;
|
|
152
174
|
constructor(dataProvider: DataProvider);
|
|
153
|
-
|
|
154
|
-
getDeckDetailByCards(cardDetails: CardDetail[], honorBonus: number):
|
|
175
|
+
getHonorBonusPower(): Promise<number>;
|
|
176
|
+
static getDeckDetailByCards(cardDetails: CardDetail[], honorBonus: number): DeckDetail;
|
|
155
177
|
getDeckDetail(deckCards: UserCard[]): Promise<DeckDetail>;
|
|
156
178
|
}
|
|
157
179
|
interface DeckDetail {
|
|
@@ -176,6 +198,13 @@ declare class EventCalculator {
|
|
|
176
198
|
private readonly cardEventCalculator;
|
|
177
199
|
constructor(dataProvider: DataProvider);
|
|
178
200
|
getDeckEventBonus(deckCards: UserCard[], eventId: number): Promise<number>;
|
|
201
|
+
static getEventPoint(type: EventLiveType, selfScore: number, musicRate?: number, deckBonus?: number, boostRate?: number, otherScore?: number, life?: number): number;
|
|
202
|
+
}
|
|
203
|
+
declare enum EventLiveType {
|
|
204
|
+
SOLO = "solo",
|
|
205
|
+
CHALLENGE = "challenge",
|
|
206
|
+
MULTI = "multi",
|
|
207
|
+
CHEERFUL = "cheerful"
|
|
179
208
|
}
|
|
180
209
|
|
|
181
210
|
interface MusicMeta {
|
|
@@ -197,10 +226,11 @@ declare class LiveCalculator {
|
|
|
197
226
|
private readonly dataProvider;
|
|
198
227
|
private readonly deckCalculator;
|
|
199
228
|
constructor(dataProvider: DataProvider);
|
|
200
|
-
private getBaseScore;
|
|
201
|
-
private getSkillScore;
|
|
202
|
-
getLiveDetailByDeck(deckDetail: DeckDetail, musicMeta: MusicMeta, liveType: LiveType, skillDetails?: SkillDetail[] | undefined, multiPowerSum?: number):
|
|
203
|
-
private getMultiLiveSkill;
|
|
229
|
+
private static getBaseScore;
|
|
230
|
+
private static getSkillScore;
|
|
231
|
+
static getLiveDetailByDeck(deckDetail: DeckDetail, musicMeta: MusicMeta, liveType: LiveType, skillDetails?: SkillDetail[] | undefined, multiPowerSum?: number): LiveDetail;
|
|
232
|
+
private static getMultiLiveSkill;
|
|
233
|
+
private static getSoloLiveSkill;
|
|
204
234
|
getLiveDetail(deckCards: UserCard[], musicId: number, musicDiff: string, liveType: LiveType, liveSkills?: LiveSkill[] | undefined): Promise<LiveDetail>;
|
|
205
235
|
}
|
|
206
236
|
interface LiveDetail {
|
|
@@ -219,4 +249,4 @@ declare enum LiveType {
|
|
|
219
249
|
AUTO = "auto"
|
|
220
250
|
}
|
|
221
251
|
|
|
222
|
-
export { CardCalculator, CardDetail,
|
|
252
|
+
export { CardCalculator, CardDetail, CardEventCalculator, CardPowerCalculator, CardSkillCalculator, DataProvider, DeckCalculator, DeckDetail, DeckService, EventCalculator, EventLiveType, LiveCalculator, LiveDetail, LiveSkill, LiveType, SkillDetail };
|
package/dist/index.mjs
CHANGED
|
@@ -25,35 +25,93 @@ function duplicateObj(obj, times) {
|
|
|
25
25
|
ret.push(obj);
|
|
26
26
|
return ret;
|
|
27
27
|
}
|
|
28
|
-
function mapOrUndefined(arr, fun) {
|
|
29
|
-
if (arr === undefined)
|
|
30
|
-
return undefined;
|
|
31
|
-
return arr.map(fun);
|
|
32
|
-
}
|
|
33
28
|
|
|
34
29
|
class DeckService {
|
|
35
30
|
dataProvider;
|
|
36
31
|
constructor(dataProvider) {
|
|
37
32
|
this.dataProvider = dataProvider;
|
|
38
33
|
}
|
|
34
|
+
async getUserCard(cardId) {
|
|
35
|
+
const userCards = await this.dataProvider.getUserData('userCards');
|
|
36
|
+
return findOrThrow(userCards, it => it.cardId === cardId);
|
|
37
|
+
}
|
|
39
38
|
async getDeck(deckId) {
|
|
40
39
|
const userDecks = await this.dataProvider.getUserData('userDecks');
|
|
41
40
|
return findOrThrow(userDecks, it => it.deckId === deckId);
|
|
42
41
|
}
|
|
43
42
|
async getDeckCards(userDeck) {
|
|
44
|
-
const userCards = await this.dataProvider.getUserData('userCards');
|
|
45
43
|
const cardIds = [userDeck.member1, userDeck.member2, userDeck.member3, userDeck.member4, userDeck.member5];
|
|
46
|
-
return cardIds.map(id =>
|
|
44
|
+
return await Promise.all(cardIds.map(async (id) => await this.getUserCard(id)));
|
|
45
|
+
}
|
|
46
|
+
static toUserDeck(userCards, deckId = 1, name = 'ユニット01') {
|
|
47
|
+
if (userCards.length !== 5)
|
|
48
|
+
throw new Error('deck card should be 5');
|
|
49
|
+
return {
|
|
50
|
+
userId: userCards[0].userId,
|
|
51
|
+
deckId,
|
|
52
|
+
name,
|
|
53
|
+
leader: userCards[0].cardId,
|
|
54
|
+
subLeader: userCards[1].cardId,
|
|
55
|
+
member1: userCards[0].cardId,
|
|
56
|
+
member2: userCards[1].cardId,
|
|
57
|
+
member3: userCards[2].cardId,
|
|
58
|
+
member4: userCards[3].cardId,
|
|
59
|
+
member5: userCards[4].cardId
|
|
60
|
+
};
|
|
47
61
|
}
|
|
48
62
|
async getChallengeLiveSoloDeck(characterId) {
|
|
49
63
|
const userChallengeLiveSoloDecks = await this.dataProvider.getUserData('userChallengeLiveSoloDecks');
|
|
50
64
|
return findOrThrow(userChallengeLiveSoloDecks, it => it.characterId === characterId);
|
|
51
65
|
}
|
|
52
66
|
async getChallengeLiveSoloDeckCards(deck) {
|
|
53
|
-
const userCards = await this.dataProvider.getUserData('userCards');
|
|
54
67
|
const cardIds = [deck.leader, deck.support1, deck.support2, deck.support3, deck.support4];
|
|
55
|
-
return cardIds.filter(it => it !== undefined && it !== null)
|
|
56
|
-
.map(id =>
|
|
68
|
+
return await Promise.all(cardIds.filter(it => it !== undefined && it !== null)
|
|
69
|
+
.map(async (id) => await this.getUserCard(id === null ? 0 : id)));
|
|
70
|
+
}
|
|
71
|
+
static toUserChallengeLiveSoloDeck(userCards, characterId) {
|
|
72
|
+
if (userCards.length !== 5)
|
|
73
|
+
throw new Error('deck card should be 5');
|
|
74
|
+
return {
|
|
75
|
+
characterId,
|
|
76
|
+
leader: userCards[0].cardId,
|
|
77
|
+
support1: userCards[1].cardId,
|
|
78
|
+
support2: userCards[2].cardId,
|
|
79
|
+
support3: userCards[3].cardId,
|
|
80
|
+
support4: userCards[4].cardId
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
class CardDetailMap {
|
|
86
|
+
min = Number.MAX_SAFE_INTEGER;
|
|
87
|
+
max = Number.MIN_SAFE_INTEGER;
|
|
88
|
+
values = new Map();
|
|
89
|
+
set(unit, unitMember, attrMember, value) {
|
|
90
|
+
this.min = Math.min(this.min, value);
|
|
91
|
+
this.max = Math.max(this.max, value);
|
|
92
|
+
this.values.set(CardDetailMap.getKey(unit, unitMember, attrMember), value);
|
|
93
|
+
}
|
|
94
|
+
get(unit, unitMember, attrMember) {
|
|
95
|
+
const attrMember0 = attrMember === 5 ? 5 : 1;
|
|
96
|
+
let best = this.getInternal(unit, unitMember, attrMember0);
|
|
97
|
+
if (best !== undefined)
|
|
98
|
+
return best;
|
|
99
|
+
best = this.getInternal(unit, unitMember === 5 ? 5 : 1, attrMember0);
|
|
100
|
+
if (best !== undefined)
|
|
101
|
+
return best;
|
|
102
|
+
best = this.getInternal('any', 1, 1);
|
|
103
|
+
if (best !== undefined)
|
|
104
|
+
return best;
|
|
105
|
+
throw new Error('case not found');
|
|
106
|
+
}
|
|
107
|
+
getInternal(unit, unitMember, attrMember) {
|
|
108
|
+
return this.values.get(CardDetailMap.getKey(unit, unitMember, attrMember));
|
|
109
|
+
}
|
|
110
|
+
static getKey(unit, unitMember, attrMember) {
|
|
111
|
+
return `${unit}-${unitMember}-${attrMember}`;
|
|
112
|
+
}
|
|
113
|
+
isCertainlyLessThen(another) {
|
|
114
|
+
return this.max < another.min;
|
|
57
115
|
}
|
|
58
116
|
}
|
|
59
117
|
|
|
@@ -173,14 +231,55 @@ class CardSkillCalculator {
|
|
|
173
231
|
}
|
|
174
232
|
}
|
|
175
233
|
|
|
234
|
+
class CardEventCalculator {
|
|
235
|
+
dataProvider;
|
|
236
|
+
constructor(dataProvider) {
|
|
237
|
+
this.dataProvider = dataProvider;
|
|
238
|
+
}
|
|
239
|
+
async getEventDeckBonus(eventId, card) {
|
|
240
|
+
const eventDeckBonuses = await this.dataProvider.getMasterData('eventDeckBonuses');
|
|
241
|
+
const gameCharacterUnits = await this.dataProvider.getMasterData('gameCharacterUnits');
|
|
242
|
+
return eventDeckBonuses.filter(it => it.eventId === eventId &&
|
|
243
|
+
(it.cardAttr === undefined || it.cardAttr === card.attr))
|
|
244
|
+
.reduce((v, eventDeckBonus) => {
|
|
245
|
+
if (eventDeckBonus.gameCharacterUnitId === undefined)
|
|
246
|
+
return Math.max(v, eventDeckBonus.bonusRate);
|
|
247
|
+
const gameCharacterUnit = findOrThrow(gameCharacterUnits, unit => unit.id === eventDeckBonus.gameCharacterUnitId);
|
|
248
|
+
if (gameCharacterUnit.gameCharacterId !== card.characterId)
|
|
249
|
+
return v;
|
|
250
|
+
if (card.characterId < 21 || card.supportUnit === gameCharacterUnit.unit) {
|
|
251
|
+
return Math.max(v, eventDeckBonus.bonusRate);
|
|
252
|
+
}
|
|
253
|
+
return Math.max(v, card.supportUnit === 'none' ? eventDeckBonus.bonusRate - 10 : 0);
|
|
254
|
+
}, 0);
|
|
255
|
+
}
|
|
256
|
+
async getCardEventBonus(userCard, eventId) {
|
|
257
|
+
const cards = await this.dataProvider.getMasterData('cards');
|
|
258
|
+
const eventCards = await this.dataProvider.getMasterData('eventCards');
|
|
259
|
+
const eventRarityBonusRates = await this.dataProvider.getMasterData('eventRarityBonusRates');
|
|
260
|
+
let eventBonus = 0;
|
|
261
|
+
const card = findOrThrow(cards, it => it.id === userCard.cardId);
|
|
262
|
+
eventBonus += await this.getEventDeckBonus(eventId, card);
|
|
263
|
+
const cardBonus = eventCards.find((it) => it.eventId === eventId && it.cardId === card.id);
|
|
264
|
+
if (cardBonus != null) {
|
|
265
|
+
eventBonus += cardBonus.bonusRate;
|
|
266
|
+
}
|
|
267
|
+
const masterRankBonus = findOrThrow(eventRarityBonusRates, it => it.cardRarityType === card.cardRarityType && it.masterRank === userCard.masterRank);
|
|
268
|
+
eventBonus += masterRankBonus.bonusRate;
|
|
269
|
+
return eventBonus;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
176
273
|
class CardCalculator {
|
|
177
274
|
dataProvider;
|
|
178
275
|
powerCalculator;
|
|
179
276
|
skillCalculator;
|
|
277
|
+
eventCalculator;
|
|
180
278
|
constructor(dataProvider) {
|
|
181
279
|
this.dataProvider = dataProvider;
|
|
182
280
|
this.powerCalculator = new CardPowerCalculator(dataProvider);
|
|
183
281
|
this.skillCalculator = new CardSkillCalculator(dataProvider);
|
|
282
|
+
this.eventCalculator = new CardEventCalculator(dataProvider);
|
|
184
283
|
}
|
|
185
284
|
async getCardUnits(card) {
|
|
186
285
|
const gameCharacters = await this.dataProvider.getMasterData('gameCharacters');
|
|
@@ -190,52 +289,35 @@ class CardCalculator {
|
|
|
190
289
|
units.push(findOrThrow(gameCharacters, it => it.id === card.characterId).unit);
|
|
191
290
|
return units;
|
|
192
291
|
}
|
|
193
|
-
async getCardDetail(userCard, userAreaItemLevels) {
|
|
292
|
+
async getCardDetail(userCard, userAreaItemLevels, eventId = 0) {
|
|
194
293
|
const cards = await this.dataProvider.getMasterData('cards');
|
|
195
294
|
const card = findOrThrow(cards, it => it.id === userCard.cardId);
|
|
196
295
|
const units = await this.getCardUnits(card);
|
|
197
296
|
const skill = await this.skillCalculator.getCardSkill(userCard, card);
|
|
198
297
|
const power = await this.powerCalculator.getCardPower(userCard, card, units, userAreaItemLevels);
|
|
298
|
+
const eventBonus = eventId === 0 ? undefined : await this.eventCalculator.getCardEventBonus(userCard, eventId);
|
|
199
299
|
return {
|
|
200
300
|
cardId: card.id,
|
|
301
|
+
characterId: card.characterId,
|
|
201
302
|
units,
|
|
202
303
|
attr: card.attr,
|
|
203
304
|
power,
|
|
204
305
|
scoreSkill: skill.scoreUp,
|
|
205
|
-
lifeSkill: skill.lifeRecovery
|
|
306
|
+
lifeSkill: skill.lifeRecovery,
|
|
307
|
+
eventBonus
|
|
206
308
|
};
|
|
207
309
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
set(unit, unitMember, attrMember, value) {
|
|
214
|
-
this.min = Math.min(this.min, value);
|
|
215
|
-
this.max = Math.max(this.max, value);
|
|
216
|
-
this.values.set(CardDetailMap.getKey(unit, unitMember, attrMember), value);
|
|
217
|
-
}
|
|
218
|
-
get(unit, unitMember, attrMember) {
|
|
219
|
-
const attrMember0 = attrMember === 5 ? 5 : 1;
|
|
220
|
-
let best = this.getInternal(unit, unitMember, attrMember0);
|
|
221
|
-
if (best !== undefined)
|
|
222
|
-
return best;
|
|
223
|
-
best = this.getInternal(unit, unitMember === 5 ? 5 : 1, attrMember0);
|
|
224
|
-
if (best !== undefined)
|
|
225
|
-
return best;
|
|
226
|
-
best = this.getInternal('any', 1, 1);
|
|
227
|
-
if (best !== undefined)
|
|
228
|
-
return best;
|
|
229
|
-
throw new Error('case not found');
|
|
230
|
-
}
|
|
231
|
-
getInternal(unit, unitMember, attrMember) {
|
|
232
|
-
return this.values.get(CardDetailMap.getKey(unit, unitMember, attrMember));
|
|
310
|
+
async batchGetCardDetail(userCards, eventId = 0) {
|
|
311
|
+
const areaItemLevels = await this.dataProvider.getMasterData('areaItemLevels');
|
|
312
|
+
const userAreas = await this.dataProvider.getUserData('userAreas');
|
|
313
|
+
const userItemLevels = userAreas.flatMap(it => it.areaItems).map(areaItem => findOrThrow(areaItemLevels, it => it.areaItemId === areaItem.areaItemId && it.level === areaItem.level));
|
|
314
|
+
return await Promise.all(userCards.map(async (it) => await this.getCardDetail(it, userItemLevels, eventId)));
|
|
233
315
|
}
|
|
234
|
-
static
|
|
235
|
-
return
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
316
|
+
static isCertainlyLessThan(cardDetail0, cardDetail1) {
|
|
317
|
+
return cardDetail0.power.isCertainlyLessThen(cardDetail1.power) &&
|
|
318
|
+
cardDetail0.scoreSkill.isCertainlyLessThen(cardDetail1.scoreSkill) &&
|
|
319
|
+
(cardDetail0.eventBonus === undefined || cardDetail1.eventBonus === undefined ||
|
|
320
|
+
cardDetail0.eventBonus < cardDetail1.eventBonus);
|
|
239
321
|
}
|
|
240
322
|
}
|
|
241
323
|
|
|
@@ -256,7 +338,7 @@ class DeckCalculator {
|
|
|
256
338
|
})
|
|
257
339
|
.reduce((v, it) => v + it.bonus, 0);
|
|
258
340
|
}
|
|
259
|
-
|
|
341
|
+
static getDeckDetailByCards(cardDetails, honorBonus) {
|
|
260
342
|
const map = new Map();
|
|
261
343
|
for (const cardDetail of cardDetails) {
|
|
262
344
|
computeWithDefault(map, cardDetail.attr, 0, it => it + 1);
|
|
@@ -274,50 +356,7 @@ class DeckCalculator {
|
|
|
274
356
|
return { power, skill };
|
|
275
357
|
}
|
|
276
358
|
async getDeckDetail(deckCards) {
|
|
277
|
-
|
|
278
|
-
const userAreas = await this.dataProvider.getUserData('userAreas');
|
|
279
|
-
const userItemLevels = userAreas.flatMap(it => it.areaItems).map(areaItem => findOrThrow(areaItemLevels, it => it.areaItemId === areaItem.areaItemId && it.level === areaItem.level));
|
|
280
|
-
const cardDetails = await Promise.all(deckCards.map(async (it) => await this.cardCalculator.getCardDetail(it, userItemLevels)));
|
|
281
|
-
return await this.getDeckDetailByCards(cardDetails, await this.getHonorBonusPower());
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
class CardEventCalculator {
|
|
286
|
-
dataProvider;
|
|
287
|
-
constructor(dataProvider) {
|
|
288
|
-
this.dataProvider = dataProvider;
|
|
289
|
-
}
|
|
290
|
-
async getEventDeckBonus(eventId, card) {
|
|
291
|
-
const eventDeckBonuses = await this.dataProvider.getMasterData('eventDeckBonuses');
|
|
292
|
-
const gameCharacterUnits = await this.dataProvider.getMasterData('gameCharacterUnits');
|
|
293
|
-
return eventDeckBonuses.filter(it => it.eventId === eventId &&
|
|
294
|
-
(it.cardAttr === undefined || it.cardAttr === card.attr))
|
|
295
|
-
.reduce((v, eventDeckBonus) => {
|
|
296
|
-
if (eventDeckBonus.gameCharacterUnitId === undefined)
|
|
297
|
-
return Math.max(v, eventDeckBonus.bonusRate);
|
|
298
|
-
const gameCharacterUnit = findOrThrow(gameCharacterUnits, unit => unit.id === eventDeckBonus.gameCharacterUnitId);
|
|
299
|
-
if (gameCharacterUnit.gameCharacterId !== card.characterId)
|
|
300
|
-
return v;
|
|
301
|
-
if (card.characterId < 21 || card.supportUnit === gameCharacterUnit.unit) {
|
|
302
|
-
return Math.max(v, eventDeckBonus.bonusRate);
|
|
303
|
-
}
|
|
304
|
-
return Math.max(v, card.supportUnit === 'none' ? eventDeckBonus.bonusRate - 10 : 0);
|
|
305
|
-
}, 0);
|
|
306
|
-
}
|
|
307
|
-
async getCardEventBonus(userCard, eventId) {
|
|
308
|
-
const cards = await this.dataProvider.getMasterData('cards');
|
|
309
|
-
const eventCards = await this.dataProvider.getMasterData('eventCards');
|
|
310
|
-
const eventRarityBonusRates = await this.dataProvider.getMasterData('eventRarityBonusRates');
|
|
311
|
-
let eventBonus = 0;
|
|
312
|
-
const card = findOrThrow(cards, it => it.id === userCard.cardId);
|
|
313
|
-
eventBonus += await this.getEventDeckBonus(eventId, card);
|
|
314
|
-
const cardBonus = eventCards.find((it) => it.eventId === eventId && it.cardId === card.id);
|
|
315
|
-
if (cardBonus != null) {
|
|
316
|
-
eventBonus += cardBonus.bonusRate;
|
|
317
|
-
}
|
|
318
|
-
const masterRankBonus = findOrThrow(eventRarityBonusRates, it => it.cardRarityType === card.cardRarityType && it.masterRank === userCard.masterRank);
|
|
319
|
-
eventBonus += masterRankBonus.bonusRate;
|
|
320
|
-
return eventBonus;
|
|
359
|
+
return DeckCalculator.getDeckDetailByCards(await this.cardCalculator.batchGetCardDetail(deckCards), await this.getHonorBonusPower());
|
|
321
360
|
}
|
|
322
361
|
}
|
|
323
362
|
|
|
@@ -331,7 +370,31 @@ class EventCalculator {
|
|
|
331
370
|
async getDeckEventBonus(deckCards, eventId) {
|
|
332
371
|
return await deckCards.reduce(async (v, it) => await v + await this.cardEventCalculator.getCardEventBonus(it, eventId), Promise.resolve(0));
|
|
333
372
|
}
|
|
373
|
+
static getEventPoint(type, selfScore, musicRate = 100, deckBonus = 0, boostRate = 1, otherScore = 0, life = 1000) {
|
|
374
|
+
const musicRate0 = musicRate / 100;
|
|
375
|
+
const deckRate = deckBonus / 100 + 1;
|
|
376
|
+
switch (type) {
|
|
377
|
+
case EventLiveType.SOLO:
|
|
378
|
+
return Math.floor((100 + Math.floor(selfScore / 20000)) * musicRate0 * deckRate) * boostRate;
|
|
379
|
+
case EventLiveType.CHALLENGE:
|
|
380
|
+
return (100 + Math.floor(selfScore / 20000)) * 120;
|
|
381
|
+
case EventLiveType.MULTI:
|
|
382
|
+
return Math.floor((110 + Math.floor(selfScore / 17000) +
|
|
383
|
+
Math.floor(Math.min(otherScore, 5200000) / 400000)) * musicRate0 * deckRate) * boostRate;
|
|
384
|
+
case EventLiveType.CHEERFUL:
|
|
385
|
+
return Math.floor((114 + Math.floor(selfScore / 12500) +
|
|
386
|
+
Math.floor(Math.min(otherScore, 4400000) / 400000) + Math.floor(Math.min(life, 1000) / 25)) *
|
|
387
|
+
musicRate0 * deckRate) * boostRate;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
334
390
|
}
|
|
391
|
+
var EventLiveType;
|
|
392
|
+
(function (EventLiveType) {
|
|
393
|
+
EventLiveType["SOLO"] = "solo";
|
|
394
|
+
EventLiveType["CHALLENGE"] = "challenge";
|
|
395
|
+
EventLiveType["MULTI"] = "multi";
|
|
396
|
+
EventLiveType["CHEERFUL"] = "cheerful";
|
|
397
|
+
})(EventLiveType || (EventLiveType = {}));
|
|
335
398
|
|
|
336
399
|
class LiveCalculator {
|
|
337
400
|
dataProvider;
|
|
@@ -340,7 +403,7 @@ class LiveCalculator {
|
|
|
340
403
|
this.dataProvider = dataProvider;
|
|
341
404
|
this.deckCalculator = new DeckCalculator(dataProvider);
|
|
342
405
|
}
|
|
343
|
-
getBaseScore(musicMeta, liveType) {
|
|
406
|
+
static getBaseScore(musicMeta, liveType) {
|
|
344
407
|
switch (liveType) {
|
|
345
408
|
case LiveType.SOLO:
|
|
346
409
|
return musicMeta.base_score;
|
|
@@ -350,7 +413,7 @@ class LiveCalculator {
|
|
|
350
413
|
return musicMeta.base_score_auto;
|
|
351
414
|
}
|
|
352
415
|
}
|
|
353
|
-
getSkillScore(musicMeta, liveType) {
|
|
416
|
+
static getSkillScore(musicMeta, liveType) {
|
|
354
417
|
switch (liveType) {
|
|
355
418
|
case LiveType.SOLO:
|
|
356
419
|
return musicMeta.skill_score_solo;
|
|
@@ -360,15 +423,18 @@ class LiveCalculator {
|
|
|
360
423
|
return musicMeta.skill_score_auto;
|
|
361
424
|
}
|
|
362
425
|
}
|
|
363
|
-
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
426
|
+
static getLiveDetailByDeck(deckDetail, musicMeta, liveType, skillDetails = undefined, multiPowerSum = 0) {
|
|
427
|
+
const skills = skillDetails !== undefined
|
|
428
|
+
? skillDetails
|
|
429
|
+
: (liveType === LiveType.MULTI
|
|
430
|
+
? duplicateObj(LiveCalculator.getMultiLiveSkill(deckDetail), 6)
|
|
431
|
+
: [...[...deckDetail.skill].sort((a, b) => a.scoreUp - b.scoreUp),
|
|
432
|
+
deckDetail.skill[0]]);
|
|
433
|
+
const baseRate = LiveCalculator.getBaseScore(musicMeta, liveType);
|
|
434
|
+
const skillScores = [...LiveCalculator.getSkillScore(musicMeta, liveType)];
|
|
435
|
+
const skillRate = skillDetails === undefined
|
|
436
|
+
? [...skillScores.slice(0, 5).sort((a, b) => a - b), skillScores[5]]
|
|
437
|
+
: skillScores;
|
|
372
438
|
const rate = baseRate + skills.reduce((v, it, i) => v + it.scoreUp * skillRate[i] / 100, 0);
|
|
373
439
|
const life = skills.reduce((v, it) => v + it.lifeRecovery, 0);
|
|
374
440
|
const powerSum = multiPowerSum === 0 ? 5 * deckDetail.power : multiPowerSum;
|
|
@@ -380,19 +446,39 @@ class LiveCalculator {
|
|
|
380
446
|
tap: musicMeta.tap_count
|
|
381
447
|
};
|
|
382
448
|
}
|
|
383
|
-
getMultiLiveSkill(deckDetail) {
|
|
449
|
+
static getMultiLiveSkill(deckDetail) {
|
|
384
450
|
const scoreUp = deckDetail.skill.reduce((v, it, i) => v + (i === 0 ? it.scoreUp : (it.scoreUp / 5)), 0);
|
|
385
451
|
const lifeRecovery = deckDetail.skill[0].lifeRecovery;
|
|
386
|
-
return {
|
|
452
|
+
return {
|
|
453
|
+
scoreUp,
|
|
454
|
+
lifeRecovery
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
static getSoloLiveSkill(liveSkills, skillDetails) {
|
|
458
|
+
if (liveSkills === undefined)
|
|
459
|
+
return undefined;
|
|
460
|
+
const skills = liveSkills.map(liveSkill => findOrThrow(skillDetails, it => it.cardId === liveSkill.cardId));
|
|
461
|
+
const ret = [];
|
|
462
|
+
for (let i = 0; i < 6; ++i) {
|
|
463
|
+
ret.push({
|
|
464
|
+
scoreUp: 0,
|
|
465
|
+
lifeRecovery: 0
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
for (let i = 0; i < skills.length - 1; ++i) {
|
|
469
|
+
ret[i] = skills[i];
|
|
470
|
+
}
|
|
471
|
+
ret[5] = skills[skills.length - 1];
|
|
472
|
+
return ret;
|
|
387
473
|
}
|
|
388
474
|
async getLiveDetail(deckCards, musicId, musicDiff, liveType, liveSkills = undefined) {
|
|
389
475
|
const musicMetas = await this.dataProvider.getMusicMeta();
|
|
390
476
|
const musicMeta = findOrThrow(musicMetas, it => it.music_id === musicId && it.difficulty === musicDiff);
|
|
391
477
|
const deckDetail = await this.deckCalculator.getDeckDetail(deckCards);
|
|
392
478
|
const skills = liveType === LiveType.MULTI
|
|
393
|
-
?
|
|
394
|
-
: (
|
|
395
|
-
return
|
|
479
|
+
? undefined
|
|
480
|
+
: LiveCalculator.getSoloLiveSkill(liveSkills, deckDetail.skill);
|
|
481
|
+
return LiveCalculator.getLiveDetailByDeck(deckDetail, musicMeta, liveType, skills);
|
|
396
482
|
}
|
|
397
483
|
}
|
|
398
484
|
var LiveType;
|
|
@@ -402,4 +488,4 @@ var LiveType;
|
|
|
402
488
|
LiveType["AUTO"] = "auto";
|
|
403
489
|
})(LiveType || (LiveType = {}));
|
|
404
490
|
|
|
405
|
-
export { CardCalculator,
|
|
491
|
+
export { CardCalculator, CardEventCalculator, CardPowerCalculator, CardSkillCalculator, DeckCalculator, DeckService, EventCalculator, EventLiveType, LiveCalculator, LiveType };
|