/** 工具类 主要用来进行一些辅助函数的计算 */ interface Utils { /** * 四个方向的坐标增量 */ readonly scan: DeepReadonly; /** * 八个方向的坐标增量 */ readonly scan2: DeepReadonly; /** * 将一段文字中的${}(表达式)进行替换。很多情况下可以用模板字符串替代 * @example * // 把主角的生命值和持有的黄钥匙数量代入这句话 * core.replaceText('衬衫的价格是${status:hp}镑${item:yellowKey}便士。'); * @param text 模板字符串,可以使用${}计算js表达式 * @param prefix 独立开关前缀 * @returns 替换完毕后的字符串 */ replaceText(text: string, prefix?: string): string; /** * 对一个表达式中的特殊规则进行替换,如status:xxx等。 * 其中变量和全局存储会替换中文冒号,其余的不会替换 * @example * // 把这两个冒号表达式替换为core.getStatus('hp')和core.itemCount('yellowKey')这样的函数调用 * core.replaceValue('衬衫的价格是${status:hp}镑${item:yellowKey}便士。'); * @param value 模板字符串,注意独立开关不会被替换 * @returns 替换完毕后的字符串 */ replaceValue(value: string): string; /** * 计算一个表达式的值,支持status:xxx等的计算。 * @example core.calValue('status:hp + status:def'); // 计算主角的生命值加防御力 * @param value 待求值的表达式 * @param prefix 独立开关前缀,一般可省略 * @returns 求出的值 */ calValue(value: string | Function, prefix?: string): any; /** * @deprecated * 将b(可以是另一个数组)插入数组a的开头,用Array.unshift就行 * @example core.unshift(todo, {type: 'unfollow'}); // 在事件指令数组todo的开头插入“取消所有跟随者”指令 * @param a 原数组 * @param b 待插入的新首项或前缀数组 * @returns 插入完毕后的新数组,它是改变原数组a本身得到的 */ unshift(a: A, b: B): [...B, ...A]; /** * @deprecated * 将b(可以是另一个数组)插入数组a的末尾,用Array.push就行 * @example core.push(todo, {type: 'unfollow'}); // 在事件指令数组todo的末尾插入“取消所有跟随者”指令 * @param a 原数组 * @param b 待插入的新末项或后缀数组 * @returns 插入完毕后的新数组,它是改变原数组a本身得到的 */ push(a: A, b: B): [...A, ...B]; /** * 解压缩一个数据,我也不知道这个解压的是什么 * @param 要解压的内容,字符串 */ decompress(value: string): any; /** * @deprecated * 设置本地存储 * @param key 本地存储的名称 * @param value 本地存储的值,不填代表删除 */ setLocalStorage(key: string, value?: any): void; /** * @deprecated * 获得本地存储 * @param key 获取的本地存储的名称 * @param defaultValue 当不存在的时候的默认值 */ getLocalStorage(key: string, defaultValue?: T): T; /** * @deprecated * 移除本地存储 * @param key 要移除的本地存储的值 */ removeLocalStorage(key: string): void; /** * 异步写入localforage * @param key 写入的键 * @param value 写入的值 * @param successCallback 写入成功的回调函数 * @param errorCallback 写入出错的回调函数 */ setLocalForage( key: string, value?: any, successCallback?: () => void, errorCallback?: (err: Error) => void ): void; /** * 从localforage读出一段数据 */ getLocalForage( key: string, defaultValue?: T, successCallback?: (data: T) => void, errorCallback?: (err: Error) => void ): void; /** * 移除localforage的数据 */ removeLocalForage( key: string, successCallback?: () => void, errorCallback?: (err: Error) => void ): void; /** * 清除localforage所有的数据 * @param callback 清除完毕的回调函数 */ clearLocalForage(callback?: (err?: Error) => void): void; /** * 迭代localforage的数据 * @param iteratee 迭代器 * @param callback 迭代完毕的回调函数 */ iterateLocalForage( iteratee: (value: T, key: string, iterationNumber: number) => U, callback?: (err: any, result: U) => void ): void; /** * 获取localforage数据的所有的键 * @param callback 回调函数 */ keysLocalForage(callback?: (err: any, keys: string[]) => void): void; /** * 获取localforage数据的数据量 * @param callback 回调函数 */ lengthLocalForage( callback?: (err: any, numberOfKeys: number) => void ): void; /** * 设置一个全局存储,适用于global:xxx,录像播放时将忽略此函数。 * @example core.setBlobal('一周目已通关', true); // 设置全局存储“一周目已通关”为true,方便二周目游戏中的新要素。 * @param key 全局变量名称,支持中文 * @param value 全局变量的新值,不填或null表示清除此全局存储 */ setGlobal(key: string, value?: any): void; /** * 读取一个全局存储,适用于global:xxx,支持录像。 * @example if (core.getGlobal('一周目已通关', false) === true) core.getItem('dagger'); // 二周目游戏进行到此处时会获得一把屠龙匕首 * @param key 全局变量名称,支持中文 * @param defaultValue 可选,当此全局变量不存在或值为null、undefined时,用此值代替 * @returns 全局变量的值 */ getGlobal(key: string, defaultValue?: T): T; /** * @deprecated * 深拷贝一个对象(函数将原样返回) * @example core.clone(core.status.hero, (name, value) => (name == 'items' || typeof value == 'number'), false); // 深拷贝主角的属性和道具 * @param data 待拷贝对象 * @param filter 过滤器,可选,表示data为数组或对象时拷贝哪些项或属性,true表示拷贝 * @param recursion 过滤器是否递归,可选。true表示过滤器也被递归 * @returns 拷贝的结果,注意函数将原样返回 */ clone( data: T, filter?: (name: string, value: any) => boolean, recursion?: boolean ): T; /** * @deprecated * 深拷贝一个1D或2D的数组 * @param data 要拷贝的数据 */ cloneArray(data: T): T; /** * 等比例切分一张图片 * @example core.splitImage(core.material.images.images['npc48.png'], 32, 48); // 把npc48.png切分成若干32×48px的小人 * @param image 图片名(支持映射前的中文名)或图片对象(参见上面的例子),获取不到时返回[] * @param width 子图的宽度,单位为像素。原图总宽度必须是其倍数,不填视为32 * @param height 子图的高度,单位为像素。原图总高度必须是其倍数,不填视为正方形 * @returns 子图组成的数组,在原图中呈先行后列,从左到右、从上到下排列。 */ splitImage( image: NameMapIn | ImageIds | HTMLImageElement, width?: number, height?: number ): HTMLImageElement[]; /** * 格式化日期为字符串 * @param date 时间,不填代表当前时间 * @returns 格式: yyyy-mm-dd hh:mm:ss */ formatDate(date?: Date): string; /** * 格式化日期为最简字符串 * @param date 时间,不填代表当前时间 * @returns 格式: yyyymmddhhmmss */ formatDate2(date?: Date): string; /** * 格式化时间 * @param time 时间 * @returns 格式: hh:mm:ss */ formatTime(time: number): string; /** * @deprecated * 设置成两位数显示,请使用setDigits代替 */ setTwoDigits(x: number): string; /** * 设置一个数为n位数显示 * @param x 要设置的数 * @param n 设置成的位数 */ setDigits(x: number, n: number): string; /** * 格式化文件大小 * @param size 大小,字节数 * @returns 格式为xx.xxB KB MB */ formatSize(size: number): string; /** * 大数字格式化,单位为10000的倍数(w,e,z,j,g),末尾四舍五入 * @example core.formatBigNumber(123456789); // "12346w" * @param x 原数字 * @param onMap 显示的字符数 * @returns 格式化结果 */ formatBigNumber(x: T, onMap?: number): T; formatBigNumber(x: number | string, onMap?: number | boolean): string; /** * @deprecated * 变速移动,完全可以用mutate-animate代替 * @param mode 缓动模式 */ applyEasing(mode?: EaseMode): (x: number) => number; /** * 颜色数组转十六进制 * @example core.arrayToRGB([102, 204, 255]); // "#66ccff",加载画面的宣传色 * @param color 一行三列的数组,各元素必须为不大于255的自然数 * @returns 该颜色的十六进制表示,使用小写字母 */ arrayToRGB(color: RGBArray): _RGBA; /** * 颜色数组转字符串 * @example core.arrayToRGBA([102, 204, 255]); // "rgba(102,204,255,1)" * @param color 一行三列或一行四列的数组,前三个元素必须为不大于255的自然数。 * 第四个元素(如果有)必须为0或不大于1的数字,第四个元素不填视为1 * @returns 该颜色的字符串表示 */ arrayToRGBA(color: Color): _RGBA; /** * 录像一压,其结果会被再次base64压缩 * @example core.encodeRoute(core.status.route); // 一压当前录像 * @param route 原始录像,自定义内容(不予压缩,原样写入)必须由0-9A-Za-z和下划线、冒号组成, * 所以中文和数组需要用JSON.stringify预处理再base64压缩才能交由一压 * @returns 一压的结果 */ encodeRoute(route: string[]): string; /** * 录像解压的最后一步,即一压的逆过程 * @example core.decodeRoute(core.encodeRoute(core.status.route)); // 一压当前录像再解压-_-| * @param route 录像解压倒数第二步的结果,即一压的结果 * @returns 原始录像 */ decodeRoute(route: string): string[]; /** * @deprecated * 判断一个值是否不为null,undefined和NaN * @example core.isset(0/0); // false,因为0/0等于NaN * @param v 待测值 * @returns false表示待测值为null、undefined、NaN或未填写,true表示为其他值 */ isset(v?: any): boolean; /** * 判定一个数组是否为另一个数组的前缀,用于录像接续播放 * @example core.subarray(['ad', '米库', '小精灵', '小破草', '小艾'], ['ad', '米库', '小精灵']); // ['小破草', '小艾'] * @param a 可能的母数组,不填或比b短将返回null * @param b 可能的前缀,不填或比a长将返回null * @returns 如果b不是a的前缀将返回null,否则将返回a去掉此前缀后的剩余数组 */ subarray(a: any[], b: any[]): any[] | null; /** * @deprecated * 判定array是不是一个数组,以及element是否在该数组中。使用Array.includes代替 * @param array 可能的数组,不为数组或不填将导致返回值为false * @param element 待查找的元素 * @returns 如果array为数组且具有element这项,就返回true,否则返回false */ inArray(array?: any, element?: any): boolean; /** * 将x限定在[a,b]区间内,注意a和b可交换 * @example core.clamp(1200, 1, 1000); // 1000 * @param x 原始值,!x为true时x一律视为0 * @param a 下限值,大于b将导致与b交换 * @param b 上限值,小于a将导致与a交换 */ clamp(x: number, a: number, b: number): number; /** * 访问浏览器cookie */ getCookie(name: string): string; /** * @deprecated * 填写非自绘状态栏 * @example * // 更新状态栏中的主角生命,使用加载画面的宣传色 * core.setStatusBarInnerHTML('hp', core.status.hero.hp, 'color: #66CCFF'); * @param name 状态栏项的名称,如'hp', 'atk', 'def'等。必须是core.statusBar中的一个合法项 * @param value 要填写的内容,大数字会被格式化为至多6个字符,无中文的内容会被自动设为斜体 * @param css 额外的css样式,可选。如更改颜色等 */ setStatusBarInnerHTML( name: string, value: string | number, css?: string ): void; /** * 求字符串的国标码字节数,也可用于等宽字体下文本的宽度测算。请注意样板的默认字体Verdana不是等宽字体 * @example core.strlen('无敌ad'); // 6 * @param str 待测字符串 * @returns 字符串的国标码字节数,每个汉字为2,每个ASCII字符为1 */ strlen(str: string): number; /** * 计算应当转向某个方向 * @param turn 转向的方向 * @param direction 当前方向,不填视为当前方向 */ turnDirection(turn: HeroTurnDir, direction?: Dir): string; /** * 通配符匹配,用于搜索图块等批量处理。 * @example core.playSound(core.matchWildcard('*Key', itemId) ? 'item.mp3' : 'door.mp3'); // 判断捡到的是钥匙还是别的道具,从而播放不同的音效 * @param pattern 模式串,每个星号表示任意多个(0个起)字符 * @param string 待测串 * @returns true表示匹配成功,false表示匹配失败 */ matchWildcard(pattern: string, string: string): boolean; /** * 是否满足正则表达式,一般可以直接用/RegExp/.test(str)代替 * @param pattern 正则表达式 * @param string 要匹配的字符串 */ matchRegex(pattern: string, string: string): string; /** * base64加密 * @example * core.encodeBase64('If you found this note in a small wooden box with a heart on it'); * // "SWYgeW91IGZvdW5kIHRoaXMgbm90ZSBpbiBhIHNtYWxsIHdvb2RlbiBib3ggd2l0aCBhIGhlYXJ0IG9uIGl0" * @param str 明文 * @returns 密文 */ encodeBase64(str: string): string; /** * base64解密 * @example * core.decodeBase64('SWYgeW91IGZvdW5kIHRoaXMgbm90ZSBpbiBhIHNtYWxsIHdvb2RlbiBib3ggd2l0aCBhIGhlYXJ0IG9uIGl0'); * // "If you found this note in a small wooden box with a heart on it" * @param str 密文 * @returns 明文 */ decodeBase64(str: string): string; /** * 不支持SL的随机数 * @exmaple 1 + core.rand(6); // 随机生成一个小于7的正整数,模拟骰子的效果 * @param num 填正数表示生成小于num的随机自然数,否则生成小于1的随机正数 * @returns 随机数,即使读档也不会改变结果 */ rand(num?: number): number; /** * 支持SL的随机数,并计入录像 * @exmaple 1 + core.rand2(6); // 随机生成一个小于7的正整数,模拟骰子的效果 * @param num 正整数,0或不填会被视为2147483648 * @returns 属于 [0, num) 的随机数 */ rand2(num?: number): number; /** * 尝试请求读取一个本地文件内容 [异步] * @param success 成功后的回调 * @param error 失败后的回调 * @param accept input元素的accept属性 * @param readType 不设置则以文本读取,否则以DataUrl形式读取 */ readFile( success: (obj: any) => void, error: () => void, accept: string, readType: boolean ): void; /** * 文件读取完毕后的内容处理 [异步] * @param content 读取的内容 */ readFileContent(content: string): void; /** * 弹窗请求下载一个文本文件 * @example core.download('route.txt', core.status.route); // 弹窗请求下载录像 * @param filename 文件名 * @param content 文件内容 */ download(filename: string, content: string | string[]): void; /** * 尝试复制一段文本到剪切板 * @param data 赋值的东西 */ copy(data: string): void; /** * 显示确认框,类似core.drawConfirmBox() * @example core.myconfirm('重启游戏?', core.restart); // 弹窗询问玩家是否重启游戏 * @param hint 弹窗的内容 * @param yesCallback 确定后的回调函数 * @param noCallback 取消后的回调函数 */ myconfirm( hint: string, yesCallback: () => void, noCallback?: () => void ): void; /** * 让用户输入一段文字 */ myprompt( hint: string, value: string, callback?: (data?: string) => void ): void; /** * @deprecated * 动画显示某对象,有vue了,你还用这个?Transition组件和css的transition比这个强得多 */ showWithAnimate( obj?: HTMLElement, speed?: number, callback?: () => any ): void; /** * @deprecated * 动画使某对象消失 */ hideWithAnimate( obj?: HTMLElement, speed?: number, callback?: () => any ): void; /** * 获得浏览器唯一的guid */ getGuid(): string; /** * 获取一个对象的哈希值 * @param obj 要获取的对象 */ hashCode(obj: any): number; /** * 判定深层相等, 会逐层比较每个元素 * @example core.same(['1', 2], ['1', 2]); // true */ same(a: any, b: any): boolean; /** * 解压一段内容 */ unzip( blobOrUrl: string | Blob, success?: (data: any) => void, error?: (error: string) => void, convertToText?: boolean, onprogress?: (loaded: number, total: number) => void ): void; /** * 发送一个HTTP请求 [异步] * @param type 请求类型 * @param url 目标地址 * @param formData 如果是POST请求则为表单数据 * @param success 成功后的回调 * @param error 失败后的回调 */ http( type: 'GET' | 'POST', url: string, formData?: FormData, success?: (res: any) => void, error?: (err: string) => void, mimeType?: string, responseType?: XMLHttpRequestResponseType, onProgress?: (loaded: number, total: number) => void ): void; } declare const utils: new () => Utils; interface JSInterface { requestLandscape(): void; requestPortrait(): void; } interface Window { jsinterface: JSInterface; } declare const jsinterface: JSInterface; /** * 移动的方向 */ type Step = Move | 'backward'; /** * 坐标字符串 */ type LocString = `${number},${number}`; type _RGBA = | `rgb(${number},${number},${number})` | `rgba(${number},${number},${number},${number})`; /** * RGBA颜色数组 */ type RGBArray = [number, number, number, number?]; /** * 样板的颜色字符串 */ type Color = `#${string}` | _RGBA | RGBArray | 'transparent'; /** * 四个方向 */ type Dir = 'up' | 'down' | 'left' | 'right'; /** * 八个方向 */ type Dir2 = Dir | 'leftup' | 'rightup' | 'leftdown' | 'rightdown'; /** * 转向的方向 */ type TurnDir = Dir | ':left' | ':right' | ':back'; /** * 勇士转向 */ type HeroTurnDir = TurnDir | ':hero' | ':backhero'; /** * 对话框的位置 */ type TextPosition = 'up' | 'center' | 'down'; /** * 移动的方向 */ type Move = 'forward' | 'backward' | Dir; type Move2 = Move | Dir2; /** * 缓动模式,不过在高级动画插件面前不堪一击( */ type EaseMode = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut'; /** * 事件执行的操作符\ * += 增加并赋值\ * -= 减少并赋值\ * *= 相乘并赋值\ * /= 相除并赋值\ * //= 除以并取商\ * **= 取幂\ * %= 取余\ * min= 取二者的最小值\ * max= 取二者的最大值\ * 其它的任意字符串都是赋值 */ type MotaOperator = | '+=' | '-=' | '*=' | '/=' | '//=' | '**=' | '%=' | 'min=' | 'max=' | '='; /** * 位置数组 */ type LocArr = [x: number, y: number]; /** * 位置 */ interface Loc { /** * 横坐标 */ x: number; /** * 纵坐标 */ y: number; } /** * 带方向的位置 */ interface DiredLoc extends Loc { /** * 方向 */ direction: Dir; } interface CompressedStep { /** * 移动方向 */ direction: Dir; /** * 向该方向移动的步数 */ step: number; } /** * 四个方向的坐标增量 */ type Scan = { [D in Dir]: Loc; }; /** * 八个方向的坐标增量 */ type Scan2 = { [D in Dir2]: Loc; }; /** * 图片翻转 */ type ImageReverse = ':o' | ':x' | ':y'; /** * 对话框的箭头方向 */ type TextBoxDir = 'up' | 'down'; /** * 对话框的位置 */ type TextBoxPos = | `${TextBoxDir},hero` | `${TextBoxDir},${number},${number}` | TextPosition; /** * 画布信息 */ type CtxRefer = string | CanvasRenderingContext2D | HTMLCanvasElement; /** * 触发器类型 */ type MotaTrigger = | 'battle' | 'pusBox' | 'openDoor' | 'ski' | 'custom' | 'getItem' | 'changeFloor' | 'null'; /** * 切换楼层的目标坐标 */ type FloorChangeStair = | 'upFloor' | 'downFloor' | ':symmetry' | ':symmetry_x' | ':symmetry_y' | 'flyPoint'; /** * 事件值的前缀 */ type EventValuePreffix = | 'status' | 'flag' | 'item' | 'buff' | 'switch' | 'temp' | 'global'; interface Animate { /** * 动画的帧数 */ frame: number; /** * 每帧的信息 */ frames: FrameObj[][]; /** * 图片信息 */ images: HTMLImageElement[]; /** * 缩放信息 */ ratio: number; /** * 音效 */ se: any; pitch: any; } type Save = DeepReadonly<{ /** * 存档所在的楼层id */ floorId: FloorIds; /** * 存档的勇士信息 */ hero: HeroStatus; /** * 难度信息 */ hard: number; /** * 存档的地图信息,已经过压缩处理 */ maps: Record; /** * 录像信息 */ route: string; /** * 存档的全局变量信息 */ values: CoreValues; /** * 游戏版本 */ version: string; /** * 浏览器唯一guid */ guid: string; /** * 存档时间 */ time: number; }>; /** * 深度只读一个对象,使其所有属性都只读 */ type DeepReadonly = { readonly [P in keyof T]: T[P] extends number | string | boolean ? T[P] : DeepReadonly; }; /** * 深度可选一个对象,使其所有属性都可选 */ type DeepPartial = { [P in keyof T]?: T[P] extends number | string | boolean ? T[P] : DeepPartial; }; /** * 深度必选一个对象,使其所有属性都必选 */ type DeepRequired = { [P in keyof T]-?: T[P] extends number | string | boolean ? T[P] : DeepRequired; }; /** * 使一个对象的所有属性可写 */ type Writable = { -readonly [P in keyof T]: T[P]; }; /** * 深度可写一个对象,使其所有属性都可写 */ type DeepWritable = { -readonly [P in keyof T]: T[P] extends number | string | boolean ? T[P] : DeepWritable; }; /** * 从一个对象中选择类型是目标类型的属性 */ type SelectType = { [P in keyof R as R[P] extends T ? P : never]: R[P]; }; /** * 从一个对象中选择类型是目标属性的键名 */ type SelectKey = keyof SelectType; /** * 获取一段字符串的第一个字符 */ type FirstCharOf = T extends `${infer F}${infer A}` ? F : never; /** * 非对象属性 */ type NonObject = number | string | boolean; /** * 获取一个对象的非对象值 */ type NonObjectOf = SelectType; /** * 以一个字符串结尾 */ type EndsWith = `${string}${T}`; type KeyExcludesUnderline = Exclude; type ValueOf = T[keyof T];