From 8f6a6b96e208b001920ba8ac2ced961dcc57f81d Mon Sep 17 00:00:00 2001 From: hypercross Date: Mon, 23 Mar 2026 01:13:19 +0800 Subject: [PATCH] feat: mothership character store --- src/journals/mothership/characterStore.ts | 334 ++++++++++++++++++++++ src/journals/mothership/index.ts | 66 +++++ src/journals/mothership/types.ts | 76 +++++ 3 files changed, 476 insertions(+) create mode 100644 src/journals/mothership/characterStore.ts create mode 100644 src/journals/mothership/index.ts create mode 100644 src/journals/mothership/types.ts diff --git a/src/journals/mothership/characterStore.ts b/src/journals/mothership/characterStore.ts new file mode 100644 index 0000000..d3a165c --- /dev/null +++ b/src/journals/mothership/characterStore.ts @@ -0,0 +1,334 @@ +import { createStore } from "solid-js/store"; +import type { + CharacterStats, + CharacterSaves, + InventoryItem, + MothershipCharacter, + MothershipStoreState, + VitalValue, + StressValue, +} from "./types"; + +/** + * 创建默认角色数据 + */ +export function createDefaultCharacter(): MothershipCharacter { + return { + stats: { + strength: 50, + agility: 50, + combat: 50, + intellect: 50, + }, + saves: { + fear: 50, + sanity: 50, + body: 50, + }, + skills: [], + inventory: [], + status: [], + hp: { current: 0, max: 0 }, + stress: { current: 0, min: 0 }, + wounds: { current: 0, max: 0 }, + }; +} + +/** + * 限制数值在 0-99 范围内 + */ +function clampStat(value: number): number { + return Math.max(0, Math.min(99, value)); +} + +/** + * 限制数值在指定范围内 + */ +function clampValue(value: number, min: number, max: number): number { + return Math.max(min, Math.min(max, value)); +} + +const [store, setStore] = createStore({ + character: createDefaultCharacter(), +}); + +/** + * 更新单个统计值 + */ +export function setStat( + key: K, + value: number +): void { + setStore("character", "stats", key, clampStat(value)); +} + +/** + * 批量更新统计值 + */ +export function setStats(stats: Partial): void { + setStore("character", "stats", (prev) => ({ + ...prev, + ...Object.fromEntries( + Object.entries(stats).map(([key, value]) => [key, clampStat(value)]) + ), + })); +} + +/** + * 更新单个豁免值 + */ +export function setSave( + key: K, + value: number +): void { + setStore("character", "saves", key, clampStat(value)); +} + +/** + * 批量更新豁免值 + */ +export function setSaves(saves: Partial): void { + setStore("character", "saves", (prev) => ({ + ...prev, + ...Object.fromEntries( + Object.entries(saves).map(([key, value]) => [key, clampStat(value)]) + ), + })); +} + +/** + * 添加技能 + */ +export function addSkill(skill: string): void { + setStore("character", "skills", (prev) => [...prev, skill]); +} + +/** + * 移除技能 + */ +export function removeSkill(skill: string): void { + setStore("character", "skills", (prev) => + prev.filter((s) => s !== skill) + ); +} + +/** + * 设置技能列表 + */ +export function setSkills(skills: string[]): void { + setStore("character", "skills", [...skills]); +} + +/** + * 添加物品到物品栏 + */ +export function addInventoryItem( + name: string, + quantity: number = 1, + attributes?: Record +): void { + setStore("character", "inventory", (prev) => [ + ...prev, + { name, quantity: Math.max(1, quantity), attributes }, + ]); +} + +/** + * 从物品栏移除物品(通过名称) + */ +export function removeInventoryItem(name: string): void { + setStore("character", "inventory", (prev) => + prev.filter((item) => item.name !== name) + ); +} + +/** + * 更新物品数量 + */ +export function updateInventoryItemQuantity( + name: string, + quantity: number +): void { + setStore("character", "inventory", (prev) => + prev.map((item) => + item.name === name + ? { ...item, quantity: Math.max(0, quantity) } + : item + ).filter((item) => item.quantity > 0) + ); +} + +/** + * 更新物品属性 + */ +export function updateInventoryItemAttributes( + name: string, + attributes: Record +): void { + setStore("character", "inventory", (prev) => + prev.map((item) => + item.name === name + ? { ...item, attributes } + : item + ) + ); +} + +/** + * 添加状态效果 + */ +export function addStatus( + name: string, + quantity: number = 1, + attributes?: Record +): void { + setStore("character", "status", (prev) => [ + ...prev, + { name, quantity: Math.max(1, quantity), attributes }, + ]); +} + +/** + * 移除状态效果 + */ +export function removeStatus(name: string): void { + setStore("character", "status", (prev) => + prev.filter((item) => item.name !== name) + ); +} + +/** + * 设置 HP + */ +export function setHP(value: Partial): void { + setStore("character", "hp", (prev) => ({ + ...prev, + ...value, + current: value.current !== undefined + ? clampValue(value.current, 0, value.max ?? prev.max) + : prev.current, + max: value.max !== undefined + ? Math.max(0, value.max) + : prev.max, + })); +} + +/** + * 受到伤害 + */ +export function takeDamage(amount: number): void { + setStore("character", "hp", (prev) => ({ + ...prev, + current: Math.max(0, prev.current - amount), + })); +} + +/** + * 治疗 HP + */ +export function healHP(amount: number): void { + setStore("character", "hp", (prev) => ({ + ...prev, + current: Math.min(prev.max, prev.current + amount), + })); +} + +/** + * 设置压力值 + */ +export function setStress(value: Partial): void { + setStore("character", "stress", (prev) => ({ + ...prev, + ...value, + current: value.current !== undefined + ? clampValue(value.current, value.min ?? prev.min, Number.MAX_SAFE_INTEGER) + : prev.current, + min: value.min !== undefined ? Math.max(0, value.min) : prev.min, + })); +} + +/** + * 增加压力 + */ +export function addStress(amount: number): void { + setStore("character", "stress", (prev) => ({ + ...prev, + current: prev.current + amount, + })); +} + +/** + * 减少压力 + */ +export function reduceStress(amount: number): void { + setStore("character", "stress", (prev) => ({ + ...prev, + current: Math.max(prev.min, prev.current - amount), + })); +} + +/** + * 设置伤口值 + */ +export function setWounds(value: Partial): void { + setStore("character", "wounds", (prev) => ({ + ...prev, + ...value, + current: value.current !== undefined + ? clampValue(value.current, 0, value.max ?? prev.max) + : prev.current, + max: value.max !== undefined + ? Math.max(0, value.max) + : prev.max, + })); +} + +/** + * 增加伤口 + */ +export function addWound(amount: number = 1): void { + setStore("character", "wounds", (prev) => ({ + ...prev, + current: Math.min(prev.max, prev.current + amount), + })); +} + +/** + * 治疗伤口 + */ +export function healWound(amount: number = 1): void { + setStore("character", "wounds", (prev) => ({ + ...prev, + current: Math.max(0, prev.current - amount), + })); +} + +/** + * 重置角色到默认状态 + */ +export function resetCharacter(): void { + setStore("character", createDefaultCharacter()); +} + +/** + * 设置完整角色数据 + */ +export function setCharacter(character: MothershipCharacter): void { + setStore("character", character); +} + +/** + * 获取当前角色数据 + */ +export function getCharacter(): MothershipCharacter { + return store.character; +} + +/** + * 获取 Store 订阅(用于 SolidJS 组件) + */ +export function useCharacterStore() { + return store; +} + +export { store, setStore }; diff --git a/src/journals/mothership/index.ts b/src/journals/mothership/index.ts new file mode 100644 index 0000000..67c20ab --- /dev/null +++ b/src/journals/mothership/index.ts @@ -0,0 +1,66 @@ +/** + * Mothership TRPG 角色表 Store + * + * @module journals/mothership + */ + +export type { + CharacterStats, + CharacterSaves, + InventoryItem, + VitalValue, + StressValue, + MothershipCharacter, + MothershipStoreState, +} from "./types"; + +export { + // Store 核心 + store, + setStore, + useCharacterStore, + getCharacter, + + // 初始化 + createDefaultCharacter, + resetCharacter, + setCharacter, + + // Stats 操作 + setStat, + setStats, + + // Saves 操作 + setSave, + setSaves, + + // Skills 操作 + addSkill, + removeSkill, + setSkills, + + // Inventory 操作 + addInventoryItem, + removeInventoryItem, + updateInventoryItemQuantity, + updateInventoryItemAttributes, + + // Status 操作 + addStatus, + removeStatus, + + // HP 操作 + setHP, + takeDamage, + healHP, + + // Stress 操作 + setStress, + addStress, + reduceStress, + + // Wounds 操作 + setWounds, + addWound, + healWound, +} from "./characterStore"; diff --git a/src/journals/mothership/types.ts b/src/journals/mothership/types.ts new file mode 100644 index 0000000..39aaa91 --- /dev/null +++ b/src/journals/mothership/types.ts @@ -0,0 +1,76 @@ +/** + * Mothership TRPG 角色表统计值 + * 所有值范围为 0-99 + */ +export interface CharacterStats { + /** 力量 */ + strength: number; + /** 敏捷 */ + agility: number; + /** 战斗 */ + combat: number; + /** 智力 */ + intellect: number; +} + +/** + * Mothership TRPG 角色表豁免值 + * 所有值范围为 0-99 + */ +export interface CharacterSaves { + /** 恐惧豁免 */ + fear: number; + /** 理智豁免 */ + sanity: number; + /** 体质豁免 */ + body: number; +} + +/** + * 物品栏物品 + */ +export interface InventoryItem { + /** 物品名称 */ + name: string; + /** 数量 */ + quantity: number; + /** 自定义属性,如护甲值 { ap: 3 } */ + attributes?: Record; +} + +/** + * 生命值/伤口等有最大值和当前值的属性 + */ +export interface VitalValue { + current: number; + max: number; +} + +/** + * 压力值(有最小值和当前值) + */ +export interface StressValue { + current: number; + min: number; +} + +/** + * Mothership 角色表完整数据结构 + */ +export interface MothershipCharacter { + stats: CharacterStats; + saves: CharacterSaves; + skills: string[]; + inventory: InventoryItem[]; + status: InventoryItem[]; + hp: VitalValue; + stress: StressValue; + wounds: VitalValue; +} + +/** + * Store 状态类型 + */ +export type MothershipStoreState = { + character: MothershipCharacter; +};