"use client"; // 回响星核 / Echo Nexus — 游戏主入口 import { useState, useEffect } from "react"; import { StarfieldCanvas } from "@/components/game/StarfieldCanvas"; import { ResourceBar } from "@/components/game/ResourceBar"; import { CrystalOrb } from "@/components/game/CrystalOrb"; import { DecodePanel } from "@/components/game/DecodeArray"; import { TechTree } from "@/components/game/TechTree"; import { Codex } from "@/components/game/Codex"; import { PrestigeDialog } from "@/components/game/PrestigeDialog"; import { SettingsDialog } from "@/components/game/SettingsDialog"; import { ExpeditionPanel } from "@/components/game/ExpeditionPanel"; import { AchievementsPanel } from "@/components/game/AchievementsPanel"; import { AchievementNotifier } from "@/components/game/AchievementNotifier"; import { ConstellationPanel } from "@/components/game/ConstellationPanel"; import { ConstellationDialog } from "@/components/game/ConstellationDialog"; import { ChronicleDialog } from "@/components/game/ChronicleDialog"; import { BeaconPanel } from "@/components/game/BeaconPanel"; import { TutorialOverlay } from "@/components/game/TutorialOverlay"; import { OfflineReportDialog } from "@/components/game/OfflineReportDialog"; import { CruiseMode } from "@/components/game/CruiseMode"; import { AttributesPanel } from "@/components/game/AttributesPanel"; import { ExplorationRadar } from "@/components/game/ExplorationRadar"; import { RelicCodex } from "@/components/game/RelicCodex"; import { StarTideNotifier, StarTideIndicator, StarTideOverlay, } from "@/components/game/StarTide"; import { useGameLoop } from "@/hooks/useGameLoop"; import { useAudioSync } from "@/hooks/useAudio"; import { useGlobalTide } from "@/hooks/useGlobalTide"; import { useGameStore } from "@/store/gameStore"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Button } from "@/components/ui/button"; import { Settings, RotateCcw, Sparkles, Cpu, BookOpen, BarChart3, Rocket, Github, Trophy, Star, Radio, Navigation, User, Gem, Zap, Flame, Database, BookMarked, } from "lucide-react"; import { TECH_TREE, FRAGMENTS, formatNum } from "@/lib/game/config"; import { ACHIEVEMENTS } from "@/lib/game/achievements"; import { TIDE_EVENTS } from "@/lib/game/starTide"; import { CONSTELLATION_PERKS } from "@/lib/game/constellation"; import { generateDailyChallenge, loadDailyProgress, loadLeaderboard } from "@/lib/game/beacon"; export default function Page() { useGameLoop(); useAudioSync(); useGlobalTide(); const [prestigeOpen, setPrestigeOpen] = useState(false); const [settingsOpen, setSettingsOpen] = useState(false); const [constellationOpen, setConstellationOpen] = useState(false); const [chronicleOpen, setChronicleOpen] = useState(false); const [cruiseOpen, setCruiseOpen] = useState(false); const [mounted, setMounted] = useState(false); const contact = useGameStore((s) => s.contact); const totalDecoded = useGameStore((s) => s.totalDecoded); const crystalsPerSec = useGameStore((s) => s.crystalsPerSec); const ascensions = useGameStore((s) => s.ascensions); const ownedTech = useGameStore((s) => s.tech); const ownedFragments = useGameStore((s) => s.fragments); const ownedAchievements = useGameStore((s) => s.achievements); const ownedConstellation = useGameStore((s) => s.constellation ?? []); const pendingPerkChoices = useGameStore((s) => s.pendingPerkChoices); const crystals = useGameStore((s) => s.crystals); const crystalCap = useGameStore((s) => s.crystalCap); const activeTide = useGameStore((s) => s.activeTide); const globalTide = useGameStore((s) => s.globalTide); const energy = useGameStore((s) => s.energy); const hasActiveExpedition = useGameStore((s) => !!s.activeExpedition && !s.activeExpedition.finished); const chronicleCount = useGameStore((s) => s.chronicle?.length ?? 0); const pendingAttrPoints = useGameStore((s) => s.pendingAttrPoints ?? 0); // 深空信标:检测是否有可领取的奖励(独立 localStorage) const [beaconClaimable, setBeaconClaimable] = useState(false); useEffect(() => { let cancelled = false; const check = () => { try { const c = generateDailyChallenge(); const p = loadDailyProgress(); if (!cancelled) { setBeaconClaimable(p.completedAt !== null && !p.claimed && p.dateKey === c.dateKey); } } catch { if (!cancelled) setBeaconClaimable(false); } }; check(); const id = setInterval(check, 2000); return () => { cancelled = true; clearInterval(id); }; }, []); // 挂载检测:避免持久化 store 在 SSR/CSR 间产生 hydration 不一致 useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect setMounted(true); }, []); // 防止 SSR/CSR 不一致 if (!mounted) { return (
唤醒回响中…
); } const ownedTechCount = Object.values(ownedTech).filter((v) => v > 0).length; const ownedFragCount = Object.values(ownedFragments).filter(Boolean).length; const ownedAchCount = Object.values(ownedAchievements).filter(Boolean).length; const canPrestige = contact >= 100; const hasPendingPerk = pendingPerkChoices && pendingPerkChoices.length > 0; // 仓库满仓警告 const warehouseFull = crystals >= crystalCap * 0.98; // 目标提示 let goal = "点击中央晶体发起脉冲,累积记忆晶体"; if (totalDecoded === 0 && crystals >= 5) { goal = "右侧「待解码晶体」点击一颗晶体,开始解码"; } else if (totalDecoded > 0 && ownedTechCount === 0) { goal = "用洞见解锁技术树,提升产能"; } else if (totalDecoded > 0 && ownedFragCount < FRAGMENTS.length) { goal = `继续解码,拼凑记忆图谱(${ownedFragCount}/${FRAGMENTS.length})`; } if (energy >= 1 && totalDecoded >= 3) { goal = "「探险」标签可深入遗迹,获取丰厚奖励"; } if (ascensions >= 1 && ownedConstellation.length > 0) { goal = `星图天赋已觉醒 ${ownedConstellation.length}/18,继续飞升获取更多`; } if (warehouseFull) { goal = "⚠ 仓库已满,产能浪费中!请解码晶体或升级仓库"; } if (hasPendingPerk) { goal = "✦ 星图觉醒!点击顶部「星图」按钮选择一道天赋"; } if (activeTide) { const tm = TIDE_EVENTS[activeTide.type]; const prefix = globalTide ? "🌐 全球星潮 · " : ""; goal = `${prefix}${tm.icon} 星潮「${tm.name}」进行中 · ${tm.desc}`; } if (canPrestige) goal = "✦ 接触进度已满,可发起飞升进入新周目"; return (
{/* 星空背景 */} {/* 星潮背景叠层 */} {/* 顶部 Header */}

