mirror of
https://github.com/VickScarlet/lifeRestart.git
synced 2026-08-28 01:06:49 +08:00
update: game core flow pages
This commit is contained in:
@@ -7,6 +7,7 @@ export interface Config {
|
||||
pull: PullOptions
|
||||
points: number
|
||||
allocate: number
|
||||
spirit: number
|
||||
mode: number
|
||||
}
|
||||
|
||||
|
||||
+106
-26
@@ -1,9 +1,11 @@
|
||||
import { useTransition, useCallback } from 'react'
|
||||
import { useCallback, useRef, useState } from 'react'
|
||||
import { atom, useSetAtom, useAtomValue, useAtom } from 'jotai'
|
||||
import { useConfig } from './config'
|
||||
import { useProfile } from './profile'
|
||||
import { end } from '@remake/core'
|
||||
import type { GameState } from '@remake/core'
|
||||
import { useReplaced, useTalentReset } from './talent'
|
||||
import { useAlloc, useAllocReset } from './alloc'
|
||||
import { start, next, summary, end } from '@remake/core'
|
||||
import type { GameState, Properties, NextResult } from '@remake/core'
|
||||
import type { Talent } from '@remake/data/talent'
|
||||
|
||||
export enum Step {
|
||||
@@ -15,45 +17,123 @@ export enum Step {
|
||||
Summary = 'summary',
|
||||
}
|
||||
|
||||
export type Log = Omit<NextResult, 'state'> & {
|
||||
props: Omit<Properties, 'age'>
|
||||
}
|
||||
|
||||
const stepAtom = atom<Step>(Step.Idle)
|
||||
const gameStateAtom = atom<GameState | null>(null)
|
||||
const logsAtom = atom<Log[]>([])
|
||||
const summaryAtom = atom(0)
|
||||
|
||||
export const useStateReset = () => {
|
||||
const setGameState = useSetAtom(gameStateAtom)
|
||||
return useCallback(() => setGameState(null), [setGameState])
|
||||
}
|
||||
export const useLogsReset = () => {
|
||||
const setLogs = useSetAtom(logsAtom)
|
||||
return useCallback(() => setLogs([]), [setLogs])
|
||||
}
|
||||
export const useGameReset = () => {
|
||||
const resetTalent = useTalentReset()
|
||||
const resetAlloc = useAllocReset()
|
||||
const resetState = useStateReset()
|
||||
const resetLogs = useLogsReset()
|
||||
return useCallback(() => {
|
||||
resetTalent()
|
||||
resetAlloc()
|
||||
resetState()
|
||||
resetLogs()
|
||||
}, [resetTalent, resetAlloc, resetState, resetLogs])
|
||||
}
|
||||
|
||||
export const useStep = () => useAtomValue(stepAtom)
|
||||
export const useSetStep = () => useSetAtom(stepAtom)
|
||||
export const useGameState = () => useAtomValue(gameStateAtom)
|
||||
export const useSummary = () => useAtomValue(summaryAtom)
|
||||
export const useLogs = () => useAtomValue(logsAtom)
|
||||
|
||||
export const useRemake = () => {
|
||||
const config = useConfig()
|
||||
const { mode } = useConfig()
|
||||
const [{ times }] = useProfile()
|
||||
const setStep = useSetAtom(stepAtom)
|
||||
const reset = useGameReset()
|
||||
return useCallback(() => {
|
||||
reset()
|
||||
setStep(times < mode ? Step.Pick : Step.Mode)
|
||||
}, [mode, times, setStep, reset])
|
||||
}
|
||||
|
||||
export const useStart = () => {
|
||||
const { spirit } = useConfig()
|
||||
const [profile] = useProfile()
|
||||
const setStep = useSetAtom(stepAtom)
|
||||
const setState = useSetAtom(gameStateAtom)
|
||||
const allocate = useAlloc()
|
||||
const { talents: tr } = useReplaced()
|
||||
return useCallback(() => {
|
||||
const step = profile.times < config.mode ? Step.Pick : Step.Mode
|
||||
setStep(step)
|
||||
}, [config, profile, setStep])
|
||||
const alloc = { ...allocate, spirit }
|
||||
const result = start(profile, alloc, tr.talents)
|
||||
setState(result.state)
|
||||
setStep(Step.Play)
|
||||
return result.achievements
|
||||
}, [profile, allocate, spirit, tr, setStep, setState])
|
||||
}
|
||||
|
||||
export const useNext = () => {
|
||||
const [profile] = useProfile()
|
||||
const [state, setState] = useAtom(gameStateAtom)
|
||||
const [logs, setLogs] = useAtom(logsAtom)
|
||||
const endRef = useRef(false)
|
||||
const [ended, setEnded] = useState(false)
|
||||
if (!state) throw new Error('Game state is not available.')
|
||||
const nexter = useCallback(() => {
|
||||
if (!state) throw new Error('Game state is not available.')
|
||||
if (endRef.current) throw new Error('Game state is already ended.')
|
||||
const { state: s, ...result } = next(state, profile)
|
||||
setState(s)
|
||||
const { age, ...props } = s.props.current
|
||||
const log = { ...result, props }
|
||||
setLogs(prev => [...prev, log])
|
||||
if (s.life <= 0) {
|
||||
endRef.current = true
|
||||
setEnded(true)
|
||||
}
|
||||
return result.achievements
|
||||
}, [state, profile, setState])
|
||||
return [{ state, logs, ended }, nexter] as const
|
||||
}
|
||||
|
||||
export const useGotoSummary = () => {
|
||||
const [profile] = useProfile()
|
||||
const [state, setState] = useAtom(gameStateAtom)
|
||||
const setStep = useSetAtom(stepAtom)
|
||||
const setSummary = useSetAtom(summaryAtom)
|
||||
return useCallback(() => {
|
||||
if (!state) throw new Error('Game state is not available.')
|
||||
const result = summary(state, profile)
|
||||
setSummary(result.summary)
|
||||
setState(result.state)
|
||||
setStep(Step.Summary)
|
||||
return result.achievements
|
||||
}, [state, profile, setStep, setState, setSummary])
|
||||
}
|
||||
|
||||
export const useEnd = () => {
|
||||
const [profile, setProfile] = useProfile()
|
||||
const [step, setStep] = useAtom(stepAtom)
|
||||
const [state, setState] = useAtom(gameStateAtom)
|
||||
const [pending, startTransition] = useTransition()
|
||||
const ender = useCallback(
|
||||
const state = useAtomValue(gameStateAtom)
|
||||
const reset = useGameReset()
|
||||
return useCallback(
|
||||
(talent?: Talent['id']) => {
|
||||
startTransition(async () => {
|
||||
if (!state || step === Step.Summary)
|
||||
throw new Error(
|
||||
'Game state is not available or already ended.',
|
||||
)
|
||||
const { profile: next, achievements } = end(
|
||||
state,
|
||||
profile,
|
||||
talent,
|
||||
)
|
||||
setStep(Step.Idle)
|
||||
setState(null)
|
||||
setProfile(next)
|
||||
})
|
||||
if (!state)
|
||||
throw new Error('Game state is not available or already ended.')
|
||||
const result = end(state, profile, talent)
|
||||
setStep(Step.Idle)
|
||||
setProfile(result.profile)
|
||||
reset()
|
||||
return result.achievements
|
||||
},
|
||||
[state, step, profile, setStep, setState, setProfile],
|
||||
[state, step, profile, setStep, setProfile, reset],
|
||||
)
|
||||
return [pending, ender] as const
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import type { ProfileState } from '@remake/core'
|
||||
|
||||
const profileAtom = atom<ProfileState | null>(null)
|
||||
|
||||
export const useRawProfile = () => useAtom(profileAtom)
|
||||
|
||||
export const useProfile = () => {
|
||||
const [profile, setProfile] = useAtom(profileAtom)
|
||||
if (!profile) throw new Error('Profile is not loaded')
|
||||
|
||||
@@ -10,6 +10,15 @@ import type { Talent } from '@remake/data/talent'
|
||||
const pickedAtom = atom(new Set<Talent['id']>())
|
||||
const replacedAtom = atom<TalentsPickedResult | null>(null)
|
||||
|
||||
export const useTalentReset = () => {
|
||||
const setPicked = useSetAtom(pickedAtom)
|
||||
const setReplaced = useSetAtom(replacedAtom)
|
||||
return useCallback(() => {
|
||||
setPicked(new Set())
|
||||
setReplaced(null)
|
||||
}, [setPicked, setReplaced])
|
||||
}
|
||||
|
||||
export const usePicked = () => {
|
||||
const picked = useAtomValue(pickedAtom)
|
||||
if (!picked) throw new Error('No talents picked')
|
||||
@@ -26,11 +35,12 @@ export const useTalentPuller = () => {
|
||||
const [profile] = useProfile()
|
||||
const [pulled, setPulled] = useState<Talent['id'][] | null>(null)
|
||||
const puller = useCallback(
|
||||
(rng?: RNG) => setPulled(pull(p, profile, rng)),
|
||||
// (rng?: RNG) =>
|
||||
// setPulled([
|
||||
// 1142, 1143, 1144, 1145, 1146, 1086, 1122, 1111, 1130, 1048,
|
||||
// ]),
|
||||
// (rng?: RNG) => setPulled(pull(p, profile, rng)),
|
||||
(rng?: RNG) =>
|
||||
setPulled([
|
||||
1142, 1143, 1144, 1145, 1146, 1086, 1122, 1111, 1130, 1048,
|
||||
1033,
|
||||
]),
|
||||
[p, profile, setPulled],
|
||||
)
|
||||
return [pulled, puller] as const
|
||||
|
||||
Reference in New Issue
Block a user