diff --git a/packages-user/data-common/src/store/types.ts b/packages-user/data-common/src/store/types.ts index 3f078ab..8041a66 100644 --- a/packages-user/data-common/src/store/types.ts +++ b/packages-user/data-common/src/store/types.ts @@ -136,7 +136,7 @@ export const enum ItemCategory { Equipment } -export interface IItemEffect { +export interface IItemEffect { /** 即捡即用事件内容(Pick 类型) */ readonly pickEvent: unknown; /** 道具使用事件内容(Constant 和 Consumable 类型) */ @@ -146,22 +146,37 @@ export interface IItemEffect { * 即捡即用效果,拾取道具时调用 * @param item 当前道具数据 */ - pickEffect(item: IItemRawData): void; + pickEffect(item: IItemRawData): void; /** * 道具使用效果,使用道具时调用 * @param item 当前道具数据 */ - useEffect(item: IItemRawData): void; + useEffect(item: IItemRawData): void; /** * 能否使用道具 * @param item 当前道具数据 */ - canUse(item: IItemRawData): boolean; + canUse(item: IItemRawData): boolean; } -export interface IItemRawData { +export interface IItemEquipData { + /** 可以装备至的装备槽,`number` 表示指定索引装备槽,`string` 表示指定装备槽名称,每个装备槽之间为或的关系 */ + readonly slots: (number | string)[]; + /** 动画 id */ + readonly animate: AnimationIds; + /** 数值加成 */ + readonly value: Map, number>; + /** 百分比加成 */ + readonly percentage: Map, number>; + /** 穿上装备事件 */ + readonly loadEvent: unknown; + /** 脱下装备事件 */ + readonly unloadEvent: unknown; +} + +export interface IItemRawData { /** 道具在地图上的图块数字 */ readonly num: number; /** 道具的字符串标识符 */ @@ -177,26 +192,26 @@ export interface IItemRawData { readonly hideInToolbox: boolean; /** 道具效果对象(非 Equipment 类型) */ - readonly effect: IItemEffect; + readonly effect: IItemEffect; /** 装备道具属性(Equipment 类型) */ - readonly equip: unknown; + readonly equip: IItemEquipData; } -export interface IItemLegacyConverter { +export interface IItemLegacyConverter { /** * 将旧样板道具定义转换为新的道具原始数据 * @param num 道具图块数字 * @param legacy 旧样板道具定义 */ - fromLegacy(num: number, legacy: TLegacy): IItemRawData; + fromLegacy(num: number, legacy: TLegacy): IItemRawData; } -export interface IItemStore { +export interface IItemStore { /** * 获取指定图块数字对应的道具原始数据 * @param num 道具图块数字 */ - getData(num: number): IItemRawData | null; + getData(num: number): IItemRawData | null; /** * 获取指定图块数字对应的道具分类 @@ -208,20 +223,22 @@ export interface IItemStore { * 添加一个道具原始数据定义 * @param data 道具原始数据 */ - addItem(data: IItemRawData): void; + addItem(data: IItemRawData): void; /** * 挂载一个旧样板转换器 * @param converter 旧样板转换器 */ - attachLegacyConverter(converter: IItemLegacyConverter): void; + attachLegacyConverter( + converter: IItemLegacyConverter + ): void; /** * 使用当前转换器转换并写入一个旧样板道具定义 * @param num 道具图块数字 * @param legacy 旧样板道具定义 */ - fromLegacy(num: number, legacy: TLegacy): IItemRawData; + fromLegacy(num: number, legacy: TLegacy): IItemRawData; } //#endregion diff --git a/packages-user/data-common/src/types.ts b/packages-user/data-common/src/types.ts index d701821..e0e6bdb 100644 --- a/packages-user/data-common/src/types.ts +++ b/packages-user/data-common/src/types.ts @@ -47,7 +47,7 @@ export interface IDataCommon { /** 图块定义存储 */ readonly tileStore: ITileStore>; /** 道具定义存储 */ - readonly itemStore: IItemStore>>; + readonly itemStore: IItemStore>>; /** 朝向绑定 */ readonly roleFace: IRoleFaceBinder; /** 朝向管理 */ diff --git a/packages-user/data-state/src/core.ts b/packages-user/data-state/src/core.ts index 472504d..4127339 100644 --- a/packages-user/data-state/src/core.ts +++ b/packages-user/data-state/src/core.ts @@ -82,7 +82,7 @@ export class CoreState implements ICoreState { readonly roleFace: IRoleFaceBinder; readonly faceManager: IFaceManager; readonly tileStore: ITileStore; - readonly itemStore: IItemStore; + readonly itemStore: IItemStore; // Layer 1 数据层,所有可存档内容都在这,一般用于数据存储 readonly maps: IMapStore; diff --git a/packages-user/data-state/src/legacy/item.ts b/packages-user/data-state/src/legacy/item.ts index 43f2ccc..7765327 100644 --- a/packages-user/data-state/src/legacy/item.ts +++ b/packages-user/data-state/src/legacy/item.ts @@ -1,5 +1,7 @@ import { + IHeroAttr, IItemEffect, + IItemEquipData, IItemLegacyConverter, IItemRawData, ItemCategory @@ -8,16 +10,26 @@ import { IStateSystem } from '@user/data-system'; export type LegacyItemData = Item>; -type LegacyItemEffectFn = (state: IStateSystem, item: IItemRawData) => void; -type LegacyItemCanUseFn = (state: IStateSystem, item: IItemRawData) => boolean; +type LegacyItemEffectFn = ( + state: IStateSystem, + item: IItemRawData +) => void; +type LegacyItemCanUseFn = ( + state: IStateSystem, + item: IItemRawData +) => boolean; -class LegacyItemEffect implements IItemEffect { +class LegacyItemEffect implements IItemEffect { pickEvent: unknown; useEvent: unknown; + /** 即捡即用效果 */ private readonly pickFn: LegacyItemEffectFn | null = null; + /** 道具使用效果 */ private readonly useFn: LegacyItemEffectFn | null = null; + /** 是否能够使用道具 */ private readonly canUseFn: LegacyItemCanUseFn | null = null; + /** 全局状态对象 */ private readonly state: IStateSystem; constructor(legacy: LegacyItemData, state: IStateSystem) { @@ -50,24 +62,27 @@ class LegacyItemEffect implements IItemEffect { } } - pickEffect(item: IItemRawData): void { + pickEffect(item: IItemRawData): void { this.pickFn?.(this.state, item); } - useEffect(item: IItemRawData): void { + useEffect(item: IItemRawData): void { this.useFn?.(this.state, item); } - canUse(item: IItemRawData): boolean { + canUse(item: IItemRawData): boolean { if (!this.canUseFn) return true; else return this.canUseFn(this.state, item); } } -export class ItemLegacyBridge implements IItemLegacyConverter { +export class ItemLegacyBridge implements IItemLegacyConverter< + IHeroAttr, + LegacyItemData +> { constructor(private readonly state: IStateSystem) {} - fromLegacy(num: number, legacy: LegacyItemData): IItemRawData { + fromLegacy(num: number, legacy: LegacyItemData): IItemRawData { const effect = new LegacyItemEffect(legacy, this.state); return { num, @@ -77,10 +92,35 @@ export class ItemLegacyBridge implements IItemLegacyConverter { text: legacy.text ?? '', hideInToolbox: legacy.hideInToolBox, effect, - equip: legacy.equip + equip: this.convertEquip(legacy.equip) }; } + private convertEquip(legacy: Equip): IItemEquipData { + const valueMap = new Map, number>(); + const perMap = new Map, number>(); + + for (const [key, value] of Object.entries(legacy.value)) { + valueMap.set(key as SelectKey, value); + } + for (const [key, value] of Object.entries(legacy.percentage)) { + perMap.set(key as SelectKey, value); + } + + return { + slots: [legacy.type], + animate: legacy.animate, + value: valueMap, + percentage: perMap, + loadEvent: legacy.equipEvent, + unloadEvent: legacy.unequipEvent + }; + } + + /** + * 从旧样板道具类型获取新接口对应的类型 + * @param cls 旧样板道具类型 + */ private mapCategory(cls: ItemCls): ItemCategory { switch (cls) { case 'constants': diff --git a/prompt.md b/prompt.md index 7182225..b6c1173 100644 --- a/prompt.md +++ b/prompt.md @@ -22,7 +22,7 @@ 2. **不恢复我的修改**:我做的任何代码修改都是有原因的。若我在两次对话期间新增、删除或修改了部分代码,不要将其恢复。 3. **遇到歧义立即提问**:若思考或实现时遇到任何问题——例如描述模糊、接口不清晰、某些地方存在歧义等——应立即向我提问,而不是按自己的想法去写。若完成需求所需的接口尚不存在,也应当立即停止实现,向我提出疑问,而不是擅自新增接口来推进。 4. **修改文件前重读文件,修改后说明内容**:修改文件前务必重新阅读以确保内容是最新版。修改后必须在对话中说明所有改动的文件及具体改动内容。在修改文件时,**不得修改**文档的 `涉及文件` 节未提及的文件。 -5. **关于 `dev.md` 的强度升级**:`dev.md` 中"一般不建议/尽量避免"的条目在此处视为**绝对禁止**;"建议/最好"的条目在此处视为**必须遵守**。 +5. **关于 `dev.md` 的强度升级**:`dev.md` 中"一般不建议/尽量避免"的条目在此处视为**绝对禁止**;"建议/最好"的条目在此处视为**必须遵守**。所有私有方法与成员必须添加 jsDoc 注释,在构造函数的参数中定义的成员除外。 6. **渲染端永远处于被动**:任何情况下都不可能会出现数据端主动通知渲染端进行更新的场景,渲染端仅通过钩子与数据端通信,通过钩子被动获取信息,并在某些情况下影响数据端行为。 7. **关于非空判断**:对于对象,直接使用 `if (!object)` 的方式进行判断,对于字面量,使用 `lodash` 接口 `isNil` 判断 `if (isNil(value))`,不要使用 `if (value === undefined)` 这种方式。 8. **方法顺序**:对于类的方法,根据功能进行排序,而不是按照修饰词进行排序。对于较长或功能较多的类,使用 `#region` 进行分区,分区按照方法功能进行划分。所有类的成员必须写到类的开头,并按照功能排序。