feat: 实现避难所仓储系统与生存状态HUD改进

- 新增避难所仓储功能,支持物品在随身背包与仓储间转移
- 添加生存状态图标资源与状态阈值告警系统
- 重构HUD界面,优化状态显示与操作流程
- 扩展游戏核心系统,增加仓储相关动作和校验
- 更新文档说明仓储规则与实现细节
This commit is contained in:
2026-04-28 22:58:49 +08:00
parent e783e6e533
commit 6234a50bdb
27 changed files with 1455 additions and 1024 deletions
@@ -1,5 +1,5 @@
import type { GameAction, GameView } from '@tinywaste/game-core';
import { edgeDestination, getActiveQuestCount, getCurrentPlace, getRiskDots, getRouteRiskTier } from '../hudModel';
import { edgeDestination, getActiveQuestCount, getCurrentPlace, getExpeditionStatus, getRiskDots, getRouteRiskTier } from '../hudModel';
import { getPlaceThumbStyle } from '../uiAssets';
import { PanelHeader } from '../../shared/components/PanelHeader';
@@ -14,28 +14,36 @@ export function RoutePanel({
}) {
const currentPlace = getCurrentPlace(view);
const activeQuestCount = getActiveQuestCount(view);
const expedition = getExpeditionStatus(view);
return (
<section className="panel panel-route">
<PanelHeader title="Current Location" subtitle="路线、风险、耗时全部固定在当前视口内" />
<section className="panel panel-route expedition-panel">
<header className="expedition-head">
<div>
<p className="eyebrow">Expedition rail</p>
<h2>{currentPlace?.name ?? view.header.placeName}</h2>
</div>
<span className={`hud-chip ${expedition.tone === 'good' ? 'safe' : expedition.tone}`}>
{view.header.riskLabel}
</span>
</header>
<article className="route-summary-card">
<article className="expedition-core">
<span className="intel-kicker">CURRENT SECTOR</span>
<h2>{currentPlace?.name ?? view.header.placeName}</h2>
<p>{view.header.placeDesc}</p>
<div className="route-summary-meta">
<div>
<small></small>
<strong>{view.header.riskLabel}</strong>
</div>
<div>
<small></small>
<strong>{view.place.services.length || 1} </strong>
</div>
<div>
<small></small>
<strong>{activeQuestCount}</strong>
</div>
<div className="expedition-status-grid">
<article className="expedition-status-card">
<small></small>
<strong>{expedition.readiness}%</strong>
</article>
<article className="expedition-status-card">
<small></small>
<strong>{view.player.inventoryUsage}/{view.player.inventoryCapacity}</strong>
</article>
<article className="expedition-status-card">
<small></small>
<strong>{expedition.threatCount || activeQuestCount}</strong>
</article>
</div>
<div className="intel-meta">
{(currentPlace?.tags ?? []).map((tag) => (
@@ -46,7 +54,9 @@ export function RoutePanel({
</div>
</article>
<div className="route-list">
<section className="route-stack">
<PanelHeader title="Routes" subtitle="选择下一段远行目标" compact />
<div className="route-list expedition-route-list">
{view.map.edges.map((edge) => {
const destination = edgeDestination(view, edge);
if (!destination) return null;
@@ -57,7 +67,7 @@ export function RoutePanel({
return (
<button
key={`${edge.from}-${edge.to}`}
className={`route-card tone-${riskTier.tone}`}
className={`route-card expedition-route-card tone-${riskTier.tone}`}
disabled={Boolean(edge.blockedReason) || isWorking}
onClick={() => onSendAction({ type: 'travel', toPlaceId: edge.to })}
>
@@ -82,11 +92,12 @@ export function RoutePanel({
</button>
);
})}
</div>
</div>
</section>
<section className="world-map-panel">
<PanelHeader title="World Map" subtitle="节点式世界图用于压缩表达地理推进" compact />
<div className="map-node-grid">
<section className="world-map-panel expedition-map-panel">
<PanelHeader title="Known sectors" subtitle="压缩后的节点情报" compact />
<div className="map-node-grid expedition-map-grid">
{view.map.places.map((place) => (
<article key={place.id} className={`map-node-card ${place.current ? 'current' : ''}`}>
<strong>{place.name}</strong>