diff --git a/idea.md b/idea.md index 3cb82ba..23bc5b2 100644 --- a/idea.md +++ b/idea.md @@ -105,3 +105,4 @@ dam4.png ---- 存档 59 [] 完善加载系统 [] 不同怪物可以在怪物手册中添加一些不同的边框 [] 按住一个按键时显示怪物的攻防血 +[] 新的事件系统? diff --git a/src/core/main/custom/hotkey.ts b/src/core/main/custom/hotkey.ts index 81fca20..468c724 100644 --- a/src/core/main/custom/hotkey.ts +++ b/src/core/main/custom/hotkey.ts @@ -271,3 +271,10 @@ export function unwarpBinary(bin: number): AssistHoykey { alt: !!(bin & (1 << 2)) }; } + +export function checkAssist(bin: number, key: KeyCode) { + return !!( + (1 << (key === KeyCode.Ctrl ? 0 : key === KeyCode.Shift ? 1 : 2)) & + bin + ); +} diff --git a/src/core/main/custom/toolbar.ts b/src/core/main/custom/toolbar.ts new file mode 100644 index 0000000..be075d4 --- /dev/null +++ b/src/core/main/custom/toolbar.ts @@ -0,0 +1,180 @@ +import { EmitableEvent, EventEmitter } from '@/core/common/eventEmitter'; +import { KeyCode } from '@/plugin/keyCodes'; +import { flipBinary, has } from '@/plugin/utils'; +import { FunctionalComponent, reactive } from 'vue'; +import { createToolbarComponents } from '../init/toolbar'; +import { gameKey } from '../init/hotkey'; +import { unwarpBinary } from './hotkey'; + +interface CustomToolbarEvent extends EmitableEvent { + add: (item: ValueOf) => void; + delete: (item: ValueOf) => void; + set: (id: string, data: Partial) => void; + emit: (id: string) => void; +} + +type ToolbarItemType = 'hotkey' | 'item' | 'assistKey'; + +interface ToolbarItemBase { + type: T; + id: string; + com: CustomToolbarComponent; +} + +// 快捷键 +interface HotkeyToolbarItem extends ToolbarItemBase<'hotkey'> { + key: KeyCode; + assist: number; +} + +// 使用道具 +interface ItemToolbarItem extends ToolbarItemBase<'item'> { + item: ItemIdOf<'tools' | 'constants'>; +} + +// 切换辅助按键 ctrl alt shift +interface AssistKeyToolbarItem extends ToolbarItemBase<'assistKey'> { + assist: KeyCode.Ctrl | KeyCode.Shift | KeyCode.Alt; +} + +interface ToolbarItemMap { + hotkey: HotkeyToolbarItem; + item: ItemToolbarItem; + assistKey: AssistKeyToolbarItem; +} + +export type SettableItemData = + Omit; + +export interface CustomToolbarProps< + T extends ToolbarItemType = ToolbarItemType +> { + item: ToolbarItemMap[T]; + toolbar: CustomToolbar; +} +export type CustomToolbarComponent< + T extends ToolbarItemType = ToolbarItemType +> = FunctionalComponent>; + +const COM = createToolbarComponents(); + +const comMap: { + [P in ToolbarItemType]: CustomToolbarComponent

