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 +106 -17
- package/dist/index.d.ts +19 -2
- package/dist/index.mjs +106 -17
- package/package.json +2 -2
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
|
-
|
|
357
|
+
fixtureBonus,
|
|
358
|
+
gateBonus,
|
|
359
|
+
total: base + canvasBonus + areaItemBonus + characterBonus + fixtureBonus + gateBonus
|
|
353
360
|
};
|
|
354
361
|
}
|
|
355
362
|
async getCardBasePowers(userCard, card) {
|
|
356
|
-
const
|
|
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
|
|
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 =
|
|
885
|
-
const
|
|
886
|
-
const
|
|
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
|
|
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
|
-
|
|
355
|
+
fixtureBonus,
|
|
356
|
+
gateBonus,
|
|
357
|
+
total: base + canvasBonus + areaItemBonus + characterBonus + fixtureBonus + gateBonus
|
|
351
358
|
};
|
|
352
359
|
}
|
|
353
360
|
async getCardBasePowers(userCard, card) {
|
|
354
|
-
const
|
|
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
|
|
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 =
|
|
883
|
-
const
|
|
884
|
-
const
|
|
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.
|
|
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": "^
|
|
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",
|