sekai-calculator 0.12.2 → 0.13.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
@@ -326,39 +326,44 @@ class CardPowerCalculator {
326
326
  constructor(dataProvider) {
327
327
  this.dataProvider = dataProvider;
328
328
  }
329
- async getCardPower(userCard, card, cardUnits, userAreaItemLevels) {
329
+ async getCardPower(userCard, card, cardUnits, userAreaItemLevels, hasCanvasBonus, userGateBonuses) {
330
330
  const ret = new CardDetailMap();
331
331
  const basePower = await this.getCardBasePowers(userCard, card);
332
+ const canvasBonus = await this.getMysekaiCanvasBonus(card, hasCanvasBonus);
332
333
  const characterBonus = await this.getCharacterBonusPower(basePower, card.characterId);
334
+ const fixtureBonus = await this.getFixtureBonusPower(basePower, canvasBonus, card.characterId);
335
+ const gateBonus = await this.getGateBonusPower(basePower, canvasBonus, userGateBonuses, cardUnits);
333
336
  for (const unit of cardUnits) {
334
- let power = await this.getPower(card, basePower, characterBonus, userAreaItemLevels, unit, true, true);
337
+ let power = await this.getPower(card, basePower, canvasBonus, characterBonus, fixtureBonus, gateBonus, userAreaItemLevels, unit, true, true);
335
338
  ret.set(unit, 5, 5, power.total, power);
336
- power = await this.getPower(card, basePower, characterBonus, userAreaItemLevels, unit, true, false);
339
+ power = await this.getPower(card, basePower, canvasBonus, characterBonus, fixtureBonus, gateBonus, userAreaItemLevels, unit, true, false);
337
340
  ret.set(unit, 5, 1, power.total, power);
338
- power = await this.getPower(card, basePower, characterBonus, userAreaItemLevels, unit, false, true);
341
+ power = await this.getPower(card, basePower, canvasBonus, characterBonus, fixtureBonus, gateBonus, userAreaItemLevels, unit, false, true);
339
342
  ret.set(unit, 1, 5, power.total, power);
340
- power = await this.getPower(card, basePower, characterBonus, userAreaItemLevels, unit, false, false);
343
+ power = await this.getPower(card, basePower, canvasBonus, characterBonus, fixtureBonus, gateBonus, userAreaItemLevels, unit, false, false);
341
344
  ret.set(unit, 1, 1, power.total, power);
342
345
  }
343
346
  return ret;
344
347
  }
345
- async getPower(card, basePower, characterBonus, userAreaItemLevels, unit, sameUnit, sameAttr) {
348
+ async getPower(card, basePower, canvasBonusPower, characterBonus, fixtureBonus, gateBonus, userAreaItemLevels, unit, sameUnit, sameAttr) {
346
349
  const base = basePower.reduce((v, it) => v + it, 0);
350
+ const canvasBonus = canvasBonusPower.reduce((v, it) => v + it, 0);
347
351
  const areaItemBonus = await this.getAreaItemBonusPower(userAreaItemLevels, basePower, card.characterId, unit, sameUnit, card.attr, sameAttr);
348
352
  return {
349
353
  base,
354
+ canvasBonus,
350
355
  areaItemBonus,
351
356
  characterBonus,
352
- total: base + characterBonus + areaItemBonus
357
+ fixtureBonus,
358
+ gateBonus,
359
+ total: base + canvasBonus + areaItemBonus + characterBonus + fixtureBonus + gateBonus
353
360
  };
354
361
  }
355
362
  async getCardBasePowers(userCard, card) {
356
- const p = await Promise.all([
363
+ const [cardEpisodes, masterLessons] = await Promise.all([
357
364
  await this.dataProvider.getMasterData('cardEpisodes'),
358
365
  await this.dataProvider.getMasterData('masterLessons')
359
366
  ]);
360
- const cardEpisodes = p[0];
361
- const masterLessons = p[1];
362
367
  const ret = [0, 0, 0];
363
368
  const cardParameters = card.cardParameters
364
369
  .filter(it => it.cardLevel === userCard.level);
@@ -389,6 +394,17 @@ class CardPowerCalculator {
389
394
  }
390
395
  return ret;
391
396
  }
397
+ async getMysekaiCanvasBonus(card, hasMysekaiCanvas) {
398
+ const ret = [0, 0, 0];
399
+ if (hasMysekaiCanvas) {
400
+ const cardMysekaiCanvasBonuses = await this.dataProvider.getMasterData('cardMysekaiCanvasBonuses');
401
+ const canvasBonus = findOrThrow(cardMysekaiCanvasBonuses, it => it.cardRarityType === card.cardRarityType);
402
+ ret[0] += canvasBonus.power1BonusFixed;
403
+ ret[1] += canvasBonus.power2BonusFixed;
404
+ ret[2] += canvasBonus.power3BonusFixed;
405
+ }
406
+ return ret;
407
+ }
392
408
  async getAreaItemBonusPower(userAreaItemLevels, basePower, characterId, unit, sameUnit, attr, sameAttr) {
393
409
  const usedAreaItems = userAreaItemLevels.filter(it => (it.targetUnit === 'any' || it.targetUnit === unit) &&
394
410
  (it.targetCardAttr === 'any' || it.targetCardAttr === attr) &&
@@ -424,6 +440,32 @@ class CardPowerCalculator {
424
440
  .reduce((v, it, i) => v +
425
441
  Math.floor(Math.fround(Math.fround(Math.fround(it) * Math.fround(0.01)) * basePower[i])), 0);
426
442
  }
443
+ async getFixtureBonusPower(basePower, canvasBonus, characterId) {
444
+ const userFixtureBonuses = await this.dataProvider.getUserData('userMysekaiFixtureGameCharacterPerformanceBonuses');
445
+ if (userFixtureBonuses === undefined || userFixtureBonuses === null || userFixtureBonuses.length === 0) {
446
+ return 0;
447
+ }
448
+ const fitureBonus = userFixtureBonuses
449
+ .find(it => it.gameCharacterId === characterId);
450
+ if (fitureBonus === undefined || fitureBonus === null) {
451
+ return 0;
452
+ }
453
+ const powers = [...basePower, ...canvasBonus];
454
+ return powers.reduce((v, it) => v +
455
+ Math.floor(Math.fround(it * Math.fround(fitureBonus.totalBonusRate * Math.fround(0.001)))), 0);
456
+ }
457
+ async getGateBonusPower(basePower, canvasBonus, userGateBonuses, cardUnits) {
458
+ const isOnlyPiapro = cardUnits.length === 1 && cardUnits[0] === 'piapro';
459
+ let powerBonusRate = 0;
460
+ for (const bonus of userGateBonuses) {
461
+ if (isOnlyPiapro || cardUnits.includes(bonus.unit)) {
462
+ powerBonusRate = Math.max(powerBonusRate, bonus.powerBonusRate);
463
+ }
464
+ }
465
+ const powers = [...basePower, ...canvasBonus];
466
+ return powers.reduce((v, it) => v +
467
+ Math.floor(Math.fround(it * Math.fround(Math.fround(powerBonusRate) * Math.fround(0.01)))), 0);
468
+ }
427
469
  }
428
470
 
429
471
  class CardSkillCalculator {
@@ -568,6 +610,39 @@ function safeNumber(num) {
568
610
  return num;
569
611
  }
570
612
 
613
+ class MysekaiService {
614
+ dataProvider;
615
+ constructor(dataProvider) {
616
+ this.dataProvider = dataProvider;
617
+ }
618
+ async getMysekaiCanvasBonusCards() {
619
+ const userMysekaiCanvas = await this.dataProvider.getUserData('userMysekaiCanvases');
620
+ if (userMysekaiCanvas === undefined || userMysekaiCanvas === null) {
621
+ return [];
622
+ }
623
+ return userMysekaiCanvas.map(it => it.cardId);
624
+ }
625
+ async getMysekaiFixtureBonuses() {
626
+ return await this.dataProvider.getUserData('userMysekaiFixtureGameCharacterPerformanceBonuses');
627
+ }
628
+ async getMysekaiGateBonuses() {
629
+ const userMysekaiGates = await this.dataProvider.getUserData('userMysekaiGates');
630
+ if (userMysekaiGates === undefined || userMysekaiGates === null || userMysekaiGates.length === 0) {
631
+ return [];
632
+ }
633
+ const mysekaiGates = await this.dataProvider.getMasterData('mysekaiGates');
634
+ const mysekaiGateLevels = await this.dataProvider.getMasterData('mysekaiGateLevels');
635
+ return userMysekaiGates.map(it => {
636
+ const gate = findOrThrow(mysekaiGates, g => g.id === it.mysekaiGateId);
637
+ const level = findOrThrow(mysekaiGateLevels, l => l.mysekaiGateId === it.mysekaiGateId && l.level === it.mysekaiGateLevel);
638
+ return {
639
+ unit: gate.unit,
640
+ powerBonusRate: level.powerBonusRate
641
+ };
642
+ });
643
+ }
644
+ }
645
+
571
646
  class CardCalculator {
572
647
  dataProvider;
573
648
  powerCalculator;
@@ -576,6 +651,7 @@ class CardCalculator {
576
651
  bloomEventCalculator;
577
652
  areaItemService;
578
653
  cardService;
654
+ mysekaiService;
579
655
  constructor(dataProvider) {
580
656
  this.dataProvider = dataProvider;
581
657
  this.powerCalculator = new CardPowerCalculator(dataProvider);
@@ -584,8 +660,9 @@ class CardCalculator {
584
660
  this.bloomEventCalculator = new CardBloomEventCalculator(dataProvider);
585
661
  this.areaItemService = new AreaItemService(dataProvider);
586
662
  this.cardService = new CardService(dataProvider);
663
+ this.mysekaiService = new MysekaiService(dataProvider);
587
664
  }
588
- async getCardDetail(userCard, userAreaItemLevels, config = {}, { eventId = 0, specialCharacterId = 0 } = {}) {
665
+ async getCardDetail(userCard, userAreaItemLevels, config = {}, { eventId = 0, specialCharacterId = 0 } = {}, hasCanvasBonus, userGateBonuses) {
589
666
  const cards = await this.dataProvider.getMasterData('cards');
590
667
  const card = findOrThrow(cards, it => it.id === userCard.cardId);
591
668
  const config0 = config[card.cardRarityType];
@@ -594,7 +671,7 @@ class CardCalculator {
594
671
  const userCard0 = await this.cardService.applyCardConfig(userCard, card, config0);
595
672
  const units = await this.cardService.getCardUnits(card);
596
673
  const skill = await this.skillCalculator.getCardSkill(userCard0, card);
597
- const power = await this.powerCalculator.getCardPower(userCard0, card, units, userAreaItemLevels);
674
+ const power = await this.powerCalculator.getCardPower(userCard0, card, units, userAreaItemLevels, hasCanvasBonus, userGateBonuses);
598
675
  const eventBonus = eventId === 0
599
676
  ? undefined
600
677
  : await this.eventCalculator.getCardEventBonus(userCard0, eventId);
@@ -611,14 +688,17 @@ class CardCalculator {
611
688
  power,
612
689
  skill,
613
690
  eventBonus,
614
- supportDeckBonus
691
+ supportDeckBonus,
692
+ hasCanvasBonus
615
693
  };
616
694
  }
617
695
  async batchGetCardDetail(userCards, config = {}, eventConfig, areaItemLevels) {
618
696
  const areaItemLevels0 = areaItemLevels === undefined
619
697
  ? await this.areaItemService.getAreaItemLevels()
620
698
  : areaItemLevels;
621
- const ret = await Promise.all(userCards.map(async (it) => await this.getCardDetail(it, areaItemLevels0, config, eventConfig))).then(it => it.filter(it => it !== undefined));
699
+ const userCanvasBonusCards = await this.mysekaiService.getMysekaiCanvasBonusCards();
700
+ const userGateBonuses = await this.mysekaiService.getMysekaiGateBonuses();
701
+ const ret = await Promise.all(userCards.map(async (it) => await this.getCardDetail(it, areaItemLevels0, config, eventConfig, userCanvasBonusCards.includes(it.cardId), userGateBonuses))).then(it => it.filter(it => it !== undefined));
622
702
  if (eventConfig?.specialCharacterId !== undefined && eventConfig.specialCharacterId > 0) {
623
703
  return ret.sort((a, b) => safeNumber(b.supportDeckBonus) - safeNumber(a.supportDeckBonus));
624
704
  }
@@ -881,15 +961,21 @@ class DeckCalculator {
881
961
  return current.total > vv.total ? current : vv;
882
962
  }, cardDetail.power.get(cardDetail.units[0], getOrThrow(map, cardDetail.units[0]), getOrThrow(map, cardDetail.attr))));
883
963
  });
884
- const base = cardDetails.reduce((v, cardDetail) => v + getOrThrow(cardPower, cardDetail.cardId).base, 0);
885
- const areaItemBonus = cardDetails.reduce((v, cardDetail) => v + getOrThrow(cardPower, cardDetail.cardId).areaItemBonus, 0);
886
- const characterBonus = cardDetails.reduce((v, cardDetail) => v + getOrThrow(cardPower, cardDetail.cardId).characterBonus, 0);
964
+ const base = DeckCalculator.sumPower(cardDetails, cardPower, it => it.base);
965
+ const canvasBonus = DeckCalculator.sumPower(cardDetails, cardPower, it => it.canvasBonus);
966
+ const areaItemBonus = DeckCalculator.sumPower(cardDetails, cardPower, it => it.areaItemBonus);
967
+ const characterBonus = DeckCalculator.sumPower(cardDetails, cardPower, it => it.characterBonus);
968
+ const fixtureBonus = DeckCalculator.sumPower(cardDetails, cardPower, it => it.fixtureBonus);
969
+ const gateBonus = DeckCalculator.sumPower(cardDetails, cardPower, it => it.gateBonus);
887
970
  const total = base + areaItemBonus + characterBonus + honorBonus;
888
971
  const power = {
889
972
  base,
973
+ canvasBonus,
890
974
  areaItemBonus,
891
975
  characterBonus,
892
976
  honorBonus,
977
+ fixtureBonus,
978
+ gateBonus,
893
979
  total
894
980
  };
895
981
  const cards = cardDetails.map(cardDetail => {
@@ -916,6 +1002,9 @@ class DeckCalculator {
916
1002
  cards
917
1003
  };
918
1004
  }
1005
+ static sumPower(cardDetails, cardPower, attr) {
1006
+ return cardDetails.reduce((v, cardDetail) => v + attr(getOrThrow(cardPower, cardDetail.cardId)), 0);
1007
+ }
919
1008
  async getDeckDetail(deckCards, allCards, eventConfig, areaItemLevels) {
920
1009
  const allCards0 = await this.cardCalculator.batchGetCardDetail(allCards, {}, eventConfig, areaItemLevels);
921
1010
  return await this.getDeckDetailByCards(await this.cardCalculator.batchGetCardDetail(deckCards, {}, eventConfig, areaItemLevels), allCards0, await this.getHonorBonusPower(), eventConfig?.eventType);
package/dist/index.d.ts CHANGED
@@ -186,6 +186,7 @@ declare class DeckCalculator {
186
186
  constructor(dataProvider: DataProvider);
187
187
  getHonorBonusPower(): Promise<number>;
188
188
  getDeckDetailByCards(cardDetails: CardDetail[], allCards: CardDetail[], honorBonus: number, eventType?: EventType): Promise<DeckDetail>;
189
+ private static sumPower;
189
190
  getDeckDetail(deckCards: UserCard[], allCards: UserCard[], eventConfig?: EventConfig, areaItemLevels?: AreaItemLevel[]): Promise<DeckDetail>;
190
191
  }
191
192
  interface DeckDetail {
@@ -205,15 +206,21 @@ interface DeckCardDetail {
205
206
  }
206
207
  interface DeckPowerDetail {
207
208
  base: number;
209
+ canvasBonus: number;
208
210
  areaItemBonus: number;
209
211
  characterBonus: number;
210
212
  honorBonus: number;
213
+ fixtureBonus: number;
214
+ gateBonus: number;
211
215
  total: number;
212
216
  }
213
217
  interface DeckCardPowerDetail {
214
218
  base: number;
219
+ canvasBonus: number;
215
220
  areaItemBonus: number;
216
221
  characterBonus: number;
222
+ fixtureBonus: number;
223
+ gateBonus: number;
217
224
  total: number;
218
225
  }
219
226
  interface DeckCardSkillDetail {
@@ -221,6 +228,11 @@ interface DeckCardSkillDetail {
221
228
  lifeRecovery: number;
222
229
  }
223
230
 
231
+ interface MysekaiGateBonus {
232
+ unit: string;
233
+ powerBonusRate: number;
234
+ }
235
+
224
236
  declare class CardCalculator {
225
237
  private readonly dataProvider;
226
238
  private readonly powerCalculator;
@@ -229,8 +241,9 @@ declare class CardCalculator {
229
241
  private readonly bloomEventCalculator;
230
242
  private readonly areaItemService;
231
243
  private readonly cardService;
244
+ private readonly mysekaiService;
232
245
  constructor(dataProvider: DataProvider);
233
- getCardDetail(userCard: UserCard, userAreaItemLevels: AreaItemLevel[], config?: Record<string, CardConfig>, { eventId, specialCharacterId }?: EventConfig): Promise<CardDetail | undefined>;
246
+ getCardDetail(userCard: UserCard, userAreaItemLevels: AreaItemLevel[], config: Record<string, CardConfig> | undefined, { eventId, specialCharacterId }: EventConfig | undefined, hasCanvasBonus: boolean, userGateBonuses: MysekaiGateBonus[]): Promise<CardDetail | undefined>;
234
247
  batchGetCardDetail(userCards: UserCard[], config?: Record<string, CardConfig>, eventConfig?: EventConfig, areaItemLevels?: AreaItemLevel[]): Promise<CardDetail[]>;
235
248
  static isCertainlyLessThan(cardDetail0: CardDetail, cardDetail1: CardDetail): boolean;
236
249
  }
@@ -247,6 +260,7 @@ interface CardDetail {
247
260
  skill: CardDetailMap<DeckCardSkillDetail>;
248
261
  eventBonus?: number;
249
262
  supportDeckBonus?: number;
263
+ hasCanvasBonus: boolean;
250
264
  }
251
265
  interface CardConfig {
252
266
  disable?: boolean;
@@ -317,11 +331,14 @@ declare class DeckService {
317
331
  declare class CardPowerCalculator {
318
332
  private readonly dataProvider;
319
333
  constructor(dataProvider: DataProvider);
320
- getCardPower(userCard: UserCard, card: Card, cardUnits: string[], userAreaItemLevels: AreaItemLevel[]): Promise<CardDetailMap<DeckCardPowerDetail>>;
334
+ getCardPower(userCard: UserCard, card: Card, cardUnits: string[], userAreaItemLevels: AreaItemLevel[], hasCanvasBonus: boolean, userGateBonuses: MysekaiGateBonus[]): Promise<CardDetailMap<DeckCardPowerDetail>>;
321
335
  private getPower;
322
336
  private getCardBasePowers;
337
+ private getMysekaiCanvasBonus;
323
338
  private getAreaItemBonusPower;
324
339
  private getCharacterBonusPower;
340
+ private getFixtureBonusPower;
341
+ private getGateBonusPower;
325
342
  }
326
343
 
327
344
  declare class CardSkillCalculator {
package/dist/index.mjs CHANGED
@@ -324,39 +324,44 @@ class CardPowerCalculator {
324
324
  constructor(dataProvider) {
325
325
  this.dataProvider = dataProvider;
326
326
  }
327
- async getCardPower(userCard, card, cardUnits, userAreaItemLevels) {
327
+ async getCardPower(userCard, card, cardUnits, userAreaItemLevels, hasCanvasBonus, userGateBonuses) {
328
328
  const ret = new CardDetailMap();
329
329
  const basePower = await this.getCardBasePowers(userCard, card);
330
+ const canvasBonus = await this.getMysekaiCanvasBonus(card, hasCanvasBonus);
330
331
  const characterBonus = await this.getCharacterBonusPower(basePower, card.characterId);
332
+ const fixtureBonus = await this.getFixtureBonusPower(basePower, canvasBonus, card.characterId);
333
+ const gateBonus = await this.getGateBonusPower(basePower, canvasBonus, userGateBonuses, cardUnits);
331
334
  for (const unit of cardUnits) {
332
- let power = await this.getPower(card, basePower, characterBonus, userAreaItemLevels, unit, true, true);
335
+ let power = await this.getPower(card, basePower, canvasBonus, characterBonus, fixtureBonus, gateBonus, userAreaItemLevels, unit, true, true);
333
336
  ret.set(unit, 5, 5, power.total, power);
334
- power = await this.getPower(card, basePower, characterBonus, userAreaItemLevels, unit, true, false);
337
+ power = await this.getPower(card, basePower, canvasBonus, characterBonus, fixtureBonus, gateBonus, userAreaItemLevels, unit, true, false);
335
338
  ret.set(unit, 5, 1, power.total, power);
336
- power = await this.getPower(card, basePower, characterBonus, userAreaItemLevels, unit, false, true);
339
+ power = await this.getPower(card, basePower, canvasBonus, characterBonus, fixtureBonus, gateBonus, userAreaItemLevels, unit, false, true);
337
340
  ret.set(unit, 1, 5, power.total, power);
338
- power = await this.getPower(card, basePower, characterBonus, userAreaItemLevels, unit, false, false);
341
+ power = await this.getPower(card, basePower, canvasBonus, characterBonus, fixtureBonus, gateBonus, userAreaItemLevels, unit, false, false);
339
342
  ret.set(unit, 1, 1, power.total, power);
340
343
  }
341
344
  return ret;
342
345
  }
343
- async getPower(card, basePower, characterBonus, userAreaItemLevels, unit, sameUnit, sameAttr) {
346
+ async getPower(card, basePower, canvasBonusPower, characterBonus, fixtureBonus, gateBonus, userAreaItemLevels, unit, sameUnit, sameAttr) {
344
347
  const base = basePower.reduce((v, it) => v + it, 0);
348
+ const canvasBonus = canvasBonusPower.reduce((v, it) => v + it, 0);
345
349
  const areaItemBonus = await this.getAreaItemBonusPower(userAreaItemLevels, basePower, card.characterId, unit, sameUnit, card.attr, sameAttr);
346
350
  return {
347
351
  base,
352
+ canvasBonus,
348
353
  areaItemBonus,
349
354
  characterBonus,
350
- total: base + characterBonus + areaItemBonus
355
+ fixtureBonus,
356
+ gateBonus,
357
+ total: base + canvasBonus + areaItemBonus + characterBonus + fixtureBonus + gateBonus
351
358
  };
352
359
  }
353
360
  async getCardBasePowers(userCard, card) {
354
- const p = await Promise.all([
361
+ const [cardEpisodes, masterLessons] = await Promise.all([
355
362
  await this.dataProvider.getMasterData('cardEpisodes'),
356
363
  await this.dataProvider.getMasterData('masterLessons')
357
364
  ]);
358
- const cardEpisodes = p[0];
359
- const masterLessons = p[1];
360
365
  const ret = [0, 0, 0];
361
366
  const cardParameters = card.cardParameters
362
367
  .filter(it => it.cardLevel === userCard.level);
@@ -387,6 +392,17 @@ class CardPowerCalculator {
387
392
  }
388
393
  return ret;
389
394
  }
395
+ async getMysekaiCanvasBonus(card, hasMysekaiCanvas) {
396
+ const ret = [0, 0, 0];
397
+ if (hasMysekaiCanvas) {
398
+ const cardMysekaiCanvasBonuses = await this.dataProvider.getMasterData('cardMysekaiCanvasBonuses');
399
+ const canvasBonus = findOrThrow(cardMysekaiCanvasBonuses, it => it.cardRarityType === card.cardRarityType);
400
+ ret[0] += canvasBonus.power1BonusFixed;
401
+ ret[1] += canvasBonus.power2BonusFixed;
402
+ ret[2] += canvasBonus.power3BonusFixed;
403
+ }
404
+ return ret;
405
+ }
390
406
  async getAreaItemBonusPower(userAreaItemLevels, basePower, characterId, unit, sameUnit, attr, sameAttr) {
391
407
  const usedAreaItems = userAreaItemLevels.filter(it => (it.targetUnit === 'any' || it.targetUnit === unit) &&
392
408
  (it.targetCardAttr === 'any' || it.targetCardAttr === attr) &&
@@ -422,6 +438,32 @@ class CardPowerCalculator {
422
438
  .reduce((v, it, i) => v +
423
439
  Math.floor(Math.fround(Math.fround(Math.fround(it) * Math.fround(0.01)) * basePower[i])), 0);
424
440
  }
441
+ async getFixtureBonusPower(basePower, canvasBonus, characterId) {
442
+ const userFixtureBonuses = await this.dataProvider.getUserData('userMysekaiFixtureGameCharacterPerformanceBonuses');
443
+ if (userFixtureBonuses === undefined || userFixtureBonuses === null || userFixtureBonuses.length === 0) {
444
+ return 0;
445
+ }
446
+ const fitureBonus = userFixtureBonuses
447
+ .find(it => it.gameCharacterId === characterId);
448
+ if (fitureBonus === undefined || fitureBonus === null) {
449
+ return 0;
450
+ }
451
+ const powers = [...basePower, ...canvasBonus];
452
+ return powers.reduce((v, it) => v +
453
+ Math.floor(Math.fround(it * Math.fround(fitureBonus.totalBonusRate * Math.fround(0.001)))), 0);
454
+ }
455
+ async getGateBonusPower(basePower, canvasBonus, userGateBonuses, cardUnits) {
456
+ const isOnlyPiapro = cardUnits.length === 1 && cardUnits[0] === 'piapro';
457
+ let powerBonusRate = 0;
458
+ for (const bonus of userGateBonuses) {
459
+ if (isOnlyPiapro || cardUnits.includes(bonus.unit)) {
460
+ powerBonusRate = Math.max(powerBonusRate, bonus.powerBonusRate);
461
+ }
462
+ }
463
+ const powers = [...basePower, ...canvasBonus];
464
+ return powers.reduce((v, it) => v +
465
+ Math.floor(Math.fround(it * Math.fround(Math.fround(powerBonusRate) * Math.fround(0.01)))), 0);
466
+ }
425
467
  }
426
468
 
427
469
  class CardSkillCalculator {
@@ -566,6 +608,39 @@ function safeNumber(num) {
566
608
  return num;
567
609
  }
568
610
 
611
+ class MysekaiService {
612
+ dataProvider;
613
+ constructor(dataProvider) {
614
+ this.dataProvider = dataProvider;
615
+ }
616
+ async getMysekaiCanvasBonusCards() {
617
+ const userMysekaiCanvas = await this.dataProvider.getUserData('userMysekaiCanvases');
618
+ if (userMysekaiCanvas === undefined || userMysekaiCanvas === null) {
619
+ return [];
620
+ }
621
+ return userMysekaiCanvas.map(it => it.cardId);
622
+ }
623
+ async getMysekaiFixtureBonuses() {
624
+ return await this.dataProvider.getUserData('userMysekaiFixtureGameCharacterPerformanceBonuses');
625
+ }
626
+ async getMysekaiGateBonuses() {
627
+ const userMysekaiGates = await this.dataProvider.getUserData('userMysekaiGates');
628
+ if (userMysekaiGates === undefined || userMysekaiGates === null || userMysekaiGates.length === 0) {
629
+ return [];
630
+ }
631
+ const mysekaiGates = await this.dataProvider.getMasterData('mysekaiGates');
632
+ const mysekaiGateLevels = await this.dataProvider.getMasterData('mysekaiGateLevels');
633
+ return userMysekaiGates.map(it => {
634
+ const gate = findOrThrow(mysekaiGates, g => g.id === it.mysekaiGateId);
635
+ const level = findOrThrow(mysekaiGateLevels, l => l.mysekaiGateId === it.mysekaiGateId && l.level === it.mysekaiGateLevel);
636
+ return {
637
+ unit: gate.unit,
638
+ powerBonusRate: level.powerBonusRate
639
+ };
640
+ });
641
+ }
642
+ }
643
+
569
644
  class CardCalculator {
570
645
  dataProvider;
571
646
  powerCalculator;
@@ -574,6 +649,7 @@ class CardCalculator {
574
649
  bloomEventCalculator;
575
650
  areaItemService;
576
651
  cardService;
652
+ mysekaiService;
577
653
  constructor(dataProvider) {
578
654
  this.dataProvider = dataProvider;
579
655
  this.powerCalculator = new CardPowerCalculator(dataProvider);
@@ -582,8 +658,9 @@ class CardCalculator {
582
658
  this.bloomEventCalculator = new CardBloomEventCalculator(dataProvider);
583
659
  this.areaItemService = new AreaItemService(dataProvider);
584
660
  this.cardService = new CardService(dataProvider);
661
+ this.mysekaiService = new MysekaiService(dataProvider);
585
662
  }
586
- async getCardDetail(userCard, userAreaItemLevels, config = {}, { eventId = 0, specialCharacterId = 0 } = {}) {
663
+ async getCardDetail(userCard, userAreaItemLevels, config = {}, { eventId = 0, specialCharacterId = 0 } = {}, hasCanvasBonus, userGateBonuses) {
587
664
  const cards = await this.dataProvider.getMasterData('cards');
588
665
  const card = findOrThrow(cards, it => it.id === userCard.cardId);
589
666
  const config0 = config[card.cardRarityType];
@@ -592,7 +669,7 @@ class CardCalculator {
592
669
  const userCard0 = await this.cardService.applyCardConfig(userCard, card, config0);
593
670
  const units = await this.cardService.getCardUnits(card);
594
671
  const skill = await this.skillCalculator.getCardSkill(userCard0, card);
595
- const power = await this.powerCalculator.getCardPower(userCard0, card, units, userAreaItemLevels);
672
+ const power = await this.powerCalculator.getCardPower(userCard0, card, units, userAreaItemLevels, hasCanvasBonus, userGateBonuses);
596
673
  const eventBonus = eventId === 0
597
674
  ? undefined
598
675
  : await this.eventCalculator.getCardEventBonus(userCard0, eventId);
@@ -609,14 +686,17 @@ class CardCalculator {
609
686
  power,
610
687
  skill,
611
688
  eventBonus,
612
- supportDeckBonus
689
+ supportDeckBonus,
690
+ hasCanvasBonus
613
691
  };
614
692
  }
615
693
  async batchGetCardDetail(userCards, config = {}, eventConfig, areaItemLevels) {
616
694
  const areaItemLevels0 = areaItemLevels === undefined
617
695
  ? await this.areaItemService.getAreaItemLevels()
618
696
  : areaItemLevels;
619
- const ret = await Promise.all(userCards.map(async (it) => await this.getCardDetail(it, areaItemLevels0, config, eventConfig))).then(it => it.filter(it => it !== undefined));
697
+ const userCanvasBonusCards = await this.mysekaiService.getMysekaiCanvasBonusCards();
698
+ const userGateBonuses = await this.mysekaiService.getMysekaiGateBonuses();
699
+ const ret = await Promise.all(userCards.map(async (it) => await this.getCardDetail(it, areaItemLevels0, config, eventConfig, userCanvasBonusCards.includes(it.cardId), userGateBonuses))).then(it => it.filter(it => it !== undefined));
620
700
  if (eventConfig?.specialCharacterId !== undefined && eventConfig.specialCharacterId > 0) {
621
701
  return ret.sort((a, b) => safeNumber(b.supportDeckBonus) - safeNumber(a.supportDeckBonus));
622
702
  }
@@ -879,15 +959,21 @@ class DeckCalculator {
879
959
  return current.total > vv.total ? current : vv;
880
960
  }, cardDetail.power.get(cardDetail.units[0], getOrThrow(map, cardDetail.units[0]), getOrThrow(map, cardDetail.attr))));
881
961
  });
882
- const base = cardDetails.reduce((v, cardDetail) => v + getOrThrow(cardPower, cardDetail.cardId).base, 0);
883
- const areaItemBonus = cardDetails.reduce((v, cardDetail) => v + getOrThrow(cardPower, cardDetail.cardId).areaItemBonus, 0);
884
- const characterBonus = cardDetails.reduce((v, cardDetail) => v + getOrThrow(cardPower, cardDetail.cardId).characterBonus, 0);
962
+ const base = DeckCalculator.sumPower(cardDetails, cardPower, it => it.base);
963
+ const canvasBonus = DeckCalculator.sumPower(cardDetails, cardPower, it => it.canvasBonus);
964
+ const areaItemBonus = DeckCalculator.sumPower(cardDetails, cardPower, it => it.areaItemBonus);
965
+ const characterBonus = DeckCalculator.sumPower(cardDetails, cardPower, it => it.characterBonus);
966
+ const fixtureBonus = DeckCalculator.sumPower(cardDetails, cardPower, it => it.fixtureBonus);
967
+ const gateBonus = DeckCalculator.sumPower(cardDetails, cardPower, it => it.gateBonus);
885
968
  const total = base + areaItemBonus + characterBonus + honorBonus;
886
969
  const power = {
887
970
  base,
971
+ canvasBonus,
888
972
  areaItemBonus,
889
973
  characterBonus,
890
974
  honorBonus,
975
+ fixtureBonus,
976
+ gateBonus,
891
977
  total
892
978
  };
893
979
  const cards = cardDetails.map(cardDetail => {
@@ -914,6 +1000,9 @@ class DeckCalculator {
914
1000
  cards
915
1001
  };
916
1002
  }
1003
+ static sumPower(cardDetails, cardPower, attr) {
1004
+ return cardDetails.reduce((v, cardDetail) => v + attr(getOrThrow(cardPower, cardDetail.cardId)), 0);
1005
+ }
917
1006
  async getDeckDetail(deckCards, allCards, eventConfig, areaItemLevels) {
918
1007
  const allCards0 = await this.cardCalculator.batchGetCardDetail(allCards, {}, eventConfig, areaItemLevels);
919
1008
  return await this.getDeckDetailByCards(await this.cardCalculator.batchGetCardDetail(deckCards, {}, eventConfig, areaItemLevels), allCards0, await this.getHonorBonusPower(), eventConfig?.eventType);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sekai-calculator",
3
- "version": "0.12.2",
3
+ "version": "0.13.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",
@@ -40,7 +40,7 @@
40
40
  "eslint-plugin-n": "^15.7.0",
41
41
  "eslint-plugin-promise": "^6.1.1",
42
42
  "jest": "^29.5.0",
43
- "rollup": "^3.20.2",
43
+ "rollup": "^4.22.4",
44
44
  "rollup-plugin-dts": "^5.3.0",
45
45
  "ts-jest": "^29.1.0",
46
46
  "ts-node": "^10.9.1",