feat: 实现避难所仓储系统与生存状态HUD改进
- 新增避难所仓储功能,支持物品在随身背包与仓储间转移 - 添加生存状态图标资源与状态阈值告警系统 - 重构HUD界面,优化状态显示与操作流程 - 扩展游戏核心系统,增加仓储相关动作和校验 - 更新文档说明仓储规则与实现细节
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { EdgeView, GameView, InventoryViewEntry, QuestView } from '@tinywaste/game-core';
|
||||
import { getEquipmentArt, getItemArt } from './uiAssets';
|
||||
import { getEquipmentArt, getItemArt, getStatusArt } from './uiAssets';
|
||||
|
||||
export interface EquipmentPreviewEntry {
|
||||
id: string;
|
||||
@@ -30,14 +30,45 @@ export function getAlertCount(view: GameView) {
|
||||
return Number(Boolean(view.pendingEvent)) + Number(Boolean(view.combat));
|
||||
}
|
||||
|
||||
export function getDominantAlert(view: GameView) {
|
||||
return view.survival.alerts[0] ?? null;
|
||||
}
|
||||
|
||||
export function getCurrentPlace(view: GameView) {
|
||||
return view.map.places.find((place) => place.current) ?? null;
|
||||
}
|
||||
|
||||
export function getLatestLog(view: GameView) {
|
||||
return view.logs[0] ?? null;
|
||||
}
|
||||
|
||||
export function getVisibleInventory(view: GameView, limit = 6) {
|
||||
return view.player.inventory.slice(0, limit);
|
||||
}
|
||||
|
||||
export function getQuickUseItems(view: GameView, limit = 6) {
|
||||
const priority = {
|
||||
water: 0,
|
||||
food: 1,
|
||||
medicine: 2,
|
||||
tool: 3,
|
||||
material: 4,
|
||||
weapon: 5,
|
||||
armor: 6,
|
||||
ammo: 7,
|
||||
quest: 8,
|
||||
} as const;
|
||||
|
||||
return [...view.player.inventory]
|
||||
.filter((item) => item.canUse)
|
||||
.sort((left, right) => {
|
||||
const priorityDelta = priority[left.type] - priority[right.type];
|
||||
if (priorityDelta !== 0) return priorityDelta;
|
||||
return right.count - left.count;
|
||||
})
|
||||
.slice(0, limit);
|
||||
}
|
||||
|
||||
export function getObjectiveRows(view: GameView) {
|
||||
return view.quests
|
||||
.filter((quest) => quest.state === 'active' || quest.state === 'completed')
|
||||
@@ -55,6 +86,10 @@ export function getObjectiveRows(view: GameView) {
|
||||
});
|
||||
}
|
||||
|
||||
export function getPrimaryObjective(view: GameView) {
|
||||
return getObjectiveRows(view)[0] ?? null;
|
||||
}
|
||||
|
||||
export function getAttributeRows(view: GameView) {
|
||||
const { attributes } = view.player;
|
||||
|
||||
@@ -68,35 +103,87 @@ export function getAttributeRows(view: GameView) {
|
||||
}
|
||||
|
||||
export function getStatusEffects(view: GameView) {
|
||||
const { stats, maxStats } = view.player;
|
||||
const effects: { id: string; label: string; detail: string; tone: 'good' | 'warn' | 'danger' }[] = [];
|
||||
|
||||
if (stats.life / maxStats.life <= 0.55) {
|
||||
effects.push({ id: 'life', label: '创伤', detail: '生命处于低位', tone: 'danger' });
|
||||
}
|
||||
if (stats.thirst / maxStats.thirst <= 0.5) {
|
||||
effects.push({ id: 'thirst', label: '脱水', detail: '口渴已压缩行动余量', tone: 'warn' });
|
||||
}
|
||||
if (stats.hunger / maxStats.hunger <= 0.5) {
|
||||
effects.push({ id: 'hunger', label: '饥饿', detail: '需要补充稳定热量', tone: 'warn' });
|
||||
}
|
||||
if (stats.energy / maxStats.energy <= 0.45) {
|
||||
effects.push({ id: 'energy', label: '疲劳', detail: '精力不足,适合休整', tone: 'warn' });
|
||||
}
|
||||
if (stats.sanity / maxStats.sanity <= 0.45) {
|
||||
effects.push({ id: 'sanity', label: '精神波动', detail: '理智偏低,事件风险提升', tone: 'danger' });
|
||||
}
|
||||
if (stats.radiation / maxStats.radiation >= 0.32) {
|
||||
effects.push({ id: 'radiation', label: '污染累积', detail: '辐射正在侵蚀身体', tone: 'danger' });
|
||||
}
|
||||
const effects = view.survival.alerts.map((entry) => ({
|
||||
id: entry.stat,
|
||||
label: `${entry.label} · ${entry.summary}`,
|
||||
detail: entry.impact,
|
||||
recovery: entry.recovery,
|
||||
art: getStatusArt(entry.stat),
|
||||
tone:
|
||||
entry.tier === 'strained' ? ('warn' as const) : entry.tier === 'safe' ? ('good' as const) : ('danger' as const),
|
||||
}));
|
||||
|
||||
if (!effects.length) {
|
||||
effects.push({ id: 'stable', label: '稳定', detail: '当前幸存者状态平稳', tone: 'good' });
|
||||
return [
|
||||
{
|
||||
id: 'stable',
|
||||
label: '稳定',
|
||||
detail: '当前幸存者状态平稳,可以继续规划下一步行动。',
|
||||
recovery: '保持补给循环与节奏即可。',
|
||||
art: getStatusArt('life'),
|
||||
tone: 'good' as const,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return effects.slice(0, 4);
|
||||
}
|
||||
|
||||
export function getExpeditionStatus(view: GameView) {
|
||||
const { stats, maxStats } = view.player;
|
||||
const readiness = Math.round(
|
||||
(stats.life / maxStats.life) * 34 +
|
||||
(stats.energy / maxStats.energy) * 28 +
|
||||
(stats.thirst / maxStats.thirst) * 20 +
|
||||
(stats.hunger / maxStats.hunger) * 18,
|
||||
);
|
||||
const loadPercent = Math.round((view.player.inventoryUsage / view.player.inventoryCapacity) * 100);
|
||||
const threatCount = view.survival.alerts.length;
|
||||
|
||||
return {
|
||||
readiness,
|
||||
loadPercent,
|
||||
threatCount,
|
||||
tone: readiness >= 74 && threatCount === 0 ? 'good' : readiness >= 48 ? 'warn' : 'danger',
|
||||
};
|
||||
}
|
||||
|
||||
export function getSurvivorMetrics(view: GameView) {
|
||||
const protection = Math.min(
|
||||
100,
|
||||
Math.round(
|
||||
(view.player.equipment.body ? 34 : 12) +
|
||||
view.player.attributes.str * 5 +
|
||||
(view.player.stats.life / view.player.maxStats.life) * 30,
|
||||
),
|
||||
);
|
||||
const stealth = Math.min(
|
||||
100,
|
||||
Math.round(
|
||||
view.player.attributes.agi * 8 +
|
||||
view.player.attributes.per * 5 +
|
||||
(view.player.stats.sanity / view.player.maxStats.sanity) * 20,
|
||||
),
|
||||
);
|
||||
const mobility = Math.max(
|
||||
0,
|
||||
Math.min(
|
||||
100,
|
||||
Math.round(
|
||||
view.player.attributes.agi * 7 +
|
||||
(view.player.stats.energy / view.player.maxStats.energy) * 42 -
|
||||
(view.player.inventoryUsage / view.player.inventoryCapacity) * 18,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return [
|
||||
{ id: 'protection', label: '防护', value: protection },
|
||||
{ id: 'stealth', label: '潜行', value: stealth },
|
||||
{ id: 'mobility', label: '机动', value: mobility },
|
||||
];
|
||||
}
|
||||
|
||||
export function getSupplyCounts(view: GameView) {
|
||||
const counts = {
|
||||
water: 0,
|
||||
|
||||
Reference in New Issue
Block a user