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 { 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 {
|
||||
static online = false;
|
||||
static onlineID = null;
|
||||
|
@ -38,98 +41,7 @@ export class Game extends Uninstantable {
|
|||
static phaseNumber = 0;
|
||||
static roundNumber = 0;
|
||||
static shuffleNumber = 0;
|
||||
static promises = {
|
||||
/**
|
||||
* 模仿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 promises = GamePromises;
|
||||
static globalEventHandlers = new class {
|
||||
constructor() {
|
||||
this._handlers = {};
|
||||
|
@ -361,223 +273,7 @@ export class Game extends Uninstantable {
|
|||
* textAlign: "center"
|
||||
* });
|
||||
*/
|
||||
static dynamicStyle = new class {
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
static dynamicStyle = new DynamicStyle()
|
||||
/**
|
||||
* 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 { GNC as gnc } from '../gnc/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;
|
||||
}
|
||||
}
|
||||
import { Is } from "./is.js";
|
||||
|
||||
export class Get extends Uninstantable {
|
||||
static is = Is;
|
||||
|
@ -676,7 +242,7 @@ export class Get extends Uninstantable {
|
|||
}
|
||||
static yunjiao(str) {
|
||||
const util = window.pinyinUtilx;
|
||||
if (util) str = util.removeTone(str)
|
||||
if (util) str = util.removeTone(str);
|
||||
if (lib.pinyins._metadata.zhengtirendu.includes(str)) {
|
||||
str = ('-' + str[str.length - 1]);
|
||||
}
|
||||
|
@ -1227,16 +793,18 @@ export class Get extends Uninstantable {
|
|||
}
|
||||
}
|
||||
/**
|
||||
* 深拷贝函数(虽然只处理了部分情况)
|
||||
*
|
||||
* 除了普通的Object和NullObject,均不考虑自行赋值的数据,但会原样将Symbol复制过去
|
||||
*
|
||||
* @template T
|
||||
* @param {T} obj
|
||||
* @returns {T}
|
||||
* @param {T} obj - 要复制的对象,若不是对象则直接返回原值
|
||||
* @param {WeakMap<object, unknown>} [map] - 拷贝用的临时存储,用于处理循环引用(请勿自行赋值)
|
||||
* @returns {T} - 深拷贝后的对象,若传入值不是对象则为传入值
|
||||
*/
|
||||
static copy(obj, map = new WeakMap()) {
|
||||
try {
|
||||
return structuredClone(obj);
|
||||
}
|
||||
catch {
|
||||
// obj不可序列化时,参考[这里](https://juejin.cn/post/7315612852890026021)实现深拷贝
|
||||
// 参考[这里](https://juejin.cn/post/7315612852890026021)实现深拷贝
|
||||
// 不再判断是否能structuredClone是因为structuredClone会把Symbol给毙了
|
||||
const getType = (obj) => Object.prototype.toString.call(obj);
|
||||
|
||||
const canTranverse = {
|
||||
|
@ -1247,88 +815,64 @@ export class Get extends Uninstantable {
|
|||
"[object Arguments]": true,
|
||||
};
|
||||
|
||||
const functionMap = {
|
||||
"[object Function]": true,
|
||||
"[object AsyncFunction]": true,
|
||||
"[object GeneratorFunction]": true,
|
||||
};
|
||||
if (typeof obj !== "object" || obj === null)
|
||||
return obj;
|
||||
|
||||
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
|
||||
return typeof obj === "symbol"
|
||||
? cloneSymbol(obj)
|
||||
: functionMap[getType(obj)]
|
||||
? createFunction(obj)
|
||||
: obj;
|
||||
}
|
||||
if (map.has(obj)) return map.get(obj);
|
||||
|
||||
const constructor = obj.constructor;
|
||||
let target;
|
||||
if (!canTranverse[getType(obj)]) {
|
||||
try {
|
||||
// @ts-ignore
|
||||
if (!canTranverse[getType(obj)]) return new constructor(obj);
|
||||
if (map.has(obj)) return map.get(obj);
|
||||
target = new constructor(obj);
|
||||
} catch (error) {
|
||||
if (obj instanceof HTMLElement) {
|
||||
target = obj.cloneNode(true); // 不能cloneNode就寄吧,累了
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
const target = new constructor();
|
||||
else target = constructor ? new constructor() : Object.create(null);
|
||||
map.set(obj, target);
|
||||
|
||||
if (obj instanceof Map) {
|
||||
obj.forEach((value, key) => {
|
||||
target.set(get.copy(key, map), get.copy(value, map));
|
||||
});
|
||||
return target;
|
||||
}
|
||||
|
||||
if (obj instanceof Set) {
|
||||
} else if (obj instanceof Set) {
|
||||
obj.forEach((value) => {
|
||||
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)) {
|
||||
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);
|
||||
symbols.forEach((s) => {
|
||||
target[cloneSymbol(s)] = get.copy(obj[s], map);
|
||||
symbols.forEach((symbol) => {
|
||||
target[symbol] = get.copy(obj[symbol], map);
|
||||
});
|
||||
|
||||
return target;
|
||||
}
|
||||
}
|
||||
static inpilefull(type) {
|
||||
var list = [];
|
||||
for (var i in lib.cardPile) {
|
||||
|
@ -2551,7 +2095,7 @@ export class Get extends Uninstantable {
|
|||
if (str.suit && str.number || str.isCard) {
|
||||
var cardnum = get.number(str, false) || '';
|
||||
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) {
|
||||
str2 += '(' + get.translation(str) + ')';
|
||||
|
@ -2917,7 +2461,7 @@ export class Get extends Uninstantable {
|
|||
*/
|
||||
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))
|
||||
|| (item.cardtags && item.cardtags.includes(tag))
|
||||
|| (item.cardtags && item.cardtags.includes(tag));
|
||||
}
|
||||
static tag(item, tag, item2, bool) {
|
||||
var result;
|
||||
|
@ -5004,3 +4548,7 @@ export class Get extends Uninstantable {
|
|||
}
|
||||
|
||||
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 - 卡牌包名
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export const importCardPack = generateImportFunction('card', (name) => `../../card/${name}.js`)
|
||||
|
||||
/**
|
||||
* @param {string} name - 武将包名
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export const importCharacterPack = generateImportFunction('character', (name) => `../../character/${name}.js`)
|
||||
|
||||
/**
|
||||
* @param {string} name - 扩展名
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export const importExtension = generateImportFunction('extension', (name) => `../../extension/${name}/extension.js`)
|
||||
|
||||
/**
|
||||
* @param {string} name - 模式名
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
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>}
|
||||
*/
|
||||
function generateImportFunction(type, pathParser) {
|
||||
return async function (name) {
|
||||
try {
|
||||
return async (name) => {
|
||||
const modeContent = await import(pathParser(name));
|
||||
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);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,144 +24,150 @@ export async function onload(resetGameTimeout) {
|
|||
if (lib.config.touchscreen) createTouchDraggedFilter();
|
||||
|
||||
// 不拆分,太玄学了
|
||||
if (lib.config.card_style == 'custom') {
|
||||
game.getDB('image', 'card_style', function (fileToLoad) {
|
||||
if (!fileToLoad) return;
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function (fileLoadedEvent) {
|
||||
if (ui.css.card_stylesheet) {
|
||||
ui.css.card_stylesheet.remove();
|
||||
}
|
||||
ui.css.card_stylesheet = lib.init.sheet('.card:not(*:empty){background-image:url(' + fileLoadedEvent.target.result + ')}');
|
||||
};
|
||||
if (lib.config.card_style === 'custom') {
|
||||
const fileToLoad = await game.getDB('image', 'card_style')
|
||||
if (fileToLoad) {
|
||||
const fileLoadedEvent = await new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = resolve;
|
||||
fileReader.onerror = reject;
|
||||
fileReader.readAsDataURL(fileToLoad, "UTF-8");
|
||||
});
|
||||
}
|
||||
if (lib.config.cardback_style == 'custom') {
|
||||
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 (ui.css.card_stylesheet) ui.css.card_stylesheet.remove();
|
||||
ui.css.card_stylesheet = lib.init.sheet(`.card:not(*:empty){background-image:url(${fileLoadedEvent.target.result})}`);
|
||||
}
|
||||
|
||||
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%;}');
|
||||
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");
|
||||
});
|
||||
}
|
||||
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();
|
||||
}
|
||||
if (ui.css.border_stylesheet) ui.css.border_stylesheet.remove();
|
||||
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);
|
||||
};
|
||||
}
|
||||
}
|
||||
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");
|
||||
});
|
||||
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");
|
||||
});
|
||||
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
|
||||
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);
|
||||
else if (ui.create.buttonPresets[type]) button = ui.create.buttonPresets[type](item, type, position, noClick, button);
|
||||
if (button) {
|
||||
|
@ -25,6 +30,8 @@ export class Button extends HTMLDivElement {
|
|||
const intro = button.querySelector('.intro');
|
||||
if (intro) intro.remove();
|
||||
}
|
||||
// @ts-ignore
|
||||
button._args = [item, type, position, noClick, button];
|
||||
return button;
|
||||
} else {
|
||||
console.error([item, type, position, noClick, button]);
|
||||
|
|
|
@ -13,6 +13,11 @@ export class Card extends HTMLDivElement {
|
|||
*/
|
||||
// @ts-ignore
|
||||
constructor(position, info, noclick) {
|
||||
if (position instanceof Card) {
|
||||
const other = position;
|
||||
// @ts-ignore
|
||||
[position, info, noclick] = other._args;
|
||||
}
|
||||
/**
|
||||
* @type {this}
|
||||
*/
|
||||
|
@ -20,6 +25,8 @@ export class Card extends HTMLDivElement {
|
|||
const card = ui.create.div('.card', position);
|
||||
Object.setPrototypeOf(card, Card.prototype);
|
||||
card.build(info, noclick);
|
||||
// @ts-ignore
|
||||
card._args = [position, info, noclick];
|
||||
return card;
|
||||
}
|
||||
build(info, noclick) {
|
||||
|
|
|
@ -8,9 +8,10 @@ import { GNC as gnc } from '../../gnc/index.js';
|
|||
|
||||
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) {
|
||||
if (ws instanceof Client) throw new Error('Client cannot copy.')
|
||||
this.ws = ws;
|
||||
/**
|
||||
* @type { string }
|
||||
|
|
|
@ -8,9 +8,15 @@ import { GNC as gnc } from '../../gnc/index.js';
|
|||
|
||||
export class Control extends HTMLDivElement {
|
||||
// @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 controls = Array.isArray(arguments[0]) ? arguments[0] : Array.from(arguments);
|
||||
const controls = Array.isArray(args[0]) ? args[0] : args;
|
||||
/**
|
||||
* @type {this}
|
||||
*/
|
||||
|
@ -54,6 +60,8 @@ export class Control extends HTMLDivElement {
|
|||
}
|
||||
|
||||
ui.updatec();
|
||||
// @ts-ignore
|
||||
control._args = args;
|
||||
return control;
|
||||
}
|
||||
open() {
|
||||
|
|
|
@ -7,7 +7,13 @@ import { UI as ui } from '../../ui/index.js';
|
|||
|
||||
export class Dialog extends HTMLDivElement {
|
||||
// @ts-ignore
|
||||
constructor() {
|
||||
constructor(...args) {
|
||||
if (args[0] instanceof Dialog) {
|
||||
const other = args[0];
|
||||
// @ts-ignore
|
||||
args = other._args;
|
||||
}
|
||||
|
||||
let hidden = false;
|
||||
let noTouchScroll = false;
|
||||
let forceButton = false;
|
||||
|
@ -21,7 +27,7 @@ export class Dialog extends HTMLDivElement {
|
|||
dialog.bar1 = ui.create.div('.bar.top', dialog);
|
||||
dialog.bar2 = ui.create.div('.bar.bottom', dialog);
|
||||
dialog.buttons = [];
|
||||
Array.from(arguments).forEach(argument => {
|
||||
Array.from(args).forEach(argument => {
|
||||
if (typeof argument == 'boolean') dialog.static = argument;
|
||||
else if (argument == 'hidden') hidden = true;
|
||||
else if (argument == 'notouchscroll') noTouchScroll = true;
|
||||
|
@ -42,6 +48,8 @@ export class Dialog extends HTMLDivElement {
|
|||
dialog.forcebutton = true;
|
||||
dialog.classList.add('forcebutton');
|
||||
}
|
||||
// @ts-ignore
|
||||
dialog._args = args;
|
||||
return dialog;
|
||||
}
|
||||
add(item, noclick, zoom) {
|
||||
|
|
|
@ -10,15 +10,21 @@ export class GameEvent {
|
|||
/** @type { GameEventPromise } */
|
||||
#promise;
|
||||
/**
|
||||
* @param {string} [name]
|
||||
* @param {string | GameEvent} [name]
|
||||
* @param {false} [trigger]
|
||||
*/
|
||||
constructor(name, trigger) {
|
||||
if (name instanceof GameEvent) {
|
||||
const other = name;
|
||||
[name, trigger] = other.__args;
|
||||
}
|
||||
|
||||
if (typeof name == 'string') {
|
||||
this.name = name;
|
||||
const gameEvent = get.event();
|
||||
if (gameEvent) {
|
||||
const type = `onNext${name[0].toUpperCase()}${name.slice(1)}`;
|
||||
// @ts-ignore
|
||||
if (gameEvent.hasHandler(type)) this.pushHandler(...gameEvent.getHandler(type));
|
||||
}
|
||||
game.globalEventHandlers.addHandlerToEvent(this);
|
||||
|
@ -50,6 +56,7 @@ export class GameEvent {
|
|||
**/
|
||||
this.resolve = null;
|
||||
if (trigger !== false && !game.online) this._triggered = 0;
|
||||
this.__args = [name, trigger];
|
||||
}
|
||||
static initialGameEvent() {
|
||||
return new GameEvent().finish().toPromise();
|
||||
|
|
|
@ -37,9 +37,15 @@ export class GameEventPromise extends Promise {
|
|||
}
|
||||
#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 => {
|
||||
// 设置为异步事件
|
||||
event.async = true;
|
||||
|
|
|
@ -8,10 +8,10 @@ import { GNC as gnc } from '../../gnc/index.js';
|
|||
|
||||
export class NodeWS {
|
||||
/**
|
||||
* @param {string} id
|
||||
* @param {string | NodeWS} id
|
||||
*/
|
||||
constructor(id) {
|
||||
this.wsid = id;
|
||||
this.wsid = (id instanceof NodeWS) ? id.wsid : id;
|
||||
}
|
||||
send(message) {
|
||||
game.send('server', 'send', this.wsid, message);
|
||||
|
|
|
@ -12,6 +12,11 @@ export class Player extends HTMLDivElement {
|
|||
*/
|
||||
// @ts-ignore
|
||||
constructor(position, noclick) {
|
||||
if (position instanceof Player) {
|
||||
const other = position;
|
||||
[position, noclick] = other._args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {this}
|
||||
*/
|
||||
|
@ -19,6 +24,8 @@ export class Player extends HTMLDivElement {
|
|||
const player = ui.create.div('.player', position);
|
||||
Object.setPrototypeOf(player, Player.prototype);
|
||||
player.build(noclick);
|
||||
// @ts-ignore
|
||||
player._args = [position, noclick];
|
||||
return player;
|
||||
}
|
||||
/**
|
||||
|
@ -6193,8 +6200,8 @@ export class Player extends HTMLDivElement {
|
|||
if (mark) this.markAuto(name);
|
||||
return value;
|
||||
}
|
||||
getStorage(name) {
|
||||
return this.storage[name] || [];
|
||||
getStorage(name, defaultValue = []) {
|
||||
return this.hasStorage(name) ? this.storage[name] : defaultValue;
|
||||
}
|
||||
hasStorage(name, value) {
|
||||
if (!(name in this.storage)) return false;
|
||||
|
|
|
@ -13,6 +13,11 @@ export class VCard {
|
|||
* @param { string } [nature]
|
||||
*/
|
||||
constructor(suitOrCard, numberOrCards, name, nature) {
|
||||
if (suitOrCard instanceof VCard) {
|
||||
const other = suitOrCard;
|
||||
[suitOrCard, numberOrCards, name, nature] = other._args;
|
||||
}
|
||||
|
||||
if (Array.isArray(suitOrCard)) {
|
||||
/**
|
||||
* @type {string}
|
||||
|
@ -91,6 +96,8 @@ export class VCard {
|
|||
if (typeof nature == 'string') this.nature = nature;
|
||||
if (!this.storage) this.storage = {};
|
||||
if (!this.cards) this.cards = [];
|
||||
|
||||
this._args = [suitOrCard, numberOrCards, name, nature];
|
||||
}
|
||||
sameSuitAs(card) {
|
||||
return get.suit(this) == get.suit(card);
|
||||
|
|
Loading…
Reference in New Issue