{navItems.map((item) => (
{transI18n("comingSoon")}
diff --git a/src/components/monsterBar/peak.tsx b/src/components/monsterBar/peak.tsx
new file mode 100644
index 0000000..46612a3
--- /dev/null
+++ b/src/components/monsterBar/peak.tsx
@@ -0,0 +1,272 @@
+"use client"
+import { useEffect, useMemo } from "react";
+import SelectCustomText from "../select/customSelectText";
+import useEventStore from "@/stores/eventStore";
+import { getLocaleName, replaceByParam } from "@/helper";
+import useLocaleStore from "@/stores/localeStore";
+import useUserDataStore from "@/stores/userDataStore";
+import useMonsterStore from "@/stores/monsterStore";
+import Image from "next/image";
+import cloneDeep from 'lodash/cloneDeep'
+
+import { useTranslations } from "next-intl";
+import { MonsterStore } from "@/types";
+
+export default function PeakBar() {
+ const { PEAKEvent, mapPEAKInfo } = useEventStore()
+ const { listMonster } = useMonsterStore()
+ const { locale } = useLocaleStore()
+ const {
+ peak_config,
+ setPeakConfig
+ } = useUserDataStore()
+
+ const transI18n = useTranslations("DataPage")
+
+ const listFloor = useMemo(() => {
+ if (!mapPEAKInfo?.[peak_config?.event_id?.toString()]) return []
+ return [
+ ...mapPEAKInfo[peak_config?.event_id?.toString()]?.PreLevel,
+ mapPEAKInfo[peak_config?.event_id?.toString()]?.BossLevel,
+ ]
+ }, [peak_config, mapPEAKInfo])
+
+ const eventSelected = useMemo(() => {
+ return mapPEAKInfo?.[peak_config?.event_id?.toString()]
+ }, [peak_config, mapPEAKInfo])
+
+ const bossConfig = useMemo(() => {
+ return mapPEAKInfo?.[peak_config?.event_id?.toString()]?.BossConfig;
+ }, [peak_config, mapPEAKInfo])
+
+ const challengeSelected = useMemo(() => {
+ const challenge = cloneDeep(listFloor.find((peak) => peak.Id === peak_config.challenge_id))
+ if (
+ challenge
+ && challenge.Id === mapPEAKInfo?.[peak_config?.event_id?.toString()]?.BossLevel?.Id
+ && bossConfig
+ && peak_config?.boss_mode === "Hard"
+ ) {
+ challenge.Name = bossConfig.HardName
+ challenge.EventIDList = bossConfig.EventIDList
+ challenge.InfiniteList = bossConfig.InfiniteList
+ challenge.TagList = bossConfig.TagList
+ }
+ return challenge
+ }, [peak_config, listFloor, mapPEAKInfo, bossConfig])
+
+ useEffect(() => {
+ if (!challengeSelected) return
+ if (peak_config.event_id !== 0 && peak_config.challenge_id !== 0 && challengeSelected) {
+ const newBattleConfig = cloneDeep(peak_config)
+ newBattleConfig.cycle_count = 6
+ newBattleConfig.blessings = []
+ for (const value of challengeSelected.TagList) {
+ newBattleConfig.blessings.push({
+ id: Number(value.Id),
+ level: 1
+ })
+ }
+ if (peak_config.buff_id !== 0) {
+ newBattleConfig.blessings.push({
+ id: peak_config.buff_id,
+ level: 1
+ })
+ }
+ newBattleConfig.monsters = []
+ newBattleConfig.stage_id = challengeSelected.EventIDList[0].StageID
+ for (const wave of challengeSelected.EventIDList[0].MonsterList) {
+ if (!wave) continue
+ const newWave: MonsterStore[] = []
+ for (const value of Object.values(wave)) {
+ if (!value) continue
+ newWave.push({
+ monster_id: Number(value),
+ level: challengeSelected.EventIDList[0].Level,
+ amount: 1,
+ })
+ }
+ newBattleConfig.monsters.push(newWave)
+ }
+
+ setPeakConfig(newBattleConfig)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [
+ peak_config.event_id,
+ peak_config.challenge_id,
+ peak_config.buff_id,
+ mapPEAKInfo,
+ ])
+
+
+ return (
+
+
+ {/* Title Card */}
+
+
+ peak.lang.get(locale)).map((peak) => ({
+ id: peak.id,
+ name: `${getLocaleName(locale, peak)} (${peak.id}) `,
+ }))}
+ excludeSet={[]}
+ selectedCustomSet={peak_config.event_id.toString()}
+ placeholder={transI18n("selectASEvent")}
+ setSelectedCustomSet={(id) => setPeakConfig({ ...peak_config, event_id: Number(id), challenge_id: 0, buff_id: 0 })}
+ />
+
+ {/* Settings */}
+
+
+
+
+
+
+ {eventSelected && eventSelected.BossLevel.Id === peak_config.challenge_id && (
+
+
+
+
+ )}
+
+
+ {
+ eventSelected
+ && eventSelected.BossLevel.Id === peak_config.challenge_id
+ && bossConfig
+ && bossConfig.BuffList
+ && (
+
+ ({
+ id: buff.Id.toString(),
+ name: buff?.Name || "",
+ description: replaceByParam(buff?.Desc || "", buff?.Param || []),
+ }))
+ : []
+ }
+ excludeSet={[]}
+ selectedCustomSet={peak_config?.buff_id?.toString()}
+ placeholder={transI18n("selectBuff")}
+ setSelectedCustomSet={(id) => setPeakConfig({ ...peak_config, buff_id: Number(id) })}
+ />
+
+ )
+ }
+
+ {/* Turbulence Buff */}
+
+
+
+ {transI18n("turbulenceBuff")}
+
+
+ {challengeSelected && challengeSelected?.TagList?.length > 0 ? (
+ challengeSelected.TagList.map((subOption, index) => (
+
+
+
+
+ ))
+ ) : (
+
{transI18n("noTurbulenceBuff")}
+ )}
+
+
+
+ {/* Enemy Waves */}
+
+
+
+
{challengeSelected?.Name}
+
+ {challengeSelected && Object.values(challengeSelected.InfiniteList).map((waveValue, waveIndex) => (
+
+
{transI18n("wave")} {waveIndex + 1}
+
+ {Array.from(new Set(waveValue.MonsterGroupIDList)).map((monsterId, enemyIndex) => (
+
+
+
+
+ {listMonster.find((monster) => monster.child.includes(monsterId))?.icon && monster.child.includes(monsterId))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`}
+ alt="Enemy Icon"
+ width={376}
+ height={512}
+ className="w-full h-full object-cover"
+ />}
+
+
+
+
Lv. {challengeSelected?.EventIDList[0].Level}
+
+ {listMonster
+ .find((monster) => monster.child.includes(monsterId))
+ ?.weak?.map((icon, iconIndex) => (
+
+ ))}
+
+
+
+
+ ))}
+
+
+ ))}
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/helper/connect.ts b/src/helper/connect.ts
index 327bbc1..3660680 100644
--- a/src/helper/connect.ts
+++ b/src/helper/connect.ts
@@ -53,8 +53,8 @@ export const syncDataToPS = async (): Promise<{ success: boolean, message: strin
password
} = useConnectStore.getState()
- const {avatars, battle_type, moc_config, pf_config, as_config, ce_config} = useUserDataStore.getState()
- const data = converterToFreeSRJson(avatars, battle_type, moc_config, pf_config, as_config, ce_config)
+ const {avatars, battle_type, moc_config, pf_config, as_config, ce_config, peak_config} = useUserDataStore.getState()
+ const data = converterToFreeSRJson(avatars, battle_type, moc_config, pf_config, as_config, ce_config, peak_config)
let urlQuery = serverUrl
if (!urlQuery.startsWith("http://") && !urlQuery.startsWith("https://")) {
diff --git a/src/helper/converterToFreeSRJson.ts b/src/helper/converterToFreeSRJson.ts
index cdd310e..884472e 100644
--- a/src/helper/converterToFreeSRJson.ts
+++ b/src/helper/converterToFreeSRJson.ts
@@ -1,4 +1,4 @@
-import { ASConfigStore, AvatarJson, AvatarStore, BattleConfigJson, CEConfigStore, FreeSRJson, LightconeJson, MOCConfigStore, PFConfigStore, RelicJson } from "@/types";
+import { ASConfigStore, AvatarJson, AvatarStore, BattleConfigJson, CEConfigStore, FreeSRJson, LightconeJson, MOCConfigStore, PEAKConfigStore, PFConfigStore, RelicJson } from "@/types";
export function converterToFreeSRJson(
@@ -8,6 +8,7 @@ export function converterToFreeSRJson(
pf_config: PFConfigStore,
as_config: ASConfigStore,
ce_config: CEConfigStore,
+ peak_config: PEAKConfigStore,
): FreeSRJson {
const lightcones: LightconeJson[] = []
const relics: RelicJson[] = []
@@ -52,6 +53,16 @@ export function converterToFreeSRJson(
path_resonance_id: 0,
monsters: ce_config.monsters,
}
+ } else if (battle_type === "PEAK") {
+ battleJson = {
+ battle_type: battle_type,
+ blessings: peak_config.blessings,
+ custom_stats: [],
+ cycle_count: peak_config.cycle_count,
+ stage_id: peak_config.stage_id,
+ path_resonance_id: 0,
+ monsters: peak_config.monsters,
+ }
} else {
battleJson = {
battle_type: battle_type,
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index 3e3be63..63320e0 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -6,4 +6,5 @@ export * from "./useFetchRelicData";
export * from "./useFetchMonsterData";
export * from "./useFetchPFData";
export * from "./useFetchMOCData";
-export * from "./useFetchASData";
\ No newline at end of file
+export * from "./useFetchASData";
+export * from "./useFetchPEAKData";
\ No newline at end of file
diff --git a/src/hooks/useFetchPEAKData.ts b/src/hooks/useFetchPEAKData.ts
new file mode 100644
index 0000000..2997758
--- /dev/null
+++ b/src/hooks/useFetchPEAKData.ts
@@ -0,0 +1,71 @@
+"use client"
+import { useQuery } from '@tanstack/react-query'
+import { fetchPeakByIdsNative, getPEAKEventListApi } from '@/lib/api'
+import { useEffect } from 'react'
+import { listCurrentLanguageApi } from '@/constant/constant'
+import useLocaleStore from '@/stores/localeStore'
+import { toast } from 'react-toastify'
+import useEventStore from '@/stores/eventStore'
+import { EventStageDetail, PeakDetail } from '@/types'
+
+export const useFetchPEAKData = () => {
+ const { setPEAKEvent, setMapPEAKInfo } = useEventStore()
+ const { locale } = useLocaleStore()
+ const { data: dataPEAK, error: errorPEAK } = useQuery({
+ queryKey: ['peakData'],
+ queryFn: getPEAKEventListApi,
+ select: (data) => data.sort((a, b) => Number(b.id) - Number(a.id)),
+ staleTime: 1000 * 60 * 5,
+ })
+
+ const { data: dataPEAKInfo, error: errorPEAKInfo } = useQuery({
+ queryKey: ['peakInfoData', locale],
+ queryFn: () =>
+ fetchPeakByIdsNative(
+ dataPEAK!.map((item) => item.id),
+ listCurrentLanguageApi[locale.toLowerCase()]
+ ),
+ staleTime: 1000 * 60 * 5,
+ select: (data) => {
+ const newData = { ...data }
+ for (const key in newData) {
+ for (const item of newData[key].PreLevel) {
+ item.EventIDList = item.EventIDList.map((event: EventStageDetail) => ({
+ ...event,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ MonsterList: event.MonsterList.map(({ $type, ...rest }) => rest)
+ }))
+ }
+ newData[key].BossLevel.EventIDList = newData[key].BossLevel.EventIDList.map((event: EventStageDetail) => ({
+ ...event,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ MonsterList: event.MonsterList.map(({ $type, ...rest }) => rest)
+ }))
+ newData[key].BossConfig.EventIDList = newData[key].BossConfig.EventIDList.map((event: EventStageDetail) => ({
+ ...event,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ MonsterList: event.MonsterList.map(({ $type, ...rest }) => rest)
+ }))
+ }
+ return newData
+ },
+ enabled: !!dataPEAK,
+ });
+
+ useEffect(() => {
+ if (dataPEAK && !errorPEAK) {
+ setPEAKEvent(dataPEAK)
+ } else if (errorPEAK) {
+ toast.error("Failed to load PEAK data")
+ }
+ }, [dataPEAK, errorPEAK, setPEAKEvent])
+
+ useEffect(() => {
+ if (dataPEAKInfo && !errorPEAKInfo) {
+ setMapPEAKInfo(dataPEAKInfo as Record
)
+ } else if (errorPEAKInfo) {
+ toast.error("Failed to load PEAK info data")
+ }
+
+ }, [dataPEAKInfo, errorPEAKInfo, setMapPEAKInfo])
+}
diff --git a/src/lib/api/api.ts b/src/lib/api/api.ts
index 3ae0a35..b8c4ecb 100644
--- a/src/lib/api/api.ts
+++ b/src/lib/api/api.ts
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
-import { AffixDetail, ASDetail, CharacterDetail, ConfigMaze, FreeSRJson, LightConeDetail, MocDetail, PFDetail, PSResponse, RelicDetail } from "@/types";
+import { AffixDetail, ASDetail, CharacterDetail, ConfigMaze, FreeSRJson, LightConeDetail, MocDetail, PeakDetail, PFDetail, PSResponse, RelicDetail } from "@/types";
import axios from 'axios';
import { pSResponseSchema } from "@/zod";
@@ -176,7 +176,6 @@ export async function fetchPFByIdNative(ids: string, locale: string): Promise | null> {
try {
const res = await axios.post>(`/api/${locale}/moc`, { mocIds: ids });
@@ -197,6 +196,27 @@ export async function fetchMOCByIdNative(ids: string, locale: string): Promise | null> {
+ try {
+ const res = await axios.post>(`/api/${locale}/peak`, { peakIds: ids });
+ return res.data;
+ } catch (error) {
+ console.error('Failed to fetch peak:', error);
+ return null;
+ }
+}
+
+export async function fetchPeakByIdNative(ids: string, locale: string): Promise {
+ try {
+ const res = await axios.get(`/api/${locale}/peak/${ids}`);
+ return res.data;
+ } catch (error) {
+ console.error('Failed to fetch peak:', error);
+ return null;
+ }
+}
+
export async function SendDataToServer(username: string, password: string, serverUrl: string, data: FreeSRJson | null): Promise {
try {
const response = await axios.post(`${serverUrl}`, { username, password, data })
diff --git a/src/lib/api/hakushi.ts b/src/lib/api/hakushi.ts
index a386701..e200bb6 100644
--- a/src/lib/api/hakushi.ts
+++ b/src/lib/api/hakushi.ts
@@ -1,5 +1,5 @@
import { convertAvatar, convertEvent, convertLightcone, convertMonster, convertRelicSet } from "@/helper";
-import { ASDetail, CharacterBasic, CharacterBasicRaw, CharacterDetail, EventBasic, EventBasicRaw, LightConeBasic, LightConeBasicRaw, LightConeDetail, MocDetail, MonsterBasic, MonsterBasicRaw, MonsterDetail, PFDetail, RelicBasic, RelicBasicRaw, RelicDetail } from "@/types";
+import { ASDetail, CharacterBasic, CharacterBasicRaw, CharacterDetail, EventBasic, EventBasicRaw, LightConeBasic, LightConeBasicRaw, LightConeDetail, MocDetail, MonsterBasic, MonsterBasicRaw, MonsterDetail, PeakDetail, PFDetail, RelicBasic, RelicBasicRaw, RelicDetail } from "@/types";
import axios from "axios";
export async function getLightconeInfoApi(lightconeId: number, locale: string): Promise {
@@ -134,6 +134,28 @@ export async function getPFEventInfoApi(eventId: number, locale: string): Promis
}
}
+export async function getPeakEventInfoApi(eventId: number, locale: string): Promise {
+ try {
+ const res = await axios.get(
+ `https://api.hakush.in/hsr/data/${locale}/peak/${eventId}.json`,
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ }
+ );
+
+ return res.data as PeakDetail;
+ } catch (error: unknown) {
+ if (axios.isAxiosError(error)) {
+ console.log(`Error: ${error.response?.status} - ${error.message}`);
+ } else {
+ console.log(`Unexpected error: ${String(error)}`);
+ }
+ return null;
+ }
+}
+
export async function getCharacterListApi(): Promise {
try {
const res = await axios.get>(
@@ -278,6 +300,30 @@ export async function getPFEventListApi(): Promise {
}
}
+export async function getPEAKEventListApi(): Promise {
+ try {
+ const res = await axios.get>(
+ 'https://api.hakush.in/hsr/data/maze_peak.json',
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ }
+ );
+
+ const data = new Map(Object.entries(res.data));
+
+ return Array.from(data.entries()).map(([id, it]) => convertEvent(id, it));
+ } catch (error: unknown) {
+ if (axios.isAxiosError(error)) {
+ console.log(`Error: ${error.response?.status} - ${error.message}`);
+ } else {
+ console.log(`Unexpected error: ${String(error)}`);
+ }
+ return [];
+ }
+}
+
export async function getMonsterListApi(): Promise<{list: MonsterBasic[], map: Record}> {
try {
const res = await axios.get>(
diff --git a/src/lib/loader/index.ts b/src/lib/loader/index.ts
index 1f1dea1..0238b1d 100644
--- a/src/lib/loader/index.ts
+++ b/src/lib/loader/index.ts
@@ -6,3 +6,5 @@ export * from "./relicLoader";
export * from "./asLoader";
export * from "./pfLoader";
export * from "./mocLoader";
+export * from "./peakLoader";
+
diff --git a/src/lib/loader/peakLoader.ts b/src/lib/loader/peakLoader.ts
new file mode 100644
index 0000000..b592c87
--- /dev/null
+++ b/src/lib/loader/peakLoader.ts
@@ -0,0 +1,51 @@
+import fs from 'fs';
+import path from 'path';
+import { PeakDetail } from '@/types';
+import { getPeakEventInfoApi } from '../api';
+
+const DATA_DIR = path.join(process.cwd(), 'data');
+const peakFileCache: Record> = {};
+export let peakMap: Record = {};
+
+function getJsonFilePath(locale: string): string {
+ return path.join(DATA_DIR, `peak.${locale}.json`);
+}
+
+function loadFromFileIfExists(locale: string): Record | null {
+ if (peakFileCache[locale]) return peakFileCache[locale];
+
+ const filePath = getJsonFilePath(locale);
+ if (fs.existsSync(filePath)) {
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record;
+ peakFileCache[locale] = data;
+ return data;
+ }
+ return null;
+}
+
+export async function loadPeak(charIds: string[], locale: string): Promise> {
+ const fileData = loadFromFileIfExists(locale);
+ const fileIds = fileData ? Object.keys(fileData) : [];
+
+ if (fileData && charIds.every(id => fileIds.includes(id))) {
+ peakMap = fileData;
+ return peakMap;
+ }
+
+ const result: Record = {};
+
+ await Promise.all(
+ charIds.map(async id => {
+ const info = await getPeakEventInfoApi(Number(id), locale);
+ if (info) result[id] = info;
+ })
+ );
+
+ fs.mkdirSync(DATA_DIR, { recursive: true });
+ const filePath = getJsonFilePath(locale);
+ fs.writeFileSync(filePath, JSON.stringify(result, null, 2), 'utf-8');
+
+ peakFileCache[locale] = result;
+ peakMap = result;
+ return result;
+}
diff --git a/src/stores/eventStore.ts b/src/stores/eventStore.ts
index 086cc54..3bc0994 100644
--- a/src/stores/eventStore.ts
+++ b/src/stores/eventStore.ts
@@ -1,4 +1,4 @@
-import { MocDetail, EventBasic, PFDetail, ASDetail } from '@/types';
+import { MocDetail, EventBasic, PFDetail, ASDetail, PeakDetail } from '@/types';
import { create } from 'zustand'
@@ -9,12 +9,16 @@ interface EventState {
mapPFInfo: Record;
ASEvent: EventBasic[];
mapASInfo: Record;
+ PEAKEvent: EventBasic[];
+ mapPEAKInfo: Record;
setMOCEvent: (newListEvent: EventBasic[]) => void;
setMapMOCInfo: (newMapMOCInfo: Record) => void;
setPFEvent: (newListEvent: EventBasic[]) => void;
setMapPFInfo: (newMapPFInfo: Record) => void;
setASEvent: (newListEvent: EventBasic[]) => void;
setMapASInfo: (newMapASInfo: Record) => void;
+ setPEAKEvent: (newListEvent: EventBasic[]) => void;
+ setMapPEAKInfo: (newMapPEAKInfo: Record) => void;
}
const useEventStore = create((set) => ({
@@ -24,12 +28,16 @@ const useEventStore = create((set) => ({
mapPFInfo: {},
ASEvent: [],
mapASInfo: {},
+ PEAKEvent: [],
+ mapPEAKInfo: {},
setMOCEvent: (newListEvent: EventBasic[]) => set({ MOCEvent: newListEvent }),
setMapMOCInfo: (newMapMOCInfo: Record) => set({ mapMOCInfo: newMapMOCInfo }),
setPFEvent: (newListEvent: EventBasic[]) => set({ PFEvent: newListEvent }),
setMapPFInfo: (newMapPFInfo: Record) => set({ mapPFInfo: newMapPFInfo }),
setASEvent: (newListEvent: EventBasic[]) => set({ ASEvent: newListEvent }),
setMapASInfo: (newMapASInfo: Record) => set({ mapASInfo: newMapASInfo }),
+ setPEAKEvent: (newListEvent: EventBasic[]) => set({ PEAKEvent: newListEvent }),
+ setMapPEAKInfo: (newMapPEAKInfo: Record) => set({ mapPEAKInfo: newMapPEAKInfo }),
}));
export default useEventStore;
\ No newline at end of file
diff --git a/src/stores/userDataStore.ts b/src/stores/userDataStore.ts
index e5d32ba..134f236 100644
--- a/src/stores/userDataStore.ts
+++ b/src/stores/userDataStore.ts
@@ -1,4 +1,4 @@
-import { ASConfigStore, AvatarStore, CEConfigStore, MOCConfigStore, PFConfigStore } from '@/types';
+import { ASConfigStore, AvatarStore, CEConfigStore, MOCConfigStore, PEAKConfigStore, PFConfigStore } from '@/types';
import { create } from 'zustand'
import { createJSONStorage, persist } from 'zustand/middleware';
@@ -9,6 +9,7 @@ interface UserDataState {
moc_config: MOCConfigStore;
pf_config: PFConfigStore;
as_config: ASConfigStore;
+ peak_config: PEAKConfigStore;
ce_config: CEConfigStore;
setAvatars: (newAvatars: { [key: string]: AvatarStore }) => void;
setAvatar: (newAvatar: AvatarStore) => void;
@@ -16,6 +17,7 @@ interface UserDataState {
setMocConfig: (newMocConfig: MOCConfigStore) => void;
setPfConfig: (newPfConfig: PFConfigStore) => void;
setAsConfig: (newAsConfig: ASConfigStore) => void;
+ setPeakConfig: (newPeakConfig: PEAKConfigStore) => void;
setCeConfig: (newCeConfig: CEConfigStore) => void;
}
@@ -61,12 +63,23 @@ const useUserDataStore = create()(
stage_id: 0,
monsters: [],
},
+ peak_config: {
+ event_id: 0,
+ challenge_id: 0,
+ buff_id: 0,
+ boss_mode: "Normal",
+ blessings: [],
+ cycle_count: 0,
+ stage_id: 0,
+ monsters: [],
+ },
setAvatars: (newAvatars: { [key: string]: AvatarStore }) => set({ avatars: newAvatars }),
setAvatar: (newAvatar: AvatarStore) => set((state) => ({ avatars: { ...state.avatars, [newAvatar.avatar_id.toString()]: newAvatar } })),
setBattleType: (newBattleType: string) => set({ battle_type: newBattleType }),
setMocConfig: (newMocConfig: MOCConfigStore) => set({ moc_config: newMocConfig }),
setPfConfig: (newPfConfig: PFConfigStore) => set({ pf_config: newPfConfig }),
setAsConfig: (newAsConfig: ASConfigStore) => set({ as_config: newAsConfig }),
+ setPeakConfig: (newPeakConfig: PEAKConfigStore) => set({ peak_config: newPeakConfig }),
setCeConfig: (newCeConfig: CEConfigStore) => set({ ce_config: newCeConfig }),
}),
{
diff --git a/src/types/index.ts b/src/types/index.ts
index aa303a1..22bfac3 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -17,3 +17,4 @@ export * from "./pfDetail"
export * from "./asDetail"
export * from "./mocDetail"
export * from "./monsterDetail"
+export * from "./peakDetail"
diff --git a/src/types/mics.ts b/src/types/mics.ts
index 181ea3a..02efbae 100644
--- a/src/types/mics.ts
+++ b/src/types/mics.ts
@@ -93,8 +93,18 @@ export type ASConfigStore = {
monsters: MonsterStore[][];
}
-export type CEConfigStore = {
+export type PEAKConfigStore = {
+ event_id: number;
+ challenge_id: number;
+ buff_id: number;
+ boss_mode: string;
+ blessings: BattleBuffStore[]
+ cycle_count: number;
+ stage_id: number;
+ monsters: MonsterStore[][];
+}
+export type CEConfigStore = {
blessings: BattleBuffStore[]
cycle_count: number;
stage_id: number;
diff --git a/src/types/peakDetail.ts b/src/types/peakDetail.ts
new file mode 100644
index 0000000..5681078
--- /dev/null
+++ b/src/types/peakDetail.ts
@@ -0,0 +1,37 @@
+import { EventStageDetail } from "./mocDetail";
+import { InfiniteWave } from "./pfDetail";
+
+export interface PeakDetail {
+ Id: number;
+ Name: string;
+ PreLevel: PeakLevel[];
+ BossLevel: PeakLevel;
+ BossConfig: BossConfig;
+}
+
+export interface PeakLevel {
+ Id: number;
+ Name: string;
+ DamageType: string[];
+ MazeGroupID: number;
+ NpcMonsterIDList: number[];
+ EventIDList: EventStageDetail[];
+ TagList: ChallengeTag[];
+ InfiniteList: Record;
+}
+
+export interface BossConfig {
+ HardName: string;
+ BuffList: ChallengeTag[];
+ EventIDList: EventStageDetail[];
+ TagList: ChallengeTag[];
+ InfiniteList: Record;
+}
+
+export interface ChallengeTag {
+ Id: number;
+ Name: string;
+ Desc: string;
+ Param: number[];
+}
+
diff --git a/src/zod/mics.zod.ts b/src/zod/mics.zod.ts
index 3ffe1be..a7993dd 100644
--- a/src/zod/mics.zod.ts
+++ b/src/zod/mics.zod.ts
@@ -106,6 +106,17 @@ export const cEConfigStoreSchema = z.object({
monsters: z.array(z.array(monsterStoreSchema)),
});
+export const pEAKConfigStoreSchema = z.object({
+ event_id: z.number(),
+ challenge_id: z.number(),
+ buff_id: z.number(),
+ boss_mode: z.string(),
+ blessings: z.array(battleBuffStoreSchema),
+ cycle_count: z.number(),
+ stage_id: z.number(),
+ monsters: z.array(z.array(monsterStoreSchema)),
+});
+
export const micsSchema = z.object({
avatars: z.record(avatarStoreSchema),
battle_type: z.string(),
@@ -113,4 +124,5 @@ export const micsSchema = z.object({
pf_config: pFConfigStoreSchema,
as_config: aSConfigStoreSchema,
ce_config: cEConfigStoreSchema,
+ peak_config: pEAKConfigStoreSchema,
});