From 444fea85f0e8e13aba6130909e366dc15f25b8d6 Mon Sep 17 00:00:00 2001 From: Branden J Brown Date: Fri, 21 Aug 2026 15:45:53 -0400 Subject: [PATCH] zenno: lint fixes --- zenno/src/lib/data/scenario.ts | 18 +- zenno/src/lib/data/support.spec.ts | 794 +++++----- zenno/src/lib/data/support.ts | 577 ++++--- zenno/src/lib/data/support_card_level.json | 1356 ++++++++--------- .../testdata/support-10018-bakushin-R.json | 826 +++++----- .../testdata/support-20042-bakushin-SR.json | 850 +++++------ .../testdata/support-30083-bakushin-SSR.json | 935 ++++++------ zenno/src/lib/ism.ts | 452 +++--- .../career/ismdata/SupportCardGainChart.ts | 269 ++-- 9 files changed, 3037 insertions(+), 3040 deletions(-) diff --git a/zenno/src/lib/data/scenario.ts b/zenno/src/lib/data/scenario.ts index cacda28..62466bd 100644 --- a/zenno/src/lib/data/scenario.ts +++ b/zenno/src/lib/data/scenario.ts @@ -1,15 +1,17 @@ import * as z from 'zod'; -const Scenarios = z.array(z.object({ - scenario_id: z.int32(), - name: z.string(), - title: z.string(), -})); +const Scenarios = z.array( + z.object({ + scenario_id: z.int32(), + name: z.string(), + title: z.string(), + }), +); export type Scenario = z.infer[number]; export async function scenarios(): Promise { - const r = await fetch('/api/global/scenario'); - const u = await r.json(); - return Scenarios.parse(u); + const r = await fetch('/api/global/scenario'); + const u = await r.json(); + return Scenarios.parse(u); } diff --git a/zenno/src/lib/data/support.spec.ts b/zenno/src/lib/data/support.spec.ts index caf2a71..62c7599 100644 --- a/zenno/src/lib/data/support.spec.ts +++ b/zenno/src/lib/data/support.spec.ts @@ -6,406 +6,404 @@ import * as bakushinSR from './testdata/support-20042-bakushin-SR.json'; import * as bakushinSSR from './testdata/support-30083-bakushin-SSR.json'; test.for([ - { rarity: support.Rarity.R, exp: 0, level: 1 }, - { rarity: support.Rarity.R, exp: 5, level: 2 }, - { rarity: support.Rarity.R, exp: 10, level: 2 }, - { rarity: support.Rarity.R, exp: 40510, level: 40 }, - { rarity: support.Rarity.SR, exp: 0, level: 1 }, - { rarity: support.Rarity.SR, exp: 10, level: 2 }, - { rarity: support.Rarity.SR, exp: 20, level: 2 }, - { rarity: support.Rarity.SR, exp: 74990, level: 45 }, - { rarity: support.Rarity.SSR, exp: 0, level: 1 }, - { rarity: support.Rarity.SSR, exp: 15, level: 2 }, - { rarity: support.Rarity.SSR, exp: 30, level: 2 }, - { rarity: support.Rarity.SSR, exp: 118185, level: 50 }, + { rarity: support.Rarity.R, exp: 0, level: 1 }, + { rarity: support.Rarity.R, exp: 5, level: 2 }, + { rarity: support.Rarity.R, exp: 10, level: 2 }, + { rarity: support.Rarity.R, exp: 40510, level: 40 }, + { rarity: support.Rarity.SR, exp: 0, level: 1 }, + { rarity: support.Rarity.SR, exp: 10, level: 2 }, + { rarity: support.Rarity.SR, exp: 20, level: 2 }, + { rarity: support.Rarity.SR, exp: 74990, level: 45 }, + { rarity: support.Rarity.SSR, exp: 0, level: 1 }, + { rarity: support.Rarity.SSR, exp: 15, level: 2 }, + { rarity: support.Rarity.SSR, exp: 30, level: 2 }, + { rarity: support.Rarity.SSR, exp: 118185, level: 50 }, ])('level($rarity, $exp) -> $level', ({ rarity, exp, level }) => expect(support.level(rarity, exp)).toBe(level)); describe('effects', () => { + describe('Bakushin R', () => { + test('level 1', () => { + const got = support.effects(bakushinR as support.SupportCard, 1); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 5 }, + { type: support.EffectType.MoodEffect, value: 0 }, + { type: support.EffectType.SpeedBonus, value: 0 }, + { type: support.EffectType.InitialSpeed, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 0 }, + { type: support.EffectType.RaceBonus, value: 1 }, + { type: support.EffectType.FanBonus, value: 1 }, + { type: support.EffectType.SpecialtyPriority, value: 0 }, + ], + }); + }); + test('level 2', () => { + const got = support.effects(bakushinR as support.SupportCard, 2); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 5 }, + { type: support.EffectType.MoodEffect, value: 0 }, + { type: support.EffectType.SpeedBonus, value: 0 }, + { type: support.EffectType.InitialSpeed, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 0 }, + { type: support.EffectType.RaceBonus, value: 1 }, + { type: support.EffectType.FanBonus, value: 1 }, + { type: support.EffectType.SpecialtyPriority, value: 0 }, + ], + }); + }); + test('level 5', () => { + const got = support.effects(bakushinR as support.SupportCard, 5); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 6 }, + { type: support.EffectType.MoodEffect, value: 10 }, + { type: support.EffectType.SpeedBonus, value: 0 }, + { type: support.EffectType.InitialSpeed, value: 10 }, + { type: support.EffectType.InitialFriendship, value: 10 }, + { type: support.EffectType.RaceBonus, value: 1 }, + { type: support.EffectType.FanBonus, value: 2 }, + { type: support.EffectType.SpecialtyPriority, value: 5 }, + ], + }); + }); + test('level 6', () => { + const got = support.effects(bakushinR as support.SupportCard, 6); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 6 }, + { type: support.EffectType.MoodEffect, value: 10 }, + { type: support.EffectType.SpeedBonus, value: 0 }, + { type: support.EffectType.InitialSpeed, value: 10 }, + { type: support.EffectType.InitialFriendship, value: 10 }, + { type: support.EffectType.RaceBonus, value: 2 }, + { type: support.EffectType.FanBonus, value: 3 }, + { type: support.EffectType.SpecialtyPriority, value: 6 }, + ], + }); + }); + test('level 39', () => { + const got = support.effects(bakushinR as support.SupportCard, 39); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 15 }, + { type: support.EffectType.MoodEffect, value: 25 }, + { type: support.EffectType.SpeedBonus, value: 0 }, + { type: support.EffectType.InitialSpeed, value: 20 }, + { type: support.EffectType.InitialFriendship, value: 20 }, + { type: support.EffectType.RaceBonus, value: 5 }, + { type: support.EffectType.FanBonus, value: 14 }, + { type: support.EffectType.SpecialtyPriority, value: 35 }, + ], + }); + }); + test('level 40', () => { + const got = support.effects(bakushinR as support.SupportCard, 40); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 15 }, + { type: support.EffectType.MoodEffect, value: 25 }, + { type: support.EffectType.SpeedBonus, value: 1 }, + { type: support.EffectType.InitialSpeed, value: 20 }, + { type: support.EffectType.InitialFriendship, value: 20 }, + { type: support.EffectType.RaceBonus, value: 5 }, + { type: support.EffectType.FanBonus, value: 15 }, + { type: support.EffectType.SpecialtyPriority, value: 35 }, + ], + }); + }); + }); - describe('Bakushin R', () => { - test('level 1', () => { - const got = support.effects(bakushinR as support.SupportCard, 1); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 5 }, - { type: support.EffectType.MoodEffect, value: 0 }, - { type: support.EffectType.SpeedBonus, value: 0 }, - { type: support.EffectType.InitialSpeed, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 0 }, - { type: support.EffectType.RaceBonus, value: 1 }, - { type: support.EffectType.FanBonus, value: 1 }, - { type: support.EffectType.SpecialtyPriority, value: 0 }, - ], - }); - }); - test('level 2', () => { - const got = support.effects(bakushinR as support.SupportCard, 2); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 5 }, - { type: support.EffectType.MoodEffect, value: 0 }, - { type: support.EffectType.SpeedBonus, value: 0 }, - { type: support.EffectType.InitialSpeed, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 0 }, - { type: support.EffectType.RaceBonus, value: 1 }, - { type: support.EffectType.FanBonus, value: 1 }, - { type: support.EffectType.SpecialtyPriority, value: 0 }, - ], - }); - }); - test('level 5', () => { - const got = support.effects(bakushinR as support.SupportCard, 5); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 6 }, - { type: support.EffectType.MoodEffect, value: 10 }, - { type: support.EffectType.SpeedBonus, value: 0 }, - { type: support.EffectType.InitialSpeed, value: 10 }, - { type: support.EffectType.InitialFriendship, value: 10 }, - { type: support.EffectType.RaceBonus, value: 1 }, - { type: support.EffectType.FanBonus, value: 2 }, - { type: support.EffectType.SpecialtyPriority, value: 5 }, - ], - }); - }); - test('level 6', () => { - const got = support.effects(bakushinR as support.SupportCard, 6); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 6 }, - { type: support.EffectType.MoodEffect, value: 10 }, - { type: support.EffectType.SpeedBonus, value: 0 }, - { type: support.EffectType.InitialSpeed, value: 10 }, - { type: support.EffectType.InitialFriendship, value: 10 }, - { type: support.EffectType.RaceBonus, value: 2 }, - { type: support.EffectType.FanBonus, value: 3 }, - { type: support.EffectType.SpecialtyPriority, value: 6 }, - ], - }); - }); - test('level 39', () => { - const got = support.effects(bakushinR as support.SupportCard, 39); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 15 }, - { type: support.EffectType.MoodEffect, value: 25 }, - { type: support.EffectType.SpeedBonus, value: 0 }, - { type: support.EffectType.InitialSpeed, value: 20 }, - { type: support.EffectType.InitialFriendship, value: 20 }, - { type: support.EffectType.RaceBonus, value: 5 }, - { type: support.EffectType.FanBonus, value: 14 }, - { type: support.EffectType.SpecialtyPriority, value: 35 }, - ], - }); - }); - test('level 40', () => { - const got = support.effects(bakushinR as support.SupportCard, 40); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 15 }, - { type: support.EffectType.MoodEffect, value: 25 }, - { type: support.EffectType.SpeedBonus, value: 1 }, - { type: support.EffectType.InitialSpeed, value: 20 }, - { type: support.EffectType.InitialFriendship, value: 20 }, - { type: support.EffectType.RaceBonus, value: 5 }, - { type: support.EffectType.FanBonus, value: 15 }, - { type: support.EffectType.SpecialtyPriority, value: 35 }, - ], - }); - }); - }); + describe('Bakushin SR', () => { + test('level 1', () => { + const got = support.effects(bakushinSR as support.SupportCard, 1); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 10 }, + { type: support.EffectType.PowerBonus, value: 0 }, + { type: support.EffectType.TrainingEffectiveness, value: 0 }, + { type: support.EffectType.InitialPower, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 0 }, + { type: support.EffectType.RaceBonus, value: 1 }, + { type: support.EffectType.FanBonus, value: 1 }, + { type: support.EffectType.SpecialtyPriority, value: 0 }, + ], + }); + }); + test('level 2', () => { + const got = support.effects(bakushinSR as support.SupportCard, 2); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 10 }, + { type: support.EffectType.PowerBonus, value: 0 }, + { type: support.EffectType.TrainingEffectiveness, value: 0 }, + { type: support.EffectType.InitialPower, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 0 }, + { type: support.EffectType.RaceBonus, value: 1 }, + { type: support.EffectType.FanBonus, value: 1 }, + { type: support.EffectType.SpecialtyPriority, value: 0 }, + ], + }); + }); + test('level 5', () => { + const got = support.effects(bakushinSR as support.SupportCard, 5); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 11 }, + { type: support.EffectType.PowerBonus, value: 0 }, + { type: support.EffectType.TrainingEffectiveness, value: 0 }, + { type: support.EffectType.InitialPower, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 0 }, + { type: support.EffectType.RaceBonus, value: 1 }, + { type: support.EffectType.FanBonus, value: 3 }, + { type: support.EffectType.SpecialtyPriority, value: 5 }, + ], + }); + }); + test('level 24', () => { + const got = support.effects(bakushinSR as support.SupportCard, 24); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 15 }, + { type: support.EffectType.PowerBonus, value: 0 }, + { type: support.EffectType.TrainingEffectiveness, value: 5 }, + { type: support.EffectType.InitialPower, value: 15 }, + { type: support.EffectType.InitialFriendship, value: 0 }, + { type: support.EffectType.RaceBonus, value: 4 }, + { type: support.EffectType.FanBonus, value: 14 }, + { type: support.EffectType.SpecialtyPriority, value: 33 }, + ], + }); + }); + test('level 25', () => { + const got = support.effects(bakushinSR as support.SupportCard, 25); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 15 }, + { type: support.EffectType.PowerBonus, value: 0 }, + { type: support.EffectType.TrainingEffectiveness, value: 5 }, + { type: support.EffectType.InitialPower, value: 15 }, + { type: support.EffectType.InitialFriendship, value: 0 }, + { type: support.EffectType.RaceBonus, value: 5 }, + { type: support.EffectType.FanBonus, value: 15 }, + { type: support.EffectType.SpecialtyPriority, value: 35 }, + ], + unique: { + name: 'The Perfect Morning Greeting!', + description: 'Friendship Bonus and Specialty Priority', + card_level: 25, + type: support.EffectType.FriendshipBonus, + args: [10], + type2: support.EffectType.SpecialtyPriority, + args2: [20], + idle_mode_sub_rate: 0, + } satisfies support.UniqueEffect, + }); + }); + test('level 44', () => { + const got = support.effects(bakushinSR as support.SupportCard, 44); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 20 }, + { type: support.EffectType.PowerBonus, value: 0 }, + { type: support.EffectType.TrainingEffectiveness, value: 5 }, + { type: support.EffectType.InitialPower, value: 20 }, + { type: support.EffectType.InitialFriendship, value: 20 }, + { type: support.EffectType.RaceBonus, value: 9 }, + { type: support.EffectType.FanBonus, value: 19 }, + { type: support.EffectType.SpecialtyPriority, value: 49 }, + ], + unique: { + name: 'The Perfect Morning Greeting!', + description: 'Friendship Bonus and Specialty Priority', + card_level: 25, + type: support.EffectType.FriendshipBonus, + args: [10], + type2: support.EffectType.SpecialtyPriority, + args2: [20], + idle_mode_sub_rate: 0, + } satisfies support.UniqueEffect, + }); + }); + test('level 45', () => { + const got = support.effects(bakushinSR as support.SupportCard, 45); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 20 }, + { type: support.EffectType.PowerBonus, value: 1 }, + { type: support.EffectType.TrainingEffectiveness, value: 5 }, + { type: support.EffectType.InitialPower, value: 20 }, + { type: support.EffectType.InitialFriendship, value: 20 }, + { type: support.EffectType.RaceBonus, value: 10 }, + { type: support.EffectType.FanBonus, value: 20 }, + { type: support.EffectType.SpecialtyPriority, value: 50 }, + ], + unique: { + name: 'The Perfect Morning Greeting!', + description: 'Friendship Bonus and Specialty Priority', + card_level: 25, + type: support.EffectType.FriendshipBonus, + args: [10], + type2: support.EffectType.SpecialtyPriority, + args2: [20], + idle_mode_sub_rate: 0, + } satisfies support.UniqueEffect, + }); + }); + }); - describe('Bakushin SR', () => { - test('level 1', () => { - const got = support.effects(bakushinSR as support.SupportCard, 1); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 10 }, - { type: support.EffectType.PowerBonus, value: 0 }, - { type: support.EffectType.TrainingEffectiveness, value: 0 }, - { type: support.EffectType.InitialPower, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 0 }, - { type: support.EffectType.RaceBonus, value: 1 }, - { type: support.EffectType.FanBonus, value: 1 }, - { type: support.EffectType.SpecialtyPriority, value: 0 }, - ], - }); - }); - test('level 2', () => { - const got = support.effects(bakushinSR as support.SupportCard, 2); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 10 }, - { type: support.EffectType.PowerBonus, value: 0 }, - { type: support.EffectType.TrainingEffectiveness, value: 0 }, - { type: support.EffectType.InitialPower, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 0 }, - { type: support.EffectType.RaceBonus, value: 1 }, - { type: support.EffectType.FanBonus, value: 1 }, - { type: support.EffectType.SpecialtyPriority, value: 0 }, - ], - }); - }); - test('level 5', () => { - const got = support.effects(bakushinSR as support.SupportCard, 5); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 11 }, - { type: support.EffectType.PowerBonus, value: 0 }, - { type: support.EffectType.TrainingEffectiveness, value: 0 }, - { type: support.EffectType.InitialPower, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 0 }, - { type: support.EffectType.RaceBonus, value: 1 }, - { type: support.EffectType.FanBonus, value: 3 }, - { type: support.EffectType.SpecialtyPriority, value: 5 }, - ], - }); - }); - test('level 24', () => { - const got = support.effects(bakushinSR as support.SupportCard, 24); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 15 }, - { type: support.EffectType.PowerBonus, value: 0 }, - { type: support.EffectType.TrainingEffectiveness, value: 5 }, - { type: support.EffectType.InitialPower, value: 15 }, - { type: support.EffectType.InitialFriendship, value: 0 }, - { type: support.EffectType.RaceBonus, value: 4 }, - { type: support.EffectType.FanBonus, value: 14 }, - { type: support.EffectType.SpecialtyPriority, value: 33 }, - ], - }); - }); - test('level 25', () => { - const got = support.effects(bakushinSR as support.SupportCard, 25); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 15 }, - { type: support.EffectType.PowerBonus, value: 0 }, - { type: support.EffectType.TrainingEffectiveness, value: 5 }, - { type: support.EffectType.InitialPower, value: 15 }, - { type: support.EffectType.InitialFriendship, value: 0 }, - { type: support.EffectType.RaceBonus, value: 5 }, - { type: support.EffectType.FanBonus, value: 15 }, - { type: support.EffectType.SpecialtyPriority, value: 35 }, - ], - unique: { - name: 'The Perfect Morning Greeting!', - description: 'Friendship Bonus and Specialty Priority', - card_level: 25, - type: support.EffectType.FriendshipBonus, - args: [10], - type2: support.EffectType.SpecialtyPriority, - args2: [20], - idle_mode_sub_rate: 0, - } satisfies support.UniqueEffect, - }); - }); - test('level 44', () => { - const got = support.effects(bakushinSR as support.SupportCard, 44); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 20 }, - { type: support.EffectType.PowerBonus, value: 0 }, - { type: support.EffectType.TrainingEffectiveness, value: 5 }, - { type: support.EffectType.InitialPower, value: 20 }, - { type: support.EffectType.InitialFriendship, value: 20 }, - { type: support.EffectType.RaceBonus, value: 9 }, - { type: support.EffectType.FanBonus, value: 19 }, - { type: support.EffectType.SpecialtyPriority, value: 49 }, - ], - unique: { - name: 'The Perfect Morning Greeting!', - description: 'Friendship Bonus and Specialty Priority', - card_level: 25, - type: support.EffectType.FriendshipBonus, - args: [10], - type2: support.EffectType.SpecialtyPriority, - args2: [20], - idle_mode_sub_rate: 0, - } satisfies support.UniqueEffect, - }); - }); - test('level 45', () => { - const got = support.effects(bakushinSR as support.SupportCard, 45); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 20 }, - { type: support.EffectType.PowerBonus, value: 1 }, - { type: support.EffectType.TrainingEffectiveness, value: 5 }, - { type: support.EffectType.InitialPower, value: 20 }, - { type: support.EffectType.InitialFriendship, value: 20 }, - { type: support.EffectType.RaceBonus, value: 10 }, - { type: support.EffectType.FanBonus, value: 20 }, - { type: support.EffectType.SpecialtyPriority, value: 50 }, - ], - unique: { - name: 'The Perfect Morning Greeting!', - description: 'Friendship Bonus and Specialty Priority', - card_level: 25, - type: support.EffectType.FriendshipBonus, - args: [10], - type2: support.EffectType.SpecialtyPriority, - args2: [20], - idle_mode_sub_rate: 0, - } satisfies support.UniqueEffect, - }); - }); - }) - - describe('Bakushin SSR', () => { - test('level 1', () => { - const got = support.effects(bakushinSSR as support.SupportCard, 1); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 10 }, - { type: support.EffectType.MoodEffect, value: 0 }, - { type: support.EffectType.GutsBonus, value: 0 }, - { type: support.EffectType.InitialGuts, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 0 }, - { type: support.EffectType.RaceBonus, value: 1 }, - { type: support.EffectType.FanBonus, value: 1 }, - { type: support.EffectType.HintLevels, value: 1 }, - { type: support.EffectType.HintFrequency, value: 5 }, - ], - }); - }); - test('level 2', () => { - const got = support.effects(bakushinSSR as support.SupportCard, 2); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 10 }, - { type: support.EffectType.MoodEffect, value: 0 }, - { type: support.EffectType.GutsBonus, value: 0 }, - { type: support.EffectType.InitialGuts, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 0 }, - { type: support.EffectType.RaceBonus, value: 1 }, - { type: support.EffectType.FanBonus, value: 1 }, - { type: support.EffectType.HintLevels, value: 1 }, - { type: support.EffectType.HintFrequency, value: 6 }, - ], - }); - }); - test('level 5', () => { - const got = support.effects(bakushinSSR as support.SupportCard, 5); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 12 }, - { type: support.EffectType.MoodEffect, value: 0 }, - { type: support.EffectType.GutsBonus, value: 0 }, - { type: support.EffectType.InitialGuts, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 0 }, - { type: support.EffectType.RaceBonus, value: 1 }, - { type: support.EffectType.FanBonus, value: 2 }, - { type: support.EffectType.HintLevels, value: 1 }, - { type: support.EffectType.HintFrequency, value: 9 }, - ], - }); - }); - test('level 10', () => { - const got = support.effects(bakushinSSR as support.SupportCard, 10); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 14 }, - { type: support.EffectType.MoodEffect, value: 0 }, - { type: support.EffectType.GutsBonus, value: 0 }, - { type: support.EffectType.InitialGuts, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 10 }, - { type: support.EffectType.RaceBonus, value: 2 }, - { type: support.EffectType.FanBonus, value: 5 }, - { type: support.EffectType.HintLevels, value: 1 }, - { type: support.EffectType.HintFrequency, value: 15 }, - ], - }); - }); - test('level 11', () => { - const got = support.effects(bakushinSSR as support.SupportCard, 11); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 15 }, - { type: support.EffectType.MoodEffect, value: 0 }, - { type: support.EffectType.GutsBonus, value: 0 }, - { type: support.EffectType.InitialGuts, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 10 }, - { type: support.EffectType.RaceBonus, value: 2 }, - { type: support.EffectType.FanBonus, value: 5 }, - { type: support.EffectType.HintLevels, value: 1 }, - { type: support.EffectType.HintFrequency, value: 17 }, - ], - }); - }); - test('level 30', () => { - const got = support.effects(bakushinSSR as support.SupportCard, 30); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 25 }, - { type: support.EffectType.MoodEffect, value: 20 }, - { type: support.EffectType.GutsBonus, value: 0 }, - { type: support.EffectType.InitialGuts, value: 0 }, - { type: support.EffectType.InitialFriendship, value: 20 }, - { type: support.EffectType.RaceBonus, value: 5 }, - { type: support.EffectType.FanBonus, value: 15 }, - { type: support.EffectType.HintLevels, value: 2 }, - { type: support.EffectType.HintFrequency, value: 40 }, - ], - unique: { - name: 'Super! Sonic! Flower Power!', - description: 'Increases Training Effectiveness when not on preferred training. (Friendship 80+)', - card_level: 30, - type: support.EffectType.UniqueOffSpecialty, - args: [80, 20], - idle_mode_sub_rate: 30, - } satisfies support.UniqueEffect, - }); - }); - test('level 49', () => { - const got = support.effects(bakushinSSR as support.SupportCard, 49); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 34 }, - { type: support.EffectType.MoodEffect, value: 30 }, - { type: support.EffectType.GutsBonus, value: 1 }, - { type: support.EffectType.InitialGuts, value: 27 }, - { type: support.EffectType.InitialFriendship, value: 25 }, - { type: support.EffectType.RaceBonus, value: 9 }, - { type: support.EffectType.FanBonus, value: 19 }, - { type: support.EffectType.HintLevels, value: 2 }, - { type: support.EffectType.HintFrequency, value: 49 }, - ], - unique: { - name: 'Super! Sonic! Flower Power!', - description: 'Increases Training Effectiveness when not on preferred training. (Friendship 80+)', - card_level: 30, - type: support.EffectType.UniqueOffSpecialty, - args: [80, 20], - idle_mode_sub_rate: 30, - } satisfies support.UniqueEffect, - }); - }); - test('level 50', () => { - const got = support.effects(bakushinSSR as support.SupportCard, 50); - expect(got).toStrictEqual({ - effects: [ - { type: support.EffectType.FriendshipBonus, value: 35 }, - { type: support.EffectType.MoodEffect, value: 30 }, - { type: support.EffectType.GutsBonus, value: 1 }, - { type: support.EffectType.InitialGuts, value: 30 }, - { type: support.EffectType.InitialFriendship, value: 25 }, - { type: support.EffectType.RaceBonus, value: 10 }, - { type: support.EffectType.FanBonus, value: 20 }, - { type: support.EffectType.HintLevels, value: 3 }, - { type: support.EffectType.HintFrequency, value: 50 }, - ], - unique: { - name: 'Super! Sonic! Flower Power!', - description: 'Increases Training Effectiveness when not on preferred training. (Friendship 80+)', - card_level: 30, - type: support.EffectType.UniqueOffSpecialty, - args: [80, 20], - idle_mode_sub_rate: 30, - } satisfies support.UniqueEffect, - }); - }); - }); - -}); \ No newline at end of file + describe('Bakushin SSR', () => { + test('level 1', () => { + const got = support.effects(bakushinSSR as support.SupportCard, 1); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 10 }, + { type: support.EffectType.MoodEffect, value: 0 }, + { type: support.EffectType.GutsBonus, value: 0 }, + { type: support.EffectType.InitialGuts, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 0 }, + { type: support.EffectType.RaceBonus, value: 1 }, + { type: support.EffectType.FanBonus, value: 1 }, + { type: support.EffectType.HintLevels, value: 1 }, + { type: support.EffectType.HintFrequency, value: 5 }, + ], + }); + }); + test('level 2', () => { + const got = support.effects(bakushinSSR as support.SupportCard, 2); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 10 }, + { type: support.EffectType.MoodEffect, value: 0 }, + { type: support.EffectType.GutsBonus, value: 0 }, + { type: support.EffectType.InitialGuts, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 0 }, + { type: support.EffectType.RaceBonus, value: 1 }, + { type: support.EffectType.FanBonus, value: 1 }, + { type: support.EffectType.HintLevels, value: 1 }, + { type: support.EffectType.HintFrequency, value: 6 }, + ], + }); + }); + test('level 5', () => { + const got = support.effects(bakushinSSR as support.SupportCard, 5); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 12 }, + { type: support.EffectType.MoodEffect, value: 0 }, + { type: support.EffectType.GutsBonus, value: 0 }, + { type: support.EffectType.InitialGuts, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 0 }, + { type: support.EffectType.RaceBonus, value: 1 }, + { type: support.EffectType.FanBonus, value: 2 }, + { type: support.EffectType.HintLevels, value: 1 }, + { type: support.EffectType.HintFrequency, value: 9 }, + ], + }); + }); + test('level 10', () => { + const got = support.effects(bakushinSSR as support.SupportCard, 10); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 14 }, + { type: support.EffectType.MoodEffect, value: 0 }, + { type: support.EffectType.GutsBonus, value: 0 }, + { type: support.EffectType.InitialGuts, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 10 }, + { type: support.EffectType.RaceBonus, value: 2 }, + { type: support.EffectType.FanBonus, value: 5 }, + { type: support.EffectType.HintLevels, value: 1 }, + { type: support.EffectType.HintFrequency, value: 15 }, + ], + }); + }); + test('level 11', () => { + const got = support.effects(bakushinSSR as support.SupportCard, 11); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 15 }, + { type: support.EffectType.MoodEffect, value: 0 }, + { type: support.EffectType.GutsBonus, value: 0 }, + { type: support.EffectType.InitialGuts, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 10 }, + { type: support.EffectType.RaceBonus, value: 2 }, + { type: support.EffectType.FanBonus, value: 5 }, + { type: support.EffectType.HintLevels, value: 1 }, + { type: support.EffectType.HintFrequency, value: 17 }, + ], + }); + }); + test('level 30', () => { + const got = support.effects(bakushinSSR as support.SupportCard, 30); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 25 }, + { type: support.EffectType.MoodEffect, value: 20 }, + { type: support.EffectType.GutsBonus, value: 0 }, + { type: support.EffectType.InitialGuts, value: 0 }, + { type: support.EffectType.InitialFriendship, value: 20 }, + { type: support.EffectType.RaceBonus, value: 5 }, + { type: support.EffectType.FanBonus, value: 15 }, + { type: support.EffectType.HintLevels, value: 2 }, + { type: support.EffectType.HintFrequency, value: 40 }, + ], + unique: { + name: 'Super! Sonic! Flower Power!', + description: 'Increases Training Effectiveness when not on preferred training. (Friendship 80+)', + card_level: 30, + type: support.EffectType.UniqueOffSpecialty, + args: [80, 20], + idle_mode_sub_rate: 30, + } satisfies support.UniqueEffect, + }); + }); + test('level 49', () => { + const got = support.effects(bakushinSSR as support.SupportCard, 49); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 34 }, + { type: support.EffectType.MoodEffect, value: 30 }, + { type: support.EffectType.GutsBonus, value: 1 }, + { type: support.EffectType.InitialGuts, value: 27 }, + { type: support.EffectType.InitialFriendship, value: 25 }, + { type: support.EffectType.RaceBonus, value: 9 }, + { type: support.EffectType.FanBonus, value: 19 }, + { type: support.EffectType.HintLevels, value: 2 }, + { type: support.EffectType.HintFrequency, value: 49 }, + ], + unique: { + name: 'Super! Sonic! Flower Power!', + description: 'Increases Training Effectiveness when not on preferred training. (Friendship 80+)', + card_level: 30, + type: support.EffectType.UniqueOffSpecialty, + args: [80, 20], + idle_mode_sub_rate: 30, + } satisfies support.UniqueEffect, + }); + }); + test('level 50', () => { + const got = support.effects(bakushinSSR as support.SupportCard, 50); + expect(got).toStrictEqual({ + effects: [ + { type: support.EffectType.FriendshipBonus, value: 35 }, + { type: support.EffectType.MoodEffect, value: 30 }, + { type: support.EffectType.GutsBonus, value: 1 }, + { type: support.EffectType.InitialGuts, value: 30 }, + { type: support.EffectType.InitialFriendship, value: 25 }, + { type: support.EffectType.RaceBonus, value: 10 }, + { type: support.EffectType.FanBonus, value: 20 }, + { type: support.EffectType.HintLevels, value: 3 }, + { type: support.EffectType.HintFrequency, value: 50 }, + ], + unique: { + name: 'Super! Sonic! Flower Power!', + description: 'Increases Training Effectiveness when not on preferred training. (Friendship 80+)', + card_level: 30, + type: support.EffectType.UniqueOffSpecialty, + args: [80, 20], + idle_mode_sub_rate: 30, + } satisfies support.UniqueEffect, + }); + }); + }); +}); diff --git a/zenno/src/lib/data/support.ts b/zenno/src/lib/data/support.ts index 325ffea..7dc77d0 100644 --- a/zenno/src/lib/data/support.ts +++ b/zenno/src/lib/data/support.ts @@ -4,227 +4,215 @@ import * as support_card_level from './support_card_level.json'; * Support card definitions. */ export interface SupportCard { - /** - * Support card ID. - */ - id: number; - /** - * Support card name including variant, e.g. - * `[The Brightest Star in Japan!] Special Week`. - */ - name: string; - /** - * ID of the card's representative character. - */ - chara_id: number; - /** - * Name of the card's character. - * May differ from the name of the `chara_id` character. - */ - chara_name: string; - /** - * Support card rarity. - */ - rarity: Rarity; - /** - * Support card specialty. - */ - specialty: Specialty; - /** - * Blanket support card type. - */ - type: Type; - /** - * Support card effects per five level increment. - */ - effects: [ - Effect[], - Effect[], - Effect[], - Effect[], - Effect[], - Effect[], - Effect[], - Effect[], - Effect[], - Effect[], - Effect[], - ]; - /** - * Unique effect, for cards that have them. - */ - unique_effect?: UniqueEffect; - /** - * Hints that the card can yield. - */ - hints: Hint[]; - /** - * Number of recreation events available with the card, - * not including recreation with the individual characters in a group. - */ - outings?: number; + /** + * Support card ID. + */ + id: number; + /** + * Support card name including variant, e.g. + * `[The Brightest Star in Japan!] Special Week`. + */ + name: string; + /** + * ID of the card's representative character. + */ + chara_id: number; + /** + * Name of the card's character. + * May differ from the name of the `chara_id` character. + */ + chara_name: string; + /** + * Support card rarity. + */ + rarity: Rarity; + /** + * Support card specialty. + */ + specialty: Specialty; + /** + * Blanket support card type. + */ + type: Type; + /** + * Support card effects per five level increment. + */ + effects: [Effect[], Effect[], Effect[], Effect[], Effect[], Effect[], Effect[], Effect[], Effect[], Effect[], Effect[]]; + /** + * Unique effect, for cards that have them. + */ + unique_effect?: UniqueEffect; + /** + * Hints that the card can yield. + */ + hints: Hint[]; + /** + * Number of recreation events available with the card, + * not including recreation with the individual characters in a group. + */ + outings?: number; } /** * Support card rarity levels. */ export enum Rarity { - R = 1, - SR = 2, - SSR = 3, + R = 1, + SR = 2, + SSR = 3, } /** * Support card specialty attribute. */ export enum Specialty { - None = 0, // for pals and groups - Speed = 101, - Power = 102, - Guts = 103, - Stamina = 105, - Wit = 106, + None = 0, // for pals and groups + Speed = 101, + Power = 102, + Guts = 103, + Stamina = 105, + Wit = 106, } /** * Support card types. */ export enum Type { - Normal = 1, - Pal = 2, - Group = 3, + Normal = 1, + Pal = 2, + Group = 3, } /** * Support card basic effects. */ export interface Effect { - /** - * Type of the effect. - */ - type: EffectType; - /** - * When positive, the amount of the effect. - * When -1, interpolate between the previous and next nonnegative values. - */ - value: number; + /** + * Type of the effect. + */ + type: EffectType; + /** + * When positive, the amount of the effect. + * When -1, interpolate between the previous and next nonnegative values. + */ + value: number; } /** * Support card unique effects. */ export interface UniqueEffect { - /** - * Name of the unique effect. - */ - name: string; - /** - * In-game description of the effect. - */ - description: string; - /** - * Card level at which the unique effect unlocks. - */ - card_level: number; - /** - * First type of the effect. - */ - type: EffectType; - /** - * Values parameterizing the first type. - */ - args: number[]; - /** - * Second type of the effect, if applicable. - */ - type2?: EffectType; - /** - * Values parameterizing the second type. - */ - args2?: number[]; - /** - * Mystery parameter that one day we might figure out. - */ - idle_mode_sub_rate: number; + /** + * Name of the unique effect. + */ + name: string; + /** + * In-game description of the effect. + */ + description: string; + /** + * Card level at which the unique effect unlocks. + */ + card_level: number; + /** + * First type of the effect. + */ + type: EffectType; + /** + * Values parameterizing the first type. + */ + args: number[]; + /** + * Second type of the effect, if applicable. + */ + type2?: EffectType; + /** + * Values parameterizing the second type. + */ + args2?: number[]; + /** + * Mystery parameter that one day we might figure out. + */ + idle_mode_sub_rate: number; } /** * Basic and unique effect types. */ export enum EffectType { - FriendshipBonus = 1, - MoodEffect = 2, - SpeedBonus = 3, - StaminaBonus = 4, - PowerBonus = 5, - GutsBonus = 6, - WitBonus = 7, - TrainingEffectiveness = 8, - InitialSpeed = 9, - InitialStamina = 10, - InitialPower = 11, - InitialGuts = 12, - InitialWit = 13, - InitialFriendship = 14, - RaceBonus = 15, - FanBonus = 16, - HintLevels = 17, - HintFrequency = 18, - SpecialtyPriority = 19, - MaxSpeed = 20, - MaxStamina = 21, - MaxPower = 22, - MaxGuts = 23, - MaxWit = 24, - EventRecovery = 25, - EventEffectiveness = 26, - FailureProtection = 27, - EnergyCostReduction = 28, - MinigameEffectiveness = 29, - SkillPointBonus = 30, - WitFriendshipRecovery = 31, + FriendshipBonus = 1, + MoodEffect = 2, + SpeedBonus = 3, + StaminaBonus = 4, + PowerBonus = 5, + GutsBonus = 6, + WitBonus = 7, + TrainingEffectiveness = 8, + InitialSpeed = 9, + InitialStamina = 10, + InitialPower = 11, + InitialGuts = 12, + InitialWit = 13, + InitialFriendship = 14, + RaceBonus = 15, + FanBonus = 16, + HintLevels = 17, + HintFrequency = 18, + SpecialtyPriority = 19, + MaxSpeed = 20, + MaxStamina = 21, + MaxPower = 22, + MaxGuts = 23, + MaxWit = 24, + EventRecovery = 25, + EventEffectiveness = 26, + FailureProtection = 27, + EnergyCostReduction = 28, + MinigameEffectiveness = 29, + SkillPointBonus = 30, + WitFriendshipRecovery = 31, - UniqueFriendshipThreshold = 101, - UniqueOffSpecialty = 102, - UniqueColorThresholdTrainingEffectiveness = 103, - UniqueFanScalingTrainingEffectiveness = 104, - UniqueColorInitialStats = 105, - UniqueRainbowStack = 106, - UniqueLowEnergyScaling = 107, - UniqueMaxEnergyScaling = 108, - UniqueTotalFriendship = 109, - UniqueCardCount = 110, - UniqueFacilityLevel = 111, - UniqueDisableFailure = 112, - UniqueFriendshipTrainingAdditionalEffect = 113, + UniqueFriendshipThreshold = 101, + UniqueOffSpecialty = 102, + UniqueColorThresholdTrainingEffectiveness = 103, + UniqueFanScalingTrainingEffectiveness = 104, + UniqueColorInitialStats = 105, + UniqueRainbowStack = 106, + UniqueLowEnergyScaling = 107, + UniqueMaxEnergyScaling = 108, + UniqueTotalFriendship = 109, + UniqueCardCount = 110, + UniqueFacilityLevel = 111, + UniqueDisableFailure = 112, + UniqueFriendshipTrainingAdditionalEffect = 113, } /** * Hint event bonuses. */ export interface Hint { - skill_id?: number; - speed?: number; - stamina?: number; - power?: number; - guts?: number; - wit?: number; - sp?: number; + skill_id?: number; + speed?: number; + stamina?: number; + power?: number; + guts?: number; + wit?: number; + sp?: number; } export async function supports(): Promise { - const resp = await fetch('/api/global/support'); - return resp.json(); + const resp = await fetch('/api/global/support'); + return resp.json(); } export const SPECIALTY_ICON = { - Speed: 0, - Stamina: 1, - Power: 2, - Guts: 3, - Wit: 4, - Pal: 5, - Group: 6, + Speed: 0, + Stamina: 1, + Power: 2, + Guts: 3, + Wit: 4, + Pal: 5, + Group: 6, } as const; /** @@ -234,135 +222,138 @@ export const SPECIALTY_ICON = { * @returns Current support card effects and its unique effect if active at the given level. */ export function effects(card: SupportCard, level: number) { - const j = Math.floor(level / 5); - const k = Math.ceil(level / 5); - const effects = card.effects[0].map((e) => { - const s = card.effects.map((l) => l.find((f) => f.type === e.type)!); - const left = s.findLastIndex((f, i) => i <= j && f.value >= 0); - const right = s.findIndex((f, i) => k <= i && f.value >= 0); - if (left < 0) { - // Effect isn't yet active. - return { type: e.type, value: 0 }; - } - if (right < 0) { - // Effect is at its maximum value. - return { type: e.type, value: s[left]!.value }; - } - if (left === right) { - // The current level is an interpolation boundary. - // Don't try to interpolate. - return { type: e.type, value: s[left]!.value }; - } - const xl = Math.max(left * 5, 1); - const xr = Math.max(right * 5, 1); - const lo = s[left]!.value; - const hi = s[right]!.value; - const value = Math.floor((hi * (level - xl) + lo * (xr - level)) / (xr - xl)); - return { type: e.type, value }; - }); - if (card.unique_effect != null && level >= card.unique_effect.card_level) { - return { effects, unique: card.unique_effect } - } - return { effects }; + const j = Math.floor(level / 5); + const k = Math.ceil(level / 5); + const effects = card.effects[0].map((e) => { + const s = card.effects.map((l) => l.find((f) => f.type === e.type)!); + const left = s.findLastIndex((f, i) => i <= j && f.value >= 0); + const right = s.findIndex((f, i) => k <= i && f.value >= 0); + if (left < 0) { + // Effect isn't yet active. + return { type: e.type, value: 0 }; + } + if (right < 0) { + // Effect is at its maximum value. + return { type: e.type, value: s[left]!.value }; + } + if (left === right) { + // The current level is an interpolation boundary. + // Don't try to interpolate. + return { type: e.type, value: s[left]!.value }; + } + const xl = Math.max(left * 5, 1); + const xr = Math.max(right * 5, 1); + const lo = s[left]!.value; + const hi = s[right]!.value; + const value = Math.floor((hi * (level - xl) + lo * (xr - level)) / (xr - xl)); + return { type: e.type, value }; + }); + if (card.unique_effect != null && level >= card.unique_effect.card_level) { + return { effects, unique: card.unique_effect }; + } + return { effects }; } export function level(rarity: Rarity, exp: number) { - // We use the ! assertion because we want an error when exp is nonsense. - return support_card_level.levels.findLast((l) => l.rarity === rarity && l.exp <= exp)!.level; + // We use the ! assertion because we want an error when exp is nonsense. + return support_card_level.levels.findLast((l) => l.rarity === rarity && l.exp <= exp)!.level; } function singleUniqueEffects(type: EffectType, args: number[], deck: SupportCard[]): Effect[] { - switch (type) { - case EffectType.FriendshipBonus: - case EffectType.MoodEffect: - case EffectType.SpeedBonus: - case EffectType.StaminaBonus: - case EffectType.PowerBonus: - case EffectType.GutsBonus: - case EffectType.WitBonus: - case EffectType.TrainingEffectiveness: - case EffectType.InitialSpeed: - case EffectType.InitialStamina: - case EffectType.InitialPower: - case EffectType.InitialGuts: - case EffectType.InitialWit: - case EffectType.InitialFriendship: - case EffectType.RaceBonus: - case EffectType.FanBonus: - case EffectType.HintLevels: - case EffectType.HintFrequency: - case EffectType.SpecialtyPriority: - case EffectType.MaxSpeed: - case EffectType.MaxStamina: - case EffectType.MaxPower: - case EffectType.MaxGuts: - case EffectType.MaxWit: - case EffectType.EventRecovery: - case EffectType.EventEffectiveness: - case EffectType.FailureProtection: - case EffectType.EnergyCostReduction: - case EffectType.MinigameEffectiveness: - case EffectType.SkillPointBonus: - case EffectType.WitFriendshipRecovery: - return [{ type, value: args[0] }]; + switch (type) { + case EffectType.FriendshipBonus: + case EffectType.MoodEffect: + case EffectType.SpeedBonus: + case EffectType.StaminaBonus: + case EffectType.PowerBonus: + case EffectType.GutsBonus: + case EffectType.WitBonus: + case EffectType.TrainingEffectiveness: + case EffectType.InitialSpeed: + case EffectType.InitialStamina: + case EffectType.InitialPower: + case EffectType.InitialGuts: + case EffectType.InitialWit: + case EffectType.InitialFriendship: + case EffectType.RaceBonus: + case EffectType.FanBonus: + case EffectType.HintLevels: + case EffectType.HintFrequency: + case EffectType.SpecialtyPriority: + case EffectType.MaxSpeed: + case EffectType.MaxStamina: + case EffectType.MaxPower: + case EffectType.MaxGuts: + case EffectType.MaxWit: + case EffectType.EventRecovery: + case EffectType.EventEffectiveness: + case EffectType.FailureProtection: + case EffectType.EnergyCostReduction: + case EffectType.MinigameEffectiveness: + case EffectType.SkillPointBonus: + case EffectType.WitFriendshipRecovery: + return [{ type, value: args[0] }]; - case EffectType.UniqueFriendshipThreshold: - return [{ type: args[1], value: args[2] }, { type: args[3], value: args[4] }]; - case EffectType.UniqueOffSpecialty: - return [{ type: EffectType.TrainingEffectiveness, value: args[1] }]; - case EffectType.UniqueColorThresholdTrainingEffectiveness: - if (new Set(deck.map((card) => card.specialty)).size < args[0]) { - return []; - } - return [{ type: EffectType.TrainingEffectiveness, value: args[1] }]; - case EffectType.UniqueFanScalingTrainingEffectiveness: - return [{ type: EffectType.TrainingEffectiveness, value: args[1] }] - case EffectType.UniqueColorInitialStats: - return deck.flatMap((card) => { - switch (card.specialty) { - case Specialty.Speed: - return [{ type: EffectType.InitialSpeed, value: args[0] }]; - case Specialty.Power: - return [{ type: EffectType.InitialPower, value: args[0] }]; - case Specialty.Guts: - return [{ type: EffectType.InitialGuts, value: args[0] }]; - case Specialty.Stamina: - return [{ type: EffectType.InitialStamina, value: args[0] }]; - case Specialty.Wit: - return [{ type: EffectType.InitialWit, value: args[0] }]; - default: - return [ - { type: EffectType.InitialSpeed, value: args[1] }, - { type: EffectType.InitialStamina, value: args[1] }, - { type: EffectType.InitialPower, value: args[1] }, - { type: EffectType.InitialGuts, value: args[1] }, - { type: EffectType.InitialWit, value: args[1] }, - ]; - } - }) - case EffectType.UniqueRainbowStack: - return [{ type: args[1], value: args[0] * args[2] }]; - case EffectType.UniqueLowEnergyScaling: - return [{ type: args[0], value: args[3] }]; - case EffectType.UniqueMaxEnergyScaling: - return [{ type: args[0], value: args[4] }]; - case EffectType.UniqueTotalFriendship: - return [{ type: args[0], value: 600 / args[1] }]; - case EffectType.UniqueCardCount: - return [{ type: args[0], value: 5 * args[1] }]; - case EffectType.UniqueFacilityLevel: - return [{ type: args[0], value: 5 * args[1] }]; - case EffectType.UniqueDisableFailure: - return []; - case EffectType.UniqueFriendshipTrainingAdditionalEffect: - return [{ type: args[0], value: args[1] }]; - } + case EffectType.UniqueFriendshipThreshold: + return [ + { type: args[1], value: args[2] }, + { type: args[3], value: args[4] }, + ]; + case EffectType.UniqueOffSpecialty: + return [{ type: EffectType.TrainingEffectiveness, value: args[1] }]; + case EffectType.UniqueColorThresholdTrainingEffectiveness: + if (new Set(deck.map((card) => card.specialty)).size < args[0]) { + return []; + } + return [{ type: EffectType.TrainingEffectiveness, value: args[1] }]; + case EffectType.UniqueFanScalingTrainingEffectiveness: + return [{ type: EffectType.TrainingEffectiveness, value: args[1] }]; + case EffectType.UniqueColorInitialStats: + return deck.flatMap((card) => { + switch (card.specialty) { + case Specialty.Speed: + return [{ type: EffectType.InitialSpeed, value: args[0] }]; + case Specialty.Power: + return [{ type: EffectType.InitialPower, value: args[0] }]; + case Specialty.Guts: + return [{ type: EffectType.InitialGuts, value: args[0] }]; + case Specialty.Stamina: + return [{ type: EffectType.InitialStamina, value: args[0] }]; + case Specialty.Wit: + return [{ type: EffectType.InitialWit, value: args[0] }]; + default: + return [ + { type: EffectType.InitialSpeed, value: args[1] }, + { type: EffectType.InitialStamina, value: args[1] }, + { type: EffectType.InitialPower, value: args[1] }, + { type: EffectType.InitialGuts, value: args[1] }, + { type: EffectType.InitialWit, value: args[1] }, + ]; + } + }); + case EffectType.UniqueRainbowStack: + return [{ type: args[1], value: args[0] * args[2] }]; + case EffectType.UniqueLowEnergyScaling: + return [{ type: args[0], value: args[3] }]; + case EffectType.UniqueMaxEnergyScaling: + return [{ type: args[0], value: args[4] }]; + case EffectType.UniqueTotalFriendship: + return [{ type: args[0], value: 600 / args[1] }]; + case EffectType.UniqueCardCount: + return [{ type: args[0], value: 5 * args[1] }]; + case EffectType.UniqueFacilityLevel: + return [{ type: args[0], value: 5 * args[1] }]; + case EffectType.UniqueDisableFailure: + return []; + case EffectType.UniqueFriendshipTrainingAdditionalEffect: + return [{ type: args[0], value: args[1] }]; + } } export function flattenUnique(unique: UniqueEffect, deck: SupportCard[]): Effect[] { - const r = [...singleUniqueEffects(unique.type, unique.args, deck)]; - if (unique.type2 != null) { - r.push(...singleUniqueEffects(unique.type2, unique.args2!, deck)); - } - return r; + const r = [...singleUniqueEffects(unique.type, unique.args, deck)]; + if (unique.type2 != null) { + r.push(...singleUniqueEffects(unique.type2, unique.args2!, deck)); + } + return r; } diff --git a/zenno/src/lib/data/support_card_level.json b/zenno/src/lib/data/support_card_level.json index d7562ac..41e7962 100644 --- a/zenno/src/lib/data/support_card_level.json +++ b/zenno/src/lib/data/support_card_level.json @@ -1,679 +1,679 @@ { - "levels": [ - { - "rarity": 1, - "exp": 0, - "level": 1 - }, - { - "rarity": 1, - "exp": 5, - "level": 2 - }, - { - "rarity": 1, - "exp": 15, - "level": 3 - }, - { - "rarity": 1, - "exp": 30, - "level": 4 - }, - { - "rarity": 1, - "exp": 50, - "level": 5 - }, - { - "rarity": 1, - "exp": 80, - "level": 6 - }, - { - "rarity": 1, - "exp": 120, - "level": 7 - }, - { - "rarity": 1, - "exp": 170, - "level": 8 - }, - { - "rarity": 1, - "exp": 230, - "level": 9 - }, - { - "rarity": 1, - "exp": 310, - "level": 10 - }, - { - "rarity": 1, - "exp": 410, - "level": 11 - }, - { - "rarity": 1, - "exp": 530, - "level": 12 - }, - { - "rarity": 1, - "exp": 680, - "level": 13 - }, - { - "rarity": 1, - "exp": 860, - "level": 14 - }, - { - "rarity": 1, - "exp": 1080, - "level": 15 - }, - { - "rarity": 1, - "exp": 1340, - "level": 16 - }, - { - "rarity": 1, - "exp": 1650, - "level": 17 - }, - { - "rarity": 1, - "exp": 2010, - "level": 18 - }, - { - "rarity": 1, - "exp": 2430, - "level": 19 - }, - { - "rarity": 1, - "exp": 2910, - "level": 20 - }, - { - "rarity": 1, - "exp": 3460, - "level": 21 - }, - { - "rarity": 1, - "exp": 4090, - "level": 22 - }, - { - "rarity": 1, - "exp": 4810, - "level": 23 - }, - { - "rarity": 1, - "exp": 5630, - "level": 24 - }, - { - "rarity": 1, - "exp": 6560, - "level": 25 - }, - { - "rarity": 1, - "exp": 7610, - "level": 26 - }, - { - "rarity": 1, - "exp": 8790, - "level": 27 - }, - { - "rarity": 1, - "exp": 10110, - "level": 28 - }, - { - "rarity": 1, - "exp": 11580, - "level": 29 - }, - { - "rarity": 1, - "exp": 13210, - "level": 30 - }, - { - "rarity": 1, - "exp": 15010, - "level": 31 - }, - { - "rarity": 1, - "exp": 16990, - "level": 32 - }, - { - "rarity": 1, - "exp": 19160, - "level": 33 - }, - { - "rarity": 1, - "exp": 21530, - "level": 34 - }, - { - "rarity": 1, - "exp": 24110, - "level": 35 - }, - { - "rarity": 1, - "exp": 26910, - "level": 36 - }, - { - "rarity": 1, - "exp": 29940, - "level": 37 - }, - { - "rarity": 1, - "exp": 33210, - "level": 38 - }, - { - "rarity": 1, - "exp": 36730, - "level": 39 - }, - { - "rarity": 1, - "exp": 40510, - "level": 40 - }, - { - "rarity": 2, - "exp": 0, - "level": 1 - }, - { - "rarity": 2, - "exp": 10, - "level": 2 - }, - { - "rarity": 2, - "exp": 30, - "level": 3 - }, - { - "rarity": 2, - "exp": 60, - "level": 4 - }, - { - "rarity": 2, - "exp": 110, - "level": 5 - }, - { - "rarity": 2, - "exp": 180, - "level": 6 - }, - { - "rarity": 2, - "exp": 270, - "level": 7 - }, - { - "rarity": 2, - "exp": 390, - "level": 8 - }, - { - "rarity": 2, - "exp": 540, - "level": 9 - }, - { - "rarity": 2, - "exp": 720, - "level": 10 - }, - { - "rarity": 2, - "exp": 940, - "level": 11 - }, - { - "rarity": 2, - "exp": 1200, - "level": 12 - }, - { - "rarity": 2, - "exp": 1510, - "level": 13 - }, - { - "rarity": 2, - "exp": 1870, - "level": 14 - }, - { - "rarity": 2, - "exp": 2290, - "level": 15 - }, - { - "rarity": 2, - "exp": 2770, - "level": 16 - }, - { - "rarity": 2, - "exp": 3320, - "level": 17 - }, - { - "rarity": 2, - "exp": 3940, - "level": 18 - }, - { - "rarity": 2, - "exp": 4640, - "level": 19 - }, - { - "rarity": 2, - "exp": 5420, - "level": 20 - }, - { - "rarity": 2, - "exp": 6290, - "level": 21 - }, - { - "rarity": 2, - "exp": 7250, - "level": 22 - }, - { - "rarity": 2, - "exp": 8310, - "level": 23 - }, - { - "rarity": 2, - "exp": 9470, - "level": 24 - }, - { - "rarity": 2, - "exp": 10740, - "level": 25 - }, - { - "rarity": 2, - "exp": 12130, - "level": 26 - }, - { - "rarity": 2, - "exp": 13650, - "level": 27 - }, - { - "rarity": 2, - "exp": 15310, - "level": 28 - }, - { - "rarity": 2, - "exp": 17120, - "level": 29 - }, - { - "rarity": 2, - "exp": 19090, - "level": 30 - }, - { - "rarity": 2, - "exp": 21230, - "level": 31 - }, - { - "rarity": 2, - "exp": 23550, - "level": 32 - }, - { - "rarity": 2, - "exp": 26060, - "level": 33 - }, - { - "rarity": 2, - "exp": 28770, - "level": 34 - }, - { - "rarity": 2, - "exp": 31690, - "level": 35 - }, - { - "rarity": 2, - "exp": 34830, - "level": 36 - }, - { - "rarity": 2, - "exp": 38200, - "level": 37 - }, - { - "rarity": 2, - "exp": 41810, - "level": 38 - }, - { - "rarity": 2, - "exp": 45670, - "level": 39 - }, - { - "rarity": 2, - "exp": 49790, - "level": 40 - }, - { - "rarity": 2, - "exp": 54190, - "level": 41 - }, - { - "rarity": 2, - "exp": 58890, - "level": 42 - }, - { - "rarity": 2, - "exp": 63910, - "level": 43 - }, - { - "rarity": 2, - "exp": 69270, - "level": 44 - }, - { - "rarity": 2, - "exp": 74990, - "level": 45 - }, - { - "rarity": 3, - "exp": 0, - "level": 1 - }, - { - "rarity": 3, - "exp": 15, - "level": 2 - }, - { - "rarity": 3, - "exp": 45, - "level": 3 - }, - { - "rarity": 3, - "exp": 95, - "level": 4 - }, - { - "rarity": 3, - "exp": 165, - "level": 5 - }, - { - "rarity": 3, - "exp": 265, - "level": 6 - }, - { - "rarity": 3, - "exp": 395, - "level": 7 - }, - { - "rarity": 3, - "exp": 565, - "level": 8 - }, - { - "rarity": 3, - "exp": 775, - "level": 9 - }, - { - "rarity": 3, - "exp": 1035, - "level": 10 - }, - { - "rarity": 3, - "exp": 1345, - "level": 11 - }, - { - "rarity": 3, - "exp": 1715, - "level": 12 - }, - { - "rarity": 3, - "exp": 2145, - "level": 13 - }, - { - "rarity": 3, - "exp": 2645, - "level": 14 - }, - { - "rarity": 3, - "exp": 3215, - "level": 15 - }, - { - "rarity": 3, - "exp": 3865, - "level": 16 - }, - { - "rarity": 3, - "exp": 4595, - "level": 17 - }, - { - "rarity": 3, - "exp": 5415, - "level": 18 - }, - { - "rarity": 3, - "exp": 6325, - "level": 19 - }, - { - "rarity": 3, - "exp": 7335, - "level": 20 - }, - { - "rarity": 3, - "exp": 8445, - "level": 21 - }, - { - "rarity": 3, - "exp": 9665, - "level": 22 - }, - { - "rarity": 3, - "exp": 10995, - "level": 23 - }, - { - "rarity": 3, - "exp": 12445, - "level": 24 - }, - { - "rarity": 3, - "exp": 14015, - "level": 25 - }, - { - "rarity": 3, - "exp": 15715, - "level": 26 - }, - { - "rarity": 3, - "exp": 17545, - "level": 27 - }, - { - "rarity": 3, - "exp": 19515, - "level": 28 - }, - { - "rarity": 3, - "exp": 21625, - "level": 29 - }, - { - "rarity": 3, - "exp": 23885, - "level": 30 - }, - { - "rarity": 3, - "exp": 26305, - "level": 31 - }, - { - "rarity": 3, - "exp": 28895, - "level": 32 - }, - { - "rarity": 3, - "exp": 31665, - "level": 33 - }, - { - "rarity": 3, - "exp": 34625, - "level": 34 - }, - { - "rarity": 3, - "exp": 37785, - "level": 35 - }, - { - "rarity": 3, - "exp": 41155, - "level": 36 - }, - { - "rarity": 3, - "exp": 44745, - "level": 37 - }, - { - "rarity": 3, - "exp": 48565, - "level": 38 - }, - { - "rarity": 3, - "exp": 52625, - "level": 39 - }, - { - "rarity": 3, - "exp": 56935, - "level": 40 - }, - { - "rarity": 3, - "exp": 61515, - "level": 41 - }, - { - "rarity": 3, - "exp": 66385, - "level": 42 - }, - { - "rarity": 3, - "exp": 71565, - "level": 43 - }, - { - "rarity": 3, - "exp": 77075, - "level": 44 - }, - { - "rarity": 3, - "exp": 82935, - "level": 45 - }, - { - "rarity": 3, - "exp": 89165, - "level": 46 - }, - { - "rarity": 3, - "exp": 95785, - "level": 47 - }, - { - "rarity": 3, - "exp": 102815, - "level": 48 - }, - { - "rarity": 3, - "exp": 110275, - "level": 49 - }, - { - "rarity": 3, - "exp": 118185, - "level": 50 - } - ] -} \ No newline at end of file + "levels": [ + { + "rarity": 1, + "exp": 0, + "level": 1 + }, + { + "rarity": 1, + "exp": 5, + "level": 2 + }, + { + "rarity": 1, + "exp": 15, + "level": 3 + }, + { + "rarity": 1, + "exp": 30, + "level": 4 + }, + { + "rarity": 1, + "exp": 50, + "level": 5 + }, + { + "rarity": 1, + "exp": 80, + "level": 6 + }, + { + "rarity": 1, + "exp": 120, + "level": 7 + }, + { + "rarity": 1, + "exp": 170, + "level": 8 + }, + { + "rarity": 1, + "exp": 230, + "level": 9 + }, + { + "rarity": 1, + "exp": 310, + "level": 10 + }, + { + "rarity": 1, + "exp": 410, + "level": 11 + }, + { + "rarity": 1, + "exp": 530, + "level": 12 + }, + { + "rarity": 1, + "exp": 680, + "level": 13 + }, + { + "rarity": 1, + "exp": 860, + "level": 14 + }, + { + "rarity": 1, + "exp": 1080, + "level": 15 + }, + { + "rarity": 1, + "exp": 1340, + "level": 16 + }, + { + "rarity": 1, + "exp": 1650, + "level": 17 + }, + { + "rarity": 1, + "exp": 2010, + "level": 18 + }, + { + "rarity": 1, + "exp": 2430, + "level": 19 + }, + { + "rarity": 1, + "exp": 2910, + "level": 20 + }, + { + "rarity": 1, + "exp": 3460, + "level": 21 + }, + { + "rarity": 1, + "exp": 4090, + "level": 22 + }, + { + "rarity": 1, + "exp": 4810, + "level": 23 + }, + { + "rarity": 1, + "exp": 5630, + "level": 24 + }, + { + "rarity": 1, + "exp": 6560, + "level": 25 + }, + { + "rarity": 1, + "exp": 7610, + "level": 26 + }, + { + "rarity": 1, + "exp": 8790, + "level": 27 + }, + { + "rarity": 1, + "exp": 10110, + "level": 28 + }, + { + "rarity": 1, + "exp": 11580, + "level": 29 + }, + { + "rarity": 1, + "exp": 13210, + "level": 30 + }, + { + "rarity": 1, + "exp": 15010, + "level": 31 + }, + { + "rarity": 1, + "exp": 16990, + "level": 32 + }, + { + "rarity": 1, + "exp": 19160, + "level": 33 + }, + { + "rarity": 1, + "exp": 21530, + "level": 34 + }, + { + "rarity": 1, + "exp": 24110, + "level": 35 + }, + { + "rarity": 1, + "exp": 26910, + "level": 36 + }, + { + "rarity": 1, + "exp": 29940, + "level": 37 + }, + { + "rarity": 1, + "exp": 33210, + "level": 38 + }, + { + "rarity": 1, + "exp": 36730, + "level": 39 + }, + { + "rarity": 1, + "exp": 40510, + "level": 40 + }, + { + "rarity": 2, + "exp": 0, + "level": 1 + }, + { + "rarity": 2, + "exp": 10, + "level": 2 + }, + { + "rarity": 2, + "exp": 30, + "level": 3 + }, + { + "rarity": 2, + "exp": 60, + "level": 4 + }, + { + "rarity": 2, + "exp": 110, + "level": 5 + }, + { + "rarity": 2, + "exp": 180, + "level": 6 + }, + { + "rarity": 2, + "exp": 270, + "level": 7 + }, + { + "rarity": 2, + "exp": 390, + "level": 8 + }, + { + "rarity": 2, + "exp": 540, + "level": 9 + }, + { + "rarity": 2, + "exp": 720, + "level": 10 + }, + { + "rarity": 2, + "exp": 940, + "level": 11 + }, + { + "rarity": 2, + "exp": 1200, + "level": 12 + }, + { + "rarity": 2, + "exp": 1510, + "level": 13 + }, + { + "rarity": 2, + "exp": 1870, + "level": 14 + }, + { + "rarity": 2, + "exp": 2290, + "level": 15 + }, + { + "rarity": 2, + "exp": 2770, + "level": 16 + }, + { + "rarity": 2, + "exp": 3320, + "level": 17 + }, + { + "rarity": 2, + "exp": 3940, + "level": 18 + }, + { + "rarity": 2, + "exp": 4640, + "level": 19 + }, + { + "rarity": 2, + "exp": 5420, + "level": 20 + }, + { + "rarity": 2, + "exp": 6290, + "level": 21 + }, + { + "rarity": 2, + "exp": 7250, + "level": 22 + }, + { + "rarity": 2, + "exp": 8310, + "level": 23 + }, + { + "rarity": 2, + "exp": 9470, + "level": 24 + }, + { + "rarity": 2, + "exp": 10740, + "level": 25 + }, + { + "rarity": 2, + "exp": 12130, + "level": 26 + }, + { + "rarity": 2, + "exp": 13650, + "level": 27 + }, + { + "rarity": 2, + "exp": 15310, + "level": 28 + }, + { + "rarity": 2, + "exp": 17120, + "level": 29 + }, + { + "rarity": 2, + "exp": 19090, + "level": 30 + }, + { + "rarity": 2, + "exp": 21230, + "level": 31 + }, + { + "rarity": 2, + "exp": 23550, + "level": 32 + }, + { + "rarity": 2, + "exp": 26060, + "level": 33 + }, + { + "rarity": 2, + "exp": 28770, + "level": 34 + }, + { + "rarity": 2, + "exp": 31690, + "level": 35 + }, + { + "rarity": 2, + "exp": 34830, + "level": 36 + }, + { + "rarity": 2, + "exp": 38200, + "level": 37 + }, + { + "rarity": 2, + "exp": 41810, + "level": 38 + }, + { + "rarity": 2, + "exp": 45670, + "level": 39 + }, + { + "rarity": 2, + "exp": 49790, + "level": 40 + }, + { + "rarity": 2, + "exp": 54190, + "level": 41 + }, + { + "rarity": 2, + "exp": 58890, + "level": 42 + }, + { + "rarity": 2, + "exp": 63910, + "level": 43 + }, + { + "rarity": 2, + "exp": 69270, + "level": 44 + }, + { + "rarity": 2, + "exp": 74990, + "level": 45 + }, + { + "rarity": 3, + "exp": 0, + "level": 1 + }, + { + "rarity": 3, + "exp": 15, + "level": 2 + }, + { + "rarity": 3, + "exp": 45, + "level": 3 + }, + { + "rarity": 3, + "exp": 95, + "level": 4 + }, + { + "rarity": 3, + "exp": 165, + "level": 5 + }, + { + "rarity": 3, + "exp": 265, + "level": 6 + }, + { + "rarity": 3, + "exp": 395, + "level": 7 + }, + { + "rarity": 3, + "exp": 565, + "level": 8 + }, + { + "rarity": 3, + "exp": 775, + "level": 9 + }, + { + "rarity": 3, + "exp": 1035, + "level": 10 + }, + { + "rarity": 3, + "exp": 1345, + "level": 11 + }, + { + "rarity": 3, + "exp": 1715, + "level": 12 + }, + { + "rarity": 3, + "exp": 2145, + "level": 13 + }, + { + "rarity": 3, + "exp": 2645, + "level": 14 + }, + { + "rarity": 3, + "exp": 3215, + "level": 15 + }, + { + "rarity": 3, + "exp": 3865, + "level": 16 + }, + { + "rarity": 3, + "exp": 4595, + "level": 17 + }, + { + "rarity": 3, + "exp": 5415, + "level": 18 + }, + { + "rarity": 3, + "exp": 6325, + "level": 19 + }, + { + "rarity": 3, + "exp": 7335, + "level": 20 + }, + { + "rarity": 3, + "exp": 8445, + "level": 21 + }, + { + "rarity": 3, + "exp": 9665, + "level": 22 + }, + { + "rarity": 3, + "exp": 10995, + "level": 23 + }, + { + "rarity": 3, + "exp": 12445, + "level": 24 + }, + { + "rarity": 3, + "exp": 14015, + "level": 25 + }, + { + "rarity": 3, + "exp": 15715, + "level": 26 + }, + { + "rarity": 3, + "exp": 17545, + "level": 27 + }, + { + "rarity": 3, + "exp": 19515, + "level": 28 + }, + { + "rarity": 3, + "exp": 21625, + "level": 29 + }, + { + "rarity": 3, + "exp": 23885, + "level": 30 + }, + { + "rarity": 3, + "exp": 26305, + "level": 31 + }, + { + "rarity": 3, + "exp": 28895, + "level": 32 + }, + { + "rarity": 3, + "exp": 31665, + "level": 33 + }, + { + "rarity": 3, + "exp": 34625, + "level": 34 + }, + { + "rarity": 3, + "exp": 37785, + "level": 35 + }, + { + "rarity": 3, + "exp": 41155, + "level": 36 + }, + { + "rarity": 3, + "exp": 44745, + "level": 37 + }, + { + "rarity": 3, + "exp": 48565, + "level": 38 + }, + { + "rarity": 3, + "exp": 52625, + "level": 39 + }, + { + "rarity": 3, + "exp": 56935, + "level": 40 + }, + { + "rarity": 3, + "exp": 61515, + "level": 41 + }, + { + "rarity": 3, + "exp": 66385, + "level": 42 + }, + { + "rarity": 3, + "exp": 71565, + "level": 43 + }, + { + "rarity": 3, + "exp": 77075, + "level": 44 + }, + { + "rarity": 3, + "exp": 82935, + "level": 45 + }, + { + "rarity": 3, + "exp": 89165, + "level": 46 + }, + { + "rarity": 3, + "exp": 95785, + "level": 47 + }, + { + "rarity": 3, + "exp": 102815, + "level": 48 + }, + { + "rarity": 3, + "exp": 110275, + "level": 49 + }, + { + "rarity": 3, + "exp": 118185, + "level": 50 + } + ] +} diff --git a/zenno/src/lib/data/testdata/support-10018-bakushin-R.json b/zenno/src/lib/data/testdata/support-10018-bakushin-R.json index e0add49..eb4251a 100644 --- a/zenno/src/lib/data/testdata/support-10018-bakushin-R.json +++ b/zenno/src/lib/data/testdata/support-10018-bakushin-R.json @@ -1,415 +1,415 @@ { - "id": 10018, - "name": "[Tracen Academy] Sakura Bakushin O", - "chara_id": 1041, - "chara_name": "Sakura Bakushin O", - "rarity": 1, - "specialty": 101, - "type": 1, - "effects": [ - [ - { - "type": 1, - "value": 5 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 3, - "value": -1 - }, - { - "type": 9, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": 1 - }, - { - "type": 16, - "value": 1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": 10 - }, - { - "type": 3, - "value": -1 - }, - { - "type": 9, - "value": 10 - }, - { - "type": 14, - "value": 10 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": 5 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 3, - "value": -1 - }, - { - "type": 9, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": 10 - }, - { - "type": 2, - "value": 15 - }, - { - "type": 3, - "value": -1 - }, - { - "type": 9, - "value": 15 - }, - { - "type": 14, - "value": 15 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": 20 - } - ], - [ - { - "type": 1, - "value": 10 - }, - { - "type": 2, - "value": 15 - }, - { - "type": 3, - "value": -1 - }, - { - "type": 9, - "value": 15 - }, - { - "type": 14, - "value": 15 - }, - { - "type": 15, - "value": 5 - }, - { - "type": 16, - "value": 10 - }, - { - "type": 19, - "value": 20 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 3, - "value": -1 - }, - { - "type": 9, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 3, - "value": -1 - }, - { - "type": 9, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": 15 - }, - { - "type": 2, - "value": 25 - }, - { - "type": 3, - "value": -1 - }, - { - "type": 9, - "value": 20 - }, - { - "type": 14, - "value": 20 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": 35 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 3, - "value": 1 - }, - { - "type": 9, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": 5 - }, - { - "type": 16, - "value": 15 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 3, - "value": -1 - }, - { - "type": 9, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 3, - "value": -1 - }, - { - "type": 9, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ] - ], - "hints": [ - { - "skill_id": 200652 - }, - { - "skill_id": 200791 - }, - { - "skill_id": 200841 - }, - { - "skill_id": 200962 - }, - { - "skill_id": 200972 - }, - { - "skill_id": 200982 - }, - { - "skill_id": 200992 - }, - { - "skill_id": 201012 - }, - { - "speed": 6, - "power": 2 - } - ] + "id": 10018, + "name": "[Tracen Academy] Sakura Bakushin O", + "chara_id": 1041, + "chara_name": "Sakura Bakushin O", + "rarity": 1, + "specialty": 101, + "type": 1, + "effects": [ + [ + { + "type": 1, + "value": 5 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 3, + "value": -1 + }, + { + "type": 9, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": 1 + }, + { + "type": 16, + "value": 1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": 10 + }, + { + "type": 3, + "value": -1 + }, + { + "type": 9, + "value": 10 + }, + { + "type": 14, + "value": 10 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": 5 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 3, + "value": -1 + }, + { + "type": 9, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": 10 + }, + { + "type": 2, + "value": 15 + }, + { + "type": 3, + "value": -1 + }, + { + "type": 9, + "value": 15 + }, + { + "type": 14, + "value": 15 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": 20 + } + ], + [ + { + "type": 1, + "value": 10 + }, + { + "type": 2, + "value": 15 + }, + { + "type": 3, + "value": -1 + }, + { + "type": 9, + "value": 15 + }, + { + "type": 14, + "value": 15 + }, + { + "type": 15, + "value": 5 + }, + { + "type": 16, + "value": 10 + }, + { + "type": 19, + "value": 20 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 3, + "value": -1 + }, + { + "type": 9, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 3, + "value": -1 + }, + { + "type": 9, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": 15 + }, + { + "type": 2, + "value": 25 + }, + { + "type": 3, + "value": -1 + }, + { + "type": 9, + "value": 20 + }, + { + "type": 14, + "value": 20 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": 35 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 3, + "value": 1 + }, + { + "type": 9, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": 5 + }, + { + "type": 16, + "value": 15 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 3, + "value": -1 + }, + { + "type": 9, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 3, + "value": -1 + }, + { + "type": 9, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ] + ], + "hints": [ + { + "skill_id": 200652 + }, + { + "skill_id": 200791 + }, + { + "skill_id": 200841 + }, + { + "skill_id": 200962 + }, + { + "skill_id": 200972 + }, + { + "skill_id": 200982 + }, + { + "skill_id": 200992 + }, + { + "skill_id": 201012 + }, + { + "speed": 6, + "power": 2 + } + ] } diff --git a/zenno/src/lib/data/testdata/support-20042-bakushin-SR.json b/zenno/src/lib/data/testdata/support-20042-bakushin-SR.json index 8c0f064..58d10d4 100644 --- a/zenno/src/lib/data/testdata/support-20042-bakushin-SR.json +++ b/zenno/src/lib/data/testdata/support-20042-bakushin-SR.json @@ -1,429 +1,425 @@ { - "id": 20042, - "name": "[The Perfect Morning Greeting!] Sakura Bakushin O", - "chara_id": 1041, - "chara_name": "Sakura Bakushin O", - "rarity": 2, - "specialty": 102, - "type": 1, - "effects": [ - [ - { - "type": 1, - "value": 10 - }, - { - "type": 5, - "value": -1 - }, - { - "type": 8, - "value": -1 - }, - { - "type": 11, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": 1 - }, - { - "type": 16, - "value": 1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 5, - "value": -1 - }, - { - "type": 8, - "value": -1 - }, - { - "type": 11, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": 5 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 5, - "value": -1 - }, - { - "type": 8, - "value": 1 - }, - { - "type": 11, - "value": 10 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 5, - "value": -1 - }, - { - "type": 8, - "value": -1 - }, - { - "type": 11, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": 15 - }, - { - "type": 5, - "value": -1 - }, - { - "type": 8, - "value": 5 - }, - { - "type": 11, - "value": 15 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": 15 - }, - { - "type": 5, - "value": -1 - }, - { - "type": 8, - "value": 5 - }, - { - "type": 11, - "value": 15 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": 5 - }, - { - "type": 16, - "value": 15 - }, - { - "type": 19, - "value": 35 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 5, - "value": -1 - }, - { - "type": 8, - "value": -1 - }, - { - "type": 11, - "value": -1 - }, - { - "type": 14, - "value": 10 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 5, - "value": -1 - }, - { - "type": 8, - "value": -1 - }, - { - "type": 11, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": 20 - }, - { - "type": 5, - "value": -1 - }, - { - "type": 8, - "value": 5 - }, - { - "type": 11, - "value": 20 - }, - { - "type": 14, - "value": 20 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 5, - "value": 1 - }, - { - "type": 8, - "value": -1 - }, - { - "type": 11, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": 10 - }, - { - "type": 16, - "value": 20 - }, - { - "type": 19, - "value": 50 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 5, - "value": -1 - }, - { - "type": 8, - "value": -1 - }, - { - "type": 11, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 19, - "value": -1 - } - ] - ], - "unique_effect": { - "name": "The Perfect Morning Greeting!", - "description": "Friendship Bonus and Specialty Priority", - "card_level": 25, - "type": 1, - "args": [ - 10 - ], - "type2": 19, - "args2": [ - 20 - ], - "idle_mode_sub_rate": 0 - }, - "hints": [ - { - "skill_id": 200652 - }, - { - "skill_id": 200791 - }, - { - "skill_id": 200841 - }, - { - "skill_id": 200962 - }, - { - "skill_id": 200972 - }, - { - "skill_id": 200982 - }, - { - "skill_id": 200992 - }, - { - "skill_id": 201012 - }, - { - "stamina": 2, - "power": 6 - } - ] + "id": 20042, + "name": "[The Perfect Morning Greeting!] Sakura Bakushin O", + "chara_id": 1041, + "chara_name": "Sakura Bakushin O", + "rarity": 2, + "specialty": 102, + "type": 1, + "effects": [ + [ + { + "type": 1, + "value": 10 + }, + { + "type": 5, + "value": -1 + }, + { + "type": 8, + "value": -1 + }, + { + "type": 11, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": 1 + }, + { + "type": 16, + "value": 1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 5, + "value": -1 + }, + { + "type": 8, + "value": -1 + }, + { + "type": 11, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": 5 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 5, + "value": -1 + }, + { + "type": 8, + "value": 1 + }, + { + "type": 11, + "value": 10 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 5, + "value": -1 + }, + { + "type": 8, + "value": -1 + }, + { + "type": 11, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": 15 + }, + { + "type": 5, + "value": -1 + }, + { + "type": 8, + "value": 5 + }, + { + "type": 11, + "value": 15 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": 15 + }, + { + "type": 5, + "value": -1 + }, + { + "type": 8, + "value": 5 + }, + { + "type": 11, + "value": 15 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": 5 + }, + { + "type": 16, + "value": 15 + }, + { + "type": 19, + "value": 35 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 5, + "value": -1 + }, + { + "type": 8, + "value": -1 + }, + { + "type": 11, + "value": -1 + }, + { + "type": 14, + "value": 10 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 5, + "value": -1 + }, + { + "type": 8, + "value": -1 + }, + { + "type": 11, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": 20 + }, + { + "type": 5, + "value": -1 + }, + { + "type": 8, + "value": 5 + }, + { + "type": 11, + "value": 20 + }, + { + "type": 14, + "value": 20 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 5, + "value": 1 + }, + { + "type": 8, + "value": -1 + }, + { + "type": 11, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": 10 + }, + { + "type": 16, + "value": 20 + }, + { + "type": 19, + "value": 50 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 5, + "value": -1 + }, + { + "type": 8, + "value": -1 + }, + { + "type": 11, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 19, + "value": -1 + } + ] + ], + "unique_effect": { + "name": "The Perfect Morning Greeting!", + "description": "Friendship Bonus and Specialty Priority", + "card_level": 25, + "type": 1, + "args": [10], + "type2": 19, + "args2": [20], + "idle_mode_sub_rate": 0 + }, + "hints": [ + { + "skill_id": 200652 + }, + { + "skill_id": 200791 + }, + { + "skill_id": 200841 + }, + { + "skill_id": 200962 + }, + { + "skill_id": 200972 + }, + { + "skill_id": 200982 + }, + { + "skill_id": 200992 + }, + { + "skill_id": 201012 + }, + { + "stamina": 2, + "power": 6 + } + ] } diff --git a/zenno/src/lib/data/testdata/support-30083-bakushin-SSR.json b/zenno/src/lib/data/testdata/support-30083-bakushin-SSR.json index c7963b3..3ecc9b3 100644 --- a/zenno/src/lib/data/testdata/support-30083-bakushin-SSR.json +++ b/zenno/src/lib/data/testdata/support-30083-bakushin-SSR.json @@ -1,471 +1,468 @@ { - "id": 30083, - "name": "[Super! Sonic! Flower Power!] Sakura Bakushin O", - "chara_id": 1041, - "chara_name": "Sakura Bakushin O", - "rarity": 3, - "specialty": 103, - "type": 1, - "effects": [ - [ - { - "type": 1, - "value": 10 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 6, - "value": -1 - }, - { - "type": 12, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": 1 - }, - { - "type": 16, - "value": 1 - }, - { - "type": 17, - "value": 1 - }, - { - "type": 18, - "value": 5 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 6, - "value": -1 - }, - { - "type": 12, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 17, - "value": -1 - }, - { - "type": 18, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 6, - "value": -1 - }, - { - "type": 12, - "value": -1 - }, - { - "type": 14, - "value": 10 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 17, - "value": -1 - }, - { - "type": 18, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": 10 - }, - { - "type": 6, - "value": -1 - }, - { - "type": 12, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 17, - "value": -1 - }, - { - "type": 18, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 6, - "value": -1 - }, - { - "type": 12, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 17, - "value": -1 - }, - { - "type": 18, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": 20 - }, - { - "type": 6, - "value": -1 - }, - { - "type": 12, - "value": -1 - }, - { - "type": 14, - "value": 20 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 17, - "value": -1 - }, - { - "type": 18, - "value": -1 - } - ], - [ - { - "type": 1, - "value": 25 - }, - { - "type": 2, - "value": 20 - }, - { - "type": 6, - "value": -1 - }, - { - "type": 12, - "value": -1 - }, - { - "type": 14, - "value": 20 - }, - { - "type": 15, - "value": 5 - }, - { - "type": 16, - "value": 15 - }, - { - "type": 17, - "value": 2 - }, - { - "type": 18, - "value": 40 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 6, - "value": 1 - }, - { - "type": 12, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 17, - "value": -1 - }, - { - "type": 18, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 6, - "value": -1 - }, - { - "type": 12, - "value": -1 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 17, - "value": -1 - }, - { - "type": 18, - "value": -1 - } - ], - [ - { - "type": 1, - "value": -1 - }, - { - "type": 2, - "value": 30 - }, - { - "type": 6, - "value": -1 - }, - { - "type": 12, - "value": 15 - }, - { - "type": 14, - "value": 25 - }, - { - "type": 15, - "value": -1 - }, - { - "type": 16, - "value": -1 - }, - { - "type": 17, - "value": -1 - }, - { - "type": 18, - "value": -1 - } - ], - [ - { - "type": 1, - "value": 35 - }, - { - "type": 2, - "value": -1 - }, - { - "type": 6, - "value": -1 - }, - { - "type": 12, - "value": 30 - }, - { - "type": 14, - "value": -1 - }, - { - "type": 15, - "value": 10 - }, - { - "type": 16, - "value": 20 - }, - { - "type": 17, - "value": 3 - }, - { - "type": 18, - "value": 50 - } - ] - ], - "unique_effect": { - "name": "Super! Sonic! Flower Power!", - "description": "Increases Training Effectiveness when not on preferred training. (Friendship 80+)", - "card_level": 30, - "type": 102, - "args": [ - 80, - 20 - ], - "idle_mode_sub_rate": 30 - }, - "hints": [ - { - "skill_id": 200652 - }, - { - "skill_id": 200791 - }, - { - "skill_id": 200841 - }, - { - "skill_id": 200962 - }, - { - "skill_id": 200972 - }, - { - "skill_id": 200982 - }, - { - "skill_id": 200992 - }, - { - "skill_id": 201012 - }, - { - "speed": 1, - "power": 1, - "guts": 6 - } - ] + "id": 30083, + "name": "[Super! Sonic! Flower Power!] Sakura Bakushin O", + "chara_id": 1041, + "chara_name": "Sakura Bakushin O", + "rarity": 3, + "specialty": 103, + "type": 1, + "effects": [ + [ + { + "type": 1, + "value": 10 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 6, + "value": -1 + }, + { + "type": 12, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": 1 + }, + { + "type": 16, + "value": 1 + }, + { + "type": 17, + "value": 1 + }, + { + "type": 18, + "value": 5 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 6, + "value": -1 + }, + { + "type": 12, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 17, + "value": -1 + }, + { + "type": 18, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 6, + "value": -1 + }, + { + "type": 12, + "value": -1 + }, + { + "type": 14, + "value": 10 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 17, + "value": -1 + }, + { + "type": 18, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": 10 + }, + { + "type": 6, + "value": -1 + }, + { + "type": 12, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 17, + "value": -1 + }, + { + "type": 18, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 6, + "value": -1 + }, + { + "type": 12, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 17, + "value": -1 + }, + { + "type": 18, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": 20 + }, + { + "type": 6, + "value": -1 + }, + { + "type": 12, + "value": -1 + }, + { + "type": 14, + "value": 20 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 17, + "value": -1 + }, + { + "type": 18, + "value": -1 + } + ], + [ + { + "type": 1, + "value": 25 + }, + { + "type": 2, + "value": 20 + }, + { + "type": 6, + "value": -1 + }, + { + "type": 12, + "value": -1 + }, + { + "type": 14, + "value": 20 + }, + { + "type": 15, + "value": 5 + }, + { + "type": 16, + "value": 15 + }, + { + "type": 17, + "value": 2 + }, + { + "type": 18, + "value": 40 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 6, + "value": 1 + }, + { + "type": 12, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 17, + "value": -1 + }, + { + "type": 18, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 6, + "value": -1 + }, + { + "type": 12, + "value": -1 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 17, + "value": -1 + }, + { + "type": 18, + "value": -1 + } + ], + [ + { + "type": 1, + "value": -1 + }, + { + "type": 2, + "value": 30 + }, + { + "type": 6, + "value": -1 + }, + { + "type": 12, + "value": 15 + }, + { + "type": 14, + "value": 25 + }, + { + "type": 15, + "value": -1 + }, + { + "type": 16, + "value": -1 + }, + { + "type": 17, + "value": -1 + }, + { + "type": 18, + "value": -1 + } + ], + [ + { + "type": 1, + "value": 35 + }, + { + "type": 2, + "value": -1 + }, + { + "type": 6, + "value": -1 + }, + { + "type": 12, + "value": 30 + }, + { + "type": 14, + "value": -1 + }, + { + "type": 15, + "value": 10 + }, + { + "type": 16, + "value": 20 + }, + { + "type": 17, + "value": 3 + }, + { + "type": 18, + "value": 50 + } + ] + ], + "unique_effect": { + "name": "Super! Sonic! Flower Power!", + "description": "Increases Training Effectiveness when not on preferred training. (Friendship 80+)", + "card_level": 30, + "type": 102, + "args": [80, 20], + "idle_mode_sub_rate": 30 + }, + "hints": [ + { + "skill_id": 200652 + }, + { + "skill_id": 200791 + }, + { + "skill_id": 200841 + }, + { + "skill_id": 200962 + }, + { + "skill_id": 200972 + }, + { + "skill_id": 200982 + }, + { + "skill_id": 200992 + }, + { + "skill_id": 201012 + }, + { + "speed": 1, + "power": 1, + "guts": 6 + } + ] } diff --git a/zenno/src/lib/ism.ts b/zenno/src/lib/ism.ts index 3cf7670..9f9867b 100644 --- a/zenno/src/lib/ism.ts +++ b/zenno/src/lib/ism.ts @@ -2,71 +2,71 @@ import * as z from 'zod'; import * as race from './race'; const Skill = z.strictObject({ - skill_id: z.int32(), - level: z.int32(), + skill_id: z.int32(), + level: z.int32(), }); export type Skill = z.infer; const SkillTip = z.strictObject({ - group_id: z.int32(), - rarity: z.int32(), - level: z.int32(), + group_id: z.int32(), + rarity: z.int32(), + level: z.int32(), }); export type SkillTip = z.infer; /** SingleModeSupportCard */ const SupportCard = z.strictObject({ - position: z.int32(), - support_card_id: z.int32(), - limit_break_count: z.int32(), - exp: z.int32(), - owner_viewer_id: z.number(), + position: z.int32(), + support_card_id: z.int32(), + limit_break_count: z.int32(), + exp: z.int32(), + owner_viewer_id: z.number(), }); export type SupportCard = z.infer; const GroupOuting = z.strictObject({ - chara_id: z.int32(), - is_outing: z.int32(), - story_step: z.int32(), + chara_id: z.int32(), + is_outing: z.int32(), + story_step: z.int32(), }); export type GroupOuting = z.infer; const Evaluation = z.strictObject({ - target_id: z.int32(), - training_partner_id: z.int32(), - evaluation: z.int32(), - is_outing: z.int32(), - story_step: z.int32(), - is_appear: z.int32(), - group_outing_info_array: z.array(GroupOuting), + target_id: z.int32(), + training_partner_id: z.int32(), + evaluation: z.int32(), + is_outing: z.int32(), + story_step: z.int32(), + is_appear: z.int32(), + group_outing_info_array: z.array(GroupOuting), }); export type Evaluation = z.infer; const TrainingLevel = z.strictObject({ - command_id: z.int32(), - level: z.int32(), + command_id: z.int32(), + level: z.int32(), }); export type TrainingLevel = z.infer; const GuestOuting = z.strictObject({ - support_card_id: z.int32(), - story_step: z.int32(), - group_outing_info_array: z.array(GroupOuting), + support_card_id: z.int32(), + story_step: z.int32(), + group_outing_info_array: z.array(GroupOuting), }); export type GuestOuting = z.infer; /** SingleModeSkillUpgrade */ const SkillUpgrade = z.strictObject({ - condition_id: z.int32(), - total_count: z.int32(), - current_count: z.int32(), + condition_id: z.int32(), + total_count: z.int32(), + current_count: z.int32(), }); export type SkillUpgrade = z.infer; @@ -74,290 +74,290 @@ export type SkillUpgrade = z.infer; const AptitudeLevel = z.enum(race.AptitudeLevel); const SingleModeChara = z.strictObject({ - single_mode_chara_id: z.int32(), - card_id: z.int32(), - chara_grade: z.int32(), - speed: z.int32(), - stamina: z.int32(), - power: z.int32(), - wiz: z.int32(), - guts: z.int32(), - vital: z.int32(), - max_speed: z.int32(), - max_stamina: z.int32(), - max_power: z.int32(), - max_wiz: z.int32(), - max_guts: z.int32(), - default_max_speed: z.int32(), - default_max_stamina: z.int32(), - default_max_power: z.int32(), - default_max_wiz: z.int32(), - default_max_guts: z.int32(), - max_vital: z.int32(), - motivation: z.int32(), - fans: z.int32(), - rarity: z.int32(), - race_program_id: z.int32(), - reserve_race_program_id: z.int32(), - race_running_style: z.int32(), - is_short_race: z.int32(), - talent_level: z.int32(), - skill_array: z.array(Skill), - disable_skill_id_array: z.array(z.int32()), - skill_tips_array: z.array(SkillTip), - support_card_array: z.array(SupportCard), - succession_trained_chara_id_1: z.int32(), - succession_trained_chara_id_2: z.int32(), - proper_distance_short: AptitudeLevel, - proper_distance_mile: AptitudeLevel, - proper_distance_middle: AptitudeLevel, - proper_distance_long: AptitudeLevel, - proper_running_style_nige: AptitudeLevel, - proper_running_style_senko: AptitudeLevel, - proper_running_style_sashi: AptitudeLevel, - proper_running_style_oikomi: AptitudeLevel, - proper_ground_turf: AptitudeLevel, - proper_ground_dirt: AptitudeLevel, - turn: z.int32(), - skill_point: z.int32(), - short_cut_state: z.int32(), - state: z.int32(), - playing_state: z.int32(), - scenario_id: z.int32(), - route_id: z.int32(), - start_time: z.string(), - evaluation_info_array: z.array(Evaluation), - training_level_info_array: z.array(TrainingLevel), - nickname_id_array: z.array(z.int32()), - chara_effect_id_array: z.array(z.int32()), - route_race_id_array: z.array(z.int32()), - guest_outing_info_array: z.array(GuestOuting), - skill_upgrade_info_array: z.array(SkillUpgrade), + single_mode_chara_id: z.int32(), + card_id: z.int32(), + chara_grade: z.int32(), + speed: z.int32(), + stamina: z.int32(), + power: z.int32(), + wiz: z.int32(), + guts: z.int32(), + vital: z.int32(), + max_speed: z.int32(), + max_stamina: z.int32(), + max_power: z.int32(), + max_wiz: z.int32(), + max_guts: z.int32(), + default_max_speed: z.int32(), + default_max_stamina: z.int32(), + default_max_power: z.int32(), + default_max_wiz: z.int32(), + default_max_guts: z.int32(), + max_vital: z.int32(), + motivation: z.int32(), + fans: z.int32(), + rarity: z.int32(), + race_program_id: z.int32(), + reserve_race_program_id: z.int32(), + race_running_style: z.int32(), + is_short_race: z.int32(), + talent_level: z.int32(), + skill_array: z.array(Skill), + disable_skill_id_array: z.array(z.int32()), + skill_tips_array: z.array(SkillTip), + support_card_array: z.array(SupportCard), + succession_trained_chara_id_1: z.int32(), + succession_trained_chara_id_2: z.int32(), + proper_distance_short: AptitudeLevel, + proper_distance_mile: AptitudeLevel, + proper_distance_middle: AptitudeLevel, + proper_distance_long: AptitudeLevel, + proper_running_style_nige: AptitudeLevel, + proper_running_style_senko: AptitudeLevel, + proper_running_style_sashi: AptitudeLevel, + proper_running_style_oikomi: AptitudeLevel, + proper_ground_turf: AptitudeLevel, + proper_ground_dirt: AptitudeLevel, + turn: z.int32(), + skill_point: z.int32(), + short_cut_state: z.int32(), + state: z.int32(), + playing_state: z.int32(), + scenario_id: z.int32(), + route_id: z.int32(), + start_time: z.string(), + evaluation_info_array: z.array(Evaluation), + training_level_info_array: z.array(TrainingLevel), + nickname_id_array: z.array(z.int32()), + chara_effect_id_array: z.array(z.int32()), + route_race_id_array: z.array(z.int32()), + guest_outing_info_array: z.array(GuestOuting), + skill_upgrade_info_array: z.array(SkillUpgrade), }); const ZeroedSingleModeChara = z.strictObject({ - single_mode_chara_id: z.literal(0), - card_id: z.int32(), - chara_grade: z.literal(0), - speed: z.literal(0), - stamina: z.literal(0), - power: z.literal(0), - wiz: z.literal(0), - guts: z.literal(0), - vital: z.literal(0), - max_speed: z.literal(0), - max_stamina: z.literal(0), - max_power: z.literal(0), - max_wiz: z.literal(0), - max_guts: z.literal(0), - default_max_speed: z.literal(0), - default_max_stamina: z.literal(0), - default_max_power: z.literal(0), - default_max_wiz: z.literal(0), - default_max_guts: z.literal(0), - max_vital: z.literal(0), - motivation: z.literal(0), - fans: z.literal(0), - rarity: z.int32(), - race_program_id: z.literal(0), - reserve_race_program_id: z.literal(0), - race_running_style: z.literal(0), - is_short_race: z.literal(0), - talent_level: z.int32(), - skill_array: z.array(z.never()), - disable_skill_id_array: z.array(z.never()), - skill_tips_array: z.array(z.never()), - support_card_array: z.array(z.never()), - succession_trained_chara_id_1: z.int32(), - succession_trained_chara_id_2: z.int32(), - proper_distance_short: z.literal(0), - proper_distance_mile: z.literal(0), - proper_distance_middle: z.literal(0), - proper_distance_long: z.literal(0), - proper_running_style_nige: z.literal(0), - proper_running_style_senko: z.literal(0), - proper_running_style_sashi: z.literal(0), - proper_running_style_oikomi: z.literal(0), - proper_ground_turf: z.literal(0), - proper_ground_dirt: z.literal(0), - turn: z.literal(0), - skill_point: z.literal(0), - short_cut_state: z.literal(0), - state: z.literal(0), - playing_state: z.literal(0), - scenario_id: z.int32(), - route_id: z.literal(0), - start_time: z.literal(''), - evaluation_info_array: z.array(z.never()), - training_level_info_array: z.array(z.never()), - nickname_id_array: z.array(z.never()), - chara_effect_id_array: z.array(z.never()), - route_race_id_array: z.array(z.never()), - guest_outing_info_array: z.array(z.never()), - skill_upgrade_info_array: z.array(z.never()), + single_mode_chara_id: z.literal(0), + card_id: z.int32(), + chara_grade: z.literal(0), + speed: z.literal(0), + stamina: z.literal(0), + power: z.literal(0), + wiz: z.literal(0), + guts: z.literal(0), + vital: z.literal(0), + max_speed: z.literal(0), + max_stamina: z.literal(0), + max_power: z.literal(0), + max_wiz: z.literal(0), + max_guts: z.literal(0), + default_max_speed: z.literal(0), + default_max_stamina: z.literal(0), + default_max_power: z.literal(0), + default_max_wiz: z.literal(0), + default_max_guts: z.literal(0), + max_vital: z.literal(0), + motivation: z.literal(0), + fans: z.literal(0), + rarity: z.int32(), + race_program_id: z.literal(0), + reserve_race_program_id: z.literal(0), + race_running_style: z.literal(0), + is_short_race: z.literal(0), + talent_level: z.int32(), + skill_array: z.array(z.never()), + disable_skill_id_array: z.array(z.never()), + skill_tips_array: z.array(z.never()), + support_card_array: z.array(z.never()), + succession_trained_chara_id_1: z.int32(), + succession_trained_chara_id_2: z.int32(), + proper_distance_short: z.literal(0), + proper_distance_mile: z.literal(0), + proper_distance_middle: z.literal(0), + proper_distance_long: z.literal(0), + proper_running_style_nige: z.literal(0), + proper_running_style_senko: z.literal(0), + proper_running_style_sashi: z.literal(0), + proper_running_style_oikomi: z.literal(0), + proper_ground_turf: z.literal(0), + proper_ground_dirt: z.literal(0), + turn: z.literal(0), + skill_point: z.literal(0), + short_cut_state: z.literal(0), + state: z.literal(0), + playing_state: z.literal(0), + scenario_id: z.int32(), + route_id: z.literal(0), + start_time: z.literal(''), + evaluation_info_array: z.array(z.never()), + training_level_info_array: z.array(z.never()), + nickname_id_array: z.array(z.never()), + chara_effect_id_array: z.array(z.never()), + route_race_id_array: z.array(z.never()), + guest_outing_info_array: z.array(z.never()), + skill_upgrade_info_array: z.array(z.never()), }); export type SingleModeChara = z.infer; const ProgressInfo = z.strictObject({ - chara_info: z.optional(SingleModeChara.or(ZeroedSingleModeChara)), - start_time: z.string(), - end_time: z.string(), - dress_id: z.int32(), + chara_info: z.optional(SingleModeChara.or(ZeroedSingleModeChara)), + start_time: z.string(), + end_time: z.string(), + dress_id: z.int32(), }); export type ProgressInfo = z.infer; const CharaEffectLog = z.strictObject({ - chara_effect_id: z.int32(), - is_active: z.boolean(), + chara_effect_id: z.int32(), + is_active: z.boolean(), }); export type CharaEffectLog = z.infer; /** IdleSingleModeSignedInt */ const SignedInt = z.strictObject({ - sign: z.int32(), - value: z.int32(), + sign: z.int32(), + value: z.int32(), }); export type SignedInt = z.infer; /** IdleSingleModeGainInfo */ const GainInfo = z.strictObject({ - speed: SignedInt, - stamina: SignedInt, - power: SignedInt, - wiz: SignedInt, - guts: SignedInt, - max_speed: z.int32(), - max_stamina: z.int32(), - max_power: z.int32(), - max_wiz: z.int32(), - max_guts: z.int32(), - proper_distance_short: z.int32(), - proper_distance_mile: z.int32(), - proper_distance_middle: z.int32(), - proper_distance_long: z.int32(), - proper_running_style_nige: z.int32(), - proper_running_style_senko: z.int32(), - proper_running_style_sashi: z.int32(), - proper_running_style_oikomi: z.int32(), - proper_ground_turf: z.int32(), - proper_ground_dirt: z.int32(), - skill_point: z.int32(), - skill_tips_array: z.array(SkillTip), + speed: SignedInt, + stamina: SignedInt, + power: SignedInt, + wiz: SignedInt, + guts: SignedInt, + max_speed: z.int32(), + max_stamina: z.int32(), + max_power: z.int32(), + max_wiz: z.int32(), + max_guts: z.int32(), + proper_distance_short: z.int32(), + proper_distance_mile: z.int32(), + proper_distance_middle: z.int32(), + proper_distance_long: z.int32(), + proper_running_style_nige: z.int32(), + proper_running_style_senko: z.int32(), + proper_running_style_sashi: z.int32(), + proper_running_style_oikomi: z.int32(), + proper_ground_turf: z.int32(), + proper_ground_dirt: z.int32(), + skill_point: z.int32(), + skill_tips_array: z.array(SkillTip), }); export type GainInfo = z.infer; /** IdleSingleModeSupportCardGain */ const SupportCardGain = z.strictObject({ - support_card_id: z.int32(), - gain_info: GainInfo, + support_card_id: z.int32(), + gain_info: GainInfo, }); export type SupportCardGain = z.infer; const Factor = z.strictObject({ - factor_id: z.int32(), - level: z.int32(), + factor_id: z.int32(), + level: z.int32(), }); export type Factor = z.infer; /** IdleSingleModeSuccessionFactorGain */ const SuccessionFactorGain = z.strictObject({ - year: z.int32(), - gain_factor_info_array: z.array(Factor), + year: z.int32(), + gain_factor_info_array: z.array(Factor), }); export type SuccessionFactorGain = z.infer; const SingleRaceHistory = z.strictObject({ - turn: z.int32(), - program_id: z.int32(), - weather: z.int32(), - ground_condition: z.int32(), - running_style: z.int32(), - result_rank: z.int32(), - frame_order: z.int32(), - npc_count: z.int32(), + turn: z.int32(), + program_id: z.int32(), + weather: z.int32(), + ground_condition: z.int32(), + running_style: z.int32(), + result_rank: z.int32(), + frame_order: z.int32(), + npc_count: z.int32(), }); export type SingleRaceHistory = z.infer; const RaceReward = z.strictObject({ - item_type: z.int32(), - item_id: z.int32(), - item_num: z.int32(), + item_type: z.int32(), + item_id: z.int32(), + item_num: z.int32(), }); export type RaceReward = z.infer; const RaceRewardLimit = z.strictObject({ - reward_id: z.int32(), - item_type: z.int32(), - item_id: z.int32(), - item_num: z.int32(), - rest_count: z.int32(), + reward_id: z.int32(), + item_type: z.int32(), + item_id: z.int32(), + item_num: z.int32(), + rest_count: z.int32(), }); export type RaceRewardLimit = z.infer; const CharaRaceReward = z.strictObject({ - result_rank: z.int32(), - result_time: z.int32(), - race_reward: z.array(RaceReward), - race_reward_bonus: z.array(RaceReward), - race_reward_plus_bonus: z.array(RaceReward), - race_reward_bonus_win: z.array(RaceReward), - race_reward_limit: z.optional(z.array(RaceRewardLimit)), - gained_fans: z.int32(), - campaign_id_array: z.array(z.int32()), + result_rank: z.int32(), + result_time: z.int32(), + race_reward: z.array(RaceReward), + race_reward_bonus: z.array(RaceReward), + race_reward_plus_bonus: z.array(RaceReward), + race_reward_bonus_win: z.array(RaceReward), + race_reward_limit: z.optional(z.array(RaceRewardLimit)), + gained_fans: z.int32(), + campaign_id_array: z.array(z.int32()), }); export type CharaRaceReward = z.infer; /** IdleSingleModeRaceHistory */ const RaceHistory = z.strictObject({ - race_history: SingleRaceHistory, - race_reward_info: CharaRaceReward, - lose_tips_id: z.int32(), + race_history: SingleRaceHistory, + race_reward_info: CharaRaceReward, + lose_tips_id: z.int32(), }); export type RaceHistory = z.infer; /** IdleSingleModeProgressLog */ const ProgressLog = z.strictObject({ - chara_effect_log_array: z.array(CharaEffectLog), - support_card_gain_info_array: z.array(SupportCardGain), - event_gain_info: GainInfo, - succession_gain_info: GainInfo, - succession_factor_gain_array: z.array(SuccessionFactorGain), - race_history_array: z.array(RaceHistory), - gain_skill_id_array: z.array(z.int32()), - total_skill_point: z.int32(), + chara_effect_log_array: z.array(CharaEffectLog), + support_card_gain_info_array: z.array(SupportCardGain), + event_gain_info: GainInfo, + succession_gain_info: GainInfo, + succession_factor_gain_array: z.array(SuccessionFactorGain), + race_history_array: z.array(RaceHistory), + gain_skill_id_array: z.array(z.int32()), + total_skill_point: z.int32(), }); export type ProgressLog = z.infer; const AddItem = z.strictObject({ - item_id: z.int32(), - number: z.int32(), + item_id: z.int32(), + number: z.int32(), }); export type AddItem = z.infer; const RewardSummary = z.strictObject({ - add_item_list: z.array(AddItem), + add_item_list: z.array(AddItem), }); export type RewardSummary = z.infer; const End = z.strictObject({ - chara_info: SingleModeChara, - reward_summary_info: RewardSummary, + chara_info: SingleModeChara, + reward_summary_info: RewardSummary, }); export type End = z.infer; @@ -366,9 +366,9 @@ export type End = z.infer; * WorkIdleSingleMode, or all the data extracted from an ISM career. */ export const Career = z.object({ - progress_info: ProgressInfo, - progress_log_info: ProgressLog, - end_info: End, + progress_info: ProgressInfo, + progress_log_info: ProgressLog, + end_info: End, }); export type Career = z.infer; diff --git a/zenno/src/routes/career/ismdata/SupportCardGainChart.ts b/zenno/src/routes/career/ismdata/SupportCardGainChart.ts index 428d25b..9e5835c 100644 --- a/zenno/src/routes/career/ismdata/SupportCardGainChart.ts +++ b/zenno/src/routes/career/ismdata/SupportCardGainChart.ts @@ -3,145 +3,158 @@ import * as support from '$lib/data/support'; import * as scenario from '$lib/data/scenario'; function gainTotalStats(gain: ism.GainInfo) { - return gain.speed.value + gain.stamina.value + gain.power.value + gain.guts.value + gain.wiz.value; + return gain.speed.value + gain.stamina.value + gain.power.value + gain.guts.value + gain.wiz.value; } export const DEPENDENT = [ - { - name: 'Total Stats', - map: (gain: ism.GainInfo, _effects: support.Effect[]) => gainTotalStats(gain), - }, - { - name: 'Total Stats + SP', - map: (gain: ism.GainInfo, _effects: support.Effect[]) => gainTotalStats(gain) + gain.skill_point, - }, - { - name: 'Speed', - map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.speed.value, - }, - { - name: 'Stamina', - map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.stamina.value, - }, - { - name: 'Power', - map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.power.value, - }, - { - name: 'Guts', - map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.guts.value, - }, - { - name: 'Wit', - map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.wiz.value, - }, - { - name: 'SP', - map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.skill_point, - }, - { - name: 'Skill Hints', - map: (gain: ism.GainInfo, effects: support.Effect[]) => { - // NOTE(zephyr): reduction starts with 1 because we want the value - // of each hint, not just the bonus from effects - const hintLevels = effects.reduce((l, e) => e.type === support.EffectType.HintLevels ? l + e.value : l, 1); - return gain.skill_tips_array.reduce((n, t) => n + Math.ceil(t.level / hintLevels), 0); - }, - }, - { - name: 'Skills', - map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.skill_tips_array.length, - }, + { + name: 'Total Stats', + map: (gain: ism.GainInfo) => gainTotalStats(gain), + }, + { + name: 'Total Stats + SP', + map: (gain: ism.GainInfo) => gainTotalStats(gain) + gain.skill_point, + }, + { + name: 'Speed', + map: (gain: ism.GainInfo) => gain.speed.value, + }, + { + name: 'Stamina', + map: (gain: ism.GainInfo) => gain.stamina.value, + }, + { + name: 'Power', + map: (gain: ism.GainInfo) => gain.power.value, + }, + { + name: 'Guts', + map: (gain: ism.GainInfo) => gain.guts.value, + }, + { + name: 'Wit', + map: (gain: ism.GainInfo) => gain.wiz.value, + }, + { + name: 'SP', + map: (gain: ism.GainInfo) => gain.skill_point, + }, + { + name: 'Skill Hints', + map: (gain: ism.GainInfo, effects: support.Effect[]) => { + // NOTE(zephyr): reduction starts with 1 because we want the value + // of each hint, not just the bonus from effects + const hintLevels = effects.reduce((l, e) => (e.type === support.EffectType.HintLevels ? l + e.value : l), 1); + return gain.skill_tips_array.reduce((n, t) => n + Math.ceil(t.level / hintLevels), 0); + }, + }, + { + name: 'Skills', + map: (gain: ism.GainInfo) => gain.skill_tips_array.length, + }, ] as const; function label(c: ism.Career): string { - return `${c.end_info.chara_info.single_mode_chara_id} - ${c.end_info.chara_info.start_time}`; + return `${c.end_info.chara_info.single_mode_chara_id} - ${c.end_info.chara_info.start_time}`; } export const INDEPENDENT = [ - { - name: 'Friendship Bonus', - effect: support.EffectType.FriendshipBonus, - }, - { - name: 'Mood Effect', - effect: support.EffectType.MoodEffect, - }, - { - name: 'Speed Bonus', - effect: support.EffectType.SpeedBonus, - }, - { - name: 'Stamina Bonus', - effect: support.EffectType.StaminaBonus, - }, - { - name: 'Power Bonus', - effect: support.EffectType.PowerBonus, - }, - { - name: 'Guts Bonus', - effect: support.EffectType.GutsBonus, - }, - { - name: 'Wit Bonus', - effect: support.EffectType.WitBonus, - }, - { - name: 'Skill Point Bonus', - effect: support.EffectType.SkillPointBonus, - }, - { - name: 'Training Effectiveness', - effect: support.EffectType.TrainingEffectiveness, - }, - { - name: 'Initial Friendship', - effect: support.EffectType.InitialFriendship, - }, - { - name: 'Race Bonus', - effect: support.EffectType.RaceBonus, - }, - { - name: 'Hint Frequency', - effect: support.EffectType.HintFrequency, - }, - { - name: 'Specialty Priority', - effect: support.EffectType.SpecialtyPriority, - }, + { + name: 'Friendship Bonus', + effect: support.EffectType.FriendshipBonus, + }, + { + name: 'Mood Effect', + effect: support.EffectType.MoodEffect, + }, + { + name: 'Speed Bonus', + effect: support.EffectType.SpeedBonus, + }, + { + name: 'Stamina Bonus', + effect: support.EffectType.StaminaBonus, + }, + { + name: 'Power Bonus', + effect: support.EffectType.PowerBonus, + }, + { + name: 'Guts Bonus', + effect: support.EffectType.GutsBonus, + }, + { + name: 'Wit Bonus', + effect: support.EffectType.WitBonus, + }, + { + name: 'Skill Point Bonus', + effect: support.EffectType.SkillPointBonus, + }, + { + name: 'Training Effectiveness', + effect: support.EffectType.TrainingEffectiveness, + }, + { + name: 'Initial Friendship', + effect: support.EffectType.InitialFriendship, + }, + { + name: 'Race Bonus', + effect: support.EffectType.RaceBonus, + }, + { + name: 'Hint Frequency', + effect: support.EffectType.HintFrequency, + }, + { + name: 'Specialty Priority', + effect: support.EffectType.SpecialtyPriority, + }, ] as const; export type SupportCardDatum = { - 'Career': string; - 'Scenario': string; - 'Source': string; - 'Unique Effect': string; - 'Idle Mode Sub Rate': number; - 'Races': number; - 'Race Wins': number; -} & Record & Record; + Career: string; + Scenario: string; + Source: string; + 'Unique Effect': string; + 'Idle Mode Sub Rate': number; + Races: number; + 'Race Wins': number; +} & Record<(typeof INDEPENDENT)[number]['name'], number> & + Record<(typeof DEPENDENT)[number]['name'], number>; -export function supportVariables(career: ism.Career, lookupCard: (id: number) => support.SupportCard, lookupScenario: (id: number) => scenario.Scenario): SupportCardDatum[] { - const deck = career.progress_log_info.support_card_gain_info_array.map((g) => lookupCard(g.support_card_id)); - const scen = lookupScenario(career.end_info.chara_info.scenario_id); - return career.progress_log_info.support_card_gain_info_array.map((g, i) => { - const card = deck[i]; - const level = support.level(card.rarity, career.end_info.chara_info.support_card_array[i].exp); - const { effects, unique } = support.effects(lookupCard(g.support_card_id), level); - const indep = Object.fromEntries(INDEPENDENT.map((t) => [t.name, effects.find((e) => e.type === t.effect)?.value ?? 0])) as Record; - const dep = Object.fromEntries(DEPENDENT.map((t) => [t.name, t.map(g.gain_info, effects)])) as Record; - return { - 'Career': label(career), - 'Scenario': scen.name, - 'Source': card.name, - 'Unique Effect': unique?.description ?? 'None', - 'Idle Mode Sub Rate': unique?.idle_mode_sub_rate ?? 0, - 'Races': career.progress_log_info.race_history_array.length, - 'Race Wins': career.progress_log_info.race_history_array.reduce((w, r) => r.race_history.result_rank === 1 ? w + 1 : w, 0), - ...indep, - ...dep, - }; - }); +export function supportVariables( + career: ism.Career, + lookupCard: (id: number) => support.SupportCard, + lookupScenario: (id: number) => scenario.Scenario, +): SupportCardDatum[] { + const deck = career.progress_log_info.support_card_gain_info_array.map((g) => lookupCard(g.support_card_id)); + const scen = lookupScenario(career.end_info.chara_info.scenario_id); + return career.progress_log_info.support_card_gain_info_array.map((g, i) => { + const card = deck[i]; + const level = support.level(card.rarity, career.end_info.chara_info.support_card_array[i].exp); + const { effects, unique } = support.effects(lookupCard(g.support_card_id), level); + const indep = Object.fromEntries( + INDEPENDENT.map((t) => [t.name, effects.find((e) => e.type === t.effect)?.value ?? 0]), + ) as Record<(typeof INDEPENDENT)[number]['name'], number>; + const dep = Object.fromEntries(DEPENDENT.map((t) => [t.name, t.map(g.gain_info, effects)])) as Record< + (typeof DEPENDENT)[number]['name'], + number + >; + return { + Career: label(career), + Scenario: scen.name, + Source: card.name, + 'Unique Effect': unique?.description ?? 'None', + 'Idle Mode Sub Rate': unique?.idle_mode_sub_rate ?? 0, + Races: career.progress_log_info.race_history_array.length, + 'Race Wins': career.progress_log_info.race_history_array.reduce( + (w, r) => (r.race_history.result_rank === 1 ? w + 1 : w), + 0, + ), + ...indep, + ...dep, + }; + }); }