; +} = { + hotkey: COM.KeyTool, + item: COM.ItemTool, + assistKey: COM.AssistKeyTool +}; + +export class CustomToolbar extends EventEmitter { + static num: number = 0; + static list: CustomToolbar[] = []; + + items: ValueOf[] = reactive([]); + num: number = CustomToolbar.num++; + id: string; + // ----- size + x: number = 300; + y: number = 300; + width: number = 300; + height: number = 100; + // ----- other + assistKey: number = 0; + + constructor(id: string) { + super(); + this.id = id; + CustomToolbar.list.push(this); + } + + /** + * 添加一个自定义项 + * @param item 要添加的自定义工具栏项 + */ + add(item: Omit) { + // @ts-ignore + const data: ToolbarItemMap[K] = { + com: comMap[item.type], + ...item + } as ToolbarItemMap[K]; + this.items.push(data); + this.emit('add', data); + } + + /** + * 删除一个自定义项 + * @param id 要删除的项的id + */ + delete(id: string) { + const index = this.items.findIndex(v => v.id === id); + if (index === -1) return; + const item = this.items[index]; + this.items.splice(index, 1); + this.emit('delete', item); + } + + /** + * 设置一个项 + * @param id 要设置的项的id + * @param item 要设置的属性内容 + */ + set( + id: string, + item: Partial> + ) { + const toSet = this.items.find(v => v.id === id); + if (!toSet) return; + Object.assign(toSet, item); + this.emit('set', id, item); + } + + /** + * 触发一个自定义工具 + * @param id 要触发的自定义工具的id + */ + emitTool(id: string) { + const item = this.items.find(v => v.id === id); + if (!item) return; + this.emit(id); + if (item.type === 'hotkey') { + // 按键 + const { ctrl, shift, alt } = unwarpBinary( + item.assist | this.assistKey + ); + const ev = new KeyboardEvent('keyup', { + ctrlKey: ctrl, + shiftKey: shift, + altKey: alt + }); + + // todo: Advanced KeyboardEvent simulate + gameKey.emitKey(item.key, item.assist, 'up', ev); + } else if (item.type === 'item') { + // 道具 + core.tryUseItem(item.item); + } else if (item.type === 'assistKey') { + // 辅助按键 + if (item.assist === KeyCode.Ctrl) { + this.assistKey = flipBinary(this.assistKey, 0); + } else if (item.assist === KeyCode.Shift) { + this.assistKey = flipBinary(this.assistKey, 1); + } else if (item.assist === KeyCode.Alt) { + this.assistKey = flipBinary(this.assistKey, 2); + } + } + } + + setPos(x?: number, y?: number) { + has(x) && (this.x = x); + has(y) && (this.y = y); + } + + setSize(width?: number, height?: number) { + has(width) && (this.width = width); + has(height) && (this.height = height); + } + + static get(id: string) { + return this.list.find(v => v.id === id); + } +} diff --git a/src/core/main/init/toolbar.tsx b/src/core/main/init/toolbar.tsx new file mode 100644 index 0000000..5b6dc83 --- /dev/null +++ b/src/core/main/init/toolbar.tsx @@ -0,0 +1,71 @@ +import { KeyCodeUtils } from '@/plugin/keyCodes'; +import type { + CustomToolbarComponent, + CustomToolbarProps +} from '../custom/toolbar'; +import BoxAnimate from '@/components/boxAnimate.vue'; +import { onUnmounted, ref } from 'vue'; +import { checkAssist } from '../custom/hotkey'; + +interface Components { + DefaultTool: CustomToolbarComponent; + KeyTool: CustomToolbarComponent<'hotkey'>; + ItemTool: CustomToolbarComponent<'item'>; + AssistKeyTool: CustomToolbarComponent<'assistKey'>; +} + +export function createToolbarComponents() { + const com: Components = { + DefaultTool, + KeyTool, + ItemTool, + AssistKeyTool + }; + return com; +} + +function DefaultTool(props: CustomToolbarProps) { + return 未知工具; +} + +function KeyTool(props: CustomToolbarProps<'hotkey'>) { + const { item, toolbar } = props; + return ( + toolbar.emitTool(item.id)}> + {KeyCodeUtils.toString(item.key)} + + ); +} + +function ItemTool(props: CustomToolbarProps<'item'>) { + const { item, toolbar } = props; + return ( +

toolbar.emitTool(item.id)}> + +
+ ); +} + +function AssistKeyTool(props: CustomToolbarProps<'assistKey'>) { + const { item, toolbar } = props; + const pressed = ref(checkAssist(toolbar.assistKey, item.assist)); + const listen = () => { + pressed.value = checkAssist(toolbar.assistKey, item.assist); + }; + toolbar.on('emit', listen); + + onUnmounted(() => { + toolbar.off('emit', listen); + }); + + return ( + toolbar.emitTool(item.id)} + > + {KeyCodeUtils.toString(item.assist)} + + ); +} diff --git a/src/core/main/init/ui.ts b/src/core/main/init/ui.ts index 7cdb1fb..12a3404 100644 --- a/src/core/main/init/ui.ts +++ b/src/core/main/init/ui.ts @@ -28,7 +28,8 @@ fixedUi.register( new GameUi('fixed', UI.Fixed), new GameUi('chapter', UI.Chapter), new GameUi('completeAchi', UI.CompleteAchi), - new GameUi('start', UI.Start) + new GameUi('start', UI.Start), + new GameUi('toolbar', UI.Toolbar) ); fixedUi.showAll(); diff --git a/src/plugin/utils.ts b/src/plugin/utils.ts index d858f20..f3c13f4 100644 --- a/src/plugin/utils.ts +++ b/src/plugin/utils.ts @@ -333,3 +333,9 @@ export function getStatusLabel(name: string) { }[name] || name ); } + +export function flipBinary(num: number, col: number) { + const n = 1 << col; + if (num & col) return num & ~n; + else return num | n; +} diff --git a/src/ui/index.ts b/src/ui/index.ts index 42472cc..697cbcf 100644 --- a/src/ui/index.ts +++ b/src/ui/index.ts @@ -20,3 +20,4 @@ export { default as Studied } from './studied.vue'; export { default as Study } from './study.vue'; export { default as Toolbox } from './toolbox.vue'; export { default as Hotkey } from './hotkey.vue'; +export { default as Toolbar } from './toolbar.vue'; diff --git a/src/ui/toolbar.vue b/src/ui/toolbar.vue new file mode 100644 index 0000000..1e59e33 --- /dev/null +++ b/src/ui/toolbar.vue @@ -0,0 +1,62 @@ + + + + +