回响星核

ECHO NEXUS · v0.10

{hasPendingPerk && ( )} {canPrestige && ( )}
setPrestigeOpen(true)} />
{/* 主体 — v0.10 工单 #2 布局重构:反转左右比例,左栏紧凑晶体球,右栏扩展核心玩法 */}
{/* 左侧:脉冲晶体(紧凑模式) + 收益 + 探索雷达 */}
{/* 装饰光圈 */}
{/* v0.10 装饰全息环(缩小适应紧凑布局) */}
{/* 四角全息标记 */}
{/* 顶部状态条 */}
CRYSTAL CORE · ONLINE
{/* 晶体球区域(紧凑居中) */}
{/* v0.9 全息收益信息面板 */} {/* v0.10 探索目标雷达(新增)— 填充留白,让晶体球区有价值 */}
{/* 右侧:解码 + 标签面板(v0.10 扩展,从 420px 扩到 1fr) */}
{/* 解码面板 */}
{/* 标签面板:探险 / 技术 / 星图 / 图谱 / 成就 / 信标 / 统计 / 角色 / 遗迹图鉴 */}
{/* v0.10 标签页响应式布局,小屏 3 列 3 行避免拥挤遮挡,大屏 9 列 */} 探险 {energy >= 1 && !hasActiveExpedition && ( )} {hasActiveExpedition && ( )} 技术 星图 {hasPendingPerk && ( )} 图谱 成就 {ownedAchCount < ACHIEVEMENTS.length && ( )} 信标 {beaconClaimable && ( )} 统计 角色 {pendingAttrPoints > 0 && ( )} 图鉴
{/* 底部 Footer */}
{goal} | 产能 {formatNum(crystalsPerSec)}/s
{cruiseOpen && setCruiseOpen(false)} />}
); } /** * v0.9 工单 #2:全息收益信息面板 * 在中央晶体球下方展示 4 项核心收益指标(产能 / 脉冲 / 连击 / 仓库), * 让玩家明确感知晶体球的价值,缓解"占地方又没用"的反馈。 * 严格四色全息配色:emerald / rose / amber / fuchsia(禁止蓝色/靛色)。 */ function CrystalYieldPanel() { const crystalsPerSec = useGameStore((s) => s.crystalsPerSec); const pulsePower = useGameStore((s) => s.pulsePower); const combo = useGameStore((s) => s._combo); const crystals = useGameStore((s) => s.crystals); const crystalCap = useGameStore((s) => s.crystalCap); // 连击倍率:1 + (combo - 1) * 0.15(仅 combo≥1 时生效) const comboMult = combo >= 1 ? 1 + (combo - 1) * 0.15 : 1; const comboHot = combo >= 3; // 连击≥3 高亮闪烁 // 仓库容量百分比 const fillPct = crystalCap > 0 ? (crystals / crystalCap) * 100 : 0; const warehouseWarn = fillPct >= 90; // ≥90% 警告色 + pulse return (
{/* 晶体产能 — emerald */}
晶体产能
{formatNum(crystalsPerSec)} /s
{/* 主动脉冲 — rose */}
主动脉冲
{formatNum(pulsePower)} {combo >= 1 && ( ×{comboMult.toFixed(2)} )}
{/* 当前连击 — amber,≥3 时高亮闪烁 */}
当前连击
{combo} /10
{/* 仓库容量 — fuchsia,≥90% 切 rose 警告色 + pulse */}
仓库容量
{formatNum(crystals)} /{formatNum(crystalCap)}
); } function StatsPanel() { const s = useGameStore(); const achCount = Object.values(s.achievements).filter(Boolean).length; // 深空信标本地排行榜最高分(独立 localStorage) const [beaconBest, setBeaconBest] = useState(null); useEffect(() => { try { const lb = loadLeaderboard(); // eslint-disable-next-line react-hooks/set-state-in-effect setBeaconBest(lb.length > 0 ? lb[0].score : null); } catch { setBeaconBest(null); } }, []); const rows = [ { label: "累计解码晶体", value: `${s.totalDecoded} 颗` }, { label: "飞升周目", value: `${s.ascensions}` }, { label: "持有蓝图", value: `${s.blueprints.length} / 6` }, { label: "已学技术", value: `${Object.values(s.tech).filter((v) => v > 0).length} / ${TECH_TREE.length}` }, { label: "已获碎片", value: `${Object.values(s.fragments).filter(Boolean).length} / ${FRAGMENTS.length}` }, { label: "已解锁成就", value: `${achCount} / ${ACHIEVEMENTS.length}` }, { label: "星图天赋", value: `${s.constellation?.length ?? 0} / ${CONSTELLATION_PERKS.length}` }, { label: "接触进度", value: `${s.contact.toFixed(1)}%` }, { label: "晶体产能", value: `${s.crystalsPerSec.toFixed(2)} /s` }, { label: "仓库上限", value: `${formatNum(s.crystalCap)}` }, { label: "洞见倍率", value: `×${s.insightMult.toFixed(2)}` }, { label: "累计探险", value: `${s.totalExpeditions} 次` }, { label: "BOSS 击破", value: `${s.bossKills ?? 0} 次` }, { label: "星潮亲历", value: `${(s.starTidesEncountered ?? []).length} / 9` }, { label: "编年史条目", value: `${(s.chronicle ?? []).length} 纪元` }, { label: "探险能量", value: `${Math.floor(s.energy)} / ${s.energyMax}` }, { label: "信标最高分", value: beaconBest !== null ? formatNum(beaconBest) : "—" }, { label: "探索力", value: `${s.attributes?.exploration ?? 0} / 100` }, { label: "智慧", value: `${s.attributes?.wisdom ?? 0} / 100` }, { label: "勇气", value: `${s.attributes?.courage ?? 0} / 100` }, { label: "灵感", value: `${s.attributes?.inspiration ?? 0} / 100` }, { label: "待分配属性点", value: `${s.pendingAttrPoints ?? 0}` }, ]; return (
{rows.map((r) => (
{r.label} {r.value}
))}
); }