feat: mothership character store
This commit is contained in:
parent
c5e091da08
commit
8f6a6b96e2
|
|
@ -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<MothershipStoreState>({
|
||||||
|
character: createDefaultCharacter(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新单个统计值
|
||||||
|
*/
|
||||||
|
export function setStat<K extends keyof CharacterStats>(
|
||||||
|
key: K,
|
||||||
|
value: number
|
||||||
|
): void {
|
||||||
|
setStore("character", "stats", key, clampStat(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新统计值
|
||||||
|
*/
|
||||||
|
export function setStats(stats: Partial<CharacterStats>): void {
|
||||||
|
setStore("character", "stats", (prev) => ({
|
||||||
|
...prev,
|
||||||
|
...Object.fromEntries(
|
||||||
|
Object.entries(stats).map(([key, value]) => [key, clampStat(value)])
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新单个豁免值
|
||||||
|
*/
|
||||||
|
export function setSave<K extends keyof CharacterSaves>(
|
||||||
|
key: K,
|
||||||
|
value: number
|
||||||
|
): void {
|
||||||
|
setStore("character", "saves", key, clampStat(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新豁免值
|
||||||
|
*/
|
||||||
|
export function setSaves(saves: Partial<CharacterSaves>): 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<string, any>
|
||||||
|
): 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<string, any>
|
||||||
|
): void {
|
||||||
|
setStore("character", "inventory", (prev) =>
|
||||||
|
prev.map((item) =>
|
||||||
|
item.name === name
|
||||||
|
? { ...item, attributes }
|
||||||
|
: item
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加状态效果
|
||||||
|
*/
|
||||||
|
export function addStatus(
|
||||||
|
name: string,
|
||||||
|
quantity: number = 1,
|
||||||
|
attributes?: Record<string, any>
|
||||||
|
): 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<VitalValue>): 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<StressValue>): 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<VitalValue>): 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 };
|
||||||
|
|
@ -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";
|
||||||
|
|
@ -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<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命值/伤口等有最大值和当前值的属性
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue