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 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 => findOrThrow(userCards, it => it.cardId === 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 => findOrThrow(userCards, it => it.cardId === 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
- class CardDetailMap {
212
- min = Number.MAX_SAFE_INTEGER;
213
- max = Number.MIN_SAFE_INTEGER;
214
- values = new Map();
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 getKey(unit, unitMember, attrMember) {
237
- return `${unit}-${unitMember}-${attrMember}`;
238
- }
239
- isCertainlyLessThen(another) {
240
- return this.max < another.min;
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
- async getDeckDetailByCards(cardDetails, honorBonus) {
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
- const areaItemLevels = await this.dataProvider.getMasterData('areaItemLevels');
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
- async getLiveDetailByDeck(deckDetail, musicMeta, liveType, skillDetails = undefined, multiPowerSum = 0) {
366
- const bestSkill = skillDetails === undefined;
367
- const skills = bestSkill
368
- ? [...deckDetail.skill, deckDetail.skill[0]].sort((a, b) => a.scoreUp - b.scoreUp)
369
- : skillDetails;
370
- const baseRate = this.getBaseScore(musicMeta, liveType);
371
- const skillRate = bestSkill
372
- ? [...this.getSkillScore(musicMeta, liveType)].sort((a, b) => a - b)
373
- : this.getSkillScore(musicMeta, liveType);
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 { scoreUp, lifeRecovery };
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
- ? duplicateObj(this.getMultiLiveSkill(deckDetail), 6)
396
- : (mapOrUndefined(liveSkills, liveSkill => findOrThrow(deckDetail.skill, it => it.cardId === liveSkill.cardId)));
397
- return await this.getLiveDetailByDeck(deckDetail, musicMeta, liveType, skills);
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?: string;
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
- private getHonorBonusPower;
154
- getDeckDetailByCards(cardDetails: CardDetail[], honorBonus: number): Promise<DeckDetail>;
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): Promise<LiveDetail>;
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, CardDetailMap, CardEventCalculator, CardPowerCalculator, CardSkillCalculator, DataProvider, DeckCalculator, DeckDetail, DeckService, EventCalculator, LiveCalculator, LiveDetail, LiveSkill, LiveType, SkillDetail };
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 => findOrThrow(userCards, it => it.cardId === 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 => findOrThrow(userCards, it => it.cardId === 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
- class CardDetailMap {
210
- min = Number.MAX_SAFE_INTEGER;
211
- max = Number.MIN_SAFE_INTEGER;
212
- values = new Map();
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 getKey(unit, unitMember, attrMember) {
235
- return `${unit}-${unitMember}-${attrMember}`;
236
- }
237
- isCertainlyLessThen(another) {
238
- return this.max < another.min;
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
- async getDeckDetailByCards(cardDetails, honorBonus) {
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
- const areaItemLevels = await this.dataProvider.getMasterData('areaItemLevels');
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
- async getLiveDetailByDeck(deckDetail, musicMeta, liveType, skillDetails = undefined, multiPowerSum = 0) {
364
- const bestSkill = skillDetails === undefined;
365
- const skills = bestSkill
366
- ? [...deckDetail.skill, deckDetail.skill[0]].sort((a, b) => a.scoreUp - b.scoreUp)
367
- : skillDetails;
368
- const baseRate = this.getBaseScore(musicMeta, liveType);
369
- const skillRate = bestSkill
370
- ? [...this.getSkillScore(musicMeta, liveType)].sort((a, b) => a - b)
371
- : this.getSkillScore(musicMeta, liveType);
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 { scoreUp, lifeRecovery };
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
- ? duplicateObj(this.getMultiLiveSkill(deckDetail), 6)
394
- : (mapOrUndefined(liveSkills, liveSkill => findOrThrow(deckDetail.skill, it => it.cardId === liveSkill.cardId)));
395
- return await this.getLiveDetailByDeck(deckDetail, musicMeta, liveType, skills);
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, CardDetailMap, CardEventCalculator, CardPowerCalculator, CardSkillCalculator, DeckCalculator, DeckService, EventCalculator, LiveCalculator, LiveType };
491
+ export { CardCalculator, CardEventCalculator, CardPowerCalculator, CardSkillCalculator, DeckCalculator, DeckService, EventCalculator, EventLiveType, LiveCalculator, LiveType };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sekai-calculator",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Project SEKAI Calculator for deck power, live score, event point and more.",
5
5
  "type": "module",
6
6
  "types": "dist/index.d.ts",