zenno: lint fixes
ci/woodpecker/push/horsebot Pipeline was successful
ci/woodpecker/push/zenno Pipeline was successful

This commit is contained in:
2026-08-21 15:45:53 -04:00
parent e92ce64b17
commit 444fea85f0
9 changed files with 3037 additions and 3040 deletions
+10 -8
View File
@@ -1,15 +1,17 @@
import * as z from 'zod'; import * as z from 'zod';
const Scenarios = z.array(z.object({ const Scenarios = z.array(
scenario_id: z.int32(), z.object({
name: z.string(), scenario_id: z.int32(),
title: z.string(), name: z.string(),
})); title: z.string(),
}),
);
export type Scenario = z.infer<typeof Scenarios>[number]; export type Scenario = z.infer<typeof Scenarios>[number];
export async function scenarios(): Promise<Scenario[]> { export async function scenarios(): Promise<Scenario[]> {
const r = await fetch('/api/global/scenario'); const r = await fetch('/api/global/scenario');
const u = await r.json(); const u = await r.json();
return Scenarios.parse(u); return Scenarios.parse(u);
} }
+396 -398
View File
@@ -6,406 +6,404 @@ import * as bakushinSR from './testdata/support-20042-bakushin-SR.json';
import * as bakushinSSR from './testdata/support-30083-bakushin-SSR.json'; import * as bakushinSSR from './testdata/support-30083-bakushin-SSR.json';
test.for([ test.for([
{ rarity: support.Rarity.R, exp: 0, level: 1 }, { rarity: support.Rarity.R, exp: 0, level: 1 },
{ rarity: support.Rarity.R, exp: 5, level: 2 }, { rarity: support.Rarity.R, exp: 5, level: 2 },
{ rarity: support.Rarity.R, exp: 10, level: 2 }, { rarity: support.Rarity.R, exp: 10, level: 2 },
{ rarity: support.Rarity.R, exp: 40510, level: 40 }, { rarity: support.Rarity.R, exp: 40510, level: 40 },
{ rarity: support.Rarity.SR, exp: 0, level: 1 }, { rarity: support.Rarity.SR, exp: 0, level: 1 },
{ rarity: support.Rarity.SR, exp: 10, level: 2 }, { rarity: support.Rarity.SR, exp: 10, level: 2 },
{ rarity: support.Rarity.SR, exp: 20, level: 2 }, { rarity: support.Rarity.SR, exp: 20, level: 2 },
{ rarity: support.Rarity.SR, exp: 74990, level: 45 }, { rarity: support.Rarity.SR, exp: 74990, level: 45 },
{ rarity: support.Rarity.SSR, exp: 0, level: 1 }, { rarity: support.Rarity.SSR, exp: 0, level: 1 },
{ rarity: support.Rarity.SSR, exp: 15, level: 2 }, { rarity: support.Rarity.SSR, exp: 15, level: 2 },
{ rarity: support.Rarity.SSR, exp: 30, level: 2 }, { rarity: support.Rarity.SSR, exp: 30, level: 2 },
{ rarity: support.Rarity.SSR, exp: 118185, level: 50 }, { rarity: support.Rarity.SSR, exp: 118185, level: 50 },
])('level($rarity, $exp) -> $level', ({ rarity, exp, level }) => expect(support.level(rarity, exp)).toBe(level)); ])('level($rarity, $exp) -> $level', ({ rarity, exp, level }) => expect(support.level(rarity, exp)).toBe(level));
describe('effects', () => { 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', () => { describe('Bakushin SR', () => {
test('level 1', () => { test('level 1', () => {
const got = support.effects(bakushinR as support.SupportCard, 1); const got = support.effects(bakushinSR as support.SupportCard, 1);
expect(got).toStrictEqual({ expect(got).toStrictEqual({
effects: [ effects: [
{ type: support.EffectType.FriendshipBonus, value: 5 }, { type: support.EffectType.FriendshipBonus, value: 10 },
{ type: support.EffectType.MoodEffect, value: 0 }, { type: support.EffectType.PowerBonus, value: 0 },
{ type: support.EffectType.SpeedBonus, value: 0 }, { type: support.EffectType.TrainingEffectiveness, value: 0 },
{ type: support.EffectType.InitialSpeed, value: 0 }, { type: support.EffectType.InitialPower, value: 0 },
{ type: support.EffectType.InitialFriendship, value: 0 }, { type: support.EffectType.InitialFriendship, value: 0 },
{ type: support.EffectType.RaceBonus, value: 1 }, { type: support.EffectType.RaceBonus, value: 1 },
{ type: support.EffectType.FanBonus, value: 1 }, { type: support.EffectType.FanBonus, value: 1 },
{ type: support.EffectType.SpecialtyPriority, value: 0 }, { type: support.EffectType.SpecialtyPriority, value: 0 },
], ],
}); });
}); });
test('level 2', () => { test('level 2', () => {
const got = support.effects(bakushinR as support.SupportCard, 2); const got = support.effects(bakushinSR as support.SupportCard, 2);
expect(got).toStrictEqual({ expect(got).toStrictEqual({
effects: [ effects: [
{ type: support.EffectType.FriendshipBonus, value: 5 }, { type: support.EffectType.FriendshipBonus, value: 10 },
{ type: support.EffectType.MoodEffect, value: 0 }, { type: support.EffectType.PowerBonus, value: 0 },
{ type: support.EffectType.SpeedBonus, value: 0 }, { type: support.EffectType.TrainingEffectiveness, value: 0 },
{ type: support.EffectType.InitialSpeed, value: 0 }, { type: support.EffectType.InitialPower, value: 0 },
{ type: support.EffectType.InitialFriendship, value: 0 }, { type: support.EffectType.InitialFriendship, value: 0 },
{ type: support.EffectType.RaceBonus, value: 1 }, { type: support.EffectType.RaceBonus, value: 1 },
{ type: support.EffectType.FanBonus, value: 1 }, { type: support.EffectType.FanBonus, value: 1 },
{ type: support.EffectType.SpecialtyPriority, value: 0 }, { type: support.EffectType.SpecialtyPriority, value: 0 },
], ],
}); });
}); });
test('level 5', () => { test('level 5', () => {
const got = support.effects(bakushinR as support.SupportCard, 5); const got = support.effects(bakushinSR as support.SupportCard, 5);
expect(got).toStrictEqual({ expect(got).toStrictEqual({
effects: [ effects: [
{ type: support.EffectType.FriendshipBonus, value: 6 }, { type: support.EffectType.FriendshipBonus, value: 11 },
{ type: support.EffectType.MoodEffect, value: 10 }, { type: support.EffectType.PowerBonus, value: 0 },
{ type: support.EffectType.SpeedBonus, value: 0 }, { type: support.EffectType.TrainingEffectiveness, value: 0 },
{ type: support.EffectType.InitialSpeed, value: 10 }, { type: support.EffectType.InitialPower, value: 0 },
{ type: support.EffectType.InitialFriendship, value: 10 }, { type: support.EffectType.InitialFriendship, value: 0 },
{ type: support.EffectType.RaceBonus, value: 1 }, { type: support.EffectType.RaceBonus, value: 1 },
{ type: support.EffectType.FanBonus, value: 2 }, { type: support.EffectType.FanBonus, value: 3 },
{ type: support.EffectType.SpecialtyPriority, value: 5 }, { type: support.EffectType.SpecialtyPriority, value: 5 },
], ],
}); });
}); });
test('level 6', () => { test('level 24', () => {
const got = support.effects(bakushinR as support.SupportCard, 6); const got = support.effects(bakushinSR as support.SupportCard, 24);
expect(got).toStrictEqual({ expect(got).toStrictEqual({
effects: [ effects: [
{ type: support.EffectType.FriendshipBonus, value: 6 }, { type: support.EffectType.FriendshipBonus, value: 15 },
{ type: support.EffectType.MoodEffect, value: 10 }, { type: support.EffectType.PowerBonus, value: 0 },
{ type: support.EffectType.SpeedBonus, value: 0 }, { type: support.EffectType.TrainingEffectiveness, value: 5 },
{ type: support.EffectType.InitialSpeed, value: 10 }, { type: support.EffectType.InitialPower, value: 15 },
{ type: support.EffectType.InitialFriendship, value: 10 }, { type: support.EffectType.InitialFriendship, value: 0 },
{ type: support.EffectType.RaceBonus, value: 2 }, { type: support.EffectType.RaceBonus, value: 4 },
{ type: support.EffectType.FanBonus, value: 3 }, { type: support.EffectType.FanBonus, value: 14 },
{ type: support.EffectType.SpecialtyPriority, value: 6 }, { type: support.EffectType.SpecialtyPriority, value: 33 },
], ],
}); });
}); });
test('level 39', () => { test('level 25', () => {
const got = support.effects(bakushinR as support.SupportCard, 39); const got = support.effects(bakushinSR as support.SupportCard, 25);
expect(got).toStrictEqual({ expect(got).toStrictEqual({
effects: [ effects: [
{ type: support.EffectType.FriendshipBonus, value: 15 }, { type: support.EffectType.FriendshipBonus, value: 15 },
{ type: support.EffectType.MoodEffect, value: 25 }, { type: support.EffectType.PowerBonus, value: 0 },
{ type: support.EffectType.SpeedBonus, value: 0 }, { type: support.EffectType.TrainingEffectiveness, value: 5 },
{ type: support.EffectType.InitialSpeed, value: 20 }, { type: support.EffectType.InitialPower, value: 15 },
{ type: support.EffectType.InitialFriendship, value: 20 }, { type: support.EffectType.InitialFriendship, value: 0 },
{ type: support.EffectType.RaceBonus, value: 5 }, { type: support.EffectType.RaceBonus, value: 5 },
{ type: support.EffectType.FanBonus, value: 14 }, { type: support.EffectType.FanBonus, value: 15 },
{ type: support.EffectType.SpecialtyPriority, value: 35 }, { type: support.EffectType.SpecialtyPriority, value: 35 },
], ],
}); unique: {
}); name: 'The Perfect Morning Greeting!',
test('level 40', () => { description: 'Friendship Bonus and Specialty Priority',
const got = support.effects(bakushinR as support.SupportCard, 40); card_level: 25,
expect(got).toStrictEqual({ type: support.EffectType.FriendshipBonus,
effects: [ args: [10],
{ type: support.EffectType.FriendshipBonus, value: 15 }, type2: support.EffectType.SpecialtyPriority,
{ type: support.EffectType.MoodEffect, value: 25 }, args2: [20],
{ type: support.EffectType.SpeedBonus, value: 1 }, idle_mode_sub_rate: 0,
{ type: support.EffectType.InitialSpeed, value: 20 }, } satisfies support.UniqueEffect,
{ type: support.EffectType.InitialFriendship, value: 20 }, });
{ type: support.EffectType.RaceBonus, value: 5 }, });
{ type: support.EffectType.FanBonus, value: 15 }, test('level 44', () => {
{ type: support.EffectType.SpecialtyPriority, value: 35 }, 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', () => { describe('Bakushin SSR', () => {
test('level 1', () => { test('level 1', () => {
const got = support.effects(bakushinSR as support.SupportCard, 1); const got = support.effects(bakushinSSR as support.SupportCard, 1);
expect(got).toStrictEqual({ expect(got).toStrictEqual({
effects: [ effects: [
{ type: support.EffectType.FriendshipBonus, value: 10 }, { type: support.EffectType.FriendshipBonus, value: 10 },
{ type: support.EffectType.PowerBonus, value: 0 }, { type: support.EffectType.MoodEffect, value: 0 },
{ type: support.EffectType.TrainingEffectiveness, value: 0 }, { type: support.EffectType.GutsBonus, value: 0 },
{ type: support.EffectType.InitialPower, value: 0 }, { type: support.EffectType.InitialGuts, value: 0 },
{ type: support.EffectType.InitialFriendship, value: 0 }, { type: support.EffectType.InitialFriendship, value: 0 },
{ type: support.EffectType.RaceBonus, value: 1 }, { type: support.EffectType.RaceBonus, value: 1 },
{ type: support.EffectType.FanBonus, value: 1 }, { type: support.EffectType.FanBonus, value: 1 },
{ type: support.EffectType.SpecialtyPriority, value: 0 }, { type: support.EffectType.HintLevels, value: 1 },
], { type: support.EffectType.HintFrequency, value: 5 },
}); ],
}); });
test('level 2', () => { });
const got = support.effects(bakushinSR as support.SupportCard, 2); test('level 2', () => {
expect(got).toStrictEqual({ const got = support.effects(bakushinSSR as support.SupportCard, 2);
effects: [ expect(got).toStrictEqual({
{ type: support.EffectType.FriendshipBonus, value: 10 }, effects: [
{ type: support.EffectType.PowerBonus, value: 0 }, { type: support.EffectType.FriendshipBonus, value: 10 },
{ type: support.EffectType.TrainingEffectiveness, value: 0 }, { type: support.EffectType.MoodEffect, value: 0 },
{ type: support.EffectType.InitialPower, value: 0 }, { type: support.EffectType.GutsBonus, value: 0 },
{ type: support.EffectType.InitialFriendship, value: 0 }, { type: support.EffectType.InitialGuts, value: 0 },
{ type: support.EffectType.RaceBonus, value: 1 }, { type: support.EffectType.InitialFriendship, value: 0 },
{ type: support.EffectType.FanBonus, value: 1 }, { type: support.EffectType.RaceBonus, value: 1 },
{ type: support.EffectType.SpecialtyPriority, value: 0 }, { 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(bakushinSR as support.SupportCard, 5); });
expect(got).toStrictEqual({ test('level 5', () => {
effects: [ const got = support.effects(bakushinSSR as support.SupportCard, 5);
{ type: support.EffectType.FriendshipBonus, value: 11 }, expect(got).toStrictEqual({
{ type: support.EffectType.PowerBonus, value: 0 }, effects: [
{ type: support.EffectType.TrainingEffectiveness, value: 0 }, { type: support.EffectType.FriendshipBonus, value: 12 },
{ type: support.EffectType.InitialPower, value: 0 }, { type: support.EffectType.MoodEffect, value: 0 },
{ type: support.EffectType.InitialFriendship, value: 0 }, { type: support.EffectType.GutsBonus, value: 0 },
{ type: support.EffectType.RaceBonus, value: 1 }, { type: support.EffectType.InitialGuts, value: 0 },
{ type: support.EffectType.FanBonus, value: 3 }, { type: support.EffectType.InitialFriendship, value: 0 },
{ type: support.EffectType.SpecialtyPriority, value: 5 }, { 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 24', () => { ],
const got = support.effects(bakushinSR as support.SupportCard, 24); });
expect(got).toStrictEqual({ });
effects: [ test('level 10', () => {
{ type: support.EffectType.FriendshipBonus, value: 15 }, const got = support.effects(bakushinSSR as support.SupportCard, 10);
{ type: support.EffectType.PowerBonus, value: 0 }, expect(got).toStrictEqual({
{ type: support.EffectType.TrainingEffectiveness, value: 5 }, effects: [
{ type: support.EffectType.InitialPower, value: 15 }, { type: support.EffectType.FriendshipBonus, value: 14 },
{ type: support.EffectType.InitialFriendship, value: 0 }, { type: support.EffectType.MoodEffect, value: 0 },
{ type: support.EffectType.RaceBonus, value: 4 }, { type: support.EffectType.GutsBonus, value: 0 },
{ type: support.EffectType.FanBonus, value: 14 }, { type: support.EffectType.InitialGuts, value: 0 },
{ type: support.EffectType.SpecialtyPriority, value: 33 }, { type: support.EffectType.InitialFriendship, value: 10 },
], { type: support.EffectType.RaceBonus, value: 2 },
}); { type: support.EffectType.FanBonus, value: 5 },
}); { type: support.EffectType.HintLevels, value: 1 },
test('level 25', () => { { type: support.EffectType.HintFrequency, value: 15 },
const got = support.effects(bakushinSR as support.SupportCard, 25); ],
expect(got).toStrictEqual({ });
effects: [ });
{ type: support.EffectType.FriendshipBonus, value: 15 }, test('level 11', () => {
{ type: support.EffectType.PowerBonus, value: 0 }, const got = support.effects(bakushinSSR as support.SupportCard, 11);
{ type: support.EffectType.TrainingEffectiveness, value: 5 }, expect(got).toStrictEqual({
{ type: support.EffectType.InitialPower, value: 15 }, effects: [
{ type: support.EffectType.InitialFriendship, value: 0 }, { type: support.EffectType.FriendshipBonus, value: 15 },
{ type: support.EffectType.RaceBonus, value: 5 }, { type: support.EffectType.MoodEffect, value: 0 },
{ type: support.EffectType.FanBonus, value: 15 }, { type: support.EffectType.GutsBonus, value: 0 },
{ type: support.EffectType.SpecialtyPriority, value: 35 }, { type: support.EffectType.InitialGuts, value: 0 },
], { type: support.EffectType.InitialFriendship, value: 10 },
unique: { { type: support.EffectType.RaceBonus, value: 2 },
name: 'The Perfect Morning Greeting!', { type: support.EffectType.FanBonus, value: 5 },
description: 'Friendship Bonus and Specialty Priority', { type: support.EffectType.HintLevels, value: 1 },
card_level: 25, { type: support.EffectType.HintFrequency, value: 17 },
type: support.EffectType.FriendshipBonus, ],
args: [10], });
type2: support.EffectType.SpecialtyPriority, });
args2: [20], test('level 30', () => {
idle_mode_sub_rate: 0, const got = support.effects(bakushinSSR as support.SupportCard, 30);
} satisfies support.UniqueEffect, expect(got).toStrictEqual({
}); effects: [
}); { type: support.EffectType.FriendshipBonus, value: 25 },
test('level 44', () => { { type: support.EffectType.MoodEffect, value: 20 },
const got = support.effects(bakushinSR as support.SupportCard, 44); { type: support.EffectType.GutsBonus, value: 0 },
expect(got).toStrictEqual({ { type: support.EffectType.InitialGuts, value: 0 },
effects: [ { type: support.EffectType.InitialFriendship, value: 20 },
{ type: support.EffectType.FriendshipBonus, value: 20 }, { type: support.EffectType.RaceBonus, value: 5 },
{ type: support.EffectType.PowerBonus, value: 0 }, { type: support.EffectType.FanBonus, value: 15 },
{ type: support.EffectType.TrainingEffectiveness, value: 5 }, { type: support.EffectType.HintLevels, value: 2 },
{ type: support.EffectType.InitialPower, value: 20 }, { type: support.EffectType.HintFrequency, value: 40 },
{ type: support.EffectType.InitialFriendship, value: 20 }, ],
{ type: support.EffectType.RaceBonus, value: 9 }, unique: {
{ type: support.EffectType.FanBonus, value: 19 }, name: 'Super! Sonic! Flower Power!',
{ type: support.EffectType.SpecialtyPriority, value: 49 }, description: 'Increases Training Effectiveness when not on preferred training. (Friendship 80+)',
], card_level: 30,
unique: { type: support.EffectType.UniqueOffSpecialty,
name: 'The Perfect Morning Greeting!', args: [80, 20],
description: 'Friendship Bonus and Specialty Priority', idle_mode_sub_rate: 30,
card_level: 25, } satisfies support.UniqueEffect,
type: support.EffectType.FriendshipBonus, });
args: [10], });
type2: support.EffectType.SpecialtyPriority, test('level 49', () => {
args2: [20], const got = support.effects(bakushinSSR as support.SupportCard, 49);
idle_mode_sub_rate: 0, expect(got).toStrictEqual({
} satisfies support.UniqueEffect, effects: [
}); { type: support.EffectType.FriendshipBonus, value: 34 },
}); { type: support.EffectType.MoodEffect, value: 30 },
test('level 45', () => { { type: support.EffectType.GutsBonus, value: 1 },
const got = support.effects(bakushinSR as support.SupportCard, 45); { type: support.EffectType.InitialGuts, value: 27 },
expect(got).toStrictEqual({ { type: support.EffectType.InitialFriendship, value: 25 },
effects: [ { type: support.EffectType.RaceBonus, value: 9 },
{ type: support.EffectType.FriendshipBonus, value: 20 }, { type: support.EffectType.FanBonus, value: 19 },
{ type: support.EffectType.PowerBonus, value: 1 }, { type: support.EffectType.HintLevels, value: 2 },
{ type: support.EffectType.TrainingEffectiveness, value: 5 }, { type: support.EffectType.HintFrequency, value: 49 },
{ type: support.EffectType.InitialPower, value: 20 }, ],
{ type: support.EffectType.InitialFriendship, value: 20 }, unique: {
{ type: support.EffectType.RaceBonus, value: 10 }, name: 'Super! Sonic! Flower Power!',
{ type: support.EffectType.FanBonus, value: 20 }, description: 'Increases Training Effectiveness when not on preferred training. (Friendship 80+)',
{ type: support.EffectType.SpecialtyPriority, value: 50 }, card_level: 30,
], type: support.EffectType.UniqueOffSpecialty,
unique: { args: [80, 20],
name: 'The Perfect Morning Greeting!', idle_mode_sub_rate: 30,
description: 'Friendship Bonus and Specialty Priority', } satisfies support.UniqueEffect,
card_level: 25, });
type: support.EffectType.FriendshipBonus, });
args: [10], test('level 50', () => {
type2: support.EffectType.SpecialtyPriority, const got = support.effects(bakushinSSR as support.SupportCard, 50);
args2: [20], expect(got).toStrictEqual({
idle_mode_sub_rate: 0, effects: [
} satisfies support.UniqueEffect, { 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 },
describe('Bakushin SSR', () => { { type: support.EffectType.RaceBonus, value: 10 },
test('level 1', () => { { type: support.EffectType.FanBonus, value: 20 },
const got = support.effects(bakushinSSR as support.SupportCard, 1); { type: support.EffectType.HintLevels, value: 3 },
expect(got).toStrictEqual({ { type: support.EffectType.HintFrequency, value: 50 },
effects: [ ],
{ type: support.EffectType.FriendshipBonus, value: 10 }, unique: {
{ type: support.EffectType.MoodEffect, value: 0 }, name: 'Super! Sonic! Flower Power!',
{ type: support.EffectType.GutsBonus, value: 0 }, description: 'Increases Training Effectiveness when not on preferred training. (Friendship 80+)',
{ type: support.EffectType.InitialGuts, value: 0 }, card_level: 30,
{ type: support.EffectType.InitialFriendship, value: 0 }, type: support.EffectType.UniqueOffSpecialty,
{ type: support.EffectType.RaceBonus, value: 1 }, args: [80, 20],
{ type: support.EffectType.FanBonus, value: 1 }, idle_mode_sub_rate: 30,
{ type: support.EffectType.HintLevels, value: 1 }, } satisfies support.UniqueEffect,
{ 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,
});
});
});
});
+284 -293
View File
@@ -4,227 +4,215 @@ import * as support_card_level from './support_card_level.json';
* Support card definitions. * Support card definitions.
*/ */
export interface SupportCard { export interface SupportCard {
/** /**
* Support card ID. * Support card ID.
*/ */
id: number; id: number;
/** /**
* Support card name including variant, e.g. * Support card name including variant, e.g.
* `[The Brightest Star in Japan!] Special Week`. * `[The Brightest Star in Japan!] Special Week`.
*/ */
name: string; name: string;
/** /**
* ID of the card's representative character. * ID of the card's representative character.
*/ */
chara_id: number; chara_id: number;
/** /**
* Name of the card's character. * Name of the card's character.
* May differ from the name of the `chara_id` character. * May differ from the name of the `chara_id` character.
*/ */
chara_name: string; chara_name: string;
/** /**
* Support card rarity. * Support card rarity.
*/ */
rarity: Rarity; rarity: Rarity;
/** /**
* Support card specialty. * Support card specialty.
*/ */
specialty: Specialty; specialty: Specialty;
/** /**
* Blanket support card type. * Blanket support card type.
*/ */
type: Type; type: Type;
/** /**
* Support card effects per five level increment. * Support card effects per five level increment.
*/ */
effects: [ effects: [Effect[], Effect[], Effect[], Effect[], Effect[], Effect[], Effect[], Effect[], Effect[], Effect[], Effect[]];
Effect[], /**
Effect[], * Unique effect, for cards that have them.
Effect[], */
Effect[], unique_effect?: UniqueEffect;
Effect[], /**
Effect[], * Hints that the card can yield.
Effect[], */
Effect[], hints: Hint[];
Effect[], /**
Effect[], * Number of recreation events available with the card,
Effect[], * not including recreation with the individual characters in a group.
]; */
/** outings?: number;
* 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. * Support card rarity levels.
*/ */
export enum Rarity { export enum Rarity {
R = 1, R = 1,
SR = 2, SR = 2,
SSR = 3, SSR = 3,
} }
/** /**
* Support card specialty attribute. * Support card specialty attribute.
*/ */
export enum Specialty { export enum Specialty {
None = 0, // for pals and groups None = 0, // for pals and groups
Speed = 101, Speed = 101,
Power = 102, Power = 102,
Guts = 103, Guts = 103,
Stamina = 105, Stamina = 105,
Wit = 106, Wit = 106,
} }
/** /**
* Support card types. * Support card types.
*/ */
export enum Type { export enum Type {
Normal = 1, Normal = 1,
Pal = 2, Pal = 2,
Group = 3, Group = 3,
} }
/** /**
* Support card basic effects. * Support card basic effects.
*/ */
export interface Effect { export interface Effect {
/** /**
* Type of the effect. * Type of the effect.
*/ */
type: EffectType; type: EffectType;
/** /**
* When positive, the amount of the effect. * When positive, the amount of the effect.
* When -1, interpolate between the previous and next nonnegative values. * When -1, interpolate between the previous and next nonnegative values.
*/ */
value: number; value: number;
} }
/** /**
* Support card unique effects. * Support card unique effects.
*/ */
export interface UniqueEffect { export interface UniqueEffect {
/** /**
* Name of the unique effect. * Name of the unique effect.
*/ */
name: string; name: string;
/** /**
* In-game description of the effect. * In-game description of the effect.
*/ */
description: string; description: string;
/** /**
* Card level at which the unique effect unlocks. * Card level at which the unique effect unlocks.
*/ */
card_level: number; card_level: number;
/** /**
* First type of the effect. * First type of the effect.
*/ */
type: EffectType; type: EffectType;
/** /**
* Values parameterizing the first type. * Values parameterizing the first type.
*/ */
args: number[]; args: number[];
/** /**
* Second type of the effect, if applicable. * Second type of the effect, if applicable.
*/ */
type2?: EffectType; type2?: EffectType;
/** /**
* Values parameterizing the second type. * Values parameterizing the second type.
*/ */
args2?: number[]; args2?: number[];
/** /**
* Mystery parameter that one day we might figure out. * Mystery parameter that one day we might figure out.
*/ */
idle_mode_sub_rate: number; idle_mode_sub_rate: number;
} }
/** /**
* Basic and unique effect types. * Basic and unique effect types.
*/ */
export enum EffectType { export enum EffectType {
FriendshipBonus = 1, FriendshipBonus = 1,
MoodEffect = 2, MoodEffect = 2,
SpeedBonus = 3, SpeedBonus = 3,
StaminaBonus = 4, StaminaBonus = 4,
PowerBonus = 5, PowerBonus = 5,
GutsBonus = 6, GutsBonus = 6,
WitBonus = 7, WitBonus = 7,
TrainingEffectiveness = 8, TrainingEffectiveness = 8,
InitialSpeed = 9, InitialSpeed = 9,
InitialStamina = 10, InitialStamina = 10,
InitialPower = 11, InitialPower = 11,
InitialGuts = 12, InitialGuts = 12,
InitialWit = 13, InitialWit = 13,
InitialFriendship = 14, InitialFriendship = 14,
RaceBonus = 15, RaceBonus = 15,
FanBonus = 16, FanBonus = 16,
HintLevels = 17, HintLevels = 17,
HintFrequency = 18, HintFrequency = 18,
SpecialtyPriority = 19, SpecialtyPriority = 19,
MaxSpeed = 20, MaxSpeed = 20,
MaxStamina = 21, MaxStamina = 21,
MaxPower = 22, MaxPower = 22,
MaxGuts = 23, MaxGuts = 23,
MaxWit = 24, MaxWit = 24,
EventRecovery = 25, EventRecovery = 25,
EventEffectiveness = 26, EventEffectiveness = 26,
FailureProtection = 27, FailureProtection = 27,
EnergyCostReduction = 28, EnergyCostReduction = 28,
MinigameEffectiveness = 29, MinigameEffectiveness = 29,
SkillPointBonus = 30, SkillPointBonus = 30,
WitFriendshipRecovery = 31, WitFriendshipRecovery = 31,
UniqueFriendshipThreshold = 101, UniqueFriendshipThreshold = 101,
UniqueOffSpecialty = 102, UniqueOffSpecialty = 102,
UniqueColorThresholdTrainingEffectiveness = 103, UniqueColorThresholdTrainingEffectiveness = 103,
UniqueFanScalingTrainingEffectiveness = 104, UniqueFanScalingTrainingEffectiveness = 104,
UniqueColorInitialStats = 105, UniqueColorInitialStats = 105,
UniqueRainbowStack = 106, UniqueRainbowStack = 106,
UniqueLowEnergyScaling = 107, UniqueLowEnergyScaling = 107,
UniqueMaxEnergyScaling = 108, UniqueMaxEnergyScaling = 108,
UniqueTotalFriendship = 109, UniqueTotalFriendship = 109,
UniqueCardCount = 110, UniqueCardCount = 110,
UniqueFacilityLevel = 111, UniqueFacilityLevel = 111,
UniqueDisableFailure = 112, UniqueDisableFailure = 112,
UniqueFriendshipTrainingAdditionalEffect = 113, UniqueFriendshipTrainingAdditionalEffect = 113,
} }
/** /**
* Hint event bonuses. * Hint event bonuses.
*/ */
export interface Hint { export interface Hint {
skill_id?: number; skill_id?: number;
speed?: number; speed?: number;
stamina?: number; stamina?: number;
power?: number; power?: number;
guts?: number; guts?: number;
wit?: number; wit?: number;
sp?: number; sp?: number;
} }
export async function supports(): Promise<SupportCard[]> { export async function supports(): Promise<SupportCard[]> {
const resp = await fetch('/api/global/support'); const resp = await fetch('/api/global/support');
return resp.json(); return resp.json();
} }
export const SPECIALTY_ICON = { export const SPECIALTY_ICON = {
Speed: 0, Speed: 0,
Stamina: 1, Stamina: 1,
Power: 2, Power: 2,
Guts: 3, Guts: 3,
Wit: 4, Wit: 4,
Pal: 5, Pal: 5,
Group: 6, Group: 6,
} as const; } 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. * @returns Current support card effects and its unique effect if active at the given level.
*/ */
export function effects(card: SupportCard, level: number) { export function effects(card: SupportCard, level: number) {
const j = Math.floor(level / 5); const j = Math.floor(level / 5);
const k = Math.ceil(level / 5); const k = Math.ceil(level / 5);
const effects = card.effects[0].map((e) => { const effects = card.effects[0].map((e) => {
const s = card.effects.map((l) => l.find((f) => f.type === e.type)!); 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 left = s.findLastIndex((f, i) => i <= j && f.value >= 0);
const right = s.findIndex((f, i) => k <= i && f.value >= 0); const right = s.findIndex((f, i) => k <= i && f.value >= 0);
if (left < 0) { if (left < 0) {
// Effect isn't yet active. // Effect isn't yet active.
return { type: e.type, value: 0 }; return { type: e.type, value: 0 };
} }
if (right < 0) { if (right < 0) {
// Effect is at its maximum value. // Effect is at its maximum value.
return { type: e.type, value: s[left]!.value }; return { type: e.type, value: s[left]!.value };
} }
if (left === right) { if (left === right) {
// The current level is an interpolation boundary. // The current level is an interpolation boundary.
// Don't try to interpolate. // Don't try to interpolate.
return { type: e.type, value: s[left]!.value }; return { type: e.type, value: s[left]!.value };
} }
const xl = Math.max(left * 5, 1); const xl = Math.max(left * 5, 1);
const xr = Math.max(right * 5, 1); const xr = Math.max(right * 5, 1);
const lo = s[left]!.value; const lo = s[left]!.value;
const hi = s[right]!.value; const hi = s[right]!.value;
const value = Math.floor((hi * (level - xl) + lo * (xr - level)) / (xr - xl)); const value = Math.floor((hi * (level - xl) + lo * (xr - level)) / (xr - xl));
return { type: e.type, value }; return { type: e.type, value };
}); });
if (card.unique_effect != null && level >= card.unique_effect.card_level) { if (card.unique_effect != null && level >= card.unique_effect.card_level) {
return { effects, unique: card.unique_effect } return { effects, unique: card.unique_effect };
} }
return { effects }; return { effects };
} }
export function level(rarity: Rarity, exp: number) { export function level(rarity: Rarity, exp: number) {
// We use the ! assertion because we want an error when exp is nonsense. // 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; return support_card_level.levels.findLast((l) => l.rarity === rarity && l.exp <= exp)!.level;
} }
function singleUniqueEffects(type: EffectType, args: number[], deck: SupportCard[]): Effect[] { function singleUniqueEffects(type: EffectType, args: number[], deck: SupportCard[]): Effect[] {
switch (type) { switch (type) {
case EffectType.FriendshipBonus: case EffectType.FriendshipBonus:
case EffectType.MoodEffect: case EffectType.MoodEffect:
case EffectType.SpeedBonus: case EffectType.SpeedBonus:
case EffectType.StaminaBonus: case EffectType.StaminaBonus:
case EffectType.PowerBonus: case EffectType.PowerBonus:
case EffectType.GutsBonus: case EffectType.GutsBonus:
case EffectType.WitBonus: case EffectType.WitBonus:
case EffectType.TrainingEffectiveness: case EffectType.TrainingEffectiveness:
case EffectType.InitialSpeed: case EffectType.InitialSpeed:
case EffectType.InitialStamina: case EffectType.InitialStamina:
case EffectType.InitialPower: case EffectType.InitialPower:
case EffectType.InitialGuts: case EffectType.InitialGuts:
case EffectType.InitialWit: case EffectType.InitialWit:
case EffectType.InitialFriendship: case EffectType.InitialFriendship:
case EffectType.RaceBonus: case EffectType.RaceBonus:
case EffectType.FanBonus: case EffectType.FanBonus:
case EffectType.HintLevels: case EffectType.HintLevels:
case EffectType.HintFrequency: case EffectType.HintFrequency:
case EffectType.SpecialtyPriority: case EffectType.SpecialtyPriority:
case EffectType.MaxSpeed: case EffectType.MaxSpeed:
case EffectType.MaxStamina: case EffectType.MaxStamina:
case EffectType.MaxPower: case EffectType.MaxPower:
case EffectType.MaxGuts: case EffectType.MaxGuts:
case EffectType.MaxWit: case EffectType.MaxWit:
case EffectType.EventRecovery: case EffectType.EventRecovery:
case EffectType.EventEffectiveness: case EffectType.EventEffectiveness:
case EffectType.FailureProtection: case EffectType.FailureProtection:
case EffectType.EnergyCostReduction: case EffectType.EnergyCostReduction:
case EffectType.MinigameEffectiveness: case EffectType.MinigameEffectiveness:
case EffectType.SkillPointBonus: case EffectType.SkillPointBonus:
case EffectType.WitFriendshipRecovery: case EffectType.WitFriendshipRecovery:
return [{ type, value: args[0] }]; return [{ type, value: args[0] }];
case EffectType.UniqueFriendshipThreshold: case EffectType.UniqueFriendshipThreshold:
return [{ type: args[1], value: args[2] }, { type: args[3], value: args[4] }]; return [
case EffectType.UniqueOffSpecialty: { type: args[1], value: args[2] },
return [{ type: EffectType.TrainingEffectiveness, value: args[1] }]; { type: args[3], value: args[4] },
case EffectType.UniqueColorThresholdTrainingEffectiveness: ];
if (new Set(deck.map((card) => card.specialty)).size < args[0]) { case EffectType.UniqueOffSpecialty:
return []; return [{ type: EffectType.TrainingEffectiveness, value: args[1] }];
} case EffectType.UniqueColorThresholdTrainingEffectiveness:
return [{ type: EffectType.TrainingEffectiveness, value: args[1] }]; if (new Set(deck.map((card) => card.specialty)).size < args[0]) {
case EffectType.UniqueFanScalingTrainingEffectiveness: return [];
return [{ type: EffectType.TrainingEffectiveness, value: args[1] }] }
case EffectType.UniqueColorInitialStats: return [{ type: EffectType.TrainingEffectiveness, value: args[1] }];
return deck.flatMap((card) => { case EffectType.UniqueFanScalingTrainingEffectiveness:
switch (card.specialty) { return [{ type: EffectType.TrainingEffectiveness, value: args[1] }];
case Specialty.Speed: case EffectType.UniqueColorInitialStats:
return [{ type: EffectType.InitialSpeed, value: args[0] }]; return deck.flatMap((card) => {
case Specialty.Power: switch (card.specialty) {
return [{ type: EffectType.InitialPower, value: args[0] }]; case Specialty.Speed:
case Specialty.Guts: return [{ type: EffectType.InitialSpeed, value: args[0] }];
return [{ type: EffectType.InitialGuts, value: args[0] }]; case Specialty.Power:
case Specialty.Stamina: return [{ type: EffectType.InitialPower, value: args[0] }];
return [{ type: EffectType.InitialStamina, value: args[0] }]; case Specialty.Guts:
case Specialty.Wit: return [{ type: EffectType.InitialGuts, value: args[0] }];
return [{ type: EffectType.InitialWit, value: args[0] }]; case Specialty.Stamina:
default: return [{ type: EffectType.InitialStamina, value: args[0] }];
return [ case Specialty.Wit:
{ type: EffectType.InitialSpeed, value: args[1] }, return [{ type: EffectType.InitialWit, value: args[0] }];
{ type: EffectType.InitialStamina, value: args[1] }, default:
{ type: EffectType.InitialPower, value: args[1] }, return [
{ type: EffectType.InitialGuts, value: args[1] }, { type: EffectType.InitialSpeed, value: args[1] },
{ type: EffectType.InitialWit, 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.UniqueRainbowStack:
case EffectType.UniqueMaxEnergyScaling: return [{ type: args[1], value: args[0] * args[2] }];
return [{ type: args[0], value: args[4] }]; case EffectType.UniqueLowEnergyScaling:
case EffectType.UniqueTotalFriendship: return [{ type: args[0], value: args[3] }];
return [{ type: args[0], value: 600 / args[1] }]; case EffectType.UniqueMaxEnergyScaling:
case EffectType.UniqueCardCount: return [{ type: args[0], value: args[4] }];
return [{ type: args[0], value: 5 * args[1] }]; case EffectType.UniqueTotalFriendship:
case EffectType.UniqueFacilityLevel: return [{ type: args[0], value: 600 / args[1] }];
return [{ type: args[0], value: 5 * args[1] }]; case EffectType.UniqueCardCount:
case EffectType.UniqueDisableFailure: return [{ type: args[0], value: 5 * args[1] }];
return []; case EffectType.UniqueFacilityLevel:
case EffectType.UniqueFriendshipTrainingAdditionalEffect: return [{ type: args[0], value: 5 * args[1] }];
return [{ type: args[0], value: args[1] }]; case EffectType.UniqueDisableFailure:
} return [];
case EffectType.UniqueFriendshipTrainingAdditionalEffect:
return [{ type: args[0], value: args[1] }];
}
} }
export function flattenUnique(unique: UniqueEffect, deck: SupportCard[]): Effect[] { export function flattenUnique(unique: UniqueEffect, deck: SupportCard[]): Effect[] {
const r = [...singleUniqueEffects(unique.type, unique.args, deck)]; const r = [...singleUniqueEffects(unique.type, unique.args, deck)];
if (unique.type2 != null) { if (unique.type2 != null) {
r.push(...singleUniqueEffects(unique.type2, unique.args2!, deck)); r.push(...singleUniqueEffects(unique.type2, unique.args2!, deck));
} }
return r; return r;
} }
File diff suppressed because it is too large Load Diff
+413 -413
View File
@@ -1,415 +1,415 @@
{ {
"id": 10018, "id": 10018,
"name": "[Tracen Academy] Sakura Bakushin O", "name": "[Tracen Academy] Sakura Bakushin O",
"chara_id": 1041, "chara_id": 1041,
"chara_name": "Sakura Bakushin O", "chara_name": "Sakura Bakushin O",
"rarity": 1, "rarity": 1,
"specialty": 101, "specialty": 101,
"type": 1, "type": 1,
"effects": [ "effects": [
[ [
{ {
"type": 1, "type": 1,
"value": 5 "value": 5
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 3, "type": 3,
"value": -1 "value": -1
}, },
{ {
"type": 9, "type": 9,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": 1 "value": 1
}, },
{ {
"type": 16, "type": 16,
"value": 1 "value": 1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": 10 "value": 10
}, },
{ {
"type": 3, "type": 3,
"value": -1 "value": -1
}, },
{ {
"type": 9, "type": 9,
"value": 10 "value": 10
}, },
{ {
"type": 14, "type": 14,
"value": 10 "value": 10
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": 5 "value": 5
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 3, "type": 3,
"value": -1 "value": -1
}, },
{ {
"type": 9, "type": 9,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": 10 "value": 10
}, },
{ {
"type": 2, "type": 2,
"value": 15 "value": 15
}, },
{ {
"type": 3, "type": 3,
"value": -1 "value": -1
}, },
{ {
"type": 9, "type": 9,
"value": 15 "value": 15
}, },
{ {
"type": 14, "type": 14,
"value": 15 "value": 15
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": 20 "value": 20
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": 10 "value": 10
}, },
{ {
"type": 2, "type": 2,
"value": 15 "value": 15
}, },
{ {
"type": 3, "type": 3,
"value": -1 "value": -1
}, },
{ {
"type": 9, "type": 9,
"value": 15 "value": 15
}, },
{ {
"type": 14, "type": 14,
"value": 15 "value": 15
}, },
{ {
"type": 15, "type": 15,
"value": 5 "value": 5
}, },
{ {
"type": 16, "type": 16,
"value": 10 "value": 10
}, },
{ {
"type": 19, "type": 19,
"value": 20 "value": 20
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 3, "type": 3,
"value": -1 "value": -1
}, },
{ {
"type": 9, "type": 9,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 3, "type": 3,
"value": -1 "value": -1
}, },
{ {
"type": 9, "type": 9,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": 15 "value": 15
}, },
{ {
"type": 2, "type": 2,
"value": 25 "value": 25
}, },
{ {
"type": 3, "type": 3,
"value": -1 "value": -1
}, },
{ {
"type": 9, "type": 9,
"value": 20 "value": 20
}, },
{ {
"type": 14, "type": 14,
"value": 20 "value": 20
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": 35 "value": 35
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 3, "type": 3,
"value": 1 "value": 1
}, },
{ {
"type": 9, "type": 9,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": 5 "value": 5
}, },
{ {
"type": 16, "type": 16,
"value": 15 "value": 15
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 3, "type": 3,
"value": -1 "value": -1
}, },
{ {
"type": 9, "type": 9,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 3, "type": 3,
"value": -1 "value": -1
}, },
{ {
"type": 9, "type": 9,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
] ]
], ],
"hints": [ "hints": [
{ {
"skill_id": 200652 "skill_id": 200652
}, },
{ {
"skill_id": 200791 "skill_id": 200791
}, },
{ {
"skill_id": 200841 "skill_id": 200841
}, },
{ {
"skill_id": 200962 "skill_id": 200962
}, },
{ {
"skill_id": 200972 "skill_id": 200972
}, },
{ {
"skill_id": 200982 "skill_id": 200982
}, },
{ {
"skill_id": 200992 "skill_id": 200992
}, },
{ {
"skill_id": 201012 "skill_id": 201012
}, },
{ {
"speed": 6, "speed": 6,
"power": 2 "power": 2
} }
] ]
} }
+423 -427
View File
@@ -1,429 +1,425 @@
{ {
"id": 20042, "id": 20042,
"name": "[The Perfect Morning Greeting!] Sakura Bakushin O", "name": "[The Perfect Morning Greeting!] Sakura Bakushin O",
"chara_id": 1041, "chara_id": 1041,
"chara_name": "Sakura Bakushin O", "chara_name": "Sakura Bakushin O",
"rarity": 2, "rarity": 2,
"specialty": 102, "specialty": 102,
"type": 1, "type": 1,
"effects": [ "effects": [
[ [
{ {
"type": 1, "type": 1,
"value": 10 "value": 10
}, },
{ {
"type": 5, "type": 5,
"value": -1 "value": -1
}, },
{ {
"type": 8, "type": 8,
"value": -1 "value": -1
}, },
{ {
"type": 11, "type": 11,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": 1 "value": 1
}, },
{ {
"type": 16, "type": 16,
"value": 1 "value": 1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 5, "type": 5,
"value": -1 "value": -1
}, },
{ {
"type": 8, "type": 8,
"value": -1 "value": -1
}, },
{ {
"type": 11, "type": 11,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": 5 "value": 5
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 5, "type": 5,
"value": -1 "value": -1
}, },
{ {
"type": 8, "type": 8,
"value": 1 "value": 1
}, },
{ {
"type": 11, "type": 11,
"value": 10 "value": 10
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 5, "type": 5,
"value": -1 "value": -1
}, },
{ {
"type": 8, "type": 8,
"value": -1 "value": -1
}, },
{ {
"type": 11, "type": 11,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": 15 "value": 15
}, },
{ {
"type": 5, "type": 5,
"value": -1 "value": -1
}, },
{ {
"type": 8, "type": 8,
"value": 5 "value": 5
}, },
{ {
"type": 11, "type": 11,
"value": 15 "value": 15
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": 15 "value": 15
}, },
{ {
"type": 5, "type": 5,
"value": -1 "value": -1
}, },
{ {
"type": 8, "type": 8,
"value": 5 "value": 5
}, },
{ {
"type": 11, "type": 11,
"value": 15 "value": 15
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": 5 "value": 5
}, },
{ {
"type": 16, "type": 16,
"value": 15 "value": 15
}, },
{ {
"type": 19, "type": 19,
"value": 35 "value": 35
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 5, "type": 5,
"value": -1 "value": -1
}, },
{ {
"type": 8, "type": 8,
"value": -1 "value": -1
}, },
{ {
"type": 11, "type": 11,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": 10 "value": 10
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 5, "type": 5,
"value": -1 "value": -1
}, },
{ {
"type": 8, "type": 8,
"value": -1 "value": -1
}, },
{ {
"type": 11, "type": 11,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": 20 "value": 20
}, },
{ {
"type": 5, "type": 5,
"value": -1 "value": -1
}, },
{ {
"type": 8, "type": 8,
"value": 5 "value": 5
}, },
{ {
"type": 11, "type": 11,
"value": 20 "value": 20
}, },
{ {
"type": 14, "type": 14,
"value": 20 "value": 20
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 5, "type": 5,
"value": 1 "value": 1
}, },
{ {
"type": 8, "type": 8,
"value": -1 "value": -1
}, },
{ {
"type": 11, "type": 11,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": 10 "value": 10
}, },
{ {
"type": 16, "type": 16,
"value": 20 "value": 20
}, },
{ {
"type": 19, "type": 19,
"value": 50 "value": 50
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 5, "type": 5,
"value": -1 "value": -1
}, },
{ {
"type": 8, "type": 8,
"value": -1 "value": -1
}, },
{ {
"type": 11, "type": 11,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 19, "type": 19,
"value": -1 "value": -1
} }
] ]
], ],
"unique_effect": { "unique_effect": {
"name": "The Perfect Morning Greeting!", "name": "The Perfect Morning Greeting!",
"description": "Friendship Bonus and Specialty Priority", "description": "Friendship Bonus and Specialty Priority",
"card_level": 25, "card_level": 25,
"type": 1, "type": 1,
"args": [ "args": [10],
10 "type2": 19,
], "args2": [20],
"type2": 19, "idle_mode_sub_rate": 0
"args2": [ },
20 "hints": [
], {
"idle_mode_sub_rate": 0 "skill_id": 200652
}, },
"hints": [ {
{ "skill_id": 200791
"skill_id": 200652 },
}, {
{ "skill_id": 200841
"skill_id": 200791 },
}, {
{ "skill_id": 200962
"skill_id": 200841 },
}, {
{ "skill_id": 200972
"skill_id": 200962 },
}, {
{ "skill_id": 200982
"skill_id": 200972 },
}, {
{ "skill_id": 200992
"skill_id": 200982 },
}, {
{ "skill_id": 201012
"skill_id": 200992 },
}, {
{ "stamina": 2,
"skill_id": 201012 "power": 6
}, }
{ ]
"stamina": 2,
"power": 6
}
]
} }
+466 -469
View File
@@ -1,471 +1,468 @@
{ {
"id": 30083, "id": 30083,
"name": "[Super! Sonic! Flower Power!] Sakura Bakushin O", "name": "[Super! Sonic! Flower Power!] Sakura Bakushin O",
"chara_id": 1041, "chara_id": 1041,
"chara_name": "Sakura Bakushin O", "chara_name": "Sakura Bakushin O",
"rarity": 3, "rarity": 3,
"specialty": 103, "specialty": 103,
"type": 1, "type": 1,
"effects": [ "effects": [
[ [
{ {
"type": 1, "type": 1,
"value": 10 "value": 10
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 6, "type": 6,
"value": -1 "value": -1
}, },
{ {
"type": 12, "type": 12,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": 1 "value": 1
}, },
{ {
"type": 16, "type": 16,
"value": 1 "value": 1
}, },
{ {
"type": 17, "type": 17,
"value": 1 "value": 1
}, },
{ {
"type": 18, "type": 18,
"value": 5 "value": 5
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 6, "type": 6,
"value": -1 "value": -1
}, },
{ {
"type": 12, "type": 12,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 17, "type": 17,
"value": -1 "value": -1
}, },
{ {
"type": 18, "type": 18,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 6, "type": 6,
"value": -1 "value": -1
}, },
{ {
"type": 12, "type": 12,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": 10 "value": 10
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 17, "type": 17,
"value": -1 "value": -1
}, },
{ {
"type": 18, "type": 18,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": 10 "value": 10
}, },
{ {
"type": 6, "type": 6,
"value": -1 "value": -1
}, },
{ {
"type": 12, "type": 12,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 17, "type": 17,
"value": -1 "value": -1
}, },
{ {
"type": 18, "type": 18,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 6, "type": 6,
"value": -1 "value": -1
}, },
{ {
"type": 12, "type": 12,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 17, "type": 17,
"value": -1 "value": -1
}, },
{ {
"type": 18, "type": 18,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": 20 "value": 20
}, },
{ {
"type": 6, "type": 6,
"value": -1 "value": -1
}, },
{ {
"type": 12, "type": 12,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": 20 "value": 20
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 17, "type": 17,
"value": -1 "value": -1
}, },
{ {
"type": 18, "type": 18,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": 25 "value": 25
}, },
{ {
"type": 2, "type": 2,
"value": 20 "value": 20
}, },
{ {
"type": 6, "type": 6,
"value": -1 "value": -1
}, },
{ {
"type": 12, "type": 12,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": 20 "value": 20
}, },
{ {
"type": 15, "type": 15,
"value": 5 "value": 5
}, },
{ {
"type": 16, "type": 16,
"value": 15 "value": 15
}, },
{ {
"type": 17, "type": 17,
"value": 2 "value": 2
}, },
{ {
"type": 18, "type": 18,
"value": 40 "value": 40
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 6, "type": 6,
"value": 1 "value": 1
}, },
{ {
"type": 12, "type": 12,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 17, "type": 17,
"value": -1 "value": -1
}, },
{ {
"type": 18, "type": 18,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 6, "type": 6,
"value": -1 "value": -1
}, },
{ {
"type": 12, "type": 12,
"value": -1 "value": -1
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 17, "type": 17,
"value": -1 "value": -1
}, },
{ {
"type": 18, "type": 18,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": -1 "value": -1
}, },
{ {
"type": 2, "type": 2,
"value": 30 "value": 30
}, },
{ {
"type": 6, "type": 6,
"value": -1 "value": -1
}, },
{ {
"type": 12, "type": 12,
"value": 15 "value": 15
}, },
{ {
"type": 14, "type": 14,
"value": 25 "value": 25
}, },
{ {
"type": 15, "type": 15,
"value": -1 "value": -1
}, },
{ {
"type": 16, "type": 16,
"value": -1 "value": -1
}, },
{ {
"type": 17, "type": 17,
"value": -1 "value": -1
}, },
{ {
"type": 18, "type": 18,
"value": -1 "value": -1
} }
], ],
[ [
{ {
"type": 1, "type": 1,
"value": 35 "value": 35
}, },
{ {
"type": 2, "type": 2,
"value": -1 "value": -1
}, },
{ {
"type": 6, "type": 6,
"value": -1 "value": -1
}, },
{ {
"type": 12, "type": 12,
"value": 30 "value": 30
}, },
{ {
"type": 14, "type": 14,
"value": -1 "value": -1
}, },
{ {
"type": 15, "type": 15,
"value": 10 "value": 10
}, },
{ {
"type": 16, "type": 16,
"value": 20 "value": 20
}, },
{ {
"type": 17, "type": 17,
"value": 3 "value": 3
}, },
{ {
"type": 18, "type": 18,
"value": 50 "value": 50
} }
] ]
], ],
"unique_effect": { "unique_effect": {
"name": "Super! Sonic! Flower Power!", "name": "Super! Sonic! Flower Power!",
"description": "Increases Training Effectiveness when not on preferred training. (Friendship 80+)", "description": "Increases Training Effectiveness when not on preferred training. (Friendship 80+)",
"card_level": 30, "card_level": 30,
"type": 102, "type": 102,
"args": [ "args": [80, 20],
80, "idle_mode_sub_rate": 30
20 },
], "hints": [
"idle_mode_sub_rate": 30 {
}, "skill_id": 200652
"hints": [ },
{ {
"skill_id": 200652 "skill_id": 200791
}, },
{ {
"skill_id": 200791 "skill_id": 200841
}, },
{ {
"skill_id": 200841 "skill_id": 200962
}, },
{ {
"skill_id": 200962 "skill_id": 200972
}, },
{ {
"skill_id": 200972 "skill_id": 200982
}, },
{ {
"skill_id": 200982 "skill_id": 200992
}, },
{ {
"skill_id": 200992 "skill_id": 201012
}, },
{ {
"skill_id": 201012 "speed": 1,
}, "power": 1,
{ "guts": 6
"speed": 1, }
"power": 1, ]
"guts": 6
}
]
} }
+226 -226
View File
@@ -2,71 +2,71 @@ import * as z from 'zod';
import * as race from './race'; import * as race from './race';
const Skill = z.strictObject({ const Skill = z.strictObject({
skill_id: z.int32(), skill_id: z.int32(),
level: z.int32(), level: z.int32(),
}); });
export type Skill = z.infer<typeof Skill>; export type Skill = z.infer<typeof Skill>;
const SkillTip = z.strictObject({ const SkillTip = z.strictObject({
group_id: z.int32(), group_id: z.int32(),
rarity: z.int32(), rarity: z.int32(),
level: z.int32(), level: z.int32(),
}); });
export type SkillTip = z.infer<typeof SkillTip>; export type SkillTip = z.infer<typeof SkillTip>;
/** SingleModeSupportCard */ /** SingleModeSupportCard */
const SupportCard = z.strictObject({ const SupportCard = z.strictObject({
position: z.int32(), position: z.int32(),
support_card_id: z.int32(), support_card_id: z.int32(),
limit_break_count: z.int32(), limit_break_count: z.int32(),
exp: z.int32(), exp: z.int32(),
owner_viewer_id: z.number(), owner_viewer_id: z.number(),
}); });
export type SupportCard = z.infer<typeof SupportCard>; export type SupportCard = z.infer<typeof SupportCard>;
const GroupOuting = z.strictObject({ const GroupOuting = z.strictObject({
chara_id: z.int32(), chara_id: z.int32(),
is_outing: z.int32(), is_outing: z.int32(),
story_step: z.int32(), story_step: z.int32(),
}); });
export type GroupOuting = z.infer<typeof GroupOuting>; export type GroupOuting = z.infer<typeof GroupOuting>;
const Evaluation = z.strictObject({ const Evaluation = z.strictObject({
target_id: z.int32(), target_id: z.int32(),
training_partner_id: z.int32(), training_partner_id: z.int32(),
evaluation: z.int32(), evaluation: z.int32(),
is_outing: z.int32(), is_outing: z.int32(),
story_step: z.int32(), story_step: z.int32(),
is_appear: z.int32(), is_appear: z.int32(),
group_outing_info_array: z.array(GroupOuting), group_outing_info_array: z.array(GroupOuting),
}); });
export type Evaluation = z.infer<typeof Evaluation>; export type Evaluation = z.infer<typeof Evaluation>;
const TrainingLevel = z.strictObject({ const TrainingLevel = z.strictObject({
command_id: z.int32(), command_id: z.int32(),
level: z.int32(), level: z.int32(),
}); });
export type TrainingLevel = z.infer<typeof TrainingLevel>; export type TrainingLevel = z.infer<typeof TrainingLevel>;
const GuestOuting = z.strictObject({ const GuestOuting = z.strictObject({
support_card_id: z.int32(), support_card_id: z.int32(),
story_step: z.int32(), story_step: z.int32(),
group_outing_info_array: z.array(GroupOuting), group_outing_info_array: z.array(GroupOuting),
}); });
export type GuestOuting = z.infer<typeof GuestOuting>; export type GuestOuting = z.infer<typeof GuestOuting>;
/** SingleModeSkillUpgrade */ /** SingleModeSkillUpgrade */
const SkillUpgrade = z.strictObject({ const SkillUpgrade = z.strictObject({
condition_id: z.int32(), condition_id: z.int32(),
total_count: z.int32(), total_count: z.int32(),
current_count: z.int32(), current_count: z.int32(),
}); });
export type SkillUpgrade = z.infer<typeof SkillUpgrade>; export type SkillUpgrade = z.infer<typeof SkillUpgrade>;
@@ -74,290 +74,290 @@ export type SkillUpgrade = z.infer<typeof SkillUpgrade>;
const AptitudeLevel = z.enum(race.AptitudeLevel); const AptitudeLevel = z.enum(race.AptitudeLevel);
const SingleModeChara = z.strictObject({ const SingleModeChara = z.strictObject({
single_mode_chara_id: z.int32(), single_mode_chara_id: z.int32(),
card_id: z.int32(), card_id: z.int32(),
chara_grade: z.int32(), chara_grade: z.int32(),
speed: z.int32(), speed: z.int32(),
stamina: z.int32(), stamina: z.int32(),
power: z.int32(), power: z.int32(),
wiz: z.int32(), wiz: z.int32(),
guts: z.int32(), guts: z.int32(),
vital: z.int32(), vital: z.int32(),
max_speed: z.int32(), max_speed: z.int32(),
max_stamina: z.int32(), max_stamina: z.int32(),
max_power: z.int32(), max_power: z.int32(),
max_wiz: z.int32(), max_wiz: z.int32(),
max_guts: z.int32(), max_guts: z.int32(),
default_max_speed: z.int32(), default_max_speed: z.int32(),
default_max_stamina: z.int32(), default_max_stamina: z.int32(),
default_max_power: z.int32(), default_max_power: z.int32(),
default_max_wiz: z.int32(), default_max_wiz: z.int32(),
default_max_guts: z.int32(), default_max_guts: z.int32(),
max_vital: z.int32(), max_vital: z.int32(),
motivation: z.int32(), motivation: z.int32(),
fans: z.int32(), fans: z.int32(),
rarity: z.int32(), rarity: z.int32(),
race_program_id: z.int32(), race_program_id: z.int32(),
reserve_race_program_id: z.int32(), reserve_race_program_id: z.int32(),
race_running_style: z.int32(), race_running_style: z.int32(),
is_short_race: z.int32(), is_short_race: z.int32(),
talent_level: z.int32(), talent_level: z.int32(),
skill_array: z.array(Skill), skill_array: z.array(Skill),
disable_skill_id_array: z.array(z.int32()), disable_skill_id_array: z.array(z.int32()),
skill_tips_array: z.array(SkillTip), skill_tips_array: z.array(SkillTip),
support_card_array: z.array(SupportCard), support_card_array: z.array(SupportCard),
succession_trained_chara_id_1: z.int32(), succession_trained_chara_id_1: z.int32(),
succession_trained_chara_id_2: z.int32(), succession_trained_chara_id_2: z.int32(),
proper_distance_short: AptitudeLevel, proper_distance_short: AptitudeLevel,
proper_distance_mile: AptitudeLevel, proper_distance_mile: AptitudeLevel,
proper_distance_middle: AptitudeLevel, proper_distance_middle: AptitudeLevel,
proper_distance_long: AptitudeLevel, proper_distance_long: AptitudeLevel,
proper_running_style_nige: AptitudeLevel, proper_running_style_nige: AptitudeLevel,
proper_running_style_senko: AptitudeLevel, proper_running_style_senko: AptitudeLevel,
proper_running_style_sashi: AptitudeLevel, proper_running_style_sashi: AptitudeLevel,
proper_running_style_oikomi: AptitudeLevel, proper_running_style_oikomi: AptitudeLevel,
proper_ground_turf: AptitudeLevel, proper_ground_turf: AptitudeLevel,
proper_ground_dirt: AptitudeLevel, proper_ground_dirt: AptitudeLevel,
turn: z.int32(), turn: z.int32(),
skill_point: z.int32(), skill_point: z.int32(),
short_cut_state: z.int32(), short_cut_state: z.int32(),
state: z.int32(), state: z.int32(),
playing_state: z.int32(), playing_state: z.int32(),
scenario_id: z.int32(), scenario_id: z.int32(),
route_id: z.int32(), route_id: z.int32(),
start_time: z.string(), start_time: z.string(),
evaluation_info_array: z.array(Evaluation), evaluation_info_array: z.array(Evaluation),
training_level_info_array: z.array(TrainingLevel), training_level_info_array: z.array(TrainingLevel),
nickname_id_array: z.array(z.int32()), nickname_id_array: z.array(z.int32()),
chara_effect_id_array: z.array(z.int32()), chara_effect_id_array: z.array(z.int32()),
route_race_id_array: z.array(z.int32()), route_race_id_array: z.array(z.int32()),
guest_outing_info_array: z.array(GuestOuting), guest_outing_info_array: z.array(GuestOuting),
skill_upgrade_info_array: z.array(SkillUpgrade), skill_upgrade_info_array: z.array(SkillUpgrade),
}); });
const ZeroedSingleModeChara = z.strictObject({ const ZeroedSingleModeChara = z.strictObject({
single_mode_chara_id: z.literal(0), single_mode_chara_id: z.literal(0),
card_id: z.int32(), card_id: z.int32(),
chara_grade: z.literal(0), chara_grade: z.literal(0),
speed: z.literal(0), speed: z.literal(0),
stamina: z.literal(0), stamina: z.literal(0),
power: z.literal(0), power: z.literal(0),
wiz: z.literal(0), wiz: z.literal(0),
guts: z.literal(0), guts: z.literal(0),
vital: z.literal(0), vital: z.literal(0),
max_speed: z.literal(0), max_speed: z.literal(0),
max_stamina: z.literal(0), max_stamina: z.literal(0),
max_power: z.literal(0), max_power: z.literal(0),
max_wiz: z.literal(0), max_wiz: z.literal(0),
max_guts: z.literal(0), max_guts: z.literal(0),
default_max_speed: z.literal(0), default_max_speed: z.literal(0),
default_max_stamina: z.literal(0), default_max_stamina: z.literal(0),
default_max_power: z.literal(0), default_max_power: z.literal(0),
default_max_wiz: z.literal(0), default_max_wiz: z.literal(0),
default_max_guts: z.literal(0), default_max_guts: z.literal(0),
max_vital: z.literal(0), max_vital: z.literal(0),
motivation: z.literal(0), motivation: z.literal(0),
fans: z.literal(0), fans: z.literal(0),
rarity: z.int32(), rarity: z.int32(),
race_program_id: z.literal(0), race_program_id: z.literal(0),
reserve_race_program_id: z.literal(0), reserve_race_program_id: z.literal(0),
race_running_style: z.literal(0), race_running_style: z.literal(0),
is_short_race: z.literal(0), is_short_race: z.literal(0),
talent_level: z.int32(), talent_level: z.int32(),
skill_array: z.array(z.never()), skill_array: z.array(z.never()),
disable_skill_id_array: z.array(z.never()), disable_skill_id_array: z.array(z.never()),
skill_tips_array: z.array(z.never()), skill_tips_array: z.array(z.never()),
support_card_array: z.array(z.never()), support_card_array: z.array(z.never()),
succession_trained_chara_id_1: z.int32(), succession_trained_chara_id_1: z.int32(),
succession_trained_chara_id_2: z.int32(), succession_trained_chara_id_2: z.int32(),
proper_distance_short: z.literal(0), proper_distance_short: z.literal(0),
proper_distance_mile: z.literal(0), proper_distance_mile: z.literal(0),
proper_distance_middle: z.literal(0), proper_distance_middle: z.literal(0),
proper_distance_long: z.literal(0), proper_distance_long: z.literal(0),
proper_running_style_nige: z.literal(0), proper_running_style_nige: z.literal(0),
proper_running_style_senko: z.literal(0), proper_running_style_senko: z.literal(0),
proper_running_style_sashi: z.literal(0), proper_running_style_sashi: z.literal(0),
proper_running_style_oikomi: z.literal(0), proper_running_style_oikomi: z.literal(0),
proper_ground_turf: z.literal(0), proper_ground_turf: z.literal(0),
proper_ground_dirt: z.literal(0), proper_ground_dirt: z.literal(0),
turn: z.literal(0), turn: z.literal(0),
skill_point: z.literal(0), skill_point: z.literal(0),
short_cut_state: z.literal(0), short_cut_state: z.literal(0),
state: z.literal(0), state: z.literal(0),
playing_state: z.literal(0), playing_state: z.literal(0),
scenario_id: z.int32(), scenario_id: z.int32(),
route_id: z.literal(0), route_id: z.literal(0),
start_time: z.literal(''), start_time: z.literal(''),
evaluation_info_array: z.array(z.never()), evaluation_info_array: z.array(z.never()),
training_level_info_array: z.array(z.never()), training_level_info_array: z.array(z.never()),
nickname_id_array: z.array(z.never()), nickname_id_array: z.array(z.never()),
chara_effect_id_array: z.array(z.never()), chara_effect_id_array: z.array(z.never()),
route_race_id_array: z.array(z.never()), route_race_id_array: z.array(z.never()),
guest_outing_info_array: z.array(z.never()), guest_outing_info_array: z.array(z.never()),
skill_upgrade_info_array: z.array(z.never()), skill_upgrade_info_array: z.array(z.never()),
}); });
export type SingleModeChara = z.infer<typeof SingleModeChara>; export type SingleModeChara = z.infer<typeof SingleModeChara>;
const ProgressInfo = z.strictObject({ const ProgressInfo = z.strictObject({
chara_info: z.optional(SingleModeChara.or(ZeroedSingleModeChara)), chara_info: z.optional(SingleModeChara.or(ZeroedSingleModeChara)),
start_time: z.string(), start_time: z.string(),
end_time: z.string(), end_time: z.string(),
dress_id: z.int32(), dress_id: z.int32(),
}); });
export type ProgressInfo = z.infer<typeof ProgressInfo>; export type ProgressInfo = z.infer<typeof ProgressInfo>;
const CharaEffectLog = z.strictObject({ const CharaEffectLog = z.strictObject({
chara_effect_id: z.int32(), chara_effect_id: z.int32(),
is_active: z.boolean(), is_active: z.boolean(),
}); });
export type CharaEffectLog = z.infer<typeof CharaEffectLog>; export type CharaEffectLog = z.infer<typeof CharaEffectLog>;
/** IdleSingleModeSignedInt */ /** IdleSingleModeSignedInt */
const SignedInt = z.strictObject({ const SignedInt = z.strictObject({
sign: z.int32(), sign: z.int32(),
value: z.int32(), value: z.int32(),
}); });
export type SignedInt = z.infer<typeof SignedInt>; export type SignedInt = z.infer<typeof SignedInt>;
/** IdleSingleModeGainInfo */ /** IdleSingleModeGainInfo */
const GainInfo = z.strictObject({ const GainInfo = z.strictObject({
speed: SignedInt, speed: SignedInt,
stamina: SignedInt, stamina: SignedInt,
power: SignedInt, power: SignedInt,
wiz: SignedInt, wiz: SignedInt,
guts: SignedInt, guts: SignedInt,
max_speed: z.int32(), max_speed: z.int32(),
max_stamina: z.int32(), max_stamina: z.int32(),
max_power: z.int32(), max_power: z.int32(),
max_wiz: z.int32(), max_wiz: z.int32(),
max_guts: z.int32(), max_guts: z.int32(),
proper_distance_short: z.int32(), proper_distance_short: z.int32(),
proper_distance_mile: z.int32(), proper_distance_mile: z.int32(),
proper_distance_middle: z.int32(), proper_distance_middle: z.int32(),
proper_distance_long: z.int32(), proper_distance_long: z.int32(),
proper_running_style_nige: z.int32(), proper_running_style_nige: z.int32(),
proper_running_style_senko: z.int32(), proper_running_style_senko: z.int32(),
proper_running_style_sashi: z.int32(), proper_running_style_sashi: z.int32(),
proper_running_style_oikomi: z.int32(), proper_running_style_oikomi: z.int32(),
proper_ground_turf: z.int32(), proper_ground_turf: z.int32(),
proper_ground_dirt: z.int32(), proper_ground_dirt: z.int32(),
skill_point: z.int32(), skill_point: z.int32(),
skill_tips_array: z.array(SkillTip), skill_tips_array: z.array(SkillTip),
}); });
export type GainInfo = z.infer<typeof GainInfo>; export type GainInfo = z.infer<typeof GainInfo>;
/** IdleSingleModeSupportCardGain */ /** IdleSingleModeSupportCardGain */
const SupportCardGain = z.strictObject({ const SupportCardGain = z.strictObject({
support_card_id: z.int32(), support_card_id: z.int32(),
gain_info: GainInfo, gain_info: GainInfo,
}); });
export type SupportCardGain = z.infer<typeof SupportCardGain>; export type SupportCardGain = z.infer<typeof SupportCardGain>;
const Factor = z.strictObject({ const Factor = z.strictObject({
factor_id: z.int32(), factor_id: z.int32(),
level: z.int32(), level: z.int32(),
}); });
export type Factor = z.infer<typeof Factor>; export type Factor = z.infer<typeof Factor>;
/** IdleSingleModeSuccessionFactorGain */ /** IdleSingleModeSuccessionFactorGain */
const SuccessionFactorGain = z.strictObject({ const SuccessionFactorGain = z.strictObject({
year: z.int32(), year: z.int32(),
gain_factor_info_array: z.array(Factor), gain_factor_info_array: z.array(Factor),
}); });
export type SuccessionFactorGain = z.infer<typeof SuccessionFactorGain>; export type SuccessionFactorGain = z.infer<typeof SuccessionFactorGain>;
const SingleRaceHistory = z.strictObject({ const SingleRaceHistory = z.strictObject({
turn: z.int32(), turn: z.int32(),
program_id: z.int32(), program_id: z.int32(),
weather: z.int32(), weather: z.int32(),
ground_condition: z.int32(), ground_condition: z.int32(),
running_style: z.int32(), running_style: z.int32(),
result_rank: z.int32(), result_rank: z.int32(),
frame_order: z.int32(), frame_order: z.int32(),
npc_count: z.int32(), npc_count: z.int32(),
}); });
export type SingleRaceHistory = z.infer<typeof SingleRaceHistory>; export type SingleRaceHistory = z.infer<typeof SingleRaceHistory>;
const RaceReward = z.strictObject({ const RaceReward = z.strictObject({
item_type: z.int32(), item_type: z.int32(),
item_id: z.int32(), item_id: z.int32(),
item_num: z.int32(), item_num: z.int32(),
}); });
export type RaceReward = z.infer<typeof RaceReward>; export type RaceReward = z.infer<typeof RaceReward>;
const RaceRewardLimit = z.strictObject({ const RaceRewardLimit = z.strictObject({
reward_id: z.int32(), reward_id: z.int32(),
item_type: z.int32(), item_type: z.int32(),
item_id: z.int32(), item_id: z.int32(),
item_num: z.int32(), item_num: z.int32(),
rest_count: z.int32(), rest_count: z.int32(),
}); });
export type RaceRewardLimit = z.infer<typeof RaceRewardLimit>; export type RaceRewardLimit = z.infer<typeof RaceRewardLimit>;
const CharaRaceReward = z.strictObject({ const CharaRaceReward = z.strictObject({
result_rank: z.int32(), result_rank: z.int32(),
result_time: z.int32(), result_time: z.int32(),
race_reward: z.array(RaceReward), race_reward: z.array(RaceReward),
race_reward_bonus: z.array(RaceReward), race_reward_bonus: z.array(RaceReward),
race_reward_plus_bonus: z.array(RaceReward), race_reward_plus_bonus: z.array(RaceReward),
race_reward_bonus_win: z.array(RaceReward), race_reward_bonus_win: z.array(RaceReward),
race_reward_limit: z.optional(z.array(RaceRewardLimit)), race_reward_limit: z.optional(z.array(RaceRewardLimit)),
gained_fans: z.int32(), gained_fans: z.int32(),
campaign_id_array: z.array(z.int32()), campaign_id_array: z.array(z.int32()),
}); });
export type CharaRaceReward = z.infer<typeof CharaRaceReward>; export type CharaRaceReward = z.infer<typeof CharaRaceReward>;
/** IdleSingleModeRaceHistory */ /** IdleSingleModeRaceHistory */
const RaceHistory = z.strictObject({ const RaceHistory = z.strictObject({
race_history: SingleRaceHistory, race_history: SingleRaceHistory,
race_reward_info: CharaRaceReward, race_reward_info: CharaRaceReward,
lose_tips_id: z.int32(), lose_tips_id: z.int32(),
}); });
export type RaceHistory = z.infer<typeof RaceHistory>; export type RaceHistory = z.infer<typeof RaceHistory>;
/** IdleSingleModeProgressLog */ /** IdleSingleModeProgressLog */
const ProgressLog = z.strictObject({ const ProgressLog = z.strictObject({
chara_effect_log_array: z.array(CharaEffectLog), chara_effect_log_array: z.array(CharaEffectLog),
support_card_gain_info_array: z.array(SupportCardGain), support_card_gain_info_array: z.array(SupportCardGain),
event_gain_info: GainInfo, event_gain_info: GainInfo,
succession_gain_info: GainInfo, succession_gain_info: GainInfo,
succession_factor_gain_array: z.array(SuccessionFactorGain), succession_factor_gain_array: z.array(SuccessionFactorGain),
race_history_array: z.array(RaceHistory), race_history_array: z.array(RaceHistory),
gain_skill_id_array: z.array(z.int32()), gain_skill_id_array: z.array(z.int32()),
total_skill_point: z.int32(), total_skill_point: z.int32(),
}); });
export type ProgressLog = z.infer<typeof ProgressLog>; export type ProgressLog = z.infer<typeof ProgressLog>;
const AddItem = z.strictObject({ const AddItem = z.strictObject({
item_id: z.int32(), item_id: z.int32(),
number: z.int32(), number: z.int32(),
}); });
export type AddItem = z.infer<typeof AddItem>; export type AddItem = z.infer<typeof AddItem>;
const RewardSummary = z.strictObject({ const RewardSummary = z.strictObject({
add_item_list: z.array(AddItem), add_item_list: z.array(AddItem),
}); });
export type RewardSummary = z.infer<typeof RewardSummary>; export type RewardSummary = z.infer<typeof RewardSummary>;
const End = z.strictObject({ const End = z.strictObject({
chara_info: SingleModeChara, chara_info: SingleModeChara,
reward_summary_info: RewardSummary, reward_summary_info: RewardSummary,
}); });
export type End = z.infer<typeof End>; export type End = z.infer<typeof End>;
@@ -366,9 +366,9 @@ export type End = z.infer<typeof End>;
* WorkIdleSingleMode, or all the data extracted from an ISM career. * WorkIdleSingleMode, or all the data extracted from an ISM career.
*/ */
export const Career = z.object({ export const Career = z.object({
progress_info: ProgressInfo, progress_info: ProgressInfo,
progress_log_info: ProgressLog, progress_log_info: ProgressLog,
end_info: End, end_info: End,
}); });
export type Career = z.infer<typeof Career>; export type Career = z.infer<typeof Career>;
@@ -3,145 +3,158 @@ import * as support from '$lib/data/support';
import * as scenario from '$lib/data/scenario'; import * as scenario from '$lib/data/scenario';
function gainTotalStats(gain: ism.GainInfo) { 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 = [ export const DEPENDENT = [
{ {
name: 'Total Stats', name: 'Total Stats',
map: (gain: ism.GainInfo, _effects: support.Effect[]) => gainTotalStats(gain), map: (gain: ism.GainInfo) => gainTotalStats(gain),
}, },
{ {
name: 'Total Stats + SP', name: 'Total Stats + SP',
map: (gain: ism.GainInfo, _effects: support.Effect[]) => gainTotalStats(gain) + gain.skill_point, map: (gain: ism.GainInfo) => gainTotalStats(gain) + gain.skill_point,
}, },
{ {
name: 'Speed', name: 'Speed',
map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.speed.value, map: (gain: ism.GainInfo) => gain.speed.value,
}, },
{ {
name: 'Stamina', name: 'Stamina',
map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.stamina.value, map: (gain: ism.GainInfo) => gain.stamina.value,
}, },
{ {
name: 'Power', name: 'Power',
map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.power.value, map: (gain: ism.GainInfo) => gain.power.value,
}, },
{ {
name: 'Guts', name: 'Guts',
map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.guts.value, map: (gain: ism.GainInfo) => gain.guts.value,
}, },
{ {
name: 'Wit', name: 'Wit',
map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.wiz.value, map: (gain: ism.GainInfo) => gain.wiz.value,
}, },
{ {
name: 'SP', name: 'SP',
map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.skill_point, map: (gain: ism.GainInfo) => gain.skill_point,
}, },
{ {
name: 'Skill Hints', name: 'Skill Hints',
map: (gain: ism.GainInfo, effects: support.Effect[]) => { map: (gain: ism.GainInfo, effects: support.Effect[]) => {
// NOTE(zephyr): reduction starts with 1 because we want the value // NOTE(zephyr): reduction starts with 1 because we want the value
// of each hint, not just the bonus from effects // 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); 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); return gain.skill_tips_array.reduce((n, t) => n + Math.ceil(t.level / hintLevels), 0);
}, },
}, },
{ {
name: 'Skills', name: 'Skills',
map: (gain: ism.GainInfo, _effects: support.Effect[]) => gain.skill_tips_array.length, map: (gain: ism.GainInfo) => gain.skill_tips_array.length,
}, },
] as const; ] as const;
function label(c: ism.Career): string { 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 = [ export const INDEPENDENT = [
{ {
name: 'Friendship Bonus', name: 'Friendship Bonus',
effect: support.EffectType.FriendshipBonus, effect: support.EffectType.FriendshipBonus,
}, },
{ {
name: 'Mood Effect', name: 'Mood Effect',
effect: support.EffectType.MoodEffect, effect: support.EffectType.MoodEffect,
}, },
{ {
name: 'Speed Bonus', name: 'Speed Bonus',
effect: support.EffectType.SpeedBonus, effect: support.EffectType.SpeedBonus,
}, },
{ {
name: 'Stamina Bonus', name: 'Stamina Bonus',
effect: support.EffectType.StaminaBonus, effect: support.EffectType.StaminaBonus,
}, },
{ {
name: 'Power Bonus', name: 'Power Bonus',
effect: support.EffectType.PowerBonus, effect: support.EffectType.PowerBonus,
}, },
{ {
name: 'Guts Bonus', name: 'Guts Bonus',
effect: support.EffectType.GutsBonus, effect: support.EffectType.GutsBonus,
}, },
{ {
name: 'Wit Bonus', name: 'Wit Bonus',
effect: support.EffectType.WitBonus, effect: support.EffectType.WitBonus,
}, },
{ {
name: 'Skill Point Bonus', name: 'Skill Point Bonus',
effect: support.EffectType.SkillPointBonus, effect: support.EffectType.SkillPointBonus,
}, },
{ {
name: 'Training Effectiveness', name: 'Training Effectiveness',
effect: support.EffectType.TrainingEffectiveness, effect: support.EffectType.TrainingEffectiveness,
}, },
{ {
name: 'Initial Friendship', name: 'Initial Friendship',
effect: support.EffectType.InitialFriendship, effect: support.EffectType.InitialFriendship,
}, },
{ {
name: 'Race Bonus', name: 'Race Bonus',
effect: support.EffectType.RaceBonus, effect: support.EffectType.RaceBonus,
}, },
{ {
name: 'Hint Frequency', name: 'Hint Frequency',
effect: support.EffectType.HintFrequency, effect: support.EffectType.HintFrequency,
}, },
{ {
name: 'Specialty Priority', name: 'Specialty Priority',
effect: support.EffectType.SpecialtyPriority, effect: support.EffectType.SpecialtyPriority,
}, },
] as const; ] as const;
export type SupportCardDatum = { export type SupportCardDatum = {
'Career': string; Career: string;
'Scenario': string; Scenario: string;
'Source': string; Source: string;
'Unique Effect': string; 'Unique Effect': string;
'Idle Mode Sub Rate': number; 'Idle Mode Sub Rate': number;
'Races': number; Races: number;
'Race Wins': number; 'Race Wins': number;
} & Record<typeof INDEPENDENT[number]['name'], number> & Record<typeof DEPENDENT[number]['name'], 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[] { export function supportVariables(
const deck = career.progress_log_info.support_card_gain_info_array.map((g) => lookupCard(g.support_card_id)); career: ism.Career,
const scen = lookupScenario(career.end_info.chara_info.scenario_id); lookupCard: (id: number) => support.SupportCard,
return career.progress_log_info.support_card_gain_info_array.map((g, i) => { lookupScenario: (id: number) => scenario.Scenario,
const card = deck[i]; ): SupportCardDatum[] {
const level = support.level(card.rarity, career.end_info.chara_info.support_card_array[i].exp); const deck = career.progress_log_info.support_card_gain_info_array.map((g) => lookupCard(g.support_card_id));
const { effects, unique } = support.effects(lookupCard(g.support_card_id), level); const scen = lookupScenario(career.end_info.chara_info.scenario_id);
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>; return career.progress_log_info.support_card_gain_info_array.map((g, i) => {
const dep = Object.fromEntries(DEPENDENT.map((t) => [t.name, t.map(g.gain_info, effects)])) as Record<typeof DEPENDENT[number]['name'], number>; const card = deck[i];
return { const level = support.level(card.rarity, career.end_info.chara_info.support_card_array[i].exp);
'Career': label(career), const { effects, unique } = support.effects(lookupCard(g.support_card_id), level);
'Scenario': scen.name, const indep = Object.fromEntries(
'Source': card.name, INDEPENDENT.map((t) => [t.name, effects.find((e) => e.type === t.effect)?.value ?? 0]),
'Unique Effect': unique?.description ?? 'None', ) as Record<(typeof INDEPENDENT)[number]['name'], number>;
'Idle Mode Sub Rate': unique?.idle_mode_sub_rate ?? 0, const dep = Object.fromEntries(DEPENDENT.map((t) => [t.name, t.map(g.gain_info, effects)])) as Record<
'Races': career.progress_log_info.race_history_array.length, (typeof DEPENDENT)[number]['name'],
'Race Wins': career.progress_log_info.race_history_array.reduce((w, r) => r.race_history.result_rank === 1 ? w + 1 : w, 0), number
...indep, >;
...dep, 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,
};
});
} }