diff --git a/apps/web/src/containers/Chara.css b/apps/web/src/containers/Chara.css
index d3ed08d..1ea8928 100644
--- a/apps/web/src/containers/Chara.css
+++ b/apps/web/src/containers/Chara.css
@@ -1 +1,90 @@
-.screen.chara {}
\ No newline at end of file
+.screen.chara {
+ gap: 1rem;
+ > .chara-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ > .character {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ border: 0.0625rem solid var(--base-text-color);
+ box-sizing: border-box;
+ cursor: pointer;
+ > .generator > ul > li { text-align: center; }
+ > .name {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 2rem;
+ }
+ &.selected {
+ border: 0.0625rem solid var(--color-primary);
+ > .name {
+ background-color: var(--color-primary);
+ color: var(--base-background-color);
+ }
+ > .chara-details {
+ height: auto;
+ padding: 0.5rem;
+ }
+ }
+ }
+ }
+ .chara-details {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ width: 100%;
+ border-top: 0.0625rem solid var(--base-text-color);
+ box-sizing: border-box;
+ height: 0;
+ padding: 0 0.5rem;
+ overflow-y: hidden;
+ transition: all 0.3s ease-in-out;
+ interpolate-size: allow-keywords;
+ > ul.talent-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+ > ul.properties {
+ display: flex;
+ flex-direction: row;
+ gap: 0.5rem;
+ width: 100%;
+ font-weight: bold;
+ > li {
+ display: flex;
+ flex-direction: column;
+ flex: 1 0;
+ justify-content: space-between;
+ text-align: center;
+ min-width: 6rem;
+ user-select: none;
+ color: var(--grade-color);
+ span {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: 0.0625rem solid var(--grade-color);
+ box-sizing: border-box;
+ height: 2rem;
+ &:first-child {
+ border-bottom: none;
+ }
+ }
+ .name {
+ color: var(--base-background-color);
+ background-color: var(--grade-color);
+ }
+ &.charm { order: 1 }
+ &.intelligence { order: 2 }
+ &.strength { order: 3 }
+ &.money { order: 4 }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/web/src/containers/Chara.tsx b/apps/web/src/containers/Chara.tsx
index a702bb3..6dce993 100644
--- a/apps/web/src/containers/Chara.tsx
+++ b/apps/web/src/containers/Chara.tsx
@@ -1,7 +1,126 @@
+import { useCharaPuller, useCharaPicker, convertProps } from '@remake/hooks'
+import { useUnique, useUniqueGenerator, useCharaStart } from '@remake/hooks'
+import type { BaseChara } from '@remake/hooks'
+import { TalentComponent } from '@/components/Talent'
+import { judgeGradeByValue } from '@/config'
+import { characters } from '@remake/data'
+import { properties } from '@/display'
+import { keys } from '@remake/vitex'
import './Chara.css'
+function Details({ detail }: { detail: BaseChara }) {
+ const props = convertProps(detail.property)
+ return (
+
+
+ {keys(props).map(key => (
+ -
+ {properties[key]}
+ {props[key]}
+
+ ))}
+
+
+ {detail.talent.map(id => (
+ -
+
+
+ ))}
+
+
+ )
+}
+
+interface UniqueProps {
+ selected?: boolean
+ picker?: () => void
+}
+function Unique({ selected, picker }: UniqueProps) {
+ const [unique, generator] = useUniqueGenerator()
+ return (
+
+ 独一无二的我
+ {unique && }
+ {!unique && (
+
+
+ - 6000万玩家中独一无二的角色卡
+ - 所有属性 所有天赋 随机生成
+ - 每人只能生成一次
+
+
+
+ )}
+
+ )
+}
+
+interface CharacterProps {
+ id: number
+ selected?: boolean
+ picker?: (id: number) => void
+}
+function Character({ id, selected, picker }: CharacterProps) {
+ const character = characters.get(id)!
+ return (
+
picker?.(id)}
+ >
+ {character.name}
+
+
+ )
+}
+
export function Chara() {
- return
+ const u = useUnique()
+ const [{ unique, characters }, puller] = useCharaPuller()
+ const [picked, picker] = useCharaPicker()
+ const start = useCharaStart()
+ const ready = picked && (picked.type === 'unique' ? !!u : true)
+ return (
+
+
+ {unique && (
+ picker.unique()}
+ />
+ )}
+ {characters.map(id => (
+ picker.chara(id)}
+ />
+ ))}
+
+
+
+
+
+
+ )
}
export default Chara
diff --git a/apps/web/src/containers/Loading.tsx b/apps/web/src/containers/Loading.tsx
deleted file mode 100644
index 202a39f..0000000
--- a/apps/web/src/containers/Loading.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-export function Loading() {
- return (
-
-
载入中...
-
- )
-}
-
-export default Loading
diff --git a/apps/web/src/containers/Play.tsx b/apps/web/src/containers/Play.tsx
index a945f2f..2b4d3bd 100644
--- a/apps/web/src/containers/Play.tsx
+++ b/apps/web/src/containers/Play.tsx
@@ -1,4 +1,4 @@
-import { useState, useRef } from 'react'
+import { useState, useRef, useCallback } from 'react'
import { useLayoutEffect, useEffect } from 'react'
import { useNext, useGotoSummary, type Log } from '@remake/hooks'
import { useJudge } from '@/hooks/judge'
@@ -100,12 +100,12 @@ function Prop({ prop, value, grade }: PropProps) {
useEffect(() => {
const prev = prevRef.current
if (value === prev) return
+ const startValue = prevRef.current
prevRef.current = value
setTrend(value > prev ? 'up' : 'down')
setFlip(f => (f + 1) % 2)
let startTimestamp: number | null = null
const duration = 400
- const startValue = displayValue
let end = false
const step = (timestamp: number) => {
if (!startTimestamp) startTimestamp = timestamp
@@ -150,18 +150,18 @@ export function Play() {
const logRef = useRef
(null)
const autoRef = useRef(0)
const gotoSummary = useGotoSummary()
- const handleNext = () => {
+ const handleNext = useCallback(() => {
if (ended) return
const achievements = next()
// TODO: Show achievements
console.debug('Achievements:', achievements)
- }
- const handleGotoSummary = () => {
+ }, [ended, next])
+ const handleGotoSummary = useCallback(() => {
if (!ended) return
const achievements = gotoSummary()
// TODO: Show achievements
console.debug('Achievements:', achievements)
- }
+ }, [ended, gotoSummary])
useLayoutEffect(() => {
requestAnimationFrame(() => {
if (!logRef.current) return
diff --git a/apps/web/src/containers/Summary.tsx b/apps/web/src/containers/Summary.tsx
index 6610895..b84ab94 100644
--- a/apps/web/src/containers/Summary.tsx
+++ b/apps/web/src/containers/Summary.tsx
@@ -38,7 +38,7 @@ function TalentList({ picked, picker }: TalentListProps) {
}
hasInitialized.current = true
}
- }, [picked, picker])
+ }, [profile.locked, talents, picked, picker])
return (
diff --git a/apps/web/src/hooks/judge.ts b/apps/web/src/hooks/judge.ts
index 04bfe91..6b258eb 100644
--- a/apps/web/src/hooks/judge.ts
+++ b/apps/web/src/hooks/judge.ts
@@ -26,19 +26,21 @@ function judges = never>(
export const useJudge = () => {
const state = useGameState()
if (!state) throw new Error('Game state is not set')
+ const current = state.props.current
return useMemo(() => {
- const result = judges(state.props.current, ['age'])
+ const result = judges(current, ['age'])
return result
- }, [state.props.current])
+ }, [current])
}
export const useEndJudge = () => {
const summary = useSummary()
const state = useGameState()
if (!state) throw new Error('Game state is not set')
+ const highest = state.props.highest
return useMemo(() => {
- const props = { ...state.props.highest, summary }
+ const props = { ...highest, summary }
const result = judges(props)
return result
- }, [state.props.highest, summary])
+ }, [highest, summary])
}
diff --git a/apps/web/src/hooks/storage.ts b/apps/web/src/hooks/storage.ts
index cbbd55a..b31140f 100644
--- a/apps/web/src/hooks/storage.ts
+++ b/apps/web/src/hooks/storage.ts
@@ -1,6 +1,7 @@
-import { useCallback } from 'react'
+import { useEffect, useCallback, useTransition } from 'react'
import { atom, useAtom } from 'jotai'
-import { useConfigInject, useRawProfile, useProfileInject } from '@remake/hooks'
+import { useConfigInject, useProfileInject, useRawProfile } from '@remake/hooks'
+import { useUniqueInject, useUnique } from '@remake/hooks'
import { get, set } from '@/storage'
import { config } from '@/config'
@@ -9,11 +10,12 @@ const initedAtom = atom(false)
export const useInit = () => {
const configInject = useConfigInject()
const profileInject = useProfileInject()
+ const uniqueInject = useUniqueInject()
const [inited, setInited] = useAtom(initedAtom)
const loader = useCallback(async () => {
if (inited) return
configInject(config)
- const { profile } = await get(['profile'])
+ const { profile, unique } = await get(['profile', 'unique'])
const parsed = profile ? JSON.parse(profile) || {} : {}
profileInject({
...parsed,
@@ -22,15 +24,19 @@ export const useInit = () => {
events: new Set(parsed.events || []),
talents: new Set(parsed.talents || []),
})
+ if (unique) uniqueInject(JSON.parse(unique))
setInited(true)
- }, [inited, configInject, profileInject, setInited])
+ }, [inited, configInject, profileInject, uniqueInject, setInited])
return [inited, loader] as const
}
-export const useSaver = () => {
+export const useWatcher = () => {
const [profile] = useRawProfile()
+ const unique = useUnique()
const [inited] = useAtom(initedAtom)
- return useCallback(async () => {
+ const [p, saveProfile] = useTransition()
+ const [u, saveUnique] = useTransition()
+ useEffect(() => {
if (!inited || !profile) return
const str = JSON.stringify({
...profile,
@@ -39,6 +45,17 @@ export const useSaver = () => {
events: Array.from(profile.events),
talents: Array.from(profile.talents),
})
- return await set({ profile: str })
- }, [inited, profile])
+ saveProfile(async () => {
+ await set({ profile: str })
+ })
+ }, [inited, profile, saveProfile])
+ useEffect(() => {
+ if (!inited || !unique) return
+ const str = JSON.stringify(unique)
+ saveUnique(async () => {
+ await set({ unique: str })
+ })
+ }, [inited, unique, saveUnique])
+
+ return p || u
}
diff --git a/packages/core/src/character.spec.ts b/packages/core/src/character.spec.ts
index 78db4c1..b6354d5 100644
--- a/packages/core/src/character.spec.ts
+++ b/packages/core/src/character.spec.ts
@@ -1,5 +1,5 @@
import { expect, test, describe } from 'bun:test'
-import { pullCharacter, uniqueGenerate } from './character'
+import { pullChara, uniqueGenerate } from './character'
import { enableMapSet } from 'immer'
enableMapSet()
@@ -7,7 +7,7 @@ describe('Character', () => {
const sum = (map: Map) =>
Array.from(map.values()).reduce((acc, val) => acc + val, 0)
test('pull', () => {
- let result = pullCharacter(
+ let result = pullChara(
{ count: 10, knife: 10 },
{ times: 0, drawns: new Map() },
)
@@ -15,17 +15,17 @@ describe('Character', () => {
expect(result.characters.length).toBe(10)
expect(result.times.times).toBe(10)
expect(result.times.drawns.size).toBe(10)
- result = pullCharacter({ count: 3, knife: 10 }, result.times)
+ result = pullChara({ count: 3, knife: 10 }, result.times)
expect(result.characters).not.toContainValue(null)
expect(result.characters.length).toBe(3)
expect(result.times.times).toBe(13)
expect(sum(result.times.drawns)).toBe(13)
- result = pullCharacter({ count: 3, knife: 10 }, result.times)
+ result = pullChara({ count: 3, knife: 10 }, result.times)
expect(result.characters).not.toContainValue(null)
expect(result.characters.length).toBe(3)
expect(result.times.times).toBe(16)
expect(sum(result.times.drawns)).toBe(16)
- result = pullCharacter({ count: 20, knife: 1 }, result.times)
+ result = pullChara({ count: 20, knife: 1 }, result.times)
expect(result.characters).not.toContainValue(null)
expect(result.characters.length).toBe(20)
expect(result.times.times).toBe(36)
@@ -56,6 +56,5 @@ describe('Character', () => {
expect(unique.property.STR).toBeLessThanOrEqual(10)
expect(unique.property.MNY).toBeLessThanOrEqual(10)
expect(unique.talent.length).toBeLessThanOrEqual(5)
- console.debug(unique)
})
})
diff --git a/packages/core/src/character.ts b/packages/core/src/character.ts
index 6859c0c..3f208e4 100644
--- a/packages/core/src/character.ts
+++ b/packages/core/src/character.ts
@@ -1,7 +1,10 @@
-import { type Character, type Talent, characters, talents } from '@remake/data'
+import type { Character, CharacterProperty, Talent } from '@remake/data'
+import { characters, talents } from '@remake/data'
import { type RNG, type WeightItem, pick, pickWeight } from '@remake/vitex'
+import type { Allocation } from './state'
-export type UniqueChara = Omit
+export type BaseChara = Omit
+export type BaseAlloc = Omit
export interface UniqueGenCfg {
prop: WeightItem[]
talent: WeightItem[]
@@ -22,7 +25,7 @@ export function uniqueGenerate(config: UniqueGenCfg, rng?: RNG) {
picked.add(t)
count--
}
- return { property, talent: Array.from(picked) } satisfies UniqueChara
+ return { property, talent: Array.from(picked) } satisfies BaseChara
}
export interface PullCharaOpt {
@@ -37,9 +40,9 @@ export interface PullCharaRet {
characters: Character['id'][]
times: PullCharaTms
}
-export function pullCharacter(
+export function pullChara(
opt: PullCharaOpt,
- tms: PullCharaTms,
+ tms: PullCharaTms = { times: 0, drawns: new Map() },
rng?: RNG,
): PullCharaRet {
const { count, knife } = opt
@@ -69,3 +72,34 @@ function deriveWeightMap(
Array.from(characters.keys(), id => [id, base - (drawns.get(id) ?? 0)]),
)
}
+
+export function charaPropToBaseAlloc(props: CharacterProperty): BaseAlloc {
+ return {
+ charm: props.CHR,
+ intelligence: props.INT,
+ strength: props.STR,
+ money: props.MNY,
+ }
+}
+
+function charaPropToAlloc(
+ props: CharacterProperty,
+ spirit: number,
+): Allocation {
+ return { ...charaPropToBaseAlloc(props), spirit }
+}
+
+function convert(chara: BaseChara, spirit: number) {
+ return {
+ allocation: charaPropToAlloc(chara.property, spirit),
+ talents: chara.talent,
+ }
+}
+
+export function startChara(id: Character['id'], spirit: number) {
+ return convert(characters.get(id)!, spirit)
+}
+
+export function startUnique(chara: BaseChara, spirit: number) {
+ return convert(chara, spirit)
+}
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 000d8cd..c06f033 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -1,10 +1,11 @@
-export type { RNG } from '@remake/vitex'
export type { GameState, ProfileState, Properties, Allocation } from './state'
export type { PullOptions, ReplacementResult } from './talent'
export type { AdditionalPoint, AdditionalPoints } from './talent'
export type { PullCharaOpt, PullCharaTms, PullCharaRet } from './character'
-export type { UniqueChara, UniqueGenCfg } from './character'
+export type { BaseChara, UniqueGenCfg } from './character'
export type { PickResult, StartResult } from './game'
export type { NextResult, SummaryResult, EndResult } from './game'
export { pull, exclude } from './talent'
+export { uniqueGenerate, pullChara, charaPropToBaseAlloc } from './character'
+export { startUnique, startChara } from './character'
export { pick, start, next, summary, end } from './game'
diff --git a/packages/hooks/src/alloc.ts b/packages/hooks/src/alloc.ts
index e48dc29..5036a6c 100644
--- a/packages/hooks/src/alloc.ts
+++ b/packages/hooks/src/alloc.ts
@@ -47,7 +47,7 @@ export const useAllocator = () => {
return { ...prev, [key]: final }
})
},
- [allocate, total],
+ [allocate, total, setAlloc],
)
return [alloc, allocator] as const
}
@@ -71,7 +71,7 @@ export const usePointRandomizer = () => {
}
setAlloc(alloc)
},
- [allocate, total],
+ [allocate, total, setAlloc],
)
}
diff --git a/packages/hooks/src/character.ts b/packages/hooks/src/character.ts
new file mode 100644
index 0000000..a7c63c9
--- /dev/null
+++ b/packages/hooks/src/character.ts
@@ -0,0 +1,104 @@
+import { useCallback, useState } from 'react'
+import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'
+import { useConfig, useProfile, useSetStep, useSetGameState, Step } from '.'
+import { uniqueGenerate, startUnique, startChara } from '@remake/core'
+import { pullChara, start, pick } from '@remake/core'
+import type { BaseChara, PullCharaTms } from '@remake/core'
+import type { Character } from '@remake/data'
+import type { RNG } from '@remake/vitex'
+
+export const uniqueAtom = atom(null)
+export const timesAtom = atom(undefined)
+
+export const useUnique = () => useAtomValue(uniqueAtom)
+export const useUniqueInject = () => {
+ const setUnique = useSetAtom(uniqueAtom)
+ return useCallback((unique: BaseChara) => setUnique(unique), [setUnique])
+}
+
+export const useUniqueGenerator = () => {
+ const { config } = useConfig().unique
+ const [unique, setUnique] = useAtom(uniqueAtom)
+ const generator = useCallback(
+ (rng?: RNG) => {
+ if (unique) return unique
+ const generated = uniqueGenerate(config, rng)
+ setUnique(generated)
+ return generated
+ },
+ [config, unique, setUnique],
+ )
+ return [unique, generator] as const
+}
+
+export interface PullCharaResult {
+ characters: Character['id'][]
+ unique: boolean
+}
+export const useCharaPuller = (rng?: RNG) => {
+ const { unique: u, chara } = useConfig()
+ const [unique] = useAtom(uniqueAtom)
+ const [times, setTimes] = useAtom(timesAtom)
+ const [pulled, setPulled] = useState({
+ characters: pullChara(chara, times, rng).characters,
+ unique: !!unique,
+ })
+ const puller = useCallback(() => {
+ const result = pullChara(chara, times, rng)
+ setTimes(result.times)
+ setPulled({
+ characters: result.characters,
+ unique: !!unique || result.times?.times >= u.limit * chara.count,
+ })
+ }, [u, chara, unique, times, setTimes, rng])
+ return [pulled, puller] as const
+}
+
+export type PickUnique = { type: 'unique'; id?: never }
+export type PickCharacter = {
+ type: 'character'
+ id: Character['id']
+}
+export type CharaPick = PickUnique | PickCharacter
+export const useCharaPicker = () => {
+ const [picked, setPicked] = useState(null)
+ const chara = useCallback(
+ (id: Character['id']) => setPicked({ type: 'character', id }),
+ [setPicked],
+ )
+ const uni = useCallback(() => setPicked({ type: 'unique' }), [setPicked])
+ return [picked, { chara, unique: uni }] as const
+}
+
+export const useCharaStart = () => {
+ const { spirit } = useConfig()
+ const [profile] = useProfile()
+ const unique = useAtomValue(uniqueAtom)
+ const setStep = useSetStep()
+ const setState = useSetGameState()
+ return useCallback(
+ (picked: CharaPick, rng?: RNG) => {
+ let result
+ if (picked.type === 'unique') {
+ if (!unique)
+ throw new Error('Unique character not generated yet')
+ result = startUnique(unique, spirit)
+ } else {
+ result = startChara(picked.id, spirit)
+ }
+ const { talents, additionalPoints } = pick(result.talents, rng)
+ // TODO: additionalPoints
+ const { state, achievements } = start(
+ profile,
+ result.allocation,
+ talents.talents,
+ )
+ setState(state)
+ setStep(Step.Play)
+ return achievements
+ },
+ [spirit, profile, unique, setStep, setState],
+ )
+}
+
+export { charaPropToBaseAlloc as convertProps } from '@remake/core'
diff --git a/packages/hooks/src/config.ts b/packages/hooks/src/config.ts
index 81d300b..3195cbf 100644
--- a/packages/hooks/src/config.ts
+++ b/packages/hooks/src/config.ts
@@ -1,6 +1,6 @@
import { useCallback } from 'react'
import { atom, useSetAtom, useAtomValue } from 'jotai'
-import type { PullOptions, PullCharaOpt } from '@remake/core'
+import type { PullOptions, PullCharaOpt, UniqueGenCfg } from '@remake/core'
export interface Config {
/** 游戏锁定天赋数量 */
lock: number
@@ -20,6 +20,11 @@ export interface Config {
pull: PullOptions
/** 名人模式配置 */
chara: PullCharaOpt
+ /** 唯一角色限制 */
+ unique: {
+ limit: number
+ config: UniqueGenCfg
+ }
}
export const configAtom = atom(null)
diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts
index 91ad7c0..3626b85 100644
--- a/packages/hooks/src/index.ts
+++ b/packages/hooks/src/index.ts
@@ -3,4 +3,5 @@ export * from './profile'
export * from './talent'
export * from './play'
export * from './alloc'
+export * from './character'
export type * from '@remake/core'
diff --git a/packages/hooks/src/play.ts b/packages/hooks/src/play.ts
index 2e5e38b..e887f7e 100644
--- a/packages/hooks/src/play.ts
+++ b/packages/hooks/src/play.ts
@@ -25,6 +25,7 @@ export type Log = Omit & {
props: Omit
}
+export const modeAtom = atom(Mode.Classic)
export const stepAtom = atom(Step.Idle)
export const gameStateAtom = atom(null)
export const logsAtom = atom([])
@@ -51,9 +52,10 @@ export const useGameReset = () => {
}, [resetTalent, resetAlloc, resetState, resetLogs])
}
-export const useStep = () => [useAtomValue(stepAtom), Step] as const
-export const useSetStep = () => [useSetAtom(stepAtom), Step] as const
+export const useStep = () => useAtomValue(stepAtom)
+export const useSetStep = () => useSetAtom(stepAtom)
export const useGameState = () => useAtomValue(gameStateAtom)
+export const useSetGameState = () => useSetAtom(gameStateAtom)
export const useSummary = () => useAtomValue(summaryAtom)
export const useLogs = () => useAtomValue(logsAtom)
@@ -69,16 +71,15 @@ export const useRemake = () => {
}
export const useModeChoose = () => {
+ const setMode = useSetAtom(modeAtom)
const setStep = useSetAtom(stepAtom)
const choose = useCallback(
(mode: Mode) => {
+ setMode(mode)
+ /* prettier-ignore */
switch (mode) {
- case Mode.Classic:
- setStep(Step.Pick)
- break
- case Mode.Celebrity:
- setStep(Step.Chara)
- break
+ case Mode.Classic: return setStep(Step.Pick)
+ case Mode.Celebrity: return setStep(Step.Chara)
}
},
[setStep],
@@ -122,7 +123,7 @@ export const useNext = () => {
setEnded(true)
}
return result.achievements
- }, [state, profile, setState])
+ }, [state, profile, setState, setLogs])
return [{ logs, ended }, nexter] as const
}
@@ -144,7 +145,7 @@ export const useGotoSummary = () => {
export const useEnd = () => {
const { lock } = useConfig()
const [profile, setProfile] = useProfile()
- const [step, setStep] = useAtom(stepAtom)
+ const setStep = useSetAtom(stepAtom)
const state = useAtomValue(gameStateAtom)
const reset = useGameReset()
const [locked, setLocked] = useState>(new Set())
@@ -163,7 +164,7 @@ export const useEnd = () => {
return next
})
},
- [setLocked],
+ [lock, setLocked],
)
const ender = useCallback(() => {
if (!state)
@@ -174,6 +175,6 @@ export const useEnd = () => {
setProfile(result.profile)
reset()
return result.achievements
- }, [state, step, profile, locked, setStep, setProfile, reset])
+ }, [state, profile, locked, setStep, setProfile, reset])
return [locked, picker, ender] as const
}
diff --git a/packages/hooks/src/talent.ts b/packages/hooks/src/talent.ts
index 48dcbac..754c68c 100644
--- a/packages/hooks/src/talent.ts
+++ b/packages/hooks/src/talent.ts
@@ -1,6 +1,6 @@
import { useState, useCallback } from 'react'
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'
-import { useConfig, useProfile, useSetStep } from '.'
+import { useConfig, useProfile, useSetStep, Step } from '.'
import { pull, exclude, pick, type PickResult } from '@remake/core'
import type { Talent } from '@remake/data'
import type { RNG } from '@remake/vitex'
@@ -82,7 +82,7 @@ export const useTalentSubmit = () => {
const picked = useAtomValue(pickedAtom)
const setReplaced = useSetAtom(replacedAtom)
const { enabled } = useSubmitIsEnable()
- const [setStep, Step] = useSetStep()
+ const setStep = useSetStep()
return useCallback(
(rng?: RNG) => {
if (!enabled) throw new Error('Not enough talents picked')