Merge pull request #767 from nofficalfs/Dev-Enhancement-DivideMore
Fix `get.copy`
This commit is contained in:
commit
43d1fb4394
|
@ -0,0 +1,221 @@
|
||||||
|
|
||||||
|
export class DynamicStyle {
|
||||||
|
/**
|
||||||
|
* Object of style
|
||||||
|
* 表示样式的对象
|
||||||
|
*
|
||||||
|
* @typedef {Record<string, string | number>} StyleObject
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Rule to record style info.
|
||||||
|
* 用于记录样式信息的规则
|
||||||
|
*
|
||||||
|
* @typedef {[string, StyleObject]} Rule
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Type used to declare the place to store css info.
|
||||||
|
* 用来存CSS信息的空间的类型
|
||||||
|
*
|
||||||
|
* @typedef {object} DynamicStyleCache
|
||||||
|
* @property {Rule[]} rules 记录的规则
|
||||||
|
* @property {HTMLStyleElement} style 全局Style标签
|
||||||
|
* @property {CSSStyleSheet} sheet Style标签的Sheet
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place to store css info.
|
||||||
|
* 存CSS信息的空间
|
||||||
|
*
|
||||||
|
* @type {DynamicStyleCache}
|
||||||
|
*/
|
||||||
|
#cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize dynamicStyle.
|
||||||
|
* 初始化数据
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
/**
|
||||||
|
* @type {DynamicStyleCache}
|
||||||
|
*/
|
||||||
|
const cache = Object.create(null);
|
||||||
|
cache.rules = [];
|
||||||
|
cache.style = document.createElement("style");
|
||||||
|
cache.style.id = "game.dynamicStyle";
|
||||||
|
document.head.appendChild(cache.style);
|
||||||
|
cache.sheet = cache.style.sheet;
|
||||||
|
|
||||||
|
this.#cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn the Object Style to string format.
|
||||||
|
* 将给定的对象样式转换成字符串的形式
|
||||||
|
*
|
||||||
|
* @param {StyleObject} style 给定的对象样式
|
||||||
|
* @returns {string} 样式的字符串形式
|
||||||
|
*/
|
||||||
|
translate(style) {
|
||||||
|
return Object.entries(style).map(item =>
|
||||||
|
`${item[0].replace(/([A-Z])/g, match =>
|
||||||
|
`-${match.toLowerCase()}`)}: ${item[1]};`).join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the common css selector.
|
||||||
|
* 生成标准的CSS样式
|
||||||
|
*
|
||||||
|
* @param {string} name 选择器
|
||||||
|
* @param {StyleObject} style 对象样式
|
||||||
|
* @returns {string} 标准的CSS样式
|
||||||
|
*/
|
||||||
|
generate(name, style) {
|
||||||
|
return `${name} { ${this.translate(style)} }`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the selector is in rules.
|
||||||
|
* 检查是否存在对应选择器的规则
|
||||||
|
*
|
||||||
|
* @param {string} name 选择器
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
has(name) {
|
||||||
|
return this.#cache.rules.some(item => item[0] === name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the style of given selector, or return null.
|
||||||
|
* 获得对应选择器的样式对象,若不存在,则返回`null`
|
||||||
|
*
|
||||||
|
* @param {string} name 选择器
|
||||||
|
* @returns {?StyleObject}
|
||||||
|
*/
|
||||||
|
get(name) {
|
||||||
|
const result = this.find(item => item[0] === name);
|
||||||
|
return result ? result[1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback of `DynamicStyle#find`, getting the rule wanted.
|
||||||
|
* `DynamicStyle#find`的回调函数,用于获取符合要求的规则
|
||||||
|
*
|
||||||
|
* @callback FindCallback
|
||||||
|
* @param {Rule} rule 样式规则
|
||||||
|
* @param {number} index 样式编号
|
||||||
|
* @param {Rule[]} rules 规则集
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the rule wanted by given function.
|
||||||
|
* 通过给定的函数,获取符合要求的规则
|
||||||
|
*
|
||||||
|
* @param {FindCallback} fn 用于检查的函数
|
||||||
|
* @returns {Rule}
|
||||||
|
*/
|
||||||
|
find(fn) {
|
||||||
|
return this.#cache.rules.find(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Length of rules.
|
||||||
|
* 规则集的长度
|
||||||
|
*
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
size() {
|
||||||
|
return this.#cache.rules.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index of given selector, or return `-1`.
|
||||||
|
* 获得对应选择器的位置,若不存在,则返回`-1`
|
||||||
|
*
|
||||||
|
* @param {string} name 选择器
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
indexOf(name) {
|
||||||
|
for (let i = 0; i < this.#cache.rules.length; ++i) {
|
||||||
|
if (name === this.#cache.rules[i][0]) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后面部分就不说明了,可以顾名思义
|
||||||
|
/**
|
||||||
|
* @param {string} name 选择器
|
||||||
|
* @param {StyleObject} style 要添加的样式对象
|
||||||
|
* @returns {boolean} 添加的结果,为`true`则添加成功,为`false`则添加失败
|
||||||
|
*/
|
||||||
|
add(name, style) {
|
||||||
|
return this.update(name, this.has(name) ? Object.assign({}, this.get(name), style) : style);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Record<string, StyleObject>} object 以`name: style`存储的映射
|
||||||
|
* @returns {boolean[]} 添加的结果,为`true`则添加成功,为`false`则添加失败
|
||||||
|
*/
|
||||||
|
addObject(object) {
|
||||||
|
return Object.entries(object).map(item => this.add(item[0], item[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name 要移除规则的选择器
|
||||||
|
* @returns {boolean} 移除的结果,为`true`则移除成功,为`false`则移除失败
|
||||||
|
*/
|
||||||
|
remove(name) {
|
||||||
|
if (!this.has(name)) return false;
|
||||||
|
try {
|
||||||
|
const index = this.indexOf(name);
|
||||||
|
this.#cache.rules.splice(index, 1);
|
||||||
|
this.#cache.sheet.deleteRule(index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name 要移除规则的选择器
|
||||||
|
* @param {string[]} styles 要移除的样式
|
||||||
|
* @returns {boolean} 移除的结果,为`true`则移除成功,为`false`则移除失败
|
||||||
|
*/
|
||||||
|
removeStyles(name, styles) {
|
||||||
|
if (!this.has(name)) return false;
|
||||||
|
const style = this.get(name);
|
||||||
|
styles.forEach(styleName => {
|
||||||
|
delete style[styleName];
|
||||||
|
});
|
||||||
|
return this.update(name, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加或修改一个规则所对应的样式
|
||||||
|
*
|
||||||
|
* @param {string} name 要变更规则的选择器
|
||||||
|
* @param {StyleObject} style 变更规则的样式
|
||||||
|
* @returns {boolean} 更新的结果,为`true`则更新成功,为`false`则更新失败
|
||||||
|
*/
|
||||||
|
update(name, style) {
|
||||||
|
try {
|
||||||
|
if (this.has(name)) {
|
||||||
|
const index = this.indexOf(name);
|
||||||
|
this.#cache.sheet.deleteRule(index);
|
||||||
|
this.#cache.sheet.insertRule(this.generate(name, style), index);
|
||||||
|
this.#cache.rules[index] = [name, style];
|
||||||
|
} else {
|
||||||
|
const index = this.#cache.rules.length;
|
||||||
|
this.#cache.rules.push([name, style]);
|
||||||
|
this.#cache.sheet.insertRule(this.generate(name, style), index);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,9 @@ import { UI as ui } from '../ui/index.js';
|
||||||
import { GNC as gnc } from '../gnc/index.js';
|
import { GNC as gnc } from '../gnc/index.js';
|
||||||
import { userAgent, Uninstantable, GeneratorFunction, AsyncFunction, delay } from "../util/index.js";
|
import { userAgent, Uninstantable, GeneratorFunction, AsyncFunction, delay } from "../util/index.js";
|
||||||
|
|
||||||
|
import { DynamicStyle } from "./dynamic-style/index.js";
|
||||||
|
import { GamePromises } from "./promises.js";
|
||||||
|
|
||||||
export class Game extends Uninstantable {
|
export class Game extends Uninstantable {
|
||||||
static online = false;
|
static online = false;
|
||||||
static onlineID = null;
|
static onlineID = null;
|
||||||
|
@ -38,98 +41,7 @@ export class Game extends Uninstantable {
|
||||||
static phaseNumber = 0;
|
static phaseNumber = 0;
|
||||||
static roundNumber = 0;
|
static roundNumber = 0;
|
||||||
static shuffleNumber = 0;
|
static shuffleNumber = 0;
|
||||||
static promises = {
|
static promises = GamePromises;
|
||||||
/**
|
|
||||||
* 模仿h5的prompt,用于显示可提示用户进行输入的对话框
|
|
||||||
*
|
|
||||||
* 注: 由于参数列表是随意的,在这里我准备限制一下这个函数的参数顺序
|
|
||||||
*
|
|
||||||
* @type {{
|
|
||||||
* (title: string): Promise<string | false>;
|
|
||||||
* (title: string, forced: true): Promise<string>;
|
|
||||||
* (alertOption: 'alert', title: string): Promise<true>;
|
|
||||||
* }}
|
|
||||||
*
|
|
||||||
* @param { string } title 设置prompt标题与input内容
|
|
||||||
* @param { boolean } [forced] 为true的话将没有"取消按钮"
|
|
||||||
* @param { string } alertOption 设置prompt是否模拟alert
|
|
||||||
* @example
|
|
||||||
* ```js
|
|
||||||
* // 只设置标题(但是input的初始值就变成了undefined)
|
|
||||||
* game.promises.prompt('###prompt标题').then(value => console.log(value));
|
|
||||||
* // 设置标题和input初始内容
|
|
||||||
* game.promises.prompt('###prompt标题###input初始内容').then(value => console.log(value));
|
|
||||||
* ```
|
|
||||||
* @returns { Promise<string> }
|
|
||||||
*/
|
|
||||||
// @ts-ignore
|
|
||||||
prompt(alertOption, title, forced) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (alertOption != 'alert') {
|
|
||||||
// @ts-ignore
|
|
||||||
forced = title || false;
|
|
||||||
title = alertOption;
|
|
||||||
game.prompt(title, forced, resolve);
|
|
||||||
} else {
|
|
||||||
game.prompt(title, alertOption, resolve);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 模仿h5的alert,用于显示信息的对话框
|
|
||||||
*
|
|
||||||
* @param { string } title
|
|
||||||
* @example
|
|
||||||
* ```js
|
|
||||||
* await game.promises.alert('弹窗内容');
|
|
||||||
* ```
|
|
||||||
* @returns { Promise<true> }
|
|
||||||
*/
|
|
||||||
alert(title) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
game.prompt(title, 'alert', resolve);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 读写函数promises化(不用考虑其对应函数是否存在)
|
|
||||||
download(url, folder, dev, onprogress) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
game.download(url, folder, resolve, reject, dev, onprogress);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
readFile(filename) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
game.readFile(filename, resolve, reject);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
readFileAsText(filename) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
game.readFileAsText(filename, resolve, reject);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
writeFile(data, path, name) {
|
|
||||||
return (new Promise((resolve, reject) => {
|
|
||||||
game.writeFile(data, path, name, resolve);
|
|
||||||
})).then(result => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (result instanceof Error) {
|
|
||||||
reject(result);
|
|
||||||
} else {
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
ensureDirectory(list, callback, file) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
game.ensureDirectory(list, callback, file).then(resolve).catch(reject);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
createDir(directory) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
game.createDir(directory, resolve, reject);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}
|
|
||||||
static globalEventHandlers = new class {
|
static globalEventHandlers = new class {
|
||||||
constructor() {
|
constructor() {
|
||||||
this._handlers = {};
|
this._handlers = {};
|
||||||
|
@ -361,223 +273,7 @@ export class Game extends Uninstantable {
|
||||||
* textAlign: "center"
|
* textAlign: "center"
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
static dynamicStyle = new class {
|
static dynamicStyle = new DynamicStyle()
|
||||||
/**
|
|
||||||
* Object of style
|
|
||||||
* 表示样式的对象
|
|
||||||
*
|
|
||||||
* @typedef {Record<string, string | number>} StyleObject
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Rule to record style info.
|
|
||||||
* 用于记录样式信息的规则
|
|
||||||
*
|
|
||||||
* @typedef {[string, StyleObject]} Rule
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Type used to declare the place to store css info.
|
|
||||||
* 用来存CSS信息的空间的类型
|
|
||||||
*
|
|
||||||
* @typedef {object} DynamicStyleCache
|
|
||||||
* @property {Rule[]} rules 记录的规则
|
|
||||||
* @property {HTMLStyleElement} style 全局Style标签
|
|
||||||
* @property {CSSStyleSheet} sheet Style标签的Sheet
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize dynamicStyle.
|
|
||||||
* 初始化数据
|
|
||||||
*/
|
|
||||||
constructor() {
|
|
||||||
/**
|
|
||||||
* @type {DynamicStyleCache}
|
|
||||||
*/
|
|
||||||
let cache = Object.create(null);
|
|
||||||
cache.rules = new Array;
|
|
||||||
cache.style = document.createElement("style");
|
|
||||||
cache.style.id = "game.dynamicStyle";
|
|
||||||
document.head.appendChild(cache.style);
|
|
||||||
cache.sheet = cache.style.sheet;
|
|
||||||
/**
|
|
||||||
* Place to store css info.
|
|
||||||
* 存CSS信息的空间
|
|
||||||
*
|
|
||||||
* @type {DynamicStyleCache}
|
|
||||||
*/
|
|
||||||
this._cache = cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn the Object Style to string format.
|
|
||||||
* 将给定的对象样式转换成字符串的形式
|
|
||||||
*
|
|
||||||
* @param {StyleObject} style 给定的对象样式
|
|
||||||
* @returns {string} 样式的字符串形式
|
|
||||||
*/
|
|
||||||
translate(style) {
|
|
||||||
return Object.entries(style).map(item =>
|
|
||||||
`${item[0].replace(/([A-Z])/g, match =>
|
|
||||||
`-${match.toLowerCase()}`)}: ${item[1]};`).join(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the common css selector.
|
|
||||||
* 生成标准的CSS样式
|
|
||||||
*
|
|
||||||
* @param {string} name 选择器
|
|
||||||
* @param {StyleObject} style 对象样式
|
|
||||||
* @returns {string} 标准的CSS样式
|
|
||||||
*/
|
|
||||||
generate(name, style) {
|
|
||||||
return `${name} { ${this.translate(style)} }`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the selector is in rules.
|
|
||||||
* 检查是否存在对应选择器的规则
|
|
||||||
*
|
|
||||||
* @param {string} name 选择器
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
has(name) {
|
|
||||||
return this._cache.rules.some(item => item[0] == name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the style of given selector, or return null.
|
|
||||||
* 获得对应选择器的样式对象,若不存在,则返回`null`
|
|
||||||
*
|
|
||||||
* @param {string} name 选择器
|
|
||||||
* @returns {?StyleObject}
|
|
||||||
*/
|
|
||||||
get(name) {
|
|
||||||
const result = this.find(item => item[0] == name);
|
|
||||||
return result ? result[1] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback of `DynamicStyle#find`, getting the rule wanted.
|
|
||||||
* `DynamicStyle#find`的回调函数,用于获取符合要求的规则
|
|
||||||
*
|
|
||||||
* @callback FindCallback
|
|
||||||
* @param {Rule} rule 样式规则
|
|
||||||
* @param {number} index 样式编号
|
|
||||||
* @param {Rule[]} rules 规则集
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the rule wanted by given function.
|
|
||||||
* 通过给定的函数,获取符合要求的规则
|
|
||||||
*
|
|
||||||
* @param {FindCallback} fn 用于检查的函数
|
|
||||||
* @returns {?StyleObject}
|
|
||||||
*/
|
|
||||||
find(fn) {
|
|
||||||
return this._cache.rules.find(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Length of rules.
|
|
||||||
* 规则集的长度
|
|
||||||
*
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
size() {
|
|
||||||
return this._cache.rules.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the index of given selector, or return `-1`.
|
|
||||||
* 获得对应选择器的位置,若不存在,则返回`-1`
|
|
||||||
*
|
|
||||||
* @param {string} name 选择器
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
indexOf(name) {
|
|
||||||
for (let i = 0; i < this._cache.rules.length; ++i) {
|
|
||||||
if (name == this._cache.rules[i][0]) return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 后面部分就不说明了,可以顾名思义
|
|
||||||
/**
|
|
||||||
* @param {string} name 选择器
|
|
||||||
* @param {StyleObject} style 要添加的样式对象
|
|
||||||
* @returns {boolean} 添加的结果,为`true`则添加成功,为`false`则添加失败
|
|
||||||
*/
|
|
||||||
add(name, style) {
|
|
||||||
return this.update(name, this.has(name) ? Object.assign({}, this.get(name), style) : style);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Record<string, StyleObject>} object 以`name: style`存储的映射
|
|
||||||
* @returns {boolean} 添加的结果,为`true`则添加成功,为`false`则添加失败
|
|
||||||
*/
|
|
||||||
addObject(object) {
|
|
||||||
return Object.entries(object).map(item => this.add(item[0], item[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} name 要移除规则的选择器
|
|
||||||
* @returns {boolean} 移除的结果,为`true`则移除成功,为`false`则移除失败
|
|
||||||
*/
|
|
||||||
remove(name) {
|
|
||||||
if (!this.has(name)) return false;
|
|
||||||
try {
|
|
||||||
const index = this.indexOf(name);
|
|
||||||
this._cache.rules.splice(index, 1);
|
|
||||||
this._cache.sheet.deleteRule(index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} name 要移除规则的选择器
|
|
||||||
* @param {string[]} styles 要移除的样式
|
|
||||||
* @returns {boolean} 移除的结果,为`true`则移除成功,为`false`则移除失败
|
|
||||||
*/
|
|
||||||
removeStyles(name, styles) {
|
|
||||||
if (!this.has(name)) return false;
|
|
||||||
const style = this.get(name);
|
|
||||||
styles.forEach(styleName => {
|
|
||||||
delete style[styleName];
|
|
||||||
});
|
|
||||||
return this.update(name, style);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加或修改一个规则所对应的样式
|
|
||||||
*
|
|
||||||
* @param {string} name 要变更规则的选择器
|
|
||||||
* @param {StyleObject} style 变更规则的样式
|
|
||||||
* @returns {boolean} 更新的结果,为`true`则更新成功,为`false`则更新失败
|
|
||||||
*/
|
|
||||||
update(name, style) {
|
|
||||||
try {
|
|
||||||
if (this.has(name)) {
|
|
||||||
const index = this.indexOf(name);
|
|
||||||
this._cache.sheet.deleteRule(index);
|
|
||||||
this._cache.sheet.insertRule(this.generate(name, style), index);
|
|
||||||
this._cache.rules[index] = [name, style];
|
|
||||||
} else {
|
|
||||||
const index = this._cache.rules.length;
|
|
||||||
this._cache.rules.push([name, style]);
|
|
||||||
this._cache.sheet.insertRule(this.generate(name, style), index);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Add a background music to the config option
|
* Add a background music to the config option
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
import { Uninstantable } from "../util/index.js";
|
||||||
|
import { game, Game } from "./index.js";
|
||||||
|
|
||||||
|
export class GamePromises extends Uninstantable {
|
||||||
|
/**
|
||||||
|
* 模仿h5的prompt,用于显示可提示用户进行输入的对话框
|
||||||
|
*
|
||||||
|
* 注: 由于参数列表是随意的,在这里我准备限制一下这个函数的参数顺序
|
||||||
|
*
|
||||||
|
* @type {{
|
||||||
|
* (title: string): Promise<string | false>;
|
||||||
|
* (title: string, forced: true): Promise<string>;
|
||||||
|
* (alertOption: 'alert', title: string): Promise<true>;
|
||||||
|
* }}
|
||||||
|
*
|
||||||
|
* @param { string } title 设置prompt标题与input内容
|
||||||
|
* @param { boolean } [forced] 为true的话将没有"取消按钮"
|
||||||
|
* @param { string } alertOption 设置prompt是否模拟alert
|
||||||
|
* @example
|
||||||
|
* ```js
|
||||||
|
* // 只设置标题(但是input的初始值就变成了undefined)
|
||||||
|
* game.promises.prompt('###prompt标题').then(value => console.log(value));
|
||||||
|
* // 设置标题和input初始内容
|
||||||
|
* game.promises.prompt('###prompt标题###input初始内容').then(value => console.log(value));
|
||||||
|
* ```
|
||||||
|
* @returns { Promise<string> }
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
static prompt(alertOption, title, forced) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (alertOption !== 'alert') {
|
||||||
|
// @ts-ignore
|
||||||
|
forced = title || false;
|
||||||
|
title = alertOption;
|
||||||
|
game.prompt(title, forced, resolve);
|
||||||
|
} else {
|
||||||
|
game.prompt(title, alertOption, resolve);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 模仿h5的alert,用于显示信息的对话框
|
||||||
|
*
|
||||||
|
* @param { string } title
|
||||||
|
* @example
|
||||||
|
* ```js
|
||||||
|
* await game.promises.alert('弹窗内容');
|
||||||
|
* ```
|
||||||
|
* @returns { Promise<true> }
|
||||||
|
*/
|
||||||
|
static alert(title) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
game.prompt(title, 'alert', resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 读写函数promises化(不用考虑其对应函数是否存在)
|
||||||
|
static download(url, folder, dev, onprogress) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
game.download(url, folder, resolve, reject, dev, onprogress);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static readFile(filename) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
game.readFile(filename, resolve, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static readFileAsText(filename) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
game.readFileAsText(filename, resolve, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static writeFile(data, path, name) {
|
||||||
|
return (new Promise((resolve, reject) => {
|
||||||
|
game.writeFile(data, path, name, resolve);
|
||||||
|
})).then(result => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (result instanceof Error) {
|
||||||
|
reject(result);
|
||||||
|
} else {
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static ensureDirectory(list, callback, file) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
game.ensureDirectory(list, callback, file).then(resolve).catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static createDir(directory) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
game.createDir(directory, resolve, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,441 +6,7 @@ import { status as _status } from '../status/index.js';
|
||||||
import { UI as ui } from '../ui/index.js';
|
import { UI as ui } from '../ui/index.js';
|
||||||
import { GNC as gnc } from '../gnc/index.js';
|
import { GNC as gnc } from '../gnc/index.js';
|
||||||
|
|
||||||
export class Is extends Uninstantable {
|
import { Is } from "./is.js";
|
||||||
/**
|
|
||||||
* 判断是否为进攻坐骑
|
|
||||||
* @param { Card | VCard } card
|
|
||||||
* @param { false | Player } [player]
|
|
||||||
* @returns { boolean }
|
|
||||||
*/
|
|
||||||
static attackingMount(card, player) {
|
|
||||||
const subtype = get.subtype(card, player);
|
|
||||||
if (subtype == 'equip4') return true;
|
|
||||||
else if (subtype == 'equip6') {
|
|
||||||
const info = get.info(card, player), distance = info.distance;
|
|
||||||
if (!distance) return false;
|
|
||||||
if (distance.globalFrom && !info.notMount) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 判断是否为防御坐骑
|
|
||||||
* @param { Card | VCard } card
|
|
||||||
* @param { false | Player } [player]
|
|
||||||
* @returns { boolean }
|
|
||||||
*/
|
|
||||||
static defendingMount(card, player) {
|
|
||||||
const subtype = get.subtype(card, player);
|
|
||||||
if (subtype == 'equip3') return true;
|
|
||||||
else if (subtype == 'equip6') {
|
|
||||||
const info = get.info(card, player), distance = info.distance;
|
|
||||||
if (!distance) return false;
|
|
||||||
if (distance.globalTo && !info.notMount) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 判断坐骑栏是否被合并
|
|
||||||
* @returns { boolean }
|
|
||||||
*/
|
|
||||||
static mountCombined() {
|
|
||||||
if (lib.configOL.mount_combine) {
|
|
||||||
return lib.configOL.mount_combine;
|
|
||||||
}
|
|
||||||
else if (typeof _status.mountCombined != 'boolean') {
|
|
||||||
_status.mountCombined = lib.config.mount_combine;
|
|
||||||
}
|
|
||||||
return _status.mountCombined;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 判断传入的参数的属性是否相同(参数可以为卡牌、卡牌信息、属性等)
|
|
||||||
* @param {...} infos 要判断的属性列表
|
|
||||||
* @param {boolean} every 是否判断每一个传入的属性是否完全相同而不是存在部分相同
|
|
||||||
*/
|
|
||||||
static sameNature() {
|
|
||||||
let processedArguments = [], every = false;
|
|
||||||
Array.from(arguments).forEach(argument => {
|
|
||||||
if (typeof argument == 'boolean') every = argument;
|
|
||||||
else if (argument) processedArguments.push(argument);
|
|
||||||
});
|
|
||||||
if (!processedArguments.length) return true;
|
|
||||||
if (processedArguments.length == 1) {
|
|
||||||
const argument = processedArguments[0];
|
|
||||||
if (!Array.isArray(argument)) return false;
|
|
||||||
if (!argument.length) return true;
|
|
||||||
if (argument.length == 1) return false;
|
|
||||||
processedArguments = argument;
|
|
||||||
}
|
|
||||||
const naturesList = processedArguments.map(card => {
|
|
||||||
if (typeof card == 'string') return card.split(lib.natureSeparator);
|
|
||||||
else if (Array.isArray(card)) return card;
|
|
||||||
return get.natureList(card || {});
|
|
||||||
});
|
|
||||||
const testingNaturesList = naturesList.slice(0, naturesList.length - 1);
|
|
||||||
if (every) return testingNaturesList.every((natures, index) => naturesList.slice(index + 1).every(testingNatures => testingNatures.length == natures.length && testingNatures.every(nature => natures.includes(nature))));
|
|
||||||
return testingNaturesList.every((natures, index) => {
|
|
||||||
const comparingNaturesList = naturesList.slice(index + 1);
|
|
||||||
if (natures.length) return natures.some(nature => comparingNaturesList.every(testingNatures => testingNatures.includes(nature)));
|
|
||||||
return comparingNaturesList.every(testingNatures => !testingNatures.length);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 判断传入的参数的属性是否不同(参数可以为卡牌、卡牌信息、属性等)
|
|
||||||
* @param ...infos 要判断的属性列表
|
|
||||||
* @param every {boolean} 是否判断每一个传入的属性是否完全不同而不是存在部分不同
|
|
||||||
*/
|
|
||||||
static differentNature() {
|
|
||||||
let processedArguments = [], every = false;
|
|
||||||
Array.from(arguments).forEach(argument => {
|
|
||||||
if (typeof argument == 'boolean') every = argument;
|
|
||||||
else if (argument) processedArguments.push(argument);
|
|
||||||
});
|
|
||||||
if (!processedArguments.length) return false;
|
|
||||||
if (processedArguments.length == 1) {
|
|
||||||
const argument = processedArguments[0];
|
|
||||||
if (!Array.isArray(argument)) return true;
|
|
||||||
if (!argument.length) return false;
|
|
||||||
if (argument.length == 1) return true;
|
|
||||||
processedArguments = argument;
|
|
||||||
}
|
|
||||||
const naturesList = processedArguments.map(card => {
|
|
||||||
if (typeof card == 'string') return card.split(lib.natureSeparator);
|
|
||||||
else if (Array.isArray(card)) return card;
|
|
||||||
return get.natureList(card || {});
|
|
||||||
});
|
|
||||||
const testingNaturesList = naturesList.slice(0, naturesList.length - 1);
|
|
||||||
if (every) return testingNaturesList.every((natures, index) => naturesList.slice(index + 1).every(testingNatures => testingNatures.every(nature => !natures.includes(nature))));
|
|
||||||
return testingNaturesList.every((natures, index) => {
|
|
||||||
const comparingNaturesList = naturesList.slice(index + 1);
|
|
||||||
if (natures.length) return natures.some(nature => comparingNaturesList.every(testingNatures => !testingNatures.length || testingNatures.some(testingNature => testingNature != nature)));
|
|
||||||
return comparingNaturesList.every(testingNatures => testingNatures.length);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 判断一张牌是否为明置手牌
|
|
||||||
* @param { Card } card
|
|
||||||
*/
|
|
||||||
static shownCard(card) {
|
|
||||||
if (!card) return false;
|
|
||||||
const gaintag = card.gaintag;
|
|
||||||
return Array.isArray(gaintag) && gaintag.some(tag => tag.startsWith('visible_'));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 是否是虚拟牌
|
|
||||||
* @param { Card | VCard } card
|
|
||||||
*/
|
|
||||||
// @ts-ignore
|
|
||||||
static vituralCard(card) {
|
|
||||||
return card.isCard || (!("cards" in card) || !Array.isArray(card.cards) || card.cards.length == 0);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 是否是转化牌
|
|
||||||
* @param { Card | VCard } card
|
|
||||||
*/
|
|
||||||
// @ts-ignore
|
|
||||||
static convertedCard(card) {
|
|
||||||
return !card.isCard && ("cards" in card) && Array.isArray(card.cards) && card.cards.length > 0;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 是否是实体牌
|
|
||||||
* @param { Card | VCard } card
|
|
||||||
*/
|
|
||||||
// @ts-ignore
|
|
||||||
static ordinaryCard(card) { return card.isCard && ("cards" in card) && Array.isArray(card.cards) && card.cards.length == 1 }
|
|
||||||
/**
|
|
||||||
* 押韵判断
|
|
||||||
* @param { string } str1
|
|
||||||
* @param { string } str2
|
|
||||||
*/
|
|
||||||
static yayun(str1, str2) {
|
|
||||||
if (str1 == str2) return true;
|
|
||||||
let pinyin1 = get.pinyin(str1, false), pinyin2 = get.pinyin(str2, false);
|
|
||||||
if (!pinyin1.length || !pinyin2.length) return false;
|
|
||||||
let pron1 = pinyin1[pinyin1.length - 1], pron2 = pinyin2[pinyin2.length - 1];
|
|
||||||
if (pron1 == pron2) return true;
|
|
||||||
return get.yunjiao(pron1) == get.yunjiao(pron2);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param { string } skill 技能id
|
|
||||||
* @param { Player } player 玩家
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
static blocked(skill, player) {
|
|
||||||
if (!player.storage.skill_blocker || !player.storage.skill_blocker.length) return false;
|
|
||||||
for (let i of player.storage.skill_blocker) {
|
|
||||||
if (lib.skill[i] && lib.skill[i].skillBlocker && lib.skill[i].skillBlocker(skill, player)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 是否是双势力武将
|
|
||||||
* @param { string } name
|
|
||||||
* @param { string[] } array
|
|
||||||
* @returns { boolean | string[] }
|
|
||||||
*/
|
|
||||||
static double(name, array) {
|
|
||||||
const extraInformations = get.character(name, 4);
|
|
||||||
if (!extraInformations) return false;
|
|
||||||
for (const extraInformation of extraInformations) {
|
|
||||||
if (!extraInformation.startsWith('doublegroup:')) continue;
|
|
||||||
return array ? extraInformation.split(':').slice(1) : true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Check if the card has a Yingbian condition
|
|
||||||
*
|
|
||||||
* 检测此牌是否具有应变条件
|
|
||||||
* @param { Card | VCard } card
|
|
||||||
*/
|
|
||||||
static yingbianConditional(card) { return get.is.complexlyYingbianConditional(card) || get.is.simplyYingbianConditional(card) }
|
|
||||||
/**
|
|
||||||
* @param { Card | VCard } card
|
|
||||||
*/
|
|
||||||
static complexlyYingbianConditional(card) {
|
|
||||||
for (const key of lib.yingbian.condition.complex.keys()) {
|
|
||||||
if (get.cardtag(card, `yingbian_${key}`)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param { Card | VCard } card
|
|
||||||
*/
|
|
||||||
static simplyYingbianConditional(card) {
|
|
||||||
for (const key of lib.yingbian.condition.simple.keys()) {
|
|
||||||
if (get.cardtag(card, `yingbian_${key}`)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Check if the card has a Yingbian effect
|
|
||||||
*
|
|
||||||
* 检测此牌是否具有应变效果
|
|
||||||
*
|
|
||||||
* @param { Card | VCard } card
|
|
||||||
*/
|
|
||||||
static yingbianEffective(card) {
|
|
||||||
for (const key of lib.yingbian.effect.keys()) {
|
|
||||||
if (get.cardtag(card, `yingbian_${key}`)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param { Card | VCard } card
|
|
||||||
*/
|
|
||||||
static yingbian(card) { return get.is.yingbianConditional(card) || get.is.yingbianEffective(card) }
|
|
||||||
/**
|
|
||||||
* @param { string } [substring]
|
|
||||||
*/
|
|
||||||
static emoji(substring) {
|
|
||||||
if (substring) {
|
|
||||||
const reg = new RegExp("[~#^$@%&!?%*]", 'g');
|
|
||||||
if (substring.match(reg)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < substring.length; i++) {
|
|
||||||
const hs = substring.charCodeAt(i);
|
|
||||||
if (0xd800 <= hs && hs <= 0xdbff) {
|
|
||||||
if (substring.length > 1) {
|
|
||||||
const ls = substring.charCodeAt(i + 1);
|
|
||||||
const uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
|
|
||||||
if (0x1d000 <= uc && uc <= 0x1f77f) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (substring.length > 1) {
|
|
||||||
const ls = substring.charCodeAt(i + 1);
|
|
||||||
if (ls == 0x20e3) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (0x2100 <= hs && hs <= 0x27ff) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (0x2B05 <= hs && hs <= 0x2b07) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (0x2934 <= hs && hs <= 0x2935) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (0x3297 <= hs && hs <= 0x3299) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030
|
|
||||||
|| hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b
|
|
||||||
|| hs == 0x2b50) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param { string } str
|
|
||||||
*/
|
|
||||||
static banWords(str) { return get.is.emoji(str) || window.bannedKeyWords.some(item => str.includes(item)) }
|
|
||||||
/**
|
|
||||||
* @param { GameEventPromise } event
|
|
||||||
*/
|
|
||||||
// @ts-ignore
|
|
||||||
static converted(event) { return !(event.card && event.card.isCard) }
|
|
||||||
static safari() { return userAgent.indexOf('safari') != -1 && userAgent.indexOf('chrome') == -1 }
|
|
||||||
/**
|
|
||||||
* @param { (Card | VCard)[]} cards
|
|
||||||
*/
|
|
||||||
// @ts-ignore
|
|
||||||
static freePosition(cards) { return !cards.some(card => !card.hasPosition || card.hasPosition()) }
|
|
||||||
/**
|
|
||||||
* @param { string } name
|
|
||||||
* @param { boolean } item
|
|
||||||
*/
|
|
||||||
static nomenu(name, item) {
|
|
||||||
const menus = ['system', 'menu'];
|
|
||||||
const configs = {
|
|
||||||
show_round_menu: lib.config.show_round_menu,
|
|
||||||
round_menu_func: lib.config.round_menu_func,
|
|
||||||
touchscreen: lib.config.touchscreen,
|
|
||||||
swipe_up: lib.config.swipe_up,
|
|
||||||
swipe_down: lib.config.swipe_down,
|
|
||||||
swipe_left: lib.config.swipe_left,
|
|
||||||
swipe_right: lib.config.swipe_right,
|
|
||||||
right_click: lib.config.right_click,
|
|
||||||
phonelayout: lib.config.phonelayout
|
|
||||||
};
|
|
||||||
configs[name] = item;
|
|
||||||
if (!configs.phonelayout) return false;
|
|
||||||
if (configs.show_round_menu && menus.includes(configs.round_menu_func)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (configs.touchscreen) {
|
|
||||||
if (menus.includes(configs.swipe_up)) return false;
|
|
||||||
if (menus.includes(configs.swipe_down)) return false;
|
|
||||||
if (menus.includes(configs.swipe_left)) return false;
|
|
||||||
if (menus.includes(configs.swipe_right)) return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (configs.right_click == 'config') return false;
|
|
||||||
}
|
|
||||||
if (name) {
|
|
||||||
setTimeout(function () {
|
|
||||||
alert('请将至少一个操作绑定为显示按钮或打开菜单,否则将永远无法打开菜单');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
static altered() { return false; }
|
|
||||||
/*
|
|
||||||
skill=>{
|
|
||||||
return false;
|
|
||||||
// if(_status.connectMode) return true;
|
|
||||||
// return !lib.config.vintageSkills.includes(skill);
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @param { any } obj
|
|
||||||
* @returns { boolean }
|
|
||||||
*/
|
|
||||||
static node(obj) {
|
|
||||||
return Object.prototype.toString.call(obj).startsWith('[object HTML');
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param { any } obj
|
|
||||||
*/
|
|
||||||
static div(obj) { return Object.prototype.toString.call(obj) === '[object HTMLDivElement]' }
|
|
||||||
/**
|
|
||||||
* @param { any } obj
|
|
||||||
*/
|
|
||||||
static map(obj) { return Object.prototype.toString.call(obj) === '[object Map]' }
|
|
||||||
/**
|
|
||||||
* @param { any } obj
|
|
||||||
*/
|
|
||||||
static set(obj) { return Object.prototype.toString.call(obj) === '[object Set]' }
|
|
||||||
/**
|
|
||||||
* @param { any } obj
|
|
||||||
*/
|
|
||||||
static object(obj) { return Object.prototype.toString.call(obj) === '[object Object]' }
|
|
||||||
/**
|
|
||||||
* @overload
|
|
||||||
* @param { Function } func
|
|
||||||
* @returns { false }
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @overload
|
|
||||||
* @param { number | [number, number] } func
|
|
||||||
* @returns { boolean }
|
|
||||||
*/
|
|
||||||
static singleSelect(func) {
|
|
||||||
if (typeof func == 'function') return false;
|
|
||||||
const select = get.select(func);
|
|
||||||
return select[0] == 1 && select[1] == 1;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param { string | Player } name
|
|
||||||
*/
|
|
||||||
static jun(name) {
|
|
||||||
if (get.mode() == 'guozhan') {
|
|
||||||
if (name instanceof lib.element.Player) {
|
|
||||||
if (name.isUnseen && name.isUnseen(0)) return false;
|
|
||||||
name = name.name1;
|
|
||||||
}
|
|
||||||
if (typeof name == 'string' && name.startsWith('gz_jun_')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
static versus() { return !_status.connectMode && get.mode() == 'versus' && _status.mode == 'three' }
|
|
||||||
static changban() { return get.mode() == 'single' && _status.mode == 'changban' }
|
|
||||||
static single() { return get.mode() == 'single' && _status.mode == 'normal' }
|
|
||||||
/**
|
|
||||||
* @param { Player } [player]
|
|
||||||
*/
|
|
||||||
static mobileMe(player) { return (game.layout == 'mobile' || game.layout == 'long') && !game.chess && player && player.dataset.position == '0' }
|
|
||||||
static newLayout() { return game.layout != 'default' }
|
|
||||||
static phoneLayout() {
|
|
||||||
if (!lib.config.phonelayout) return false;
|
|
||||||
return (game.layout == 'mobile' || game.layout == 'long' || game.layout == 'long2' || game.layout == 'nova');
|
|
||||||
}
|
|
||||||
static singleHandcard() { return game.singleHandcard || game.layout == 'mobile' || game.layout == 'long' || game.layout == 'long2' || game.layout == 'nova' }
|
|
||||||
/**
|
|
||||||
* @param { Player } player
|
|
||||||
*/
|
|
||||||
static linked2(player) {
|
|
||||||
if (game.chess) return true;
|
|
||||||
if (lib.config.link_style2 != 'rotate') return true;
|
|
||||||
// if(game.chess) return false;
|
|
||||||
if (game.layout == 'long' || game.layout == 'long2' || game.layout == 'nova') return true;
|
|
||||||
if (player.dataset.position == '0') {
|
|
||||||
return ui.arena.classList.contains('oblongcard');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param { {} } obj
|
|
||||||
*/
|
|
||||||
static empty(obj) { return Object.keys(obj).length == 0 }
|
|
||||||
/**
|
|
||||||
* @param { string } str
|
|
||||||
*/
|
|
||||||
static pos(str) { return str == 'h' || str == 'e' || str == 'j' || str == 'he' || str == 'hj' || str == 'ej' || str == 'hej' }
|
|
||||||
/**
|
|
||||||
* @param { string } skill
|
|
||||||
* @param { Player } player
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
static locked(skill, player) {
|
|
||||||
const info = lib.skill[skill];
|
|
||||||
if (typeof info.locked == 'function') return info.locked(skill, player);
|
|
||||||
if (info.locked == false) return false;
|
|
||||||
if (info.trigger && info.forced) return true;
|
|
||||||
if (info.mod) return true;
|
|
||||||
if (info.locked) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Get extends Uninstantable {
|
export class Get extends Uninstantable {
|
||||||
static is = Is;
|
static is = Is;
|
||||||
|
@ -676,7 +242,7 @@ export class Get extends Uninstantable {
|
||||||
}
|
}
|
||||||
static yunjiao(str) {
|
static yunjiao(str) {
|
||||||
const util = window.pinyinUtilx;
|
const util = window.pinyinUtilx;
|
||||||
if (util) str = util.removeTone(str)
|
if (util) str = util.removeTone(str);
|
||||||
if (lib.pinyins._metadata.zhengtirendu.includes(str)) {
|
if (lib.pinyins._metadata.zhengtirendu.includes(str)) {
|
||||||
str = ('-' + str[str.length - 1]);
|
str = ('-' + str[str.length - 1]);
|
||||||
}
|
}
|
||||||
|
@ -1227,16 +793,18 @@ export class Get extends Uninstantable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
* 深拷贝函数(虽然只处理了部分情况)
|
||||||
|
*
|
||||||
|
* 除了普通的Object和NullObject,均不考虑自行赋值的数据,但会原样将Symbol复制过去
|
||||||
|
*
|
||||||
* @template T
|
* @template T
|
||||||
* @param {T} obj
|
* @param {T} obj - 要复制的对象,若不是对象则直接返回原值
|
||||||
* @returns {T}
|
* @param {WeakMap<object, unknown>} [map] - 拷贝用的临时存储,用于处理循环引用(请勿自行赋值)
|
||||||
|
* @returns {T} - 深拷贝后的对象,若传入值不是对象则为传入值
|
||||||
*/
|
*/
|
||||||
static copy(obj, map = new WeakMap()) {
|
static copy(obj, map = new WeakMap()) {
|
||||||
try {
|
// 参考[这里](https://juejin.cn/post/7315612852890026021)实现深拷贝
|
||||||
return structuredClone(obj);
|
// 不再判断是否能structuredClone是因为structuredClone会把Symbol给毙了
|
||||||
}
|
|
||||||
catch {
|
|
||||||
// obj不可序列化时,参考[这里](https://juejin.cn/post/7315612852890026021)实现深拷贝
|
|
||||||
const getType = (obj) => Object.prototype.toString.call(obj);
|
const getType = (obj) => Object.prototype.toString.call(obj);
|
||||||
|
|
||||||
const canTranverse = {
|
const canTranverse = {
|
||||||
|
@ -1247,88 +815,64 @@ export class Get extends Uninstantable {
|
||||||
"[object Arguments]": true,
|
"[object Arguments]": true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const functionMap = {
|
if (typeof obj !== "object" || obj === null)
|
||||||
"[object Function]": true,
|
return obj;
|
||||||
"[object AsyncFunction]": true,
|
|
||||||
"[object GeneratorFunction]": true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const transformFunction = (fn) => {
|
|
||||||
const str = fn.toString();
|
|
||||||
// 箭头函数
|
|
||||||
if (/^\s*(?:async)?\s*\(.*\)\s*=>/.test(str)) return str;
|
|
||||||
// 带function标识的
|
|
||||||
if (/^\s*(?:async)?\s*function/.test(str)) return str;
|
|
||||||
const hasAsync = /^\s*(?:async)/.test(str);
|
|
||||||
return `${hasAsync ? "async " : ""}function ${str.replace(/^\s*(?:async)/, '')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const createFunction = (fn) => {
|
|
||||||
let cloneFn = null;
|
|
||||||
const str = `cloneFn = ${transformFunction(fn)}`;
|
|
||||||
try {
|
|
||||||
eval(str);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(fn.toString())
|
|
||||||
console.error(str);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
return cloneFn;
|
|
||||||
};
|
|
||||||
|
|
||||||
const cloneSymbol = (s) => {
|
|
||||||
const key = Symbol.keyFor(s);
|
|
||||||
if (key) return Symbol.for(key);
|
|
||||||
const desc = s.description;
|
|
||||||
if (desc) return Symbol(desc);
|
|
||||||
return Symbol();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (typeof obj !== "object" || obj === null) {
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return typeof obj === "symbol"
|
if (map.has(obj)) return map.get(obj);
|
||||||
? cloneSymbol(obj)
|
|
||||||
: functionMap[getType(obj)]
|
|
||||||
? createFunction(obj)
|
|
||||||
: obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
const constructor = obj.constructor;
|
const constructor = obj.constructor;
|
||||||
|
let target;
|
||||||
|
if (!canTranverse[getType(obj)]) {
|
||||||
|
try {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!canTranverse[getType(obj)]) return new constructor(obj);
|
target = new constructor(obj);
|
||||||
if (map.has(obj)) return map.get(obj);
|
} catch (error) {
|
||||||
|
if (obj instanceof HTMLElement) {
|
||||||
|
target = obj.cloneNode(true); // 不能cloneNode就寄吧,累了
|
||||||
|
} else throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const target = new constructor();
|
else target = constructor ? new constructor() : Object.create(null);
|
||||||
map.set(obj, target);
|
map.set(obj, target);
|
||||||
|
|
||||||
if (obj instanceof Map) {
|
if (obj instanceof Map) {
|
||||||
obj.forEach((value, key) => {
|
obj.forEach((value, key) => {
|
||||||
target.set(get.copy(key, map), get.copy(value, map));
|
target.set(get.copy(key, map), get.copy(value, map));
|
||||||
});
|
});
|
||||||
return target;
|
} else if (obj instanceof Set) {
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof Set) {
|
|
||||||
obj.forEach((value) => {
|
obj.forEach((value) => {
|
||||||
target.add(get.copy(value, map));
|
target.add(get.copy(value, map));
|
||||||
});
|
});
|
||||||
return target;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key in obj) {
|
const descriptors = Object.getOwnPropertyDescriptors(obj);
|
||||||
|
if (descriptors) {
|
||||||
|
for (const [key, descriptor] of Object.entries(descriptors)) {
|
||||||
|
const { enumerable, configurable } = descriptor;
|
||||||
if (obj.hasOwnProperty(key)) {
|
if (obj.hasOwnProperty(key)) {
|
||||||
target[key] = get.copy(obj[key], map);
|
const result = { enumerable, configurable };
|
||||||
|
if (descriptor.hasOwnProperty('value')) {
|
||||||
|
result.value = get.copy(descriptor.value, map);
|
||||||
|
result.writable = descriptor.writable;
|
||||||
|
} else {
|
||||||
|
const { get, set } = descriptor;
|
||||||
|
result.get = get;
|
||||||
|
result.set = set;
|
||||||
|
}
|
||||||
|
Reflect.defineProperty(target, key, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const symbols = Object.getOwnPropertySymbols(obj);
|
const symbols = Object.getOwnPropertySymbols(obj);
|
||||||
symbols.forEach((s) => {
|
symbols.forEach((symbol) => {
|
||||||
target[cloneSymbol(s)] = get.copy(obj[s], map);
|
target[symbol] = get.copy(obj[symbol], map);
|
||||||
});
|
});
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
static inpilefull(type) {
|
static inpilefull(type) {
|
||||||
var list = [];
|
var list = [];
|
||||||
for (var i in lib.cardPile) {
|
for (var i in lib.cardPile) {
|
||||||
|
@ -2551,7 +2095,7 @@ export class Get extends Uninstantable {
|
||||||
if (str.suit && str.number || str.isCard) {
|
if (str.suit && str.number || str.isCard) {
|
||||||
var cardnum = get.number(str, false) || '';
|
var cardnum = get.number(str, false) || '';
|
||||||
if ([1, 11, 12, 13].includes(cardnum)) {
|
if ([1, 11, 12, 13].includes(cardnum)) {
|
||||||
cardnum = { '1': 'A', '11': 'J', '12': 'Q', '13': 'K' }[cardnum]
|
cardnum = { '1': 'A', '11': 'J', '12': 'Q', '13': 'K' }[cardnum];
|
||||||
}
|
}
|
||||||
if (arg == 'viewAs' && str.viewAs != str.name && str.viewAs) {
|
if (arg == 'viewAs' && str.viewAs != str.name && str.viewAs) {
|
||||||
str2 += '(' + get.translation(str) + ')';
|
str2 += '(' + get.translation(str) + ')';
|
||||||
|
@ -2917,7 +2461,7 @@ export class Get extends Uninstantable {
|
||||||
*/
|
*/
|
||||||
static cardtag(item, tag) {
|
static cardtag(item, tag) {
|
||||||
return (item.cardid && (get.itemtype(item) == 'card' || !item.cards || !item.cards.length || item.name == item.cards[0].name) && _status.cardtag && _status.cardtag[tag] && _status.cardtag[tag].includes(item.cardid))
|
return (item.cardid && (get.itemtype(item) == 'card' || !item.cards || !item.cards.length || item.name == item.cards[0].name) && _status.cardtag && _status.cardtag[tag] && _status.cardtag[tag].includes(item.cardid))
|
||||||
|| (item.cardtags && item.cardtags.includes(tag))
|
|| (item.cardtags && item.cardtags.includes(tag));
|
||||||
}
|
}
|
||||||
static tag(item, tag, item2, bool) {
|
static tag(item, tag, item2, bool) {
|
||||||
var result;
|
var result;
|
||||||
|
@ -5004,3 +4548,7 @@ export class Get extends Uninstantable {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const get = Get;
|
export const get = Get;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Is
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,444 @@
|
||||||
|
import { userAgent, Uninstantable, GeneratorFunction, AsyncFunction } from "../util/index.js";
|
||||||
|
import { AI as ai } from '../ai/index.js';
|
||||||
|
import { Game as game } from '../game/index.js';
|
||||||
|
import { Library as lib } from '../library/index.js';
|
||||||
|
import { status as _status } from '../status/index.js';
|
||||||
|
import { UI as ui } from '../ui/index.js';
|
||||||
|
import { GNC as gnc } from '../gnc/index.js';
|
||||||
|
import { Get as get } from "./index.js";
|
||||||
|
|
||||||
|
export class Is extends Uninstantable {
|
||||||
|
/**
|
||||||
|
* 判断是否为进攻坐骑
|
||||||
|
* @param { Card | VCard } card
|
||||||
|
* @param { false | Player } [player]
|
||||||
|
* @returns { boolean }
|
||||||
|
*/
|
||||||
|
static attackingMount(card, player) {
|
||||||
|
const subtype = get.subtype(card, player);
|
||||||
|
if (subtype == 'equip4') return true;
|
||||||
|
else if (subtype == 'equip6') {
|
||||||
|
const info = get.info(card, player), distance = info.distance;
|
||||||
|
if (!distance) return false;
|
||||||
|
if (distance.globalFrom && !info.notMount) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 判断是否为防御坐骑
|
||||||
|
* @param { Card | VCard } card
|
||||||
|
* @param { false | Player } [player]
|
||||||
|
* @returns { boolean }
|
||||||
|
*/
|
||||||
|
static defendingMount(card, player) {
|
||||||
|
const subtype = get.subtype(card, player);
|
||||||
|
if (subtype == 'equip3') return true;
|
||||||
|
else if (subtype == 'equip6') {
|
||||||
|
const info = get.info(card, player), distance = info.distance;
|
||||||
|
if (!distance) return false;
|
||||||
|
if (distance.globalTo && !info.notMount) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 判断坐骑栏是否被合并
|
||||||
|
* @returns { boolean }
|
||||||
|
*/
|
||||||
|
static mountCombined() {
|
||||||
|
if (lib.configOL.mount_combine) {
|
||||||
|
return lib.configOL.mount_combine;
|
||||||
|
}
|
||||||
|
else if (typeof _status.mountCombined != 'boolean') {
|
||||||
|
_status.mountCombined = lib.config.mount_combine;
|
||||||
|
}
|
||||||
|
return _status.mountCombined;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 判断传入的参数的属性是否相同(参数可以为卡牌、卡牌信息、属性等)
|
||||||
|
* @param {...} infos 要判断的属性列表
|
||||||
|
* @param {boolean} every 是否判断每一个传入的属性是否完全相同而不是存在部分相同
|
||||||
|
*/
|
||||||
|
static sameNature() {
|
||||||
|
let processedArguments = [], every = false;
|
||||||
|
Array.from(arguments).forEach(argument => {
|
||||||
|
if (typeof argument == 'boolean') every = argument;
|
||||||
|
else if (argument) processedArguments.push(argument);
|
||||||
|
});
|
||||||
|
if (!processedArguments.length) return true;
|
||||||
|
if (processedArguments.length == 1) {
|
||||||
|
const argument = processedArguments[0];
|
||||||
|
if (!Array.isArray(argument)) return false;
|
||||||
|
if (!argument.length) return true;
|
||||||
|
if (argument.length == 1) return false;
|
||||||
|
processedArguments = argument;
|
||||||
|
}
|
||||||
|
const naturesList = processedArguments.map(card => {
|
||||||
|
if (typeof card == 'string') return card.split(lib.natureSeparator);
|
||||||
|
else if (Array.isArray(card)) return card;
|
||||||
|
return get.natureList(card || {});
|
||||||
|
});
|
||||||
|
const testingNaturesList = naturesList.slice(0, naturesList.length - 1);
|
||||||
|
if (every) return testingNaturesList.every((natures, index) => naturesList.slice(index + 1).every(testingNatures => testingNatures.length == natures.length && testingNatures.every(nature => natures.includes(nature))));
|
||||||
|
return testingNaturesList.every((natures, index) => {
|
||||||
|
const comparingNaturesList = naturesList.slice(index + 1);
|
||||||
|
if (natures.length) return natures.some(nature => comparingNaturesList.every(testingNatures => testingNatures.includes(nature)));
|
||||||
|
return comparingNaturesList.every(testingNatures => !testingNatures.length);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 判断传入的参数的属性是否不同(参数可以为卡牌、卡牌信息、属性等)
|
||||||
|
* @param ...infos 要判断的属性列表
|
||||||
|
* @param every {boolean} 是否判断每一个传入的属性是否完全不同而不是存在部分不同
|
||||||
|
*/
|
||||||
|
static differentNature() {
|
||||||
|
let processedArguments = [], every = false;
|
||||||
|
Array.from(arguments).forEach(argument => {
|
||||||
|
if (typeof argument == 'boolean') every = argument;
|
||||||
|
else if (argument) processedArguments.push(argument);
|
||||||
|
});
|
||||||
|
if (!processedArguments.length) return false;
|
||||||
|
if (processedArguments.length == 1) {
|
||||||
|
const argument = processedArguments[0];
|
||||||
|
if (!Array.isArray(argument)) return true;
|
||||||
|
if (!argument.length) return false;
|
||||||
|
if (argument.length == 1) return true;
|
||||||
|
processedArguments = argument;
|
||||||
|
}
|
||||||
|
const naturesList = processedArguments.map(card => {
|
||||||
|
if (typeof card == 'string') return card.split(lib.natureSeparator);
|
||||||
|
else if (Array.isArray(card)) return card;
|
||||||
|
return get.natureList(card || {});
|
||||||
|
});
|
||||||
|
const testingNaturesList = naturesList.slice(0, naturesList.length - 1);
|
||||||
|
if (every) return testingNaturesList.every((natures, index) => naturesList.slice(index + 1).every(testingNatures => testingNatures.every(nature => !natures.includes(nature))));
|
||||||
|
return testingNaturesList.every((natures, index) => {
|
||||||
|
const comparingNaturesList = naturesList.slice(index + 1);
|
||||||
|
if (natures.length) return natures.some(nature => comparingNaturesList.every(testingNatures => !testingNatures.length || testingNatures.some(testingNature => testingNature != nature)));
|
||||||
|
return comparingNaturesList.every(testingNatures => testingNatures.length);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 判断一张牌是否为明置手牌
|
||||||
|
* @param { Card } card
|
||||||
|
*/
|
||||||
|
static shownCard(card) {
|
||||||
|
if (!card) return false;
|
||||||
|
const gaintag = card.gaintag;
|
||||||
|
return Array.isArray(gaintag) && gaintag.some(tag => tag.startsWith('visible_'));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 是否是虚拟牌
|
||||||
|
* @param { Card | VCard } card
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
static vituralCard(card) {
|
||||||
|
return card.isCard || (!("cards" in card) || !Array.isArray(card.cards) || card.cards.length == 0);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 是否是转化牌
|
||||||
|
* @param { Card | VCard } card
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
static convertedCard(card) {
|
||||||
|
return !card.isCard && ("cards" in card) && Array.isArray(card.cards) && card.cards.length > 0;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 是否是实体牌
|
||||||
|
* @param { Card | VCard } card
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
static ordinaryCard(card) { return card.isCard && ("cards" in card) && Array.isArray(card.cards) && card.cards.length == 1 }
|
||||||
|
/**
|
||||||
|
* 押韵判断
|
||||||
|
* @param { string } str1
|
||||||
|
* @param { string } str2
|
||||||
|
*/
|
||||||
|
static yayun(str1, str2) {
|
||||||
|
if (str1 == str2) return true;
|
||||||
|
let pinyin1 = get.pinyin(str1, false), pinyin2 = get.pinyin(str2, false);
|
||||||
|
if (!pinyin1.length || !pinyin2.length) return false;
|
||||||
|
let pron1 = pinyin1[pinyin1.length - 1], pron2 = pinyin2[pinyin2.length - 1];
|
||||||
|
if (pron1 == pron2) return true;
|
||||||
|
return get.yunjiao(pron1) == get.yunjiao(pron2);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param { string } skill 技能id
|
||||||
|
* @param { Player } player 玩家
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
static blocked(skill, player) {
|
||||||
|
if (!player.storage.skill_blocker || !player.storage.skill_blocker.length) return false;
|
||||||
|
for (let i of player.storage.skill_blocker) {
|
||||||
|
if (lib.skill[i] && lib.skill[i].skillBlocker && lib.skill[i].skillBlocker(skill, player)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 是否是双势力武将
|
||||||
|
* @param { string } name
|
||||||
|
* @param { string[] } array
|
||||||
|
* @returns { boolean | string[] }
|
||||||
|
*/
|
||||||
|
static double(name, array) {
|
||||||
|
const extraInformations = get.character(name, 4);
|
||||||
|
if (!extraInformations) return false;
|
||||||
|
for (const extraInformation of extraInformations) {
|
||||||
|
if (!extraInformation.startsWith('doublegroup:')) continue;
|
||||||
|
return array ? extraInformation.split(':').slice(1) : true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Check if the card has a Yingbian condition
|
||||||
|
*
|
||||||
|
* 检测此牌是否具有应变条件
|
||||||
|
* @param { Card | VCard } card
|
||||||
|
*/
|
||||||
|
static yingbianConditional(card) { return get.is.complexlyYingbianConditional(card) || get.is.simplyYingbianConditional(card) }
|
||||||
|
/**
|
||||||
|
* @param { Card | VCard } card
|
||||||
|
*/
|
||||||
|
static complexlyYingbianConditional(card) {
|
||||||
|
for (const key of lib.yingbian.condition.complex.keys()) {
|
||||||
|
if (get.cardtag(card, `yingbian_${key}`)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param { Card | VCard } card
|
||||||
|
*/
|
||||||
|
static simplyYingbianConditional(card) {
|
||||||
|
for (const key of lib.yingbian.condition.simple.keys()) {
|
||||||
|
if (get.cardtag(card, `yingbian_${key}`)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Check if the card has a Yingbian effect
|
||||||
|
*
|
||||||
|
* 检测此牌是否具有应变效果
|
||||||
|
*
|
||||||
|
* @param { Card | VCard } card
|
||||||
|
*/
|
||||||
|
static yingbianEffective(card) {
|
||||||
|
for (const key of lib.yingbian.effect.keys()) {
|
||||||
|
if (get.cardtag(card, `yingbian_${key}`)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param { Card | VCard } card
|
||||||
|
*/
|
||||||
|
static yingbian(card) { return get.is.yingbianConditional(card) || get.is.yingbianEffective(card) }
|
||||||
|
/**
|
||||||
|
* @param { string } [substring]
|
||||||
|
*/
|
||||||
|
static emoji(substring) {
|
||||||
|
if (substring) {
|
||||||
|
const reg = new RegExp("[~#^$@%&!?%*]", 'g');
|
||||||
|
if (substring.match(reg)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < substring.length; i++) {
|
||||||
|
const hs = substring.charCodeAt(i);
|
||||||
|
if (0xd800 <= hs && hs <= 0xdbff) {
|
||||||
|
if (substring.length > 1) {
|
||||||
|
const ls = substring.charCodeAt(i + 1);
|
||||||
|
const uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
|
||||||
|
if (0x1d000 <= uc && uc <= 0x1f77f) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (substring.length > 1) {
|
||||||
|
const ls = substring.charCodeAt(i + 1);
|
||||||
|
if (ls == 0x20e3) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (0x2100 <= hs && hs <= 0x27ff) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (0x2B05 <= hs && hs <= 0x2b07) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (0x2934 <= hs && hs <= 0x2935) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (0x3297 <= hs && hs <= 0x3299) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030
|
||||||
|
|| hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b
|
||||||
|
|| hs == 0x2b50) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param { string } str
|
||||||
|
*/
|
||||||
|
static banWords(str) { return get.is.emoji(str) || window.bannedKeyWords.some(item => str.includes(item)) }
|
||||||
|
/**
|
||||||
|
* @param { GameEventPromise } event
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
static converted(event) { return !(event.card && event.card.isCard) }
|
||||||
|
static safari() { return userAgent.indexOf('safari') != -1 && userAgent.indexOf('chrome') == -1 }
|
||||||
|
/**
|
||||||
|
* @param { (Card | VCard)[]} cards
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
static freePosition(cards) { return !cards.some(card => !card.hasPosition || card.hasPosition()) }
|
||||||
|
/**
|
||||||
|
* @param { string } name
|
||||||
|
* @param { boolean } item
|
||||||
|
*/
|
||||||
|
static nomenu(name, item) {
|
||||||
|
const menus = ['system', 'menu'];
|
||||||
|
const configs = {
|
||||||
|
show_round_menu: lib.config.show_round_menu,
|
||||||
|
round_menu_func: lib.config.round_menu_func,
|
||||||
|
touchscreen: lib.config.touchscreen,
|
||||||
|
swipe_up: lib.config.swipe_up,
|
||||||
|
swipe_down: lib.config.swipe_down,
|
||||||
|
swipe_left: lib.config.swipe_left,
|
||||||
|
swipe_right: lib.config.swipe_right,
|
||||||
|
right_click: lib.config.right_click,
|
||||||
|
phonelayout: lib.config.phonelayout
|
||||||
|
};
|
||||||
|
configs[name] = item;
|
||||||
|
if (!configs.phonelayout) return false;
|
||||||
|
if (configs.show_round_menu && menus.includes(configs.round_menu_func)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (configs.touchscreen) {
|
||||||
|
if (menus.includes(configs.swipe_up)) return false;
|
||||||
|
if (menus.includes(configs.swipe_down)) return false;
|
||||||
|
if (menus.includes(configs.swipe_left)) return false;
|
||||||
|
if (menus.includes(configs.swipe_right)) return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (configs.right_click == 'config') return false;
|
||||||
|
}
|
||||||
|
if (name) {
|
||||||
|
setTimeout(function () {
|
||||||
|
alert('请将至少一个操作绑定为显示按钮或打开菜单,否则将永远无法打开菜单');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static altered() { return false; }
|
||||||
|
/*
|
||||||
|
skill=>{
|
||||||
|
return false;
|
||||||
|
// if(_status.connectMode) return true;
|
||||||
|
// return !lib.config.vintageSkills.includes(skill);
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @param { any } obj
|
||||||
|
* @returns { boolean }
|
||||||
|
*/
|
||||||
|
static node(obj) {
|
||||||
|
return Object.prototype.toString.call(obj).startsWith('[object HTML');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param { any } obj
|
||||||
|
*/
|
||||||
|
static div(obj) { return Object.prototype.toString.call(obj) === '[object HTMLDivElement]' }
|
||||||
|
/**
|
||||||
|
* @param { any } obj
|
||||||
|
*/
|
||||||
|
static map(obj) { return Object.prototype.toString.call(obj) === '[object Map]' }
|
||||||
|
/**
|
||||||
|
* @param { any } obj
|
||||||
|
*/
|
||||||
|
static set(obj) { return Object.prototype.toString.call(obj) === '[object Set]' }
|
||||||
|
/**
|
||||||
|
* @param { any } obj
|
||||||
|
*/
|
||||||
|
static object(obj) { return Object.prototype.toString.call(obj) === '[object Object]' }
|
||||||
|
/**
|
||||||
|
* @overload
|
||||||
|
* @param { Function } func
|
||||||
|
* @returns { false }
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @overload
|
||||||
|
* @param { number | [number, number] } func
|
||||||
|
* @returns { boolean }
|
||||||
|
*/
|
||||||
|
static singleSelect(func) {
|
||||||
|
if (typeof func == 'function') return false;
|
||||||
|
const select = get.select(func);
|
||||||
|
return select[0] == 1 && select[1] == 1;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param { string | Player } name
|
||||||
|
*/
|
||||||
|
static jun(name) {
|
||||||
|
if (get.mode() == 'guozhan') {
|
||||||
|
if (name instanceof lib.element.Player) {
|
||||||
|
if (name.isUnseen && name.isUnseen(0)) return false;
|
||||||
|
name = name.name1;
|
||||||
|
}
|
||||||
|
if (typeof name == 'string' && name.startsWith('gz_jun_')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static versus() { return !_status.connectMode && get.mode() == 'versus' && _status.mode == 'three' }
|
||||||
|
static changban() { return get.mode() == 'single' && _status.mode == 'changban' }
|
||||||
|
static single() { return get.mode() == 'single' && _status.mode == 'normal' }
|
||||||
|
/**
|
||||||
|
* @param { Player } [player]
|
||||||
|
*/
|
||||||
|
static mobileMe(player) { return (game.layout == 'mobile' || game.layout == 'long') && !game.chess && player && player.dataset.position == '0' }
|
||||||
|
static newLayout() { return game.layout != 'default' }
|
||||||
|
static phoneLayout() {
|
||||||
|
if (!lib.config.phonelayout) return false;
|
||||||
|
return (game.layout == 'mobile' || game.layout == 'long' || game.layout == 'long2' || game.layout == 'nova');
|
||||||
|
}
|
||||||
|
static singleHandcard() { return game.singleHandcard || game.layout == 'mobile' || game.layout == 'long' || game.layout == 'long2' || game.layout == 'nova' }
|
||||||
|
/**
|
||||||
|
* @param { Player } player
|
||||||
|
*/
|
||||||
|
static linked2(player) {
|
||||||
|
if (game.chess) return true;
|
||||||
|
if (lib.config.link_style2 != 'rotate') return true;
|
||||||
|
// if(game.chess) return false;
|
||||||
|
if (game.layout == 'long' || game.layout == 'long2' || game.layout == 'nova') return true;
|
||||||
|
if (player.dataset.position == '0') {
|
||||||
|
return ui.arena.classList.contains('oblongcard');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param { {} } obj
|
||||||
|
*/
|
||||||
|
static empty(obj) { return Object.keys(obj).length == 0 }
|
||||||
|
/**
|
||||||
|
* @param { string } str
|
||||||
|
*/
|
||||||
|
static pos(str) { return str == 'h' || str == 'e' || str == 'j' || str == 'he' || str == 'hj' || str == 'ej' || str == 'hej' }
|
||||||
|
/**
|
||||||
|
* @param { string } skill
|
||||||
|
* @param { Player } player
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
static locked(skill, player) {
|
||||||
|
const info = lib.skill[skill];
|
||||||
|
if (typeof info.locked == 'function') return info.locked(skill, player);
|
||||||
|
if (info.locked == false) return false;
|
||||||
|
if (info.trigger && info.forced) return true;
|
||||||
|
if (info.mod) return true;
|
||||||
|
if (info.locked) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,21 +2,25 @@ import { Game as game } from '../game/index.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - 卡牌包名
|
* @param {string} name - 卡牌包名
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export const importCardPack = generateImportFunction('card', (name) => `../../card/${name}.js`)
|
export const importCardPack = generateImportFunction('card', (name) => `../../card/${name}.js`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - 武将包名
|
* @param {string} name - 武将包名
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export const importCharacterPack = generateImportFunction('character', (name) => `../../character/${name}.js`)
|
export const importCharacterPack = generateImportFunction('character', (name) => `../../character/${name}.js`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - 扩展名
|
* @param {string} name - 扩展名
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export const importExtension = generateImportFunction('extension', (name) => `../../extension/${name}/extension.js`)
|
export const importExtension = generateImportFunction('extension', (name) => `../../extension/${name}/extension.js`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - 模式名
|
* @param {string} name - 模式名
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export const importMode = generateImportFunction('mode', (name) => `../../mode/${name}.js`)
|
export const importMode = generateImportFunction('mode', (name) => `../../mode/${name}.js`)
|
||||||
|
|
||||||
|
@ -28,14 +32,10 @@ export const importMode = generateImportFunction('mode', (name) => `../../mode/$
|
||||||
* @returns {(name: string) => Promise<void>}
|
* @returns {(name: string) => Promise<void>}
|
||||||
*/
|
*/
|
||||||
function generateImportFunction(type, pathParser) {
|
function generateImportFunction(type, pathParser) {
|
||||||
return async function (name) {
|
return async (name) => {
|
||||||
try {
|
|
||||||
const modeContent = await import(pathParser(name));
|
const modeContent = await import(pathParser(name));
|
||||||
if (!modeContent.type) return;
|
if (!modeContent.type) return;
|
||||||
if (modeContent.type !== type) throw new Error(`Loaded Content doesnt conform to "${type}"`);
|
if (modeContent.type !== type) throw new Error(`Loaded Content doesn't conform to "${type}" but "${modeContent.type}".`);
|
||||||
await game.import(type, modeContent.default);
|
await game.import(type, modeContent.default);
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,144 +24,150 @@ export async function onload(resetGameTimeout) {
|
||||||
if (lib.config.touchscreen) createTouchDraggedFilter();
|
if (lib.config.touchscreen) createTouchDraggedFilter();
|
||||||
|
|
||||||
// 不拆分,太玄学了
|
// 不拆分,太玄学了
|
||||||
if (lib.config.card_style == 'custom') {
|
if (lib.config.card_style === 'custom') {
|
||||||
game.getDB('image', 'card_style', function (fileToLoad) {
|
const fileToLoad = await game.getDB('image', 'card_style')
|
||||||
if (!fileToLoad) return;
|
if (fileToLoad) {
|
||||||
var fileReader = new FileReader();
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
const fileReader = new FileReader();
|
||||||
if (ui.css.card_stylesheet) {
|
fileReader.onload = resolve;
|
||||||
ui.css.card_stylesheet.remove();
|
fileReader.onerror = reject;
|
||||||
}
|
|
||||||
ui.css.card_stylesheet = lib.init.sheet('.card:not(*:empty){background-image:url(' + fileLoadedEvent.target.result + ')}');
|
|
||||||
};
|
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
||||||
});
|
})
|
||||||
}
|
if (ui.css.card_stylesheet) ui.css.card_stylesheet.remove();
|
||||||
if (lib.config.cardback_style == 'custom') {
|
ui.css.card_stylesheet = lib.init.sheet(`.card:not(*:empty){background-image:url(${fileLoadedEvent.target.result})}`);
|
||||||
game.getDB('image', 'cardback_style', function (fileToLoad) {
|
|
||||||
if (!fileToLoad) return;
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
|
||||||
if (ui.css.cardback_stylesheet) {
|
|
||||||
ui.css.cardback_stylesheet.remove();
|
|
||||||
}
|
|
||||||
ui.css.cardback_stylesheet = lib.init.sheet('.card:empty,.card.infohidden{background-image:url(' + fileLoadedEvent.target.result + ')}');
|
|
||||||
};
|
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
|
||||||
});
|
|
||||||
game.getDB('image', 'cardback_style2', function (fileToLoad) {
|
|
||||||
if (!fileToLoad) return;
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
|
||||||
if (ui.css.cardback_stylesheet2) {
|
|
||||||
ui.css.cardback_stylesheet2.remove();
|
|
||||||
}
|
|
||||||
ui.css.cardback_stylesheet2 = lib.init.sheet('.card.infohidden:not(.infoflip){background-image:url(' + fileLoadedEvent.target.result + ')}');
|
|
||||||
};
|
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (lib.config.hp_style == 'custom') {
|
|
||||||
game.getDB('image', 'hp_style1', function (fileToLoad) {
|
|
||||||
if (!fileToLoad) return;
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
|
||||||
if (ui.css.hp_stylesheet1) {
|
|
||||||
ui.css.hp_stylesheet1.remove();
|
|
||||||
}
|
|
||||||
ui.css.hp_stylesheet1 = lib.init.sheet('.hp:not(.text):not(.actcount)[data-condition="high"]>div:not(.lost){background-image:url(' + fileLoadedEvent.target.result + ')}');
|
|
||||||
};
|
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
|
||||||
});
|
|
||||||
game.getDB('image', 'hp_style2', function (fileToLoad) {
|
|
||||||
if (!fileToLoad) return;
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
|
||||||
if (ui.css.hp_stylesheet2) {
|
|
||||||
ui.css.hp_stylesheet2.remove();
|
|
||||||
}
|
|
||||||
ui.css.hp_stylesheet2 = lib.init.sheet('.hp:not(.text):not(.actcount)[data-condition="mid"]>div:not(.lost){background-image:url(' + fileLoadedEvent.target.result + ')}');
|
|
||||||
};
|
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
|
||||||
});
|
|
||||||
game.getDB('image', 'hp_style3', function (fileToLoad) {
|
|
||||||
if (!fileToLoad) return;
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
|
||||||
if (ui.css.hp_stylesheet3) {
|
|
||||||
ui.css.hp_stylesheet3.remove();
|
|
||||||
}
|
|
||||||
ui.css.hp_stylesheet3 = lib.init.sheet('.hp:not(.text):not(.actcount)[data-condition="low"]>div:not(.lost){background-image:url(' + fileLoadedEvent.target.result + ')}');
|
|
||||||
};
|
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
|
||||||
});
|
|
||||||
game.getDB('image', 'hp_style4', function (fileToLoad) {
|
|
||||||
if (!fileToLoad) return;
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
|
||||||
if (ui.css.hp_stylesheet4) {
|
|
||||||
ui.css.hp_stylesheet4.remove();
|
|
||||||
}
|
|
||||||
ui.css.hp_stylesheet4 = lib.init.sheet('.hp:not(.text):not(.actcount)>.lost{background-image:url(' + fileLoadedEvent.target.result + ')}');
|
|
||||||
};
|
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lib.config.player_style == 'custom') {
|
}
|
||||||
|
if (lib.config.cardback_style === 'custom') {
|
||||||
|
const fileToLoad1 = await game.getDB('image', 'cardback_style');
|
||||||
|
if (fileToLoad1) {
|
||||||
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
fileReader.onload = resolve;
|
||||||
|
fileReader.onerror = reject;
|
||||||
|
fileReader.readAsDataURL(fileToLoad1, "UTF-8");
|
||||||
|
})
|
||||||
|
if (ui.css.cardback_stylesheet) ui.css.cardback_stylesheet.remove();
|
||||||
|
ui.css.cardback_stylesheet = lib.init.sheet(`.card:empty,.card.infohidden{background-image:url(${fileLoadedEvent.target.result})}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileToLoad2 = await game.getDB('image', 'cardback_style2')
|
||||||
|
if (fileToLoad2) {
|
||||||
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
fileReader.onload = resolve;
|
||||||
|
fileReader.onerror = reject;
|
||||||
|
fileReader.readAsDataURL(fileToLoad2, "UTF-8");
|
||||||
|
})
|
||||||
|
if (ui.css.cardback_stylesheet2) ui.css.cardback_stylesheet2.remove();
|
||||||
|
ui.css.cardback_stylesheet2 = lib.init.sheet(`.card.infohidden:not(.infoflip){background-image:url(${fileLoadedEvent.target.result})}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lib.config.hp_style === 'custom') {
|
||||||
|
const fileToLoad1 = await game.getDB('image', 'hp_style1')
|
||||||
|
if (fileToLoad1) {
|
||||||
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
fileReader.onload = resolve;
|
||||||
|
fileReader.onerror = reject;
|
||||||
|
fileReader.readAsDataURL(fileToLoad1, "UTF-8");
|
||||||
|
})
|
||||||
|
if (ui.css.hp_stylesheet1) ui.css.hp_stylesheet1.remove();
|
||||||
|
ui.css.hp_stylesheet1 = lib.init.sheet(`.hp:not(.text):not(.actcount)[data-condition="high"]>div:not(.lost){background-image:url(${fileLoadedEvent.target.result})}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileToLoad2 = await game.getDB('image', 'hp_style2');
|
||||||
|
if (fileToLoad2) {
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
|
fileReader.onload = resolve;
|
||||||
|
fileReader.onerror = reject;
|
||||||
|
fileReader.readAsDataURL(fileToLoad2, "UTF-8");
|
||||||
|
});
|
||||||
|
if (ui.css.hp_stylesheet2) ui.css.hp_stylesheet2.remove();
|
||||||
|
ui.css.hp_stylesheet2 = lib.init.sheet(`.hp:not(.text):not(.actcount)[data-condition="mid"]>div:not(.lost){background-image:url(${fileLoadedEvent.target.result})}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileToLoad3 = await game.getDB('image', 'hp_style3');
|
||||||
|
if (fileToLoad3) {
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
|
fileReader.onload = resolve;
|
||||||
|
fileReader.onerror = reject;
|
||||||
|
fileReader.readAsDataURL(fileToLoad3, "UTF-8");
|
||||||
|
});
|
||||||
|
if (ui.css.hp_stylesheet3) ui.css.hp_stylesheet3.remove();
|
||||||
|
ui.css.hp_stylesheet3 = lib.init.sheet(`.hp:not(.text):not(.actcount)[data-condition="low"]>div:not(.lost){background-image:url(${fileLoadedEvent.target.result})}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileToLoad4 = await game.getDB('image', 'hp_style4');
|
||||||
|
if (fileToLoad4) {
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
|
fileReader.onload = resolve;
|
||||||
|
fileReader.onerror = reject;
|
||||||
|
fileReader.readAsDataURL(fileToLoad4, "UTF-8");
|
||||||
|
});
|
||||||
|
if (ui.css.hp_stylesheet4) ui.css.hp_stylesheet4.remove();
|
||||||
|
ui.css.hp_stylesheet4 = lib.init.sheet(`.hp:not(.text):not(.actcount)>.lost{background-image:url(${fileLoadedEvent.target.result})}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lib.config.player_style === 'custom') {
|
||||||
|
const fileToLoad = await game.getDB('image', 'player_style');
|
||||||
|
if (fileToLoad) {
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
|
fileReader.onload = resolve;
|
||||||
|
fileReader.onerror = reject;
|
||||||
|
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
||||||
|
});
|
||||||
|
if (ui.css.player_stylesheet) ui.css.player_stylesheet.remove();
|
||||||
|
ui.css.player_stylesheet = lib.init.sheet(`#window .player{background-image:url("${fileLoadedEvent.target.result}");background-size:100% 100%;}`);
|
||||||
|
} else {
|
||||||
ui.css.player_stylesheet = lib.init.sheet('#window .player{background-image:none;background-size:100% 100%;}');
|
ui.css.player_stylesheet = lib.init.sheet('#window .player{background-image:none;background-size:100% 100%;}');
|
||||||
game.getDB('image', 'player_style', function (fileToLoad) {
|
|
||||||
if (!fileToLoad) return;
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
|
||||||
if (ui.css.player_stylesheet) {
|
|
||||||
ui.css.player_stylesheet.remove();
|
|
||||||
}
|
}
|
||||||
ui.css.player_stylesheet = lib.init.sheet('#window .player{background-image:url("' + fileLoadedEvent.target.result + '");background-size:100% 100%;}');
|
}
|
||||||
};
|
if (lib.config.border_style === 'custom') {
|
||||||
|
const fileToLoad = await game.getDB('image', 'border_style');
|
||||||
|
if (fileToLoad) {
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
|
fileReader.onload = resolve;
|
||||||
|
fileReader.onerror = reject;
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
||||||
});
|
});
|
||||||
}
|
if (ui.css.border_stylesheet) ui.css.border_stylesheet.remove();
|
||||||
if (lib.config.border_style == 'custom') {
|
|
||||||
game.getDB('image', 'border_style', function (fileToLoad) {
|
|
||||||
if (!fileToLoad) return;
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
|
||||||
if (ui.css.border_stylesheet) {
|
|
||||||
ui.css.border_stylesheet.remove();
|
|
||||||
}
|
|
||||||
ui.css.border_stylesheet = lib.init.sheet();
|
ui.css.border_stylesheet = lib.init.sheet();
|
||||||
ui.css.border_stylesheet.sheet.insertRule('#window .player>.framebg{display:block;background-image:url("' + fileLoadedEvent.target.result + '")}', 0);
|
ui.css.border_stylesheet.sheet.insertRule(`#window .player>.framebg{display:block;background-image:url("${fileLoadedEvent.target.result}")}`, 0);
|
||||||
ui.css.border_stylesheet.sheet.insertRule('.player>.count{z-index: 3 !important;border-radius: 2px !important;text-align: center !important;}', 0);
|
ui.css.border_stylesheet.sheet.insertRule('.player>.count{z-index: 3 !important;border-radius: 2px !important;text-align: center !important;}', 0);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
if (lib.config.control_style === 'custom') {
|
||||||
|
const fileToLoad = await game.getDB('image', 'control_style');
|
||||||
|
if (fileToLoad) {
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
|
fileReader.onload = resolve;
|
||||||
|
fileReader.onerror = reject;
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
||||||
});
|
});
|
||||||
|
if (ui.css.control_stylesheet) ui.css.control_stylesheet.remove();
|
||||||
|
ui.css.control_stylesheet = lib.init.sheet(`#window .control,.menubutton:not(.active):not(.highlight):not(.red):not(.blue),#window #system>div>div{background-image:url("${fileLoadedEvent.target.result}")}`);
|
||||||
}
|
}
|
||||||
if (lib.config.control_style == 'custom') {
|
|
||||||
game.getDB('image', 'control_style', function (fileToLoad) {
|
|
||||||
if (!fileToLoad) return;
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
|
||||||
if (ui.css.control_stylesheet) {
|
|
||||||
ui.css.control_stylesheet.remove();
|
|
||||||
}
|
}
|
||||||
ui.css.control_stylesheet = lib.init.sheet('#window .control,.menubutton:not(.active):not(.highlight):not(.red):not(.blue),#window #system>div>div{background-image:url("' + fileLoadedEvent.target.result + '")}');
|
if (lib.config.menu_style === 'custom') {
|
||||||
};
|
const fileToLoad = await game.getDB('image', 'menu_style');
|
||||||
|
if (fileToLoad) {
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||||
|
fileReader.onload = resolve;
|
||||||
|
fileReader.onerror = reject;
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
||||||
});
|
});
|
||||||
|
if (ui.css.menu_stylesheet) ui.css.menu_stylesheet.remove();
|
||||||
|
ui.css.menu_stylesheet = lib.init.sheet(`html #window>.dialog.popped,html .menu,html .menubg{background-image:url("${fileLoadedEvent.target.result}");background-size:cover}`);
|
||||||
}
|
}
|
||||||
if (lib.config.menu_style == 'custom') {
|
|
||||||
game.getDB('image', 'menu_style', function (fileToLoad) {
|
|
||||||
if (!fileToLoad) return;
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
fileReader.onload = function (fileLoadedEvent) {
|
|
||||||
if (ui.css.menu_stylesheet) {
|
|
||||||
ui.css.menu_stylesheet.remove();
|
|
||||||
}
|
|
||||||
ui.css.menu_stylesheet = lib.init.sheet('html #window>.dialog.popped,html .menu,html .menubg{background-image:url("' + fileLoadedEvent.target.result + '");background-size:cover}');
|
|
||||||
};
|
|
||||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 改不动,暂时不改了
|
// 改不动,暂时不改了
|
||||||
|
|
|
@ -15,6 +15,11 @@ export class Button extends HTMLDivElement {
|
||||||
*/
|
*/
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
constructor(item, type, position, noClick, button) {
|
constructor(item, type, position, noClick, button) {
|
||||||
|
if (item instanceof Button) {
|
||||||
|
const other = item;
|
||||||
|
// @ts-ignore
|
||||||
|
[item, type, position, noClick, button] = other._args;
|
||||||
|
}
|
||||||
if (typeof type == 'function') button = type(item, type, position, noClick, button);
|
if (typeof type == 'function') button = type(item, type, position, noClick, button);
|
||||||
else if (ui.create.buttonPresets[type]) button = ui.create.buttonPresets[type](item, type, position, noClick, button);
|
else if (ui.create.buttonPresets[type]) button = ui.create.buttonPresets[type](item, type, position, noClick, button);
|
||||||
if (button) {
|
if (button) {
|
||||||
|
@ -25,6 +30,8 @@ export class Button extends HTMLDivElement {
|
||||||
const intro = button.querySelector('.intro');
|
const intro = button.querySelector('.intro');
|
||||||
if (intro) intro.remove();
|
if (intro) intro.remove();
|
||||||
}
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
button._args = [item, type, position, noClick, button];
|
||||||
return button;
|
return button;
|
||||||
} else {
|
} else {
|
||||||
console.error([item, type, position, noClick, button]);
|
console.error([item, type, position, noClick, button]);
|
||||||
|
|
|
@ -13,6 +13,11 @@ export class Card extends HTMLDivElement {
|
||||||
*/
|
*/
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
constructor(position, info, noclick) {
|
constructor(position, info, noclick) {
|
||||||
|
if (position instanceof Card) {
|
||||||
|
const other = position;
|
||||||
|
// @ts-ignore
|
||||||
|
[position, info, noclick] = other._args;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @type {this}
|
* @type {this}
|
||||||
*/
|
*/
|
||||||
|
@ -20,6 +25,8 @@ export class Card extends HTMLDivElement {
|
||||||
const card = ui.create.div('.card', position);
|
const card = ui.create.div('.card', position);
|
||||||
Object.setPrototypeOf(card, Card.prototype);
|
Object.setPrototypeOf(card, Card.prototype);
|
||||||
card.build(info, noclick);
|
card.build(info, noclick);
|
||||||
|
// @ts-ignore
|
||||||
|
card._args = [position, info, noclick];
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
build(info, noclick) {
|
build(info, noclick) {
|
||||||
|
|
|
@ -8,9 +8,10 @@ import { GNC as gnc } from '../../gnc/index.js';
|
||||||
|
|
||||||
export class Client {
|
export class Client {
|
||||||
/**
|
/**
|
||||||
* @param {import('../index.js').NodeWS | InstanceType<typeof import('ws').WebSocket>} ws
|
* @param {import('../index.js').NodeWS | InstanceType<typeof import('ws').WebSocket> | Client} ws
|
||||||
*/
|
*/
|
||||||
constructor(ws) {
|
constructor(ws) {
|
||||||
|
if (ws instanceof Client) throw new Error('Client cannot copy.')
|
||||||
this.ws = ws;
|
this.ws = ws;
|
||||||
/**
|
/**
|
||||||
* @type { string }
|
* @type { string }
|
||||||
|
|
|
@ -8,9 +8,15 @@ import { GNC as gnc } from '../../gnc/index.js';
|
||||||
|
|
||||||
export class Control extends HTMLDivElement {
|
export class Control extends HTMLDivElement {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
constructor() {
|
constructor(...args) {
|
||||||
|
if (args[0] instanceof Control) {
|
||||||
|
const other = args[0];
|
||||||
|
// @ts-ignore
|
||||||
|
args = other._args;
|
||||||
|
}
|
||||||
|
|
||||||
const nc = !ui.control.querySelector('div:not(.removing):not(.stayleft)');
|
const nc = !ui.control.querySelector('div:not(.removing):not(.stayleft)');
|
||||||
const controls = Array.isArray(arguments[0]) ? arguments[0] : Array.from(arguments);
|
const controls = Array.isArray(args[0]) ? args[0] : args;
|
||||||
/**
|
/**
|
||||||
* @type {this}
|
* @type {this}
|
||||||
*/
|
*/
|
||||||
|
@ -54,6 +60,8 @@ export class Control extends HTMLDivElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.updatec();
|
ui.updatec();
|
||||||
|
// @ts-ignore
|
||||||
|
control._args = args;
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
open() {
|
open() {
|
||||||
|
|
|
@ -7,7 +7,13 @@ import { UI as ui } from '../../ui/index.js';
|
||||||
|
|
||||||
export class Dialog extends HTMLDivElement {
|
export class Dialog extends HTMLDivElement {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
constructor() {
|
constructor(...args) {
|
||||||
|
if (args[0] instanceof Dialog) {
|
||||||
|
const other = args[0];
|
||||||
|
// @ts-ignore
|
||||||
|
args = other._args;
|
||||||
|
}
|
||||||
|
|
||||||
let hidden = false;
|
let hidden = false;
|
||||||
let noTouchScroll = false;
|
let noTouchScroll = false;
|
||||||
let forceButton = false;
|
let forceButton = false;
|
||||||
|
@ -21,7 +27,7 @@ export class Dialog extends HTMLDivElement {
|
||||||
dialog.bar1 = ui.create.div('.bar.top', dialog);
|
dialog.bar1 = ui.create.div('.bar.top', dialog);
|
||||||
dialog.bar2 = ui.create.div('.bar.bottom', dialog);
|
dialog.bar2 = ui.create.div('.bar.bottom', dialog);
|
||||||
dialog.buttons = [];
|
dialog.buttons = [];
|
||||||
Array.from(arguments).forEach(argument => {
|
Array.from(args).forEach(argument => {
|
||||||
if (typeof argument == 'boolean') dialog.static = argument;
|
if (typeof argument == 'boolean') dialog.static = argument;
|
||||||
else if (argument == 'hidden') hidden = true;
|
else if (argument == 'hidden') hidden = true;
|
||||||
else if (argument == 'notouchscroll') noTouchScroll = true;
|
else if (argument == 'notouchscroll') noTouchScroll = true;
|
||||||
|
@ -42,6 +48,8 @@ export class Dialog extends HTMLDivElement {
|
||||||
dialog.forcebutton = true;
|
dialog.forcebutton = true;
|
||||||
dialog.classList.add('forcebutton');
|
dialog.classList.add('forcebutton');
|
||||||
}
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
dialog._args = args;
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
add(item, noclick, zoom) {
|
add(item, noclick, zoom) {
|
||||||
|
|
|
@ -10,15 +10,21 @@ export class GameEvent {
|
||||||
/** @type { GameEventPromise } */
|
/** @type { GameEventPromise } */
|
||||||
#promise;
|
#promise;
|
||||||
/**
|
/**
|
||||||
* @param {string} [name]
|
* @param {string | GameEvent} [name]
|
||||||
* @param {false} [trigger]
|
* @param {false} [trigger]
|
||||||
*/
|
*/
|
||||||
constructor(name, trigger) {
|
constructor(name, trigger) {
|
||||||
|
if (name instanceof GameEvent) {
|
||||||
|
const other = name;
|
||||||
|
[name, trigger] = other.__args;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof name == 'string') {
|
if (typeof name == 'string') {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
const gameEvent = get.event();
|
const gameEvent = get.event();
|
||||||
if (gameEvent) {
|
if (gameEvent) {
|
||||||
const type = `onNext${name[0].toUpperCase()}${name.slice(1)}`;
|
const type = `onNext${name[0].toUpperCase()}${name.slice(1)}`;
|
||||||
|
// @ts-ignore
|
||||||
if (gameEvent.hasHandler(type)) this.pushHandler(...gameEvent.getHandler(type));
|
if (gameEvent.hasHandler(type)) this.pushHandler(...gameEvent.getHandler(type));
|
||||||
}
|
}
|
||||||
game.globalEventHandlers.addHandlerToEvent(this);
|
game.globalEventHandlers.addHandlerToEvent(this);
|
||||||
|
@ -50,6 +56,7 @@ export class GameEvent {
|
||||||
**/
|
**/
|
||||||
this.resolve = null;
|
this.resolve = null;
|
||||||
if (trigger !== false && !game.online) this._triggered = 0;
|
if (trigger !== false && !game.online) this._triggered = 0;
|
||||||
|
this.__args = [name, trigger];
|
||||||
}
|
}
|
||||||
static initialGameEvent() {
|
static initialGameEvent() {
|
||||||
return new GameEvent().finish().toPromise();
|
return new GameEvent().finish().toPromise();
|
||||||
|
|
|
@ -37,9 +37,15 @@ export class GameEventPromise extends Promise {
|
||||||
}
|
}
|
||||||
#event;
|
#event;
|
||||||
/**
|
/**
|
||||||
* @param { GameEvent } event
|
* @param { GameEvent | GameEventPromise } arg
|
||||||
*/
|
*/
|
||||||
constructor(event) {
|
constructor(arg) {
|
||||||
|
if (arg instanceof GameEventPromise)
|
||||||
|
throw new Error("GameEventPromise cannot copy.")
|
||||||
|
/**
|
||||||
|
* @type {GameEvent}
|
||||||
|
*/
|
||||||
|
const event = arg;
|
||||||
super(resolve => {
|
super(resolve => {
|
||||||
// 设置为异步事件
|
// 设置为异步事件
|
||||||
event.async = true;
|
event.async = true;
|
||||||
|
|
|
@ -8,10 +8,10 @@ import { GNC as gnc } from '../../gnc/index.js';
|
||||||
|
|
||||||
export class NodeWS {
|
export class NodeWS {
|
||||||
/**
|
/**
|
||||||
* @param {string} id
|
* @param {string | NodeWS} id
|
||||||
*/
|
*/
|
||||||
constructor(id) {
|
constructor(id) {
|
||||||
this.wsid = id;
|
this.wsid = (id instanceof NodeWS) ? id.wsid : id;
|
||||||
}
|
}
|
||||||
send(message) {
|
send(message) {
|
||||||
game.send('server', 'send', this.wsid, message);
|
game.send('server', 'send', this.wsid, message);
|
||||||
|
|
|
@ -12,6 +12,11 @@ export class Player extends HTMLDivElement {
|
||||||
*/
|
*/
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
constructor(position, noclick) {
|
constructor(position, noclick) {
|
||||||
|
if (position instanceof Player) {
|
||||||
|
const other = position;
|
||||||
|
[position, noclick] = other._args;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {this}
|
* @type {this}
|
||||||
*/
|
*/
|
||||||
|
@ -19,6 +24,8 @@ export class Player extends HTMLDivElement {
|
||||||
const player = ui.create.div('.player', position);
|
const player = ui.create.div('.player', position);
|
||||||
Object.setPrototypeOf(player, Player.prototype);
|
Object.setPrototypeOf(player, Player.prototype);
|
||||||
player.build(noclick);
|
player.build(noclick);
|
||||||
|
// @ts-ignore
|
||||||
|
player._args = [position, noclick];
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -6193,8 +6200,8 @@ export class Player extends HTMLDivElement {
|
||||||
if (mark) this.markAuto(name);
|
if (mark) this.markAuto(name);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
getStorage(name) {
|
getStorage(name, defaultValue = []) {
|
||||||
return this.storage[name] || [];
|
return this.hasStorage(name) ? this.storage[name] : defaultValue;
|
||||||
}
|
}
|
||||||
hasStorage(name, value) {
|
hasStorage(name, value) {
|
||||||
if (!(name in this.storage)) return false;
|
if (!(name in this.storage)) return false;
|
||||||
|
|
|
@ -13,6 +13,11 @@ export class VCard {
|
||||||
* @param { string } [nature]
|
* @param { string } [nature]
|
||||||
*/
|
*/
|
||||||
constructor(suitOrCard, numberOrCards, name, nature) {
|
constructor(suitOrCard, numberOrCards, name, nature) {
|
||||||
|
if (suitOrCard instanceof VCard) {
|
||||||
|
const other = suitOrCard;
|
||||||
|
[suitOrCard, numberOrCards, name, nature] = other._args;
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(suitOrCard)) {
|
if (Array.isArray(suitOrCard)) {
|
||||||
/**
|
/**
|
||||||
* @type {string}
|
* @type {string}
|
||||||
|
@ -91,6 +96,8 @@ export class VCard {
|
||||||
if (typeof nature == 'string') this.nature = nature;
|
if (typeof nature == 'string') this.nature = nature;
|
||||||
if (!this.storage) this.storage = {};
|
if (!this.storage) this.storage = {};
|
||||||
if (!this.cards) this.cards = [];
|
if (!this.cards) this.cards = [];
|
||||||
|
|
||||||
|
this._args = [suitOrCard, numberOrCards, name, nature];
|
||||||
}
|
}
|
||||||
sameSuitAs(card) {
|
sameSuitAs(card) {
|
||||||
return get.suit(this) == get.suit(card);
|
return get.suit(this) == get.suit(card);
|
||||||
|
|
Loading…
Reference in New Issue