feat: add progression logic for puzzle residences

- Implemented functions to manage puzzle progress including checking if residences are started, complete, and unlocked.
- Added utility functions to retrieve piece IDs based on residence and route.
- Introduced a new TypeScript file for progression management.
- Integrated puzzle data configuration and residence data for seamless progression tracking.
This commit is contained in:
zhongyidian committed 2026-05-01 21:19:25 +08:00
1 parent 5a1c3cc368
commit 284302341c
72 files changed
+1104 -517

No files matched your search

+33 -6
View File
@@ -2,6 +2,8 @@ import { useEffect } from 'react'
import { getBackgroundImage, getStaticImage } from '@/lib/utils'
import { useNavigate, useParams } from 'react-router-dom'
import { Image } from '@/components'
import { usePuzzleStore } from '@/store/puzzleStore'
import { getResidenceStageUnlocks, isResidenceUnlocked } from '@/config/progression'
import { getUserDefine } from '@/lib/utils/api-common'
import { useChenyunStore, CHENYUN_LESSON_ID, CHENYUN_KEY } from '@/store/chenyunStore'
@@ -27,6 +29,17 @@ const Chenyun = () => {
const lastVisitedPlace = useChenyunStore((state) => state.lastVisitedPlace)
const puzzles = usePuzzleStore((state) => state.puzzles)
const isLoaded = usePuzzleStore((state) => state.isLoaded)
const { dialogueUnlocked, reflectionUnlocked, internalizationUnlocked } =
getResidenceStageUnlocks(starName, puzzles)
useEffect(() => {
if (isLoaded && !isResidenceUnlocked(starName, puzzles)) {
navigate('/menu', { replace: true })
}
}, [isLoaded, navigate, puzzles, starName])
useEffect(() => {
;(async () => {
try {
@@ -77,21 +90,35 @@ const Chenyun = () => {
<div className="absolute right-20 top-75 flex flex-col space-y-10">
{/* 对话 */}
<Image
button
button={dialogueUnlocked}
className={dialogueUnlocked ? undefined : 'opacity-50 grayscale cursor-not-allowed'}
src={getStaticImage('star/一-解锁')}
onClick={() => navigate(`/${moduleName}/${starName}/${lastVisitedPlace || 'place1'}`)}
onClick={() => {
if (!dialogueUnlocked) return
navigate(`/${moduleName}/${starName}/${lastVisitedPlace || 'place1'}`)
}}
/>
{/* 体悟 */}
<Image
button
button={reflectionUnlocked}
className={reflectionUnlocked ? undefined : 'opacity-50 grayscale cursor-not-allowed'}
src={getStaticImage('star/二-解锁')}
onClick={() => navigate(`/${moduleName}/${starName}/reflection`)}
onClick={() => {
if (!reflectionUnlocked) return
navigate(`/${moduleName}/${starName}/reflection`)
}}
/>
{/* 内化 */}
<Image
button
button={internalizationUnlocked}
className={
internalizationUnlocked ? undefined : 'opacity-50 grayscale cursor-not-allowed'
}
src={getStaticImage('star/三-解锁')}
onClick={() => navigate(`/${moduleName}/${starName}/internalization`)}
onClick={() => {
if (!internalizationUnlocked) return
navigate(`/${moduleName}/${starName}/internalization`)
}}
/>
</div>
</div>