HumanBreak/src/plugin/utils.ts

404 lines
10 KiB
TypeScript
Raw Normal View History

2022-12-29 12:02:48 +08:00
import { message } from 'ant-design-vue';
import { MessageApi } from 'ant-design-vue/lib/message';
2023-05-13 21:47:37 +08:00
import { isNil } from 'lodash-es';
2023-02-21 23:22:03 +08:00
import { Animation, sleep, TimingFn } from 'mutate-animate';
2023-06-21 17:10:06 +08:00
import { ref } from 'vue';
2024-01-18 15:25:33 +08:00
import { EVENT_KEY_CODE_MAP, KeyCode } from './keyCodes';
import axios from 'axios';
import { decompressFromBase64 } from 'lz-string';
import { parseColor } from './webgl/utils';
2024-01-19 16:07:59 +08:00
import { Keyboard, KeyboardEmits } from '@/core/main/custom/keyboard';
2024-01-18 17:07:03 +08:00
import { mainUi } from '@/core/main/init/ui';
2024-01-19 16:07:59 +08:00
import { isAssist } from '@/core/main/custom/hotkey';
2022-11-16 23:01:23 +08:00
2022-11-21 20:00:34 +08:00
type CanParseCss = keyof {
[P in keyof CSSStyleDeclaration as CSSStyleDeclaration[P] extends string
? P extends string
? P
: never
: never]: CSSStyleDeclaration[P];
};
2022-11-16 23:01:23 +08:00
export default function init() {
return {
has,
getDamageColor,
parseCss,
tip,
changeLocalStorage,
swapChapter
};
2022-11-16 23:01:23 +08:00
}
/**
* undefined或null
* @param value
*/
export function has<T>(value: T): value is NonNullable<T> {
return !isNil(value);
}
/**
*
* @param damage
*/
export function getDamageColor(damage: number): Color {
2022-11-16 23:01:23 +08:00
if (typeof damage !== 'number') return '#f00';
if (damage === 0) return '#2f2';
if (damage < 0) return '#7f7';
if (damage < core.status.hero.hp / 3) return '#fff';
if (damage < (core.status.hero.hp * 2) / 3) return '#ff4';
2022-12-30 14:14:28 +08:00
if (damage < core.status.hero.hp) return '#f93';
return '#f22';
2022-11-16 23:01:23 +08:00
}
2022-11-19 11:30:14 +08:00
/**
*
* @param canvas
* @param w
* @param h
*/
export function setCanvasSize(
canvas: HTMLCanvasElement,
w: number,
h: number
): void {
canvas.width = w;
canvas.height = h;
canvas.style.width = `${w}px`;
canvas.style.height = `${h}px`;
}
2022-11-19 18:15:42 +08:00
/**
* keycode对应的键
* @param key
*/
export function keycode(key: number) {
return EVENT_KEY_CODE_MAP[key];
}
2022-11-21 20:00:34 +08:00
/**
* css字符串为CSSStyleDeclaration对象
* @param css css字符串
*/
export function parseCss(css: string): Partial<Record<CanParseCss, string>> {
2023-02-05 18:17:10 +08:00
const str = css.replace(/[\n\s\t]*/g, '').replace(/;*/g, ';');
2022-11-21 20:00:34 +08:00
const styles = str.split(';');
const res: Partial<Record<CanParseCss, string>> = {};
for (const one of styles) {
const [key, data] = one.split(':');
2022-11-30 16:42:44 +08:00
const cssKey = key.replace(/\-([a-z])/g, (str, $1) =>
2022-11-21 20:00:34 +08:00
$1.toUpperCase()
) as CanParseCss;
res[cssKey] = data;
}
return res;
}
/**
* 使
* @param str
2022-11-30 16:42:44 +08:00
* @param time 1true时
2022-11-21 20:00:34 +08:00
* @param timing 线线
2022-11-30 16:42:44 +08:00
* @param avr
2022-11-21 20:00:34 +08:00
* @returns
*/
export function type(
str: string,
time: number = 1000,
2022-11-30 16:42:44 +08:00
timing: TimingFn = n => n,
avr: boolean = false
2022-11-21 20:00:34 +08:00
): Ref<string> {
const toShow = eval('`' + str + '`') as string;
2022-11-30 16:42:44 +08:00
if (typeof toShow !== 'string') {
throw new TypeError('Error str type in typing!');
}
2022-12-29 00:26:12 +08:00
if (toShow.startsWith('!!html')) return ref(toShow);
2022-11-30 16:42:44 +08:00
if (avr) time *= toShow.length;
2022-11-21 20:00:34 +08:00
const ani = new Animation();
const content = ref('');
const all = toShow.length;
const fn = (time: number) => {
if (!has(time)) return;
const now = ani.x;
content.value = toShow.slice(0, Math.floor(now));
if (Math.floor(now) === all) {
ani.ticker.destroy();
2022-11-30 16:42:44 +08:00
content.value = toShow;
2022-11-21 20:00:34 +08:00
}
};
ani.ticker.add(fn);
ani.mode(timing).time(time).move(all, 0);
2022-12-31 19:49:43 +08:00
setTimeout(() => ani.ticker.destroy(), time + 100);
2022-11-21 20:00:34 +08:00
return content;
}
2022-12-29 12:02:48 +08:00
export function tip(
type: Exclude<keyof MessageApi, 'open' | 'config' | 'destroy'>,
text: string
) {
message[type]({
content: text,
class: 'antdv-message'
});
}
2022-12-30 23:28:27 +08:00
/**
*
* @param str
*/
export function splitText(str: string[]) {
return str
.map((v, i, a) => {
if (/^\d+\./.test(v)) return `${'&nbsp;'.repeat(12)}${v}`;
else if (
(has(a[i - 1]) && v !== '<br>' && a[i - 1] === '<br>') ||
i === 0
) {
return `${'&nbsp;'.repeat(8)}${v}`;
} else return v;
})
.join('');
}
2023-01-15 20:09:02 +08:00
/**
*
* @param cb
*/
export function nextFrame(cb: (time: number) => void) {
requestAnimationFrame(() => {
requestAnimationFrame(cb);
});
}
2023-01-23 14:38:50 +08:00
/**
*
* @param canvas
* @param name
*/
export function downloadCanvasImage(
canvas: HTMLCanvasElement,
name: string
): void {
const data = canvas.toDataURL('image/png');
download(data, name);
}
/**
*
* @param content
* @param name
*/
export function download(content: string, name: string) {
const a = document.createElement('a');
a.download = `${name}.png`;
a.href = content;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
2023-02-21 23:22:03 +08:00
/**
*
* @param funcs
* @param interval
*/
2023-02-21 23:27:40 +08:00
export async function doByInterval(
funcs: (() => void)[],
interval: number,
awaitFirst: boolean = false
) {
2023-06-21 17:10:06 +08:00
if (awaitFirst) {
await sleep(interval);
}
2023-02-21 23:22:03 +08:00
for await (const fn of funcs) {
fn();
2023-06-21 17:10:06 +08:00
await sleep(interval);
2023-02-21 23:22:03 +08:00
}
}
2023-02-23 23:10:57 +08:00
/**
*
2024-02-01 19:31:49 +08:00
* @deprecated
2023-02-23 23:10:57 +08:00
* @param name
* @param fn
* @param defaultValue
*/
export function changeLocalStorage<T>(
name: string,
fn: (data: T) => T,
defaultValue?: T
) {
const now = core.getLocalStorage(name, defaultValue);
const to = fn(now);
core.setLocalStorage(name, to);
}
export async function swapChapter(chapter: number, hard: number) {
const h = hard === 2 ? 'hard' : 'easy';
const save = await axios.get(
`${import.meta.env.BASE_URL}swap/${chapter}.${h}.h5save`,
{
responseType: 'text',
responseEncoding: 'utf-8'
}
);
const data = JSON.parse(decompressFromBase64(save.data));
core.loadData(data.data, () => {
core.removeFlag('__fromLoad__');
core.drawTip('读档成功');
});
}
2023-06-17 18:02:48 +08:00
export function ensureArray<T>(arr: T): T extends any[] ? T : T[] {
// @ts-ignore
return arr instanceof Array ? arr : [arr];
}
export function pColor(color: string) {
2023-06-21 15:43:22 +08:00
const arr = parseColor(color);
arr[3] ??= 1;
2023-07-08 11:44:00 +08:00
return `rgba(${arr.join(',')})` as Color;
}
2023-08-08 13:29:22 +08:00
2024-01-18 15:25:33 +08:00
/**
*
* @param arr
* @param ele
*/
2023-08-08 13:29:22 +08:00
export function deleteWith<T>(arr: T[], ele: T): T[] {
const index = arr.indexOf(ele);
if (index === -1) return arr;
arr.splice(index, 1);
return arr;
}
2023-08-08 16:44:43 +08:00
2023-11-18 11:33:24 +08:00
export function spliceBy<T>(arr: T[], from: T): T[] {
const index = arr.indexOf(from);
if (index === -1) return arr;
arr.splice(index);
return arr;
}
2023-08-08 16:44:43 +08:00
export async function triggerFullscreen(full: boolean) {
2024-02-01 19:31:49 +08:00
if (!Mota.Plugin.inited) return;
const { maxGameScale } = Mota.Plugin.require('utils_g');
2023-08-08 16:44:43 +08:00
if (!!document.fullscreenElement && !full) {
await document.exitFullscreen();
requestAnimationFrame(() => {
maxGameScale(1);
});
}
if (full && !document.fullscreenElement) {
await document.body.requestFullscreen();
requestAnimationFrame(() => {
maxGameScale();
});
}
}
2023-08-09 12:27:57 +08:00
2023-08-18 11:45:18 +08:00
/**
*
* @param arr
*/
2023-08-09 12:27:57 +08:00
export function generateBinary(arr: boolean[]) {
let num = 0;
arr.forEach((v, i) => {
if (v) {
num += 1 << i;
}
});
return num;
}
2023-12-01 21:47:43 +08:00
/**
*
* @param name
*/
export function getStatusLabel(name: string) {
return (
{
name: '名称',
lv: '等级',
hpmax: '生命回复',
hp: '生命',
manamax: '魔力上限',
mana: '额外攻击',
atk: '攻击',
def: '防御',
mdef: '智慧',
money: '金币',
exp: '经验',
point: '加点',
steps: '步数',
up: '升级',
none: '无'
}[name] || name
);
}
2023-12-17 18:11:58 +08:00
export function flipBinary(num: number, col: number) {
const n = 1 << col;
2023-12-18 17:10:28 +08:00
if (num & n) return num & ~n;
2023-12-17 18:11:58 +08:00
else return num | n;
}
2024-01-18 15:25:33 +08:00
/**
*
* @param emitAssist true时
*
* @param assist
*/
export function getVitualKeyOnce(
emitAssist: boolean = false,
2024-01-19 22:09:48 +08:00
assist: number = 0,
emittable: KeyCode[] = []
2024-01-18 15:25:33 +08:00
): Promise<KeyboardEmits> {
return new Promise(res => {
2024-01-19 16:07:59 +08:00
const key = Keyboard.get('full')!;
2024-01-18 17:07:03 +08:00
key.withAssist(assist);
const id = mainUi.open('virtualKey', { keyboard: key });
key.on('emit', (item, assist, index, ev) => {
ev.preventDefault();
if (emitAssist) {
2024-01-19 22:09:48 +08:00
if (emittable.length === 0 || emittable.includes(item.key)) {
res({ key: item.key, assist: 0 });
key.disposeScope();
mainUi.close(id);
}
2024-01-18 17:07:03 +08:00
} else {
2024-01-19 22:09:48 +08:00
if (
!isAssist(item.key) &&
(emittable.length === 0 || emittable.includes(item.key))
) {
2024-01-18 17:07:03 +08:00
res({ key: item.key, assist });
key.disposeScope();
2024-01-19 16:07:59 +08:00
mainUi.close(id);
2024-01-18 17:07:03 +08:00
}
}
});
2024-01-18 15:25:33 +08:00
});
}
2024-04-21 13:37:27 +08:00
export function formatSize(size: number) {
return size < 1 << 10
? `${size.toFixed(2)}B`
: size < 1 << 20
? `${(size / (1 << 10)).toFixed(2)}KB`
: size < 1 << 30
? `${(size / (1 << 20)).toFixed(2)}MB`
: `${(size / (1 << 30)).toFixed(2)}GB`;
}
let num = 0;
export function requireUniqueSymbol() {
return num++;
}