重新拆分lib.element
This commit is contained in:
parent
ea754c9642
commit
ba438ef817
|
@ -2229,10 +2229,13 @@ export class Get extends Uninstantable {
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @template T
|
* @template T
|
||||||
* @type {{
|
* @overload
|
||||||
* (key: T) => GameEvent[T];
|
* @param {T} key
|
||||||
* () => GameEvent;
|
* @returns {import("../library/index.js").GameEvent[T]}
|
||||||
* }}
|
*/
|
||||||
|
/**
|
||||||
|
* @overload
|
||||||
|
* @returns {import("../library/index.js").GameEvent}
|
||||||
*/
|
*/
|
||||||
static event(key) { return key ? _status.event[key] : _status.event }
|
static event(key) { return key ? _status.event[key] : _status.event }
|
||||||
static player() { return _status.event.player }
|
static player() { return _status.event.player }
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { AI as ai } from '../../ai/index.js';
|
||||||
|
import { Get as get } from '../../get/index.js';
|
||||||
|
import { Game as game } from '../../game/index.js';
|
||||||
|
import { Library as lib } from "../index.js";
|
||||||
|
import { status as _status } from '../../status/index.js';
|
||||||
|
import { UI as ui } from '../../ui/index.js';
|
||||||
|
|
||||||
|
export class Button extends HTMLDivElement {
|
||||||
|
/**
|
||||||
|
* @param {{}} item
|
||||||
|
* @param {keyof typeof ui.create.buttonPresets | ((item: {}, type: Function, position?: HTMLDivElement | DocumentFragment, noClick?: true, button?: typeof Button) => typeof Button)} type
|
||||||
|
* @param {HTMLDivElement|DocumentFragment} [position]
|
||||||
|
* @param {true} [noClick]
|
||||||
|
* @param { typeof Button } [button]
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
constructor(item, type, position, noClick, button) {
|
||||||
|
if (ui.create.buttonPresets[type]) button = ui.create.buttonPresets[type](item, type, position, noClick, button);
|
||||||
|
else if (typeof type == 'function') button = type(item, type, position, noClick, button);
|
||||||
|
Object.setPrototypeOf(button, Button.prototype);
|
||||||
|
// @ts-ignore
|
||||||
|
if (!noClick) button.addEventListener(lib.config.touchscreen ? 'touchend' : 'click', ui.click.button);
|
||||||
|
else {
|
||||||
|
// @ts-ignore
|
||||||
|
button.classList.add('noclick');
|
||||||
|
// @ts-ignore
|
||||||
|
const intro = button.querySelector('.intro');
|
||||||
|
if (intro) intro.remove();
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
exclude() {
|
||||||
|
if (_status.event.excludeButton == undefined) {
|
||||||
|
_status.event.excludeButton = [];
|
||||||
|
}
|
||||||
|
_status.event.excludeButton.add(this);
|
||||||
|
}
|
||||||
|
get updateTransform() {
|
||||||
|
return lib.element.Card.prototype.updateTransform;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,787 @@
|
||||||
|
import { AI as ai } from '../../ai/index.js';
|
||||||
|
import { Get as get } from '../../get/index.js';
|
||||||
|
import { Game as game } from '../../game/index.js';
|
||||||
|
import { Library as lib } from "../index.js";
|
||||||
|
import { status as _status } from '../../status/index.js';
|
||||||
|
import { UI as ui } from '../../ui/index.js';
|
||||||
|
|
||||||
|
export class Card extends HTMLDivElement {
|
||||||
|
/**
|
||||||
|
* @param {HTMLDivElement|DocumentFragment} [position]
|
||||||
|
* @param {'noclick'} [info]
|
||||||
|
* @param {true} [noclick]
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
constructor(position, info, noclick) {
|
||||||
|
/**
|
||||||
|
* @type {this}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
const card = ui.create.div('.card', position);
|
||||||
|
Object.setPrototypeOf(card, Card.prototype);
|
||||||
|
card.build(info, noclick);
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
build(info, noclick) {
|
||||||
|
let card = this;
|
||||||
|
card.buildNode();
|
||||||
|
card.buildIntro(noclick);
|
||||||
|
card.buildProperty();
|
||||||
|
card.buildEventListener(info);
|
||||||
|
}
|
||||||
|
buildEventListener(info) {
|
||||||
|
let card = this;
|
||||||
|
if (info != 'noclick') {
|
||||||
|
card.addEventListener(lib.config.touchscreen ? 'touchend' : 'click', ui.click.card);
|
||||||
|
if (lib.config.touchscreen) {
|
||||||
|
card.addEventListener('touchstart', ui.click.cardtouchstart);
|
||||||
|
card.addEventListener('touchmove', ui.click.cardtouchmove);
|
||||||
|
}
|
||||||
|
if (lib.cardSelectObserver) lib.cardSelectObserver.observe(card, {
|
||||||
|
attributes: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildProperty() {
|
||||||
|
let card = this;
|
||||||
|
card.storage = {};
|
||||||
|
card.vanishtag = [];
|
||||||
|
card.gaintag = [];
|
||||||
|
card._uncheck = [];
|
||||||
|
}
|
||||||
|
buildNode() {
|
||||||
|
this.node = {
|
||||||
|
image: ui.create.div('.image', this),
|
||||||
|
info: ui.create.div('.info', this),
|
||||||
|
name: ui.create.div('.name', this),
|
||||||
|
name2: ui.create.div('.name2', this),
|
||||||
|
background: ui.create.div('.background', this),
|
||||||
|
intro: ui.create.div('.intro', this),
|
||||||
|
range: ui.create.div('.range', this),
|
||||||
|
gaintag: ui.create.div('.gaintag', this),
|
||||||
|
};
|
||||||
|
this.node.intro.innerHTML = lib.config.intro;
|
||||||
|
}
|
||||||
|
buildIntro(noclick) {
|
||||||
|
if (!noclick) lib.setIntro(this);
|
||||||
|
}
|
||||||
|
//执行销毁一张牌的钩子函数
|
||||||
|
selfDestroy(event) {
|
||||||
|
if (this._selfDestroyed) return;
|
||||||
|
this._selfDestroyed = true;
|
||||||
|
this.fix();
|
||||||
|
this.delete();
|
||||||
|
const info = get.info(this, false);
|
||||||
|
if (!info) return;
|
||||||
|
if (info.destroyLog !== false) game.log(this, '被销毁了');
|
||||||
|
if (info.onDestroy) info.onDestroy(this, event);
|
||||||
|
}
|
||||||
|
//判断一张牌进入某个区域后是否会被销毁
|
||||||
|
willBeDestroyed(targetPosition, player, event) {
|
||||||
|
const destroyed = this.destroyed;
|
||||||
|
if (typeof destroyed == 'function') {
|
||||||
|
return destroyed(this, targetPosition, player, event);
|
||||||
|
}
|
||||||
|
else if (lib.skill[destroyed]) {
|
||||||
|
if (player) {
|
||||||
|
if (player.hasSkill(destroyed)) {
|
||||||
|
delete this.destroyed;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (typeof destroyed == 'string') {
|
||||||
|
return (destroyed == targetPosition);
|
||||||
|
}
|
||||||
|
return destroyed;
|
||||||
|
}
|
||||||
|
hasNature(nature, player) {
|
||||||
|
return game.hasNature(this, nature, player);
|
||||||
|
}
|
||||||
|
//只针对【杀】起效果
|
||||||
|
addNature(nature) {
|
||||||
|
let natures = [];
|
||||||
|
if (!this.nature) this.nature = '';
|
||||||
|
else {
|
||||||
|
natures.addArray(get.natureList(this.nature));
|
||||||
|
}
|
||||||
|
natures.addArray(get.natureList(nature));
|
||||||
|
this.nature = get.nature(natures);
|
||||||
|
this.classList.add(nature);
|
||||||
|
let str = get.translation(this.nature) + '杀';
|
||||||
|
this.node.name.innerText = str;
|
||||||
|
let name = get.name(this, false);
|
||||||
|
do {
|
||||||
|
if (name == 'sha') {
|
||||||
|
let _bg;
|
||||||
|
for (const n of natures) if (lib.natureBg.has(n)) _bg = n;
|
||||||
|
if (_bg) {
|
||||||
|
this.node.image.setBackgroundImage(lib.natureBg.get(_bg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.node.image.setBackgroundImage('image/card/' + name + '.png');
|
||||||
|
}
|
||||||
|
while (0);
|
||||||
|
return this.nature;
|
||||||
|
}
|
||||||
|
removeNature(nature) {
|
||||||
|
if (!this.nature) return;
|
||||||
|
let natures = get.natureList(this.nature);
|
||||||
|
natures.remove(nature);
|
||||||
|
if (!natures.length) delete this.nature;
|
||||||
|
else this.nature = get.nature(natures);
|
||||||
|
this.classList.remove(nature);
|
||||||
|
let str = get.translation(this.nature) + '杀';
|
||||||
|
this.node.name.innerText = str;
|
||||||
|
let name = get.name(this, false);
|
||||||
|
do {
|
||||||
|
if (name == 'sha') {
|
||||||
|
let _bg;
|
||||||
|
for (const n of natures) if (lib.natureBg.has(n)) _bg = n;
|
||||||
|
if (_bg) {
|
||||||
|
this.node.image.setBackgroundImage(lib.natureBg.get(_bg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.node.image.setBackgroundImage('image/card/' + name + '.png');
|
||||||
|
}
|
||||||
|
while (0);
|
||||||
|
return this.nature;
|
||||||
|
}
|
||||||
|
addGaintag(gaintag) {
|
||||||
|
if (Array.isArray(gaintag)) this.gaintag = gaintag.slice(0);
|
||||||
|
else this.gaintag.add(gaintag);
|
||||||
|
var str = '';
|
||||||
|
for (var gi = 0; gi < this.gaintag.length; gi++) {
|
||||||
|
var translate = get.translation(this.gaintag[gi]);
|
||||||
|
if (translate != 'invisible') {
|
||||||
|
str += translate;
|
||||||
|
if (gi < this.gaintag.length - 1) str += ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.node.gaintag.innerHTML = str;
|
||||||
|
}
|
||||||
|
removeGaintag(tag) {
|
||||||
|
if (tag === true) {
|
||||||
|
if (this.gaintag && this.gaintag.length || this.node.gaintag.innerHTML.length) this.addGaintag([]);
|
||||||
|
}
|
||||||
|
else if (this.hasGaintag(tag)) {
|
||||||
|
this.gaintag.remove(tag);
|
||||||
|
this.addGaintag(this.gaintag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hasGaintag(tag) {
|
||||||
|
return this.gaintag && this.gaintag.contains(tag);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {[string, number, string, string] | {
|
||||||
|
* suit: string;
|
||||||
|
* number: number;
|
||||||
|
* name: string;
|
||||||
|
* nature: string;
|
||||||
|
* }} card
|
||||||
|
*/
|
||||||
|
init(card) {
|
||||||
|
if (Array.isArray(card)) {
|
||||||
|
if (card[2] == 'huosha') {
|
||||||
|
card[2] = 'sha';
|
||||||
|
card[3] = 'fire';
|
||||||
|
}
|
||||||
|
else if (card[2] == 'leisha') {
|
||||||
|
card[2] = 'sha';
|
||||||
|
card[3] = 'thunder';
|
||||||
|
}
|
||||||
|
else if (card[2] == 'cisha') {
|
||||||
|
card[2] = 'sha';
|
||||||
|
card[3] = 'stab';
|
||||||
|
}
|
||||||
|
else if (card[2].length > 3) {
|
||||||
|
let prefix = card[2].slice(0, card[2].lastIndexOf('sha'));
|
||||||
|
if (lib.nature.has(prefix)) {
|
||||||
|
if (prefix.length + 3 == card[2].length) {
|
||||||
|
card[2] = 'sha';
|
||||||
|
card[3] = prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (card[2].startsWith('sha_')) {
|
||||||
|
let suffix = card[2].slice(4);
|
||||||
|
let natureList = suffix.split('_');
|
||||||
|
card[2] = 'sha';
|
||||||
|
card[3] = get.nature(natureList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (typeof card == 'object') {
|
||||||
|
card = [card.suit, card.number, card.name, card.nature];
|
||||||
|
}
|
||||||
|
var cardnum = card[1] || '';
|
||||||
|
if (parseInt(cardnum) == cardnum) cardnum = parseInt(cardnum);
|
||||||
|
|
||||||
|
if (!lib.card[card[2]]) {
|
||||||
|
lib.card[card[2]] = {};
|
||||||
|
}
|
||||||
|
var info = lib.card[card[2]];
|
||||||
|
if (info.global && !this.classList.contains('button')) {
|
||||||
|
if (Array.isArray(info.global)) {
|
||||||
|
while (info.global.length) {
|
||||||
|
game.addGlobalSkill(info.global.shift());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (typeof info.global == 'string') {
|
||||||
|
game.addGlobalSkill(info.global);
|
||||||
|
}
|
||||||
|
delete info.global;
|
||||||
|
}
|
||||||
|
this.suit = card[0];
|
||||||
|
this.number = parseInt(card[1]) || 0;
|
||||||
|
this.name = card[2];
|
||||||
|
|
||||||
|
if (info.destroy && (typeof info.destroy != 'boolean' && !lib.skill[info.destroy])) {
|
||||||
|
this.destroyed = info.destroy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_status.connectMode && !game.online && lib.cardOL && !this.cardid) {
|
||||||
|
this.cardid = get.id();
|
||||||
|
lib.cardOL[this.cardid] = this;
|
||||||
|
}
|
||||||
|
if (!_status.connectMode && !_status.video) {
|
||||||
|
this.cardid = get.id();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$init(card);
|
||||||
|
|
||||||
|
if (this.inits) {
|
||||||
|
for (var i = 0; i < this.inits.length; i++) {
|
||||||
|
this.inits[i](this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof info.init == 'function') info.init();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {[string, number, string, string]} card
|
||||||
|
*/
|
||||||
|
$init(card) {
|
||||||
|
var info = lib.card[card[2]];
|
||||||
|
var cardnum = card[1] || '';
|
||||||
|
if (parseInt(cardnum) == cardnum) cardnum = parseInt(cardnum);
|
||||||
|
if (cardnum > 0 && cardnum < 14) {
|
||||||
|
cardnum = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'][cardnum - 1];
|
||||||
|
}
|
||||||
|
if (this.name) {
|
||||||
|
this.classList.remove('epic');
|
||||||
|
this.classList.remove('legend');
|
||||||
|
this.classList.remove('gold');
|
||||||
|
this.classList.remove('unique');
|
||||||
|
this.style.background = '';
|
||||||
|
var subtype = get.subtype(this, false);
|
||||||
|
if (subtype) {
|
||||||
|
this.classList.remove(subtype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (info.epic) {
|
||||||
|
this.classList.add('epic');
|
||||||
|
}
|
||||||
|
else if (info.legend) {
|
||||||
|
this.classList.add('legend');
|
||||||
|
}
|
||||||
|
else if (info.gold) {
|
||||||
|
this.classList.add('gold');
|
||||||
|
}
|
||||||
|
else if (info.unique) {
|
||||||
|
this.classList.add('unique');
|
||||||
|
}
|
||||||
|
var bg = card[2];
|
||||||
|
if (info.cardimage) {
|
||||||
|
bg = info.cardimage;
|
||||||
|
}
|
||||||
|
var img = lib.card[bg].image;
|
||||||
|
if (img) {
|
||||||
|
if (img.startsWith('db:')) {
|
||||||
|
img = img.slice(3);
|
||||||
|
}
|
||||||
|
else if (!img.startsWith('ext:')) {
|
||||||
|
img = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.classList.remove('fullskin');
|
||||||
|
this.classList.remove('fullimage');
|
||||||
|
this.classList.remove('fullborder');
|
||||||
|
this.dataset.cardName = card[2];
|
||||||
|
this.dataset.cardType = info.type || '';
|
||||||
|
this.dataset.cardSubype = info.subtype || '';
|
||||||
|
this.dataset.cardMultitarget = info.multitarget ? '1' : '0';
|
||||||
|
this.node.name.dataset.nature = '';
|
||||||
|
this.node.info.classList.remove('red');
|
||||||
|
if (!lib.config.hide_card_image && lib.card[bg].fullskin) {
|
||||||
|
this.classList.add('fullskin');
|
||||||
|
if (img) {
|
||||||
|
if (img.startsWith('ext:')) {
|
||||||
|
this.node.image.setBackgroundImage(img.replace(/^ext:/, 'extension/'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.node.image.setBackgroundDB(img);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (lib.card[bg].modeimage) {
|
||||||
|
this.node.image.setBackgroundImage('image/mode/' + lib.card[bg].modeimage + '/card/' + bg + '.png');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
do {
|
||||||
|
let nature = card[3];
|
||||||
|
if (bg == 'sha' && typeof nature == 'string') {
|
||||||
|
let natures = get.natureList(nature), _bg;
|
||||||
|
for (const n of natures) if (lib.natureBg.has(n)) _bg = n;
|
||||||
|
if (_bg) {
|
||||||
|
this.node.image.setBackgroundImage(lib.natureBg.get(_bg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.node.image.setBackgroundImage('image/card/' + bg + '.png');
|
||||||
|
}
|
||||||
|
while (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lib.card[bg].image == 'background') {
|
||||||
|
if (card[3]) this.node.background.setBackground(bg + '_' + get.natureList(card[3])[0], 'card');
|
||||||
|
else this.node.background.setBackground(bg, 'card');
|
||||||
|
}
|
||||||
|
else if (lib.card[bg].fullimage) {
|
||||||
|
this.classList.add('fullimage');
|
||||||
|
if (img) {
|
||||||
|
if (img.startsWith('ext:')) {
|
||||||
|
this.setBackgroundImage(img.replace(/^ext:/, 'extension/'));
|
||||||
|
this.style.backgroundSize = 'cover';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setBackgroundDB(img);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lib.card[bg].image) {
|
||||||
|
if (lib.card[bg].image.startsWith('character:')) {
|
||||||
|
this.setBackground(lib.card[bg].image.slice(10), 'character');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setBackground(lib.card[bg].image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var cardPack = lib.cardPack['mode_' + get.mode()];
|
||||||
|
if (Array.isArray(cardPack) && cardPack.contains(bg)) {
|
||||||
|
this.setBackground('mode/' + get.mode() + '/card/' + bg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setBackground('card/' + bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lib.card[bg].fullborder) {
|
||||||
|
this.classList.add('fullborder');
|
||||||
|
if (lib.card[bg].fullborder == 'gold') {
|
||||||
|
this.node.name.dataset.nature = 'metalmm';
|
||||||
|
}
|
||||||
|
else if (lib.card[bg].fullborder == 'silver') {
|
||||||
|
this.node.name.dataset.nature = 'watermm';
|
||||||
|
}
|
||||||
|
if (!this.node.avatar) {
|
||||||
|
this.node.avatar = ui.create.div('.cardavatar');
|
||||||
|
this.insertBefore(this.node.avatar, this.firstChild);
|
||||||
|
}
|
||||||
|
if (!this.node.framebg) {
|
||||||
|
this.node.framebg = ui.create.div('.cardframebg');
|
||||||
|
this.node.framebg.dataset.auto = lib.card[bg].fullborder;
|
||||||
|
this.insertBefore(this.node.framebg, this.firstChild);
|
||||||
|
}
|
||||||
|
if (img) {
|
||||||
|
if (img.startsWith('ext:')) {
|
||||||
|
this.node.avatar.setBackgroundImage(img.replace(/^ext:/, 'extension/'));
|
||||||
|
this.node.avatar.style.backgroundSize = 'cover';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.node.avatar.setBackgroundDB(img);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lib.card[bg].image) {
|
||||||
|
if (lib.card[bg].image.startsWith('character:')) {
|
||||||
|
this.node.avatar.setBackground(lib.card[bg].image.slice(10), 'character');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.node.avatar.setBackground(lib.card[bg].image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var cardPack = lib.cardPack['mode_' + get.mode()];
|
||||||
|
if (Array.isArray(cardPack) && cardPack.contains(bg)) {
|
||||||
|
this.node.avatar.setBackground('mode/' + get.mode() + '/card/' + bg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.node.avatar.setBackground('card/' + bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lib.card[bg].image == 'card') {
|
||||||
|
if (card[3]) this.setBackground(bg + '_' + get.natureList(card[3])[0], 'card');
|
||||||
|
else this.setBackground(bg, 'card');
|
||||||
|
}
|
||||||
|
else if (typeof lib.card[bg].image == 'string' && !lib.card[bg].fullskin) {
|
||||||
|
if (img) {
|
||||||
|
if (img.startsWith('ext:')) {
|
||||||
|
this.setBackgroundImage(img.replace(/^ext:/, 'extension/'));
|
||||||
|
this.style.backgroundSize = 'cover';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setBackgroundDB(img);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setBackground(lib.card[bg].image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.node.background.innerHTML = lib.translate[bg + '_cbg'] || lib.translate[bg + '_bg'] || get.translation(bg)[0];
|
||||||
|
// this.node.background.style.fontFamily=lib.config.card_font;
|
||||||
|
if (this.node.background.innerHTML.length > 1) this.node.background.classList.add('tight');
|
||||||
|
else this.node.background.classList.remove('tight');
|
||||||
|
}
|
||||||
|
if (!lib.card[bg].fullborder && this.node.avatar && this.node.framebg) {
|
||||||
|
this.node.avatar.remove();
|
||||||
|
this.node.framebg.remove();
|
||||||
|
delete this.node.avatar;
|
||||||
|
delete this.node.framebg;
|
||||||
|
}
|
||||||
|
if (info.noname && !this.classList.contains('button')) {
|
||||||
|
this.node.name.style.display = 'none';
|
||||||
|
}
|
||||||
|
if (info.color) {
|
||||||
|
this.style.color = info.color;
|
||||||
|
}
|
||||||
|
if (info.textShadow) {
|
||||||
|
this.style.textShadow = info.textShadow;
|
||||||
|
}
|
||||||
|
if (info.opacity) {
|
||||||
|
this.node.info.style.opacity = info.opacity;
|
||||||
|
this.node.name.style.opacity = info.opacity;
|
||||||
|
}
|
||||||
|
if (info.modinfo) {
|
||||||
|
this.node.info.innerHTML = info.modinfo;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.node.info.innerHTML = get.translation(card[0]) + '<span style="font-family:xinwei"> </span><span style="font-family:xinwei">' + cardnum + '</span>';
|
||||||
|
}
|
||||||
|
if (info.addinfo) {
|
||||||
|
if (!this.node.addinfo) {
|
||||||
|
this.node.addinfo = ui.create.div('.range', this);
|
||||||
|
}
|
||||||
|
this.node.addinfo.innerHTML = info.addinfo;
|
||||||
|
}
|
||||||
|
else if (this.node.addinfo) {
|
||||||
|
this.node.addinfo.remove();
|
||||||
|
delete this.node.addinfo;
|
||||||
|
}
|
||||||
|
if (card[0] == 'heart' || card[0] == 'diamond') {
|
||||||
|
this.node.info.classList.add('red');
|
||||||
|
}
|
||||||
|
this.node.image.className = 'image';
|
||||||
|
var name = get.translation(card[2]);
|
||||||
|
if (card[2] == 'sha') {
|
||||||
|
name = '';
|
||||||
|
let nature = card[3];
|
||||||
|
if (nature) {
|
||||||
|
let natures = get.natureList(nature);
|
||||||
|
natures.sort(lib.sort.nature);
|
||||||
|
for (let nature of natures) {
|
||||||
|
name += lib.translate['nature_' + nature] || lib.translate[nature] || '';
|
||||||
|
if (nature != 'stab') this.node.image.classList.add(nature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name += '杀';
|
||||||
|
}
|
||||||
|
this.node.name.innerHTML = name;
|
||||||
|
if (name.length >= 5) {
|
||||||
|
this.node.name.classList.add('long');
|
||||||
|
if (name.length >= 7) {
|
||||||
|
this.node.name.classList.add('longlong');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.node.name2.innerHTML = get.translation(card[0]) + cardnum + ' ' + name;
|
||||||
|
this.classList.add('card');
|
||||||
|
if (card[3]) {
|
||||||
|
let natures = get.natureList(card[3]);
|
||||||
|
natures.forEach(n => { if (n) this.classList.add(n); });
|
||||||
|
this.nature = natures.filter(n => lib.nature.has(n)).sort(lib.sort.nature).join(lib.natureSeparator);
|
||||||
|
}
|
||||||
|
else if (this.nature) {
|
||||||
|
this.classList.remove(this.nature);
|
||||||
|
delete this.nature;
|
||||||
|
}
|
||||||
|
if (info.subtype) this.classList.add(info.subtype);
|
||||||
|
this.node.range.innerHTML = '';
|
||||||
|
switch (get.subtype(this, false)) {
|
||||||
|
case 'equip1':
|
||||||
|
var added = false;
|
||||||
|
if (lib.card[this.name] && lib.card[this.name].distance) {
|
||||||
|
var dist = lib.card[this.name].distance;
|
||||||
|
if (dist.attackFrom) {
|
||||||
|
added = true;
|
||||||
|
this.node.range.innerHTML = '范围: ' + (-dist.attackFrom + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!added) {
|
||||||
|
this.node.range.innerHTML = '范围: 1';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'equip3':
|
||||||
|
if (info.distance && info.distance.globalTo) {
|
||||||
|
this.node.range.innerHTML = '防御: ' + info.distance.globalTo;
|
||||||
|
this.node.name2.innerHTML += '+';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'equip4':
|
||||||
|
if (info.distance && info.distance.globalFrom) {
|
||||||
|
this.node.range.innerHTML = '进攻: ' + (-info.distance.globalFrom);
|
||||||
|
this.node.name2.innerHTML += '-';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var tags = [];
|
||||||
|
if (Array.isArray(card[4])) {
|
||||||
|
tags.addArray(card[4]);
|
||||||
|
}
|
||||||
|
if (this.cardid) {
|
||||||
|
if (!_status.cardtag) {
|
||||||
|
_status.cardtag = {};
|
||||||
|
}
|
||||||
|
for (var i in _status.cardtag) {
|
||||||
|
if (_status.cardtag[i].contains(this.cardid)) {
|
||||||
|
tags.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tags.length) {
|
||||||
|
var tagstr = ' <span class="cardtag">';
|
||||||
|
for (var i = 0; i < tags.length; i++) {
|
||||||
|
var tag = tags[i];
|
||||||
|
if (!_status.cardtag[tag]) {
|
||||||
|
_status.cardtag[tag] = [];
|
||||||
|
}
|
||||||
|
_status.cardtag[tag].add(this.cardid);
|
||||||
|
tagstr += lib.translate[tag + '_tag'];
|
||||||
|
//if(i<tags.length-1) tagstr+=' ';
|
||||||
|
}
|
||||||
|
tagstr += '</span>';
|
||||||
|
this.node.range.innerHTML += tagstr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
updateTransform(bool, delay) {
|
||||||
|
if (delay) {
|
||||||
|
var that = this;
|
||||||
|
setTimeout(function () {
|
||||||
|
that.updateTransform(that.classList.contains('selected'));
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (_status.event.player != game.me) return;
|
||||||
|
if (this._transform && this.parentNode && this.parentNode.parentNode &&
|
||||||
|
this.parentNode.parentNode.parentNode == ui.me &&
|
||||||
|
(!_status.mousedown || _status.mouseleft) &&
|
||||||
|
(!this.parentNode.parentNode.classList.contains('scrollh') || (game.layout == 'long2' || game.layout == 'nova'))) {
|
||||||
|
if (bool) {
|
||||||
|
this.style.transform = this._transform + ' translateY(-20px)';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.style.transform = this._transform || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aiexclude() {
|
||||||
|
_status.event._aiexclude.add(this);
|
||||||
|
}
|
||||||
|
//为此牌添加知情者。参数可为数组,若参数为字符串'everyone',则所有玩家均为知情者。
|
||||||
|
addKnower(player) {
|
||||||
|
if (!this._knowers) {
|
||||||
|
this._knowers = [];
|
||||||
|
}
|
||||||
|
if (typeof player == 'string') {
|
||||||
|
this._knowers.add(player);
|
||||||
|
} else {
|
||||||
|
let type = get.itemtype(player);
|
||||||
|
if (type == 'player') {
|
||||||
|
this._knowers.add(player.playerid);
|
||||||
|
} else if (type == 'players') {
|
||||||
|
player.forEach(p => this._knowers.add(p.playerid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeKnower(player) {
|
||||||
|
if (!this._knowers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof player == 'string') {
|
||||||
|
this._knowers.remove(player);
|
||||||
|
} else {
|
||||||
|
let type = get.itemtype(player);
|
||||||
|
if (type == 'player') {
|
||||||
|
this._knowers.remove(player.playerid);
|
||||||
|
} else if (type == 'players') {
|
||||||
|
player.forEach(p => this._knowers.remove(p.playerid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//清除此牌的知情者。
|
||||||
|
clearKnowers() {
|
||||||
|
if (this._knowers) delete this._knowers;
|
||||||
|
}
|
||||||
|
//判断玩家对此牌是否知情。
|
||||||
|
isKnownBy(player) {
|
||||||
|
if (['e', 'j'].includes(get.position(this))) return true;//装备区或者判定区的牌,必知情。
|
||||||
|
let owner = get.owner(this);
|
||||||
|
if (owner) {
|
||||||
|
if (owner == player) return true;//是牌主,必知情。
|
||||||
|
if (player.hasSkillTag('viewHandcard', null, owner, true)) return true;//有viewHandcard标签,必知情。
|
||||||
|
if (owner.isUnderControl(true, player)) return true;//被操控,必知情。
|
||||||
|
}
|
||||||
|
if (get.is.shownCard(this)) return true;//此牌是明置牌,必知情。
|
||||||
|
if (this._knowers) {
|
||||||
|
return this._knowers.includes('everyone') || this._knowers.includes(player.playerid);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
getSource(name) {
|
||||||
|
if (this.name == name) return true;
|
||||||
|
var info = lib.card[this.name];
|
||||||
|
if (info && Array.isArray(info.source)) {
|
||||||
|
return info.source.contains(name);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
moveDelete(player) {
|
||||||
|
this.fixed = true;
|
||||||
|
if (!this._listeningEnd || this._transitionEnded) {
|
||||||
|
this.moveTo(player);
|
||||||
|
var that = this;
|
||||||
|
setTimeout(function () {
|
||||||
|
that.delete();
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._onEndMoveDelete = player;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moveTo(player) {
|
||||||
|
this.fixed = true;
|
||||||
|
var dx, dy;
|
||||||
|
if (this.classList.contains('center')) {
|
||||||
|
var nx = [50, -52];
|
||||||
|
var ny = [50, -52];
|
||||||
|
nx = nx[0] * ui.arena.offsetWidth / 100 + nx[1];
|
||||||
|
ny = ny[0] * ui.arena.offsetHeight / 100 + ny[1];
|
||||||
|
dx = player.getLeft() + player.offsetWidth / 2 - 52 - nx;
|
||||||
|
dy = player.getTop() + player.offsetHeight / 2 - 52 - ny;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.style.left = this.offsetLeft + 'px';
|
||||||
|
this.style.top = this.offsetTop + 'px';
|
||||||
|
|
||||||
|
dx = player.getLeft() + player.offsetWidth / 2 - 52 - this.offsetLeft;
|
||||||
|
dy = player.getTop() + player.offsetHeight / 2 - 52 - this.offsetTop;
|
||||||
|
}
|
||||||
|
if (get.is.mobileMe(player)) {
|
||||||
|
dx += get.cardOffset();
|
||||||
|
if (ui.arena.classList.contains('oblongcard')) {
|
||||||
|
dy -= 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this.style.transform && this.style.transform != 'none' && this.style.transform.indexOf('translate') == -1) {
|
||||||
|
this.style.transform += ' translate(' + dx + 'px,' + dy + 'px)';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.style.transform = 'translate(' + dx + 'px,' + dy + 'px)';
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
copy() {
|
||||||
|
/**
|
||||||
|
* @type {Card}
|
||||||
|
*/
|
||||||
|
var node = this.cloneNode(true);
|
||||||
|
node.style.transform = '';
|
||||||
|
node.name = this.name;
|
||||||
|
node.suit = this.suit;
|
||||||
|
node.number = this.number;
|
||||||
|
node.nature = this.nature;
|
||||||
|
node.classList.remove('hidden');
|
||||||
|
node.classList.remove('start');
|
||||||
|
node.classList.remove('thrown');
|
||||||
|
node.classList.remove('selectable');
|
||||||
|
node.classList.remove('selected');
|
||||||
|
node.classList.remove('removing');
|
||||||
|
node.classList.remove('drawinghidden');
|
||||||
|
node.classList.remove('glows');
|
||||||
|
node.node = {
|
||||||
|
name: node.querySelector('.name'),
|
||||||
|
info: node.querySelector('.info'),
|
||||||
|
intro: node.querySelector('.intro'),
|
||||||
|
background: node.querySelector('.background'),
|
||||||
|
image: node.querySelector('.image'),
|
||||||
|
gaintag: node.querySelector('.gaintag'),
|
||||||
|
};
|
||||||
|
node.node.gaintag.innerHTML = '';
|
||||||
|
var clone = true;
|
||||||
|
var position;
|
||||||
|
for (var i = 0; i < arguments.length; i++) {
|
||||||
|
if (typeof arguments[i] == 'string') node.classList.add(arguments[i]);
|
||||||
|
else if (['div', 'fragment'].includes(get.objtype(arguments[i]))) position = arguments[i];
|
||||||
|
else if (typeof arguments[i] == 'boolean') clone = arguments[i];
|
||||||
|
}
|
||||||
|
node.moveTo = lib.element.Card.prototype.moveTo;
|
||||||
|
node.moveDelete = lib.element.Card.prototype.moveDelete;
|
||||||
|
if (clone) this.clone = node;
|
||||||
|
if (position) position.appendChild(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
uncheck(skill) {
|
||||||
|
if (skill) this._uncheck.add(skill);
|
||||||
|
this.classList.add('uncheck');
|
||||||
|
}
|
||||||
|
recheck(skill) {
|
||||||
|
if (skill) this._uncheck.remove(skill);
|
||||||
|
else this._uncheck.length = 0;
|
||||||
|
if (this._uncheck.length == 0) this.classList.remove('uncheck');
|
||||||
|
}
|
||||||
|
discard(bool) {
|
||||||
|
if (!this._selfDestroyed) {
|
||||||
|
this.fix();
|
||||||
|
ui.discardPile.appendChild(this);
|
||||||
|
}
|
||||||
|
this.classList.remove('glow');
|
||||||
|
if (bool === false) {
|
||||||
|
ui.cardPile.insertBefore(this, ui.cardPile.childNodes[Math.floor(Math.random() * ui.cardPile.childNodes.length)]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (_status.discarded) {
|
||||||
|
_status.discarded.add(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hasTag(tag) {
|
||||||
|
if (this.cardid && _status.cardtag && _status.cardtag[tag] && _status.cardtag[tag].contains(this.cardid)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
hasPosition() {
|
||||||
|
return ['h', 'e', 'j', 's', 'x'].contains(get.position(this));
|
||||||
|
}
|
||||||
|
isInPile() {
|
||||||
|
return ['c', 'd'].contains(get.position(this));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { AI as ai } from '../../ai/index.js';
|
||||||
|
import { Get as get } from '../../get/index.js';
|
||||||
|
import { Game as game } from '../../game/index.js';
|
||||||
|
import { Library as lib } from "../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';
|
||||||
|
|
||||||
|
export class Client {
|
||||||
|
/**
|
||||||
|
* @param {import('../index.js').NodeWS | InstanceType<typeof import('ws').WebSocket>} ws
|
||||||
|
*/
|
||||||
|
constructor(ws) {
|
||||||
|
this.ws = ws;
|
||||||
|
/**
|
||||||
|
* @type { string }
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.id = ws.wsid || get.id();
|
||||||
|
this.closed = false;
|
||||||
|
}
|
||||||
|
send() {
|
||||||
|
if (this.closed) return this;
|
||||||
|
var args = Array.from(arguments);
|
||||||
|
if (typeof args[0] == 'function') {
|
||||||
|
args.unshift('exec');
|
||||||
|
}
|
||||||
|
for (var i = 1; i < args.length; i++) {
|
||||||
|
args[i] = get.stringifiedResult(args[i]);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.ws.send(JSON.stringify(args));
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this.ws.close();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
lib.node.clients.remove(this);
|
||||||
|
lib.node.observing.remove(this);
|
||||||
|
if (ui.removeObserve && !lib.node.observing.length) {
|
||||||
|
ui.removeObserve.remove();
|
||||||
|
delete ui.removeObserve;
|
||||||
|
}
|
||||||
|
this.closed = true;
|
||||||
|
if (_status.waitingForPlayer) {
|
||||||
|
for (var i = 0; i < game.connectPlayers.length; i++) {
|
||||||
|
if (game.connectPlayers[i].playerid == this.id) {
|
||||||
|
game.connectPlayers[i].uninitOL();
|
||||||
|
delete game.connectPlayers[i].playerid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (game.onlinezhu == this.id) {
|
||||||
|
game.onlinezhu = null;
|
||||||
|
}
|
||||||
|
game.updateWaiting();
|
||||||
|
}
|
||||||
|
else if (lib.playerOL[this.id]) {
|
||||||
|
var player = lib.playerOL[this.id];
|
||||||
|
player.setNickname(player.nickname + ' - 离线');
|
||||||
|
// @ts-ignore
|
||||||
|
game.broadcast(function (player) {
|
||||||
|
player.setNickname(player.nickname + ' - 离线');
|
||||||
|
}, player);
|
||||||
|
player.unwait('ai');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.isNonameServer) {
|
||||||
|
// @ts-ignore
|
||||||
|
document.querySelector('#server_count').innerHTML = lib.node.clients.length;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ 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 default {
|
export const Content = {
|
||||||
emptyEvent: async (event) => {
|
emptyEvent: async (event) => {
|
||||||
event.trigger(event.name);
|
event.trigger(event.name);
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,7 +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 default {
|
export const Contents = {
|
||||||
phase: [
|
phase: [
|
||||||
async (event, _trigger, player) => {
|
async (event, _trigger, player) => {
|
||||||
// 初始化阶段列表
|
// 初始化阶段列表
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
import { AI as ai } from '../../ai/index.js';
|
||||||
|
import { Get as get } from '../../get/index.js';
|
||||||
|
import { Game as game } from '../../game/index.js';
|
||||||
|
import { Library as lib } from "../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';
|
||||||
|
|
||||||
|
export class Control extends HTMLDivElement {
|
||||||
|
// @ts-ignore
|
||||||
|
constructor() {
|
||||||
|
const nc = !ui.control.querySelector('div:not(.removing):not(.stayleft)');
|
||||||
|
const controls = Array.isArray(arguments[0]) ? arguments[0] : Array.from(arguments);
|
||||||
|
/**
|
||||||
|
* @type {this}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
const control = ui.create.div('.control');
|
||||||
|
Object.setPrototypeOf(control, Control.prototype);
|
||||||
|
ui.control.insertBefore(control, _status.createControl || ui.confirm);
|
||||||
|
controls.forEach(argument => {
|
||||||
|
if (argument == 'nozoom') return;
|
||||||
|
if (typeof argument == 'function') control.custom = argument;
|
||||||
|
else if (argument == 'stayleft') {
|
||||||
|
control.stayleft = true;
|
||||||
|
control.classList.add('stayleft');
|
||||||
|
}
|
||||||
|
else control.add(argument);
|
||||||
|
});
|
||||||
|
ui.controls.unshift(control);
|
||||||
|
if (nc) ui.control.animate('nozoom', 100);
|
||||||
|
if (control.childNodes.length) {
|
||||||
|
control.style.transition = 'opacity 0.5s';
|
||||||
|
control.animate('controlpressdownx', 500);
|
||||||
|
ui.refresh(control);
|
||||||
|
if (!control.stayleft) control.style.transform = `translateX(-${control.offsetWidth / 2}px)`;
|
||||||
|
control.style.opacity = 1;
|
||||||
|
ui.refresh(control);
|
||||||
|
control.style.transition = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
control.addEventListener(lib.config.touchscreen ? 'touchend' : 'click', ui.click.control2);
|
||||||
|
|
||||||
|
if (lib.config.button_press) {
|
||||||
|
control.addEventListener(lib.config.touchscreen ? 'touchstart' : 'mousedown', function () {
|
||||||
|
if (this.classList.contains('disabled')) return;
|
||||||
|
this.classList.add('controlpressdown');
|
||||||
|
if (typeof this._offset == 'number') this.style.transform = `translateX(${this._offset}px) scale(0.97)`;
|
||||||
|
});
|
||||||
|
control.addEventListener(lib.config.touchscreen ? 'touchend' : 'mouseup', function () {
|
||||||
|
this.classList.remove('controlpressdown');
|
||||||
|
if (typeof this._offset == 'number') this.style.transform = `translateX(${this._offset}px)`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.updatec();
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
open() {
|
||||||
|
ui.control.insertBefore(this, _status.createControl || ui.confirm);
|
||||||
|
ui.controls.unshift(this);
|
||||||
|
if (this.childNodes.length) {
|
||||||
|
this.style.transition = 'opacity 0.5s';
|
||||||
|
ui.refresh(this);
|
||||||
|
this.style.transform = 'translateX(-' + (this.offsetWidth / 2) + 'px)';
|
||||||
|
this.style.opacity = 1;
|
||||||
|
ui.refresh(this);
|
||||||
|
this.style.transition = '';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.animate('controlpressdownx', 500);
|
||||||
|
}
|
||||||
|
ui.updatec();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
add(item) {
|
||||||
|
var node = document.createElement('div');
|
||||||
|
this.appendChild(node);
|
||||||
|
node.link = item;
|
||||||
|
node.innerHTML = get.translation(item);
|
||||||
|
node.addEventListener(lib.config.touchscreen ? 'touchend' : 'click', ui.click.control);
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
this.animate('controlpressdownx', 500);
|
||||||
|
|
||||||
|
ui.controls.remove(this);
|
||||||
|
this.delete();
|
||||||
|
|
||||||
|
setTimeout(ui.updatec, 100);
|
||||||
|
|
||||||
|
|
||||||
|
if (ui.confirm == this) delete ui.confirm;
|
||||||
|
if (ui.skills == this) delete ui.skills;
|
||||||
|
if (ui.skills2 == this) delete ui.skills2;
|
||||||
|
if (ui.skills3 == this) delete ui.skills3;
|
||||||
|
}
|
||||||
|
replace() {
|
||||||
|
// this.animate('controlpressdownx',500);
|
||||||
|
if (this.replaceTransition === false) {
|
||||||
|
this.style.transitionProperty = 'none';
|
||||||
|
ui.refresh(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (this.childNodes.length) this.firstChild.remove();
|
||||||
|
var i, controls;
|
||||||
|
if (Array.isArray(arguments[0])) controls = arguments[0];
|
||||||
|
else controls = arguments;
|
||||||
|
delete this.custom;
|
||||||
|
for (i = 0; i < controls.length; i++) {
|
||||||
|
if (typeof controls[i] == 'function') {
|
||||||
|
this.custom = controls[i];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.add(controls[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.childNodes.length) {
|
||||||
|
var width = 0;
|
||||||
|
for (i = 0; i < this.childNodes.length; i++) width += this.childNodes[i].offsetWidth;
|
||||||
|
ui.refresh(this);
|
||||||
|
this.style.width = width + 'px';
|
||||||
|
}
|
||||||
|
ui.updatec();
|
||||||
|
if (this.replaceTransition === false) {
|
||||||
|
var that = this;
|
||||||
|
setTimeout(function () {
|
||||||
|
that.style.transitionProperty = '';
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
import { AI as ai } from '../../ai/index.js';
|
||||||
|
import { Get as get } from '../../get/index.js';
|
||||||
|
import { Game as game } from '../../game/index.js';
|
||||||
|
import { Library as lib } from "../index.js";
|
||||||
|
import { status as _status } from '../../status/index.js';
|
||||||
|
import { UI as ui } from '../../ui/index.js';
|
||||||
|
|
||||||
|
export class Dialog extends HTMLDivElement {
|
||||||
|
// @ts-ignore
|
||||||
|
constructor() {
|
||||||
|
let hidden = false;
|
||||||
|
let noTouchScroll = false;
|
||||||
|
let forceButton = false;
|
||||||
|
let noForceButton = false;
|
||||||
|
/** @type {this} */
|
||||||
|
// @ts-ignore
|
||||||
|
const dialog = ui.create.div('.dialog');
|
||||||
|
Object.setPrototypeOf(dialog, Dialog.prototype);
|
||||||
|
dialog.contentContainer = ui.create.div('.content-container', dialog);
|
||||||
|
dialog.content = ui.create.div('.content', dialog.contentContainer);
|
||||||
|
dialog.bar1 = ui.create.div('.bar.top', dialog);
|
||||||
|
dialog.bar2 = ui.create.div('.bar.bottom', dialog);
|
||||||
|
dialog.buttons = [];
|
||||||
|
Array.from(arguments).forEach(argument => {
|
||||||
|
if (typeof argument == 'boolean') dialog.static = argument;
|
||||||
|
else if (argument == 'hidden') hidden = true;
|
||||||
|
else if (argument == 'notouchscroll') noTouchScroll = true;
|
||||||
|
else if (argument == 'forcebutton') forceButton = true;
|
||||||
|
else if (argument == 'noforcebutton') noForceButton = true;
|
||||||
|
else dialog.add(argument);
|
||||||
|
});
|
||||||
|
if (!hidden) dialog.open();
|
||||||
|
if (!lib.config.touchscreen) dialog.contentContainer.onscroll = ui.update;
|
||||||
|
if (!noTouchScroll) {
|
||||||
|
dialog.contentContainer.ontouchstart = ui.click.dialogtouchStart;
|
||||||
|
dialog.contentContainer.ontouchmove = ui.click.touchScroll;
|
||||||
|
dialog.contentContainer.style.webkitOverflowScrolling = 'touch';
|
||||||
|
dialog.ontouchstart = ui.click.dragtouchdialog;
|
||||||
|
}
|
||||||
|
if (noForceButton) dialog.noforcebutton = true;
|
||||||
|
else if (forceButton) {
|
||||||
|
dialog.forcebutton = true;
|
||||||
|
dialog.classList.add('forcebutton');
|
||||||
|
}
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
add(item, noclick, zoom) {
|
||||||
|
if (typeof item == 'string') {
|
||||||
|
if (item.startsWith('###')) {
|
||||||
|
var items = item.slice(3).split('###');
|
||||||
|
this.add(items[0], noclick, zoom);
|
||||||
|
this.addText(items[1], items[1].length <= 20, zoom);
|
||||||
|
}
|
||||||
|
else if (noclick) {
|
||||||
|
var strstr = item;
|
||||||
|
item = ui.create.div('', this.content);
|
||||||
|
item.innerHTML = strstr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item = ui.create.caption(item, this.content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (['div', 'fragment'].includes(get.objtype(item))) {
|
||||||
|
this.content.appendChild(item);
|
||||||
|
}
|
||||||
|
else if (get.itemtype(item) == 'cards') {
|
||||||
|
var buttons = ui.create.div('.buttons', this.content);
|
||||||
|
if (zoom) buttons.classList.add('smallzoom');
|
||||||
|
this.buttons = this.buttons.concat(ui.create.buttons(item, 'card', buttons, noclick));
|
||||||
|
}
|
||||||
|
else if (get.itemtype(item) == 'players') {
|
||||||
|
var buttons = ui.create.div('.buttons', this.content);
|
||||||
|
if (zoom) buttons.classList.add('smallzoom');
|
||||||
|
this.buttons = this.buttons.concat(ui.create.buttons(item, 'player', buttons, noclick));
|
||||||
|
}
|
||||||
|
else if (item[1] == 'textbutton') {
|
||||||
|
ui.create.textbuttons(item[0], this, noclick);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var buttons = ui.create.div('.buttons', this.content);
|
||||||
|
if (zoom) buttons.classList.add('smallzoom');
|
||||||
|
this.buttons = this.buttons.concat(ui.create.buttons(item[0], item[1], buttons, noclick));
|
||||||
|
}
|
||||||
|
if (this.buttons.length) {
|
||||||
|
if (this.forcebutton !== false) this.forcebutton = true;
|
||||||
|
if (this.buttons.length > 3 || (zoom && this.buttons.length > 5)) {
|
||||||
|
this.classList.remove('forcebutton-auto');
|
||||||
|
}
|
||||||
|
else if (!this.noforcebutton) {
|
||||||
|
this.classList.add('forcebutton-auto');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.update();
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
addText(str, center) {
|
||||||
|
if (str && str.startsWith('<div')) this.add(str);
|
||||||
|
else if (center !== false) {
|
||||||
|
this.add('<div class="text center">' + str + '</div>');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.add('<div class="text">' + str + '</div>');
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
addSmall(item, noclick) {
|
||||||
|
return this.add(item, noclick, true);
|
||||||
|
}
|
||||||
|
addAuto(content) {
|
||||||
|
if (content && content.length > 4 && !this._hovercustomed) {
|
||||||
|
this.addSmall(content);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.add(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
open() {
|
||||||
|
if (this.noopen) return;
|
||||||
|
for (var i = 0; i < ui.dialogs.length; i++) {
|
||||||
|
if (ui.dialogs[i] == this) {
|
||||||
|
this.show();
|
||||||
|
this.refocus();
|
||||||
|
ui.dialogs.remove(this);
|
||||||
|
ui.dialogs.unshift(this);
|
||||||
|
ui.update();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if (ui.dialogs[i].static) ui.dialogs[i].unfocus();
|
||||||
|
else ui.dialogs[i].hide();
|
||||||
|
}
|
||||||
|
ui.dialog = this;
|
||||||
|
var translate;
|
||||||
|
if (lib.config.remember_dialog && lib.config.dialog_transform && !this.classList.contains('fixed')) {
|
||||||
|
translate = lib.config.dialog_transform;
|
||||||
|
this._dragtransform = translate;
|
||||||
|
this.style.transform = 'translate(' + translate[0] + 'px,' + translate[1] + 'px) scale(0.8)';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.style.transform = 'scale(0.8)';
|
||||||
|
}
|
||||||
|
this.style.transitionProperty = 'opacity,transform';
|
||||||
|
this.style.opacity = 0;
|
||||||
|
ui.arena.appendChild(this);
|
||||||
|
ui.dialogs.unshift(this);
|
||||||
|
ui.update();
|
||||||
|
ui.refresh(this);
|
||||||
|
if (lib.config.remember_dialog && lib.config.dialog_transform && !this.classList.contains('fixed')) {
|
||||||
|
this.style.transform = 'translate(' + translate[0] + 'px,' + translate[1] + 'px) scale(1)';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.style.transform = 'scale(1)';
|
||||||
|
}
|
||||||
|
this.style.opacity = 1;
|
||||||
|
var that = this;
|
||||||
|
setTimeout(function () {
|
||||||
|
that.style.transitionProperty = '';
|
||||||
|
}, 500);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
ui.dialogs.remove(this);
|
||||||
|
this.delete();
|
||||||
|
if (ui.dialogs.length > 0) {
|
||||||
|
ui.dialog = ui.dialogs[0];
|
||||||
|
ui.dialog.show();
|
||||||
|
ui.dialog.refocus();
|
||||||
|
ui.update();
|
||||||
|
}
|
||||||
|
// if(ui.arenalog){
|
||||||
|
// ui.arenalog.classList.remove('withdialog');
|
||||||
|
// }
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
setCaption(str) {
|
||||||
|
this.querySelector('.caption').innerHTML = str;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,855 @@
|
||||||
|
import { AI as ai } from '../../ai/index.js';
|
||||||
|
import { Get as get } from '../../get/index.js';
|
||||||
|
import { Game as game } from '../../game/index.js';
|
||||||
|
import { Library as lib } from "../index.js";
|
||||||
|
import { status as _status } from '../../status/index.js';
|
||||||
|
import { UI as ui } from '../../ui/index.js';
|
||||||
|
import { AsyncFunction } from '../../util/index.js';
|
||||||
|
|
||||||
|
export class GameEvent {
|
||||||
|
/** @type { import('./gameEventPromise.js').default } */
|
||||||
|
#promise;
|
||||||
|
/**
|
||||||
|
* @param {string} [name]
|
||||||
|
* @param {false} [trigger]
|
||||||
|
*/
|
||||||
|
constructor(name, trigger) {
|
||||||
|
if (typeof name == 'string') {
|
||||||
|
this.name = name;
|
||||||
|
const gameEvent = get.event();
|
||||||
|
if (gameEvent) {
|
||||||
|
const type = `onNext${name[0].toUpperCase()}${name.slice(1)}`;
|
||||||
|
if (gameEvent.hasHandler(type)) this.pushHandler(...gameEvent.getHandler(type));
|
||||||
|
}
|
||||||
|
game.globalEventHandlers.addHandlerToEvent(this);
|
||||||
|
}
|
||||||
|
this.step = 0;
|
||||||
|
this.finished = false;
|
||||||
|
/**
|
||||||
|
* @type {(import('./GameEventPromise.js').default)[]}
|
||||||
|
*/
|
||||||
|
this.next = [];
|
||||||
|
/**
|
||||||
|
* @type {(import('./GameEventPromise.js').default)[]}
|
||||||
|
*/
|
||||||
|
this.after = [];
|
||||||
|
this.custom = {
|
||||||
|
add: {},
|
||||||
|
replace: {}
|
||||||
|
};
|
||||||
|
this._aiexclude = [];
|
||||||
|
this._notrigger = [];
|
||||||
|
this._result = {};
|
||||||
|
this._set = [];
|
||||||
|
/**
|
||||||
|
* @type {boolean} 这个事件是否使用异步函数处理
|
||||||
|
**/
|
||||||
|
this.async = false;
|
||||||
|
/**
|
||||||
|
* @type {null|(event: GameEvent)=>any} 这个异步事件对应Promise的resolve函数
|
||||||
|
**/
|
||||||
|
this.resolve = null;
|
||||||
|
if (trigger !== false && !game.online) this._triggered = 0;
|
||||||
|
}
|
||||||
|
static initialGameEvent() {
|
||||||
|
return new GameEvent().finish().toPromise();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {keyof this} key
|
||||||
|
* @param {number} [value]
|
||||||
|
* @param {number} [baseValue]
|
||||||
|
*/
|
||||||
|
addNumber(key, value, baseValue) {
|
||||||
|
if (typeof value != 'number') value = 0;
|
||||||
|
if (typeof this[key] == 'number') this[key] += value;
|
||||||
|
else {
|
||||||
|
if (typeof baseValue != 'number') baseValue = 0;
|
||||||
|
this[key] = baseValue + value;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {keyof this} key
|
||||||
|
* @param {number} [baseValue]
|
||||||
|
*/
|
||||||
|
decrease(key, baseValue) {
|
||||||
|
if (typeof this[key] == 'number') this[key]--;
|
||||||
|
else this.subtractNumber(key, 1, baseValue);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {keyof this} key
|
||||||
|
* @param {number} [baseValue]
|
||||||
|
*/
|
||||||
|
increase(key, baseValue) {
|
||||||
|
if (typeof this[key] == 'number') this[key]++;
|
||||||
|
else this.addNumber(key, 1, baseValue);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {keyof this} key
|
||||||
|
* @param {number} [value]
|
||||||
|
* @param {number} [baseValue]
|
||||||
|
*/
|
||||||
|
subtractNumber(key, value, baseValue) {
|
||||||
|
if (typeof value != 'number') value = 0;
|
||||||
|
if (typeof this[key] == 'number') this[key] -= value;
|
||||||
|
else {
|
||||||
|
if (typeof baseValue != 'number') baseValue = 0;
|
||||||
|
this[key] = baseValue - value;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {Parameters<typeof this.hasHandler>[0]} type
|
||||||
|
* @param {GameEvent} event
|
||||||
|
* @param {{
|
||||||
|
* state?: 'begin' | 'end';
|
||||||
|
* }} option
|
||||||
|
* @returns {this}
|
||||||
|
*/
|
||||||
|
callHandler(type, event, option) {
|
||||||
|
if (this.hasHandler(type)) this.getHandler(type).forEach(handler => {
|
||||||
|
if (typeof handler == 'function') handler(event, option);
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
getDefaultHandlerType() {
|
||||||
|
const eventName = this.name;
|
||||||
|
if (eventName) return `on${eventName[0].toUpperCase()}${eventName.slice(1)}`;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {Parameters<typeof this.hasHandler>[0]} [type]
|
||||||
|
* @returns {((event: GameEvent, option: {
|
||||||
|
* state?: 'begin' | 'end';
|
||||||
|
* }) => void)[]}
|
||||||
|
*/
|
||||||
|
getHandler(type) {
|
||||||
|
if (!type) type = this.getDefaultHandlerType();
|
||||||
|
const currentHandler = this[type];
|
||||||
|
if (!currentHandler) this[type] = [];
|
||||||
|
else if (!Array.isArray(currentHandler)) this[type] = [currentHandler];
|
||||||
|
return this[type];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {`on${Capitalize<string>}`} [type]
|
||||||
|
*/
|
||||||
|
hasHandler(type) {
|
||||||
|
if (!type) type = this.getDefaultHandlerType();
|
||||||
|
return Boolean(this[type] && this.getHandler(type).length);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @overload
|
||||||
|
* @param {...((event: GameEvent, option: {
|
||||||
|
* state?: 'begin' | 'end';
|
||||||
|
* }) => void)[]} handlers
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @overload
|
||||||
|
* @param {Parameters<typeof this.hasHandler>[0]} type
|
||||||
|
* @param {...((event: GameEvent, option: {
|
||||||
|
* state?: 'begin' | 'end';
|
||||||
|
* }) => void)[]} handlers
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
pushHandler(type) {
|
||||||
|
return typeof type == 'string' ? this.getHandler(type).push(...Array.from(arguments).slice(1)) : this.getHandler().push(...arguments);
|
||||||
|
}
|
||||||
|
changeToZero() {
|
||||||
|
this.num = 0;
|
||||||
|
this.numFixed = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
finish() {
|
||||||
|
this.finished = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
putStepCache(key, value) {
|
||||||
|
if (!this._stepCache) {
|
||||||
|
this._stepCache = {};
|
||||||
|
}
|
||||||
|
this._stepCache[key] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
getStepCache(key) {
|
||||||
|
if (!this._stepCache) return undefined;
|
||||||
|
return this._stepCache[key];
|
||||||
|
}
|
||||||
|
clearStepCache(key) {
|
||||||
|
if (key !== undefined && key !== null) {
|
||||||
|
delete this._stepCache[key];
|
||||||
|
}
|
||||||
|
delete this._stepCache;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
callFuncUseStepCache(prefix, func, params) {
|
||||||
|
if (typeof func != 'function') return;
|
||||||
|
if (_status.closeStepCache) return func.apply(null, params);
|
||||||
|
var cacheKey = "[" + prefix + "]" + get.paramToCacheKey.apply(null, params);
|
||||||
|
var ret = this.getStepCache(cacheKey);
|
||||||
|
if (ret === undefined || ret === null) {
|
||||||
|
ret = func.apply(null, params);
|
||||||
|
this.putStepCache(cacheKey, ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
putTempCache(key1, key2, value) {
|
||||||
|
if (!this._tempCache) {
|
||||||
|
this._tempCache = {};
|
||||||
|
}
|
||||||
|
if (!this._tempCache[key1]) {
|
||||||
|
this._tempCache[key1] = {};
|
||||||
|
}
|
||||||
|
this._tempCache[key1][key2] = value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
getTempCache(key1, key2) {
|
||||||
|
if (!this._tempCache) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (!this._tempCache[key1]) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return this._tempCache[key1][key2];
|
||||||
|
}
|
||||||
|
cancel(arg1, arg2, notrigger) {
|
||||||
|
this.untrigger(arg1, arg2);
|
||||||
|
this.finish();
|
||||||
|
if (notrigger != 'notrigger') {
|
||||||
|
this.trigger(this.name + 'Cancelled');
|
||||||
|
if (this.player && lib.phaseName.contains(this.name)) this.player.getHistory('skipped').add(this.name);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
neutralize(event) {
|
||||||
|
this.untrigger();
|
||||||
|
this.finish();
|
||||||
|
this._neutralized = true;
|
||||||
|
this.trigger('eventNeutralized');
|
||||||
|
this._neutralize_event = event || _status.event;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
unneutralize() {
|
||||||
|
this.untrigger();
|
||||||
|
delete this._neutralized;
|
||||||
|
delete this.finished;
|
||||||
|
if (this.type == 'card' && this.card && this.name == 'sha') this.directHit = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
goto(step) {
|
||||||
|
this.step = step - 1;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
redo() {
|
||||||
|
this.step--;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
setHiddenSkill(skill) {
|
||||||
|
if (!this.player) return this;
|
||||||
|
var hidden = this.player.hiddenSkills.slice(0);
|
||||||
|
game.expandSkills(hidden);
|
||||||
|
if (hidden.contains(skill)) this.set('hsskill', skill);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
set(key, value) {
|
||||||
|
if (arguments.length == 1 && Array.isArray(arguments[0])) {
|
||||||
|
for (var i = 0; i < arguments[0].length; i++) {
|
||||||
|
if (Array.isArray(arguments[0][i])) {
|
||||||
|
this.set(arguments[0][i][0], arguments[0][i][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (typeof key != 'string') {
|
||||||
|
console.log('warning: using non-string object as event key');
|
||||||
|
console.log(key, value);
|
||||||
|
console.log(_status.event);
|
||||||
|
}
|
||||||
|
this[key] = value;
|
||||||
|
this._set.push([key, value]);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {ArrayLike<Function> | Function | keyof typeof lib.element.content} item
|
||||||
|
*/
|
||||||
|
setContent(item) {
|
||||||
|
switch (typeof item) {
|
||||||
|
case "object":
|
||||||
|
case "function":
|
||||||
|
if (item instanceof AsyncFunction) {
|
||||||
|
this.content = item;
|
||||||
|
}
|
||||||
|
else this.content = lib.init.parsex(item);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
try {
|
||||||
|
if (!(lib.element.content[item] instanceof AsyncFunction) && !lib.element.content[item]._parsed) {
|
||||||
|
lib.element.content[item] = lib.init.parsex(lib.element.content[item]);
|
||||||
|
lib.element.content[item]._parsed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
throw new Error(`Content ${item} may not exist.\nlib.element.content[${item}] = ${lib.element.content[item]}`);
|
||||||
|
}
|
||||||
|
this.content = lib.element.content[item];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {import("../util/index.js").AsyncFunction[] | keyof typeof lib.element.contents} contents
|
||||||
|
* @returns {GameEvent}
|
||||||
|
*/
|
||||||
|
setContents(contents) {
|
||||||
|
if (Array.isArray(contents)) this.contents = contents;
|
||||||
|
else if (contents in lib.element.contents) return this.setContents(lib.element.contents[contents]);
|
||||||
|
else throw new Error('not supported value.');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogv() {
|
||||||
|
for (var i = 1; i <= 3; i++) {
|
||||||
|
var event = this.getParent(i);
|
||||||
|
if (event && event.logvid) return event.logvid;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
send() {
|
||||||
|
this.player.send(function (name, args, set, event, skills) {
|
||||||
|
game.me.applySkills(skills);
|
||||||
|
var next = game.me[name].apply(game.me, args);
|
||||||
|
for (var i = 0; i < set.length; i++) {
|
||||||
|
next.set(set[i][0], set[i][1]);
|
||||||
|
}
|
||||||
|
if (next._backupevent) {
|
||||||
|
next.backup(next._backupevent);
|
||||||
|
}
|
||||||
|
next._modparent = event;
|
||||||
|
game.resume();
|
||||||
|
}, this.name, this._args || [], this._set,
|
||||||
|
get.stringifiedResult(this.parent), get.skillState(this.player));
|
||||||
|
this.player.wait();
|
||||||
|
game.pause();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
resume() {
|
||||||
|
delete this._cardChoice;
|
||||||
|
delete this._targetChoice;
|
||||||
|
delete this._skillChoice;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取事件的父节点。
|
||||||
|
* 获取事件链上的指定事件。
|
||||||
|
* 默认获取上一个父节点(核心)。
|
||||||
|
* @param {number|string|(evt:gameEvent)=>boolean} [level=1] 获取深度(number)/指定名字(string)/指定特征(function)
|
||||||
|
* @param {boolean} [forced] 若获取不到节点,默认返回{},若forced为true则返回null
|
||||||
|
* @param {boolean} [includeSelf] 若level不是数字,指定搜索时是否包含事件本身
|
||||||
|
* @returns {GameEvent|{}|null}
|
||||||
|
*/
|
||||||
|
getParent(level = 1, forced, includeSelf) {
|
||||||
|
let event = this;
|
||||||
|
const toreturn = forced ? null : {};
|
||||||
|
if (!includeSelf || typeof level === 'number') {
|
||||||
|
if (event._modparent && game.online) event = event._modparent;
|
||||||
|
else event = this.parent;
|
||||||
|
}
|
||||||
|
if (typeof level === 'number') {
|
||||||
|
for (let i = 1; i < level; i++) {
|
||||||
|
if (!event) return toreturn;
|
||||||
|
event = event.parent;
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
const historys = [];
|
||||||
|
const filter = typeof level === 'function' ? level : evt => evt.name === level;
|
||||||
|
while (true) {
|
||||||
|
if (!event) return toreturn;
|
||||||
|
historys.push(event);
|
||||||
|
if (filter(event)) return event;
|
||||||
|
event = event.parent;
|
||||||
|
if (historys.includes(event)) return toreturn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getTrigger() {
|
||||||
|
return this.getParent('arrangeTrigger')._trigger;
|
||||||
|
}
|
||||||
|
getRand(name) {
|
||||||
|
if (name) {
|
||||||
|
if (!this._rand_map) this._rand_map = {};
|
||||||
|
if (!this._rand_map[name]) this._rand_map[name] = Math.random();
|
||||||
|
return this._rand_map[name];
|
||||||
|
}
|
||||||
|
if (!this._rand) this._rand = Math.random();
|
||||||
|
return this._rand;
|
||||||
|
}
|
||||||
|
insert(content, map) {
|
||||||
|
const next = (new lib.element.GameEvent(`${this.name}Inserted`, false)).toPromise();
|
||||||
|
this.next.push(next);
|
||||||
|
next.setContent(content);
|
||||||
|
Object.entries(map).forEach(entry => next.set(entry[0], entry[1]));
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
insertAfter(content, map) {
|
||||||
|
const next = (new lib.element.GameEvent(`${this.name}Inserted`, false)).toPromise();
|
||||||
|
this.after.push(next);
|
||||||
|
next.setContent(content);
|
||||||
|
Object.entries(map).forEach(entry => next.set(entry[0], entry[1]));
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
backup(skill) {
|
||||||
|
this._backup = {
|
||||||
|
filterButton: this.filterButton,
|
||||||
|
selectButton: this.selectButton,
|
||||||
|
filterTarget: this.filterTarget,
|
||||||
|
selectTarget: this.selectTarget,
|
||||||
|
filterCard: this.filterCard,
|
||||||
|
selectCard: this.selectCard,
|
||||||
|
position: this.position,
|
||||||
|
forced: this.forced,
|
||||||
|
fakeforce: this.fakeforce,
|
||||||
|
_aiexclude: this._aiexclude,
|
||||||
|
complexSelect: this.complexSelect,
|
||||||
|
complexCard: this.complexCard,
|
||||||
|
complexTarget: this.complexTarget,
|
||||||
|
_cardChoice: this._cardChoice,
|
||||||
|
_targetChoice: this._targetChoice,
|
||||||
|
_skillChoice: this._skillChoice,
|
||||||
|
ai1: this.ai1,
|
||||||
|
ai2: this.ai2,
|
||||||
|
filterOk: this.filterOk,
|
||||||
|
};
|
||||||
|
if (skill) {
|
||||||
|
var info = get.info(skill);
|
||||||
|
this.skill = skill;
|
||||||
|
this._aiexclude = [];
|
||||||
|
if (typeof info.viewAs == 'function') {
|
||||||
|
if (info.filterButton != undefined) this.filterButton = get.filter(info.filterButton);
|
||||||
|
if (info.selectButton != undefined) this.selectButton = info.selectButton;
|
||||||
|
if (info.filterTarget != undefined) this.filterTarget = get.filter(info.filterTarget);
|
||||||
|
if (info.selectTarget != undefined) this.selectTarget = info.selectTarget;
|
||||||
|
if (info.filterCard != undefined) {
|
||||||
|
if (info.ignoreMod) this.ignoreMod = true;
|
||||||
|
this.filterCard2 = get.filter(info.filterCard);
|
||||||
|
this.filterCard = function (card, player, event) {
|
||||||
|
var evt = event || _status.event;
|
||||||
|
if (!evt.ignoreMod && player) {
|
||||||
|
var mod = game.checkMod(card, player, 'unchanged', 'cardEnabled2', player);
|
||||||
|
if (mod != 'unchanged') return mod;
|
||||||
|
}
|
||||||
|
return get.filter(evt.filterCard2).apply(this, arguments);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (info.filterOk == undefined) {
|
||||||
|
this.filterOk = function () {
|
||||||
|
var evt = _status.event;
|
||||||
|
var card = get.card(), player = get.player();
|
||||||
|
var filter = evt._backup.filterCard;
|
||||||
|
if (filter && !filter(card, player, evt)) return false;
|
||||||
|
if (evt._backup.filterOk) return evt._backup.filterOk();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else this.filterOk = info.filterOk;
|
||||||
|
if (info.selectCard != undefined) this.selectCard = info.selectCard;
|
||||||
|
if (info.position != undefined) this.position = info.position;
|
||||||
|
//if(info.forced!=undefined) this.forced=info.forced;
|
||||||
|
if (info.complexSelect != undefined) this.complexSelect = info.complexSelect;
|
||||||
|
if (info.complexCard != undefined) this.complexCard = info.complexCard;
|
||||||
|
if (info.complexTarget != undefined) this.complexTarget = info.complexTarget;
|
||||||
|
if (info.ai1 != undefined) this.ai1 = info.ai1;
|
||||||
|
if (info.ai2 != undefined) this.ai2 = info.ai2;
|
||||||
|
}
|
||||||
|
else if (info.viewAs) {
|
||||||
|
if (info.filterButton != undefined) this.filterButton = get.filter(info.filterButton);
|
||||||
|
if (info.selectButton != undefined) this.selectButton = info.selectButton;
|
||||||
|
if (info.filterTarget != undefined) this.filterTarget = get.filter(info.filterTarget);
|
||||||
|
if (info.selectTarget != undefined) this.selectTarget = info.selectTarget;
|
||||||
|
if (info.filterCard != undefined) {
|
||||||
|
if (info.ignoreMod) this.ignoreMod = true;
|
||||||
|
this.filterCard2 = get.filter(info.filterCard);
|
||||||
|
this.filterCard = function (card, player, event) {
|
||||||
|
var evt = event || _status.event;
|
||||||
|
if (!evt.ignoreMod && player) {
|
||||||
|
var mod = game.checkMod(card, player, 'unchanged', 'cardEnabled2', player);
|
||||||
|
if (mod != 'unchanged') return mod;
|
||||||
|
}
|
||||||
|
return get.filter(evt.filterCard2).apply(this, arguments);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (info.filterOk == undefined) {
|
||||||
|
this.filterOk = function () {
|
||||||
|
var evt = _status.event;
|
||||||
|
var card = get.card(), player = get.player();
|
||||||
|
var filter = evt._backup.filterCard;
|
||||||
|
if (filter && !filter(card, player, evt)) return false;
|
||||||
|
if (evt._backup.filterOk) return evt._backup.filterOk();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else this.filterOk = info.filterOk;
|
||||||
|
if (info.selectCard != undefined) this.selectCard = info.selectCard;
|
||||||
|
if (info.position != undefined) this.position = info.position;
|
||||||
|
//if(info.forced!=undefined) this.forced=info.forced;
|
||||||
|
if (info.complexSelect != undefined) this.complexSelect = info.complexSelect;
|
||||||
|
if (info.complexCard != undefined) this.complexCard = info.complexCard;
|
||||||
|
if (info.complexTarget != undefined) this.complexTarget = info.complexTarget;
|
||||||
|
if (info.ai1 != undefined) this.ai1 = info.ai1;
|
||||||
|
if (info.ai2 != undefined) this.ai2 = info.ai2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.filterButton = info.filterButton ? get.filter(info.filterButton) : undefined;
|
||||||
|
this.selectButton = info.selectButton;
|
||||||
|
this.filterTarget = info.filterTarget ? get.filter(info.filterTarget) : undefined;
|
||||||
|
this.selectTarget = info.selectTarget;
|
||||||
|
this.filterCard = info.filterCard ? get.filter(info.filterCard) : undefined;
|
||||||
|
this.selectCard = info.selectCard;
|
||||||
|
this.position = info.position;
|
||||||
|
//this.forced=info.forced;
|
||||||
|
this.complexSelect = info.complexSelect;
|
||||||
|
this.complexCard = info.complexCard;
|
||||||
|
this.complexTarget = info.complexTarget;
|
||||||
|
if (info.ai1 != undefined) this.ai1 = info.ai1;
|
||||||
|
if (info.ai2 != undefined) this.ai2 = info.ai2;
|
||||||
|
this.filterOk = info.filterOk;
|
||||||
|
}
|
||||||
|
delete this.fakeforce;
|
||||||
|
}
|
||||||
|
delete this._cardChoice;
|
||||||
|
delete this._targetChoice;
|
||||||
|
delete this._skillChoice;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
restore() {
|
||||||
|
if (this._backup) {
|
||||||
|
this.filterButton = this._backup.filterButton;
|
||||||
|
this.selectButton = this._backup.selectButton;
|
||||||
|
this.filterTarget = this._backup.filterTarget;
|
||||||
|
this.selectTarget = this._backup.selectTarget;
|
||||||
|
this.filterCard = this._backup.filterCard;
|
||||||
|
this.selectCard = this._backup.selectCard;
|
||||||
|
this.position = this._backup.position;
|
||||||
|
this.forced = this._backup.forced;
|
||||||
|
this.fakeforce = this._backup.fakeforce;
|
||||||
|
this._aiexclude = this._backup._aiexclude;
|
||||||
|
this.complexSelect = this._backup.complexSelect;
|
||||||
|
this.complexCard = this._backup.complexCard;
|
||||||
|
this.complexTarget = this._backup.complexTarget;
|
||||||
|
this.ai1 = this._backup.ai1;
|
||||||
|
this.ai2 = this._backup.ai2;
|
||||||
|
this._cardChoice = this._backup._cardChoice;
|
||||||
|
this._targetChoice = this._backup._targetChoice;
|
||||||
|
this._skillChoice = this._backup._skillChoice;
|
||||||
|
this.filterOk = this._backup.filterOk;
|
||||||
|
}
|
||||||
|
delete this.skill;
|
||||||
|
delete this.ignoreMod;
|
||||||
|
delete this.filterCard2;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
isMine() {
|
||||||
|
return (this.player && this.player == game.me && !_status.auto && !this.player.isMad() && !game.notMe);
|
||||||
|
}
|
||||||
|
isOnline() {
|
||||||
|
return (this.player && this.player.isOnline());
|
||||||
|
}
|
||||||
|
notLink() {
|
||||||
|
return this.getParent().name != '_lianhuan' && this.getParent().name != '_lianhuan2';
|
||||||
|
}
|
||||||
|
isPhaseUsing(player) {
|
||||||
|
var evt = this.getParent('phaseUse');
|
||||||
|
if (!evt || evt.name != 'phaseUse') return false;
|
||||||
|
return !player || player == evt.player;
|
||||||
|
}
|
||||||
|
addTrigger(skills, player) {
|
||||||
|
if (!player || !skills) return this;
|
||||||
|
let evt = this;
|
||||||
|
if (typeof skills == 'string') skills = [skills];
|
||||||
|
game.expandSkills(skills);
|
||||||
|
while (true) {
|
||||||
|
evt = evt.getParent('arrangeTrigger');
|
||||||
|
if (!evt || evt.name != 'arrangeTrigger' || !evt.doingList) return this;
|
||||||
|
const doing = evt.doingList.find(i => i.player === player);
|
||||||
|
const firstDo = evt.doingList.find(i => i.player === "firstDo");
|
||||||
|
const lastDo = evt.doingList.find(i => i.player === "lastDo");
|
||||||
|
|
||||||
|
skills.forEach(skill => {
|
||||||
|
const info = lib.skill[skill];
|
||||||
|
if (!info.trigger) return;
|
||||||
|
if (!Object.keys(info.trigger).some(i => {
|
||||||
|
if (Array.isArray(info.trigger[i])) return info.trigger[i].includes(evt.triggername);
|
||||||
|
return info.trigger[i] === evt.triggername;
|
||||||
|
})) return;
|
||||||
|
|
||||||
|
const toadd = {
|
||||||
|
skill: skill,
|
||||||
|
player: player,
|
||||||
|
priority: get.priority(skill),
|
||||||
|
};
|
||||||
|
const map = info.firstDo ? firstDo : info.lastDo ? lastDo : doing;
|
||||||
|
if (!map) return;
|
||||||
|
if (map.doneList.some(i => i.skill === toadd.skill && i.player === toadd.player)) return;
|
||||||
|
if (map.todoList.some(i => i.skill === toadd.skill && i.player === toadd.player)) return;
|
||||||
|
map.todoList.add(toadd);
|
||||||
|
if (typeof map.player === 'string') map.todoList.sort((a, b) => (b.priority - a.priority) || (evt.playerMap.indexOf(a) - evt.playerMap.indexOf(b)));
|
||||||
|
else map.todoList.sort((a, b) => b.priority - a.priority);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeTrigger(skills, player) {
|
||||||
|
if (!player || !skills) return this;
|
||||||
|
let evt = this;
|
||||||
|
if (typeof skills == 'string') skills = [skills];
|
||||||
|
game.expandSkills(skills);
|
||||||
|
while (true) {
|
||||||
|
evt = evt.getParent('arrangeTrigger');
|
||||||
|
if (!evt || evt.name != 'arrangeTrigger' || !evt.doingList) return this;
|
||||||
|
const doing = evt.doingList.find(i => i.player == player);
|
||||||
|
const firstDo = evt.doingList.find(i => i.player == "firstDo");
|
||||||
|
const lastDo = evt.doingList.find(i => i.player == "lastDo");
|
||||||
|
|
||||||
|
skills.forEach(skill => [doing, firstDo, lastDo].forEach(map => {
|
||||||
|
if (!map) return;
|
||||||
|
const toremove = map.todoList.filter(i => i.skill == skill && i.player == player);
|
||||||
|
if (toremove.length > 0) map.todoList.removeArray(toremove);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trigger(name) {
|
||||||
|
if (_status.video) return this;
|
||||||
|
if ((this.name === 'gain' || this.name === 'lose') && !_status.gameDrawed) return this;
|
||||||
|
if (name === 'gameDrawEnd') _status.gameDrawed = true;
|
||||||
|
if (name === 'gameStart') {
|
||||||
|
lib.announce.publish('gameStart', {});
|
||||||
|
if (_status.brawl && _status.brawl.gameStart) _status.brawl.gameStart();
|
||||||
|
if (lib.config.show_cardpile) ui.cardPileButton.style.display = '';
|
||||||
|
_status.gameStarted = true;
|
||||||
|
game.showHistory();
|
||||||
|
}
|
||||||
|
if (!lib.hookmap[name] && !lib.config.compatiblemode) return this;
|
||||||
|
if (!game.players || !game.players.length) return this;
|
||||||
|
const event = this;
|
||||||
|
let start = [_status.currentPhase, event.source, event.player, game.me, game.players[0]].find(i => get.itemtype(i) == 'player');
|
||||||
|
if (!start) return this;
|
||||||
|
if (!game.players.includes(start) && !game.dead.includes(start)) start = game.findNext(start);
|
||||||
|
const firstDo = {
|
||||||
|
player: "firstDo",
|
||||||
|
todoList: [],
|
||||||
|
doneList: [],
|
||||||
|
};
|
||||||
|
const lastDo = {
|
||||||
|
player: "lastDo",
|
||||||
|
todoList: [],
|
||||||
|
doneList: [],
|
||||||
|
};
|
||||||
|
const doingList = [];
|
||||||
|
const roles = ['player', 'source', 'target', 'global'];
|
||||||
|
const playerMap = game.players.concat(game.dead).sortBySeat(start);
|
||||||
|
let player = start;
|
||||||
|
let allbool = false;
|
||||||
|
do {
|
||||||
|
const doing = {
|
||||||
|
player: player,
|
||||||
|
todoList: [],
|
||||||
|
doneList: [],
|
||||||
|
listAdded: {},
|
||||||
|
addList(skill) {
|
||||||
|
if (!skill) return;
|
||||||
|
if (Array.isArray(skill)) return skill.forEach(i => this.addList(i));
|
||||||
|
if (this.listAdded[skill]) return;
|
||||||
|
this.listAdded[skill] = true;
|
||||||
|
|
||||||
|
const info = lib.skill[skill];
|
||||||
|
const list = info.firstDo ? firstDo.todoList : info.lastDo ? lastDo.todoList : this.todoList;
|
||||||
|
list.push({
|
||||||
|
skill: skill,
|
||||||
|
player: this.player,
|
||||||
|
priority: get.priority(skill),
|
||||||
|
});
|
||||||
|
if (typeof list.player == 'string') list.sort((a, b) => (b.priority - a.priority) || (playerMap.indexOf(a) - playerMap.indexOf(b)));
|
||||||
|
else list.sort((a, b) => b.priority - a.priority);
|
||||||
|
allbool = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const notemp = player.skills.slice();
|
||||||
|
for (const j in player.additionalSkills) {
|
||||||
|
if (!j.startsWith('hidden:')) notemp.addArray(player.additionalSkills[j]);
|
||||||
|
}
|
||||||
|
Object.keys(player.tempSkills).filter(skill => {
|
||||||
|
if (notemp.includes(skill)) return false;
|
||||||
|
const expire = player.tempSkills[skill];
|
||||||
|
if (typeof expire === 'function') return expire(event, player, name);
|
||||||
|
if (get.objtype(expire) === 'object') return roles.some(role => {
|
||||||
|
if (role !== 'global' && player !== event[role]) return false;
|
||||||
|
if (Array.isArray(expire[role])) return expire[role].includes(name);
|
||||||
|
return expire[role] === name;
|
||||||
|
});
|
||||||
|
}).forEach(skill => {
|
||||||
|
delete player.tempSkills[skill];
|
||||||
|
player.removeSkill(skill);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (lib.config.compatiblemode) {
|
||||||
|
doing.addList(game.expandSkills(player.getSkills('invisible').concat(lib.skill.global)).filter(skill => {
|
||||||
|
const info = get.info(skill);
|
||||||
|
if (!info || !info.trigger) return false;
|
||||||
|
return roles.some(role => {
|
||||||
|
if (info.trigger[role] === name) return true;
|
||||||
|
if (Array.isArray(info.trigger[role]) && info.trigger[role].includes(name)) return true;
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else roles.forEach(role => {
|
||||||
|
doing.addList(lib.hook.globalskill[role + '_' + name]);
|
||||||
|
doing.addList(lib.hook[player.playerid + '_' + role + '_' + name]);
|
||||||
|
});
|
||||||
|
delete doing.listAdded;
|
||||||
|
delete doing.addList;
|
||||||
|
doingList.push(doing);
|
||||||
|
player = player.nextSeat;
|
||||||
|
} while (player && player !== start);
|
||||||
|
doingList.unshift(firstDo);
|
||||||
|
doingList.push(lastDo);
|
||||||
|
// console.log(name,event.player,doingList.map(i=>({player:i.player,todoList:i.todoList.slice(),doneList:i.doneList.slice()})))
|
||||||
|
|
||||||
|
if (allbool) {
|
||||||
|
const next = game.createEvent('arrangeTrigger', false, event);
|
||||||
|
next.setContent('arrangeTrigger');
|
||||||
|
next.doingList = doingList;
|
||||||
|
next._trigger = event;
|
||||||
|
next.triggername = name;
|
||||||
|
next.playerMap = playerMap;
|
||||||
|
event._triggering = next;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
untrigger(all = true, player) {
|
||||||
|
const evt = this._triggering;
|
||||||
|
if (all) {
|
||||||
|
this._triggered = 5;
|
||||||
|
if (evt && evt.doingList) {
|
||||||
|
evt.doingList.forEach(doing => doing.todoList = []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (player) {
|
||||||
|
this._notrigger.add(player);
|
||||||
|
// if(!evt||!evt.doingList) return this;
|
||||||
|
// const doing=evt.doingList.find(doing=>doing.player==player);
|
||||||
|
// if(doing) doing.todoList=[];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 事件转为Promise化
|
||||||
|
*
|
||||||
|
* @returns { import('../index.js').GameEventPromise }
|
||||||
|
*/
|
||||||
|
toPromise() {
|
||||||
|
if (!this.#promise) {
|
||||||
|
this.#promise = new lib.element.GameEventPromise(this);
|
||||||
|
}
|
||||||
|
return this.#promise;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @returns {never}
|
||||||
|
*/
|
||||||
|
typeAnnotation() {
|
||||||
|
/**
|
||||||
|
* @type {import('../index.js').Player}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.source;
|
||||||
|
/**
|
||||||
|
* @type {import('../index.js').Player}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.player;
|
||||||
|
/**
|
||||||
|
* @type {import('../index.js').Player}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.target;
|
||||||
|
/**
|
||||||
|
* @type {import('../index.js').Player[]}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.targets;
|
||||||
|
/**
|
||||||
|
* @type {import('../index.js').Card}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.card;
|
||||||
|
/**
|
||||||
|
* @type {import('../index.js').Card[]}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.cards;
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.skill;
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.forced;
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.num;
|
||||||
|
/**
|
||||||
|
* @type {GameEvent}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this._trigger;
|
||||||
|
/**
|
||||||
|
* @type {Record<string, any>}
|
||||||
|
*/
|
||||||
|
this._result;
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.baseDamage;
|
||||||
|
/**
|
||||||
|
* @type {import('../index.js').Player}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.customSource;
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.extraDamage;
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.nature;
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.notrigger;
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.original_num;
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.unreal;
|
||||||
|
/**
|
||||||
|
* @type { import('../index.js').Button[] }
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
this.excludeButton;
|
||||||
|
throw new Error('Do not call this method');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
import { AI as ai } from '../../ai/index.js';
|
||||||
|
import { Get as get } from '../../get/index.js';
|
||||||
|
import { Game as game } from '../../game/index.js';
|
||||||
|
import { Library as lib } from "../index.js";
|
||||||
|
import { status as _status } from '../../status/index.js';
|
||||||
|
import { UI as ui } from '../../ui/index.js';
|
||||||
|
import { AsyncFunction } from '../../util/index.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将事件Promise化以使用async异步函数来执行事件。
|
||||||
|
*
|
||||||
|
* 事件Promise化后,需要既能使用await等待事件完成,
|
||||||
|
* 又需要在执行之前对事件进行配置。
|
||||||
|
*
|
||||||
|
* 所以这个类的实例集成了事件和Promise二者的所有属性,
|
||||||
|
* 且Promise的原有属性无法被修改,一切对这个类实例的属性修改,删除,
|
||||||
|
* 再配置等操作都会转发到事件对应的属性中。
|
||||||
|
*
|
||||||
|
* @todo 需要完成异步事件的debugger方法
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* 使用await xx()等待异步事件执行:
|
||||||
|
* ```js
|
||||||
|
* await game.xxx().setContent('yyy').set(zzz, 'i');
|
||||||
|
* ```
|
||||||
|
* 使用await player.xxx()等待异步事件执行:
|
||||||
|
* ```js
|
||||||
|
* await player.draw(2);
|
||||||
|
* game.log('等待', player, '摸牌完成执行log');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class GameEventPromise extends Promise {
|
||||||
|
// 我谢谢你,这里是必须有的
|
||||||
|
// 否则Promise的方法对其子类无效
|
||||||
|
static get [Symbol.species]() {
|
||||||
|
return Promise;
|
||||||
|
}
|
||||||
|
#event;
|
||||||
|
/**
|
||||||
|
* @param { import('./gameEvent.js').default } event
|
||||||
|
* @returns { Promise<import('./gameEvent.js').default> & import('./gameEvent.js').default }
|
||||||
|
*/
|
||||||
|
constructor(event) {
|
||||||
|
super(resolve => {
|
||||||
|
// 设置为异步事件
|
||||||
|
event.async = true;
|
||||||
|
// 事件结束后触发resolve
|
||||||
|
event.resolve = resolve;
|
||||||
|
if (!_status.event) return;
|
||||||
|
// game.createEvent的时候还没立即push到next里
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
game.executingAsyncEventMap.set(_status.event.toEvent(), (game.executingAsyncEventMap.get(_status.event.toEvent()) || Promise.resolve()).then(() => {
|
||||||
|
let eventPromise = _status.event.next.find(e => e.toEvent() == event);
|
||||||
|
// 如果父级事件也是一个异步的话,那应该立即执行这个事件的
|
||||||
|
// 如果在AsyncFunction执行过程中在别的位置新建了一个异步事件,那也直接(等会set配置完)执行
|
||||||
|
if (eventPromise && (_status.event.content instanceof AsyncFunction || Array.isArray(_status.event.contents))) {
|
||||||
|
// 异步执行game.loop
|
||||||
|
// 不直接game.loop(event)是因为需要让别人可以手动set()和setContent()
|
||||||
|
// 再执行game.loop是因为原有的game.loop被await卡住了,
|
||||||
|
// 得新执行一个只执行这个异步事件的game.loop
|
||||||
|
|
||||||
|
// 事件自行处理skip情况
|
||||||
|
if (event.player && event.player.skipList.includes(event.name)) {
|
||||||
|
_status.event.trigger(event.name + 'Skipped');
|
||||||
|
event.player.skipList.remove(event.name);
|
||||||
|
if (lib.phaseName.includes(event.name)) event.player.getHistory('skipped').add(event.name);
|
||||||
|
_status.event.next.remove(eventPromise);
|
||||||
|
event.finish();
|
||||||
|
resolve();
|
||||||
|
return eventPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_status.event != eventPromise) {
|
||||||
|
eventPromise.parent = _status.event;
|
||||||
|
_status.event = eventPromise;
|
||||||
|
game.getGlobalHistory('everything').push(eventPromise);
|
||||||
|
}
|
||||||
|
return game.loop(eventPromise).then(() => {
|
||||||
|
// 有时候event.finished还是false
|
||||||
|
return eventPromise;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.#event = event;
|
||||||
|
return new Proxy(this, {
|
||||||
|
get(target, prop, receiver) {
|
||||||
|
const thisValue = Reflect.get(target, prop);
|
||||||
|
if (thisValue) {
|
||||||
|
if (typeof thisValue == 'function') {
|
||||||
|
return thisValue.bind(target);
|
||||||
|
}
|
||||||
|
return thisValue;
|
||||||
|
}
|
||||||
|
const eventValue = Reflect.get(event, prop);
|
||||||
|
return eventValue == event ? receiver : eventValue;
|
||||||
|
},
|
||||||
|
set(target, prop, newValue) {
|
||||||
|
return Reflect.set(event, prop, newValue);
|
||||||
|
},
|
||||||
|
deleteProperty(target, prop) {
|
||||||
|
return Reflect.deleteProperty(event, prop);
|
||||||
|
},
|
||||||
|
defineProperty(target, prop, attributes) {
|
||||||
|
return Reflect.defineProperty(event, prop, attributes);
|
||||||
|
},
|
||||||
|
has(target, prop) {
|
||||||
|
return Reflect.has(event, prop);
|
||||||
|
},
|
||||||
|
ownKeys(target) {
|
||||||
|
return Reflect.ownKeys(event);
|
||||||
|
},
|
||||||
|
getOwnPropertyDescriptor(target, prop) {
|
||||||
|
return Reflect.getOwnPropertyDescriptor(event, prop);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取原事件对象 */
|
||||||
|
toEvent() {
|
||||||
|
return this.#event;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 在某个异步事件中调试变量信息
|
||||||
|
*
|
||||||
|
* 注: 在调试步骤中`定义的变量只在当前输入的语句有效`
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* 在技能中调试技能content相关的信息
|
||||||
|
* ```js
|
||||||
|
* await event.debugger();
|
||||||
|
* ```
|
||||||
|
* 在技能中调试触发此技能事件的相关的信息
|
||||||
|
* ```js
|
||||||
|
* await trigger.debugger();
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
async debugger() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const runCode = function (event, code) {
|
||||||
|
try {
|
||||||
|
// 为了使玩家调试时使用var player=xxx时不报错,故使用var
|
||||||
|
var { player, _trigger: trigger, _result: result } = event;
|
||||||
|
return eval(code);
|
||||||
|
} catch (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}.bind(window);
|
||||||
|
const inputCallback = inputResult => {
|
||||||
|
if (inputResult === false) {
|
||||||
|
resolve(null);
|
||||||
|
} else {
|
||||||
|
const obj = runCode(this.toEvent(), inputResult);
|
||||||
|
alert((!obj || obj instanceof Error) ? String(obj) : get.stringify(obj));
|
||||||
|
game.promises.prompt('debugger调试').then(inputCallback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
game.promises.prompt('debugger调试').then(inputCallback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
export { Button } from "./button.js";
|
||||||
|
export { Card } from "./card.js";
|
||||||
|
export { Client } from "./client.js";
|
||||||
|
export { Content } from "./content.js";
|
||||||
|
export { Contents } from "./contents.js";
|
||||||
|
export { Control } from "./control.js";
|
||||||
|
export { Dialog } from "./dialog.js";
|
||||||
|
export { GameEvent } from "./gameEvent.js";
|
||||||
|
export { GameEventPromise } from "./gameEventPromise.js";
|
||||||
|
export { NodeWS } from "./nodeWs.js";
|
||||||
|
export { Player } from "./player.js";
|
||||||
|
export { VCard } from "./vcard.js";
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { AI as ai } from '../../ai/index.js';
|
||||||
|
import { Get as get } from '../../get/index.js';
|
||||||
|
import { Game as game } from '../../game/index.js';
|
||||||
|
import { Library as lib } from "../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';
|
||||||
|
|
||||||
|
export class NodeWS {
|
||||||
|
/**
|
||||||
|
* @param {string} id
|
||||||
|
*/
|
||||||
|
constructor(id) {
|
||||||
|
this.wsid = id;
|
||||||
|
}
|
||||||
|
send(message) {
|
||||||
|
game.send('server', 'send', this.wsid, message);
|
||||||
|
}
|
||||||
|
on(type, func) {
|
||||||
|
this['on' + type] = func;
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
game.send('server', 'close', this.wsid);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,9 +5,9 @@ import { Library as lib } from "../index.js";
|
||||||
import { status as _status } from '../../status/index.js';
|
import { status as _status } from '../../status/index.js';
|
||||||
import { UI as ui } from '../../ui/index.js';
|
import { UI as ui } from '../../ui/index.js';
|
||||||
|
|
||||||
export default class extends HTMLDivElement {
|
export class Player extends HTMLDivElement {
|
||||||
/**
|
/**
|
||||||
* @param {HTMLDivElement} [position]
|
* @param {HTMLDivElement|DocumentFragment} [position]
|
||||||
* @param {true} [noclick]
|
* @param {true} [noclick]
|
||||||
*/
|
*/
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -17,7 +17,7 @@ export default class extends HTMLDivElement {
|
||||||
*/
|
*/
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const player = ui.create.div('.player', position);
|
const player = ui.create.div('.player', position);
|
||||||
Object.setPrototypeOf(player, lib.element.Player.prototype);
|
Object.setPrototypeOf(player, Player.prototype);
|
||||||
player.build(noclick);
|
player.build(noclick);
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
import { AI as ai } from '../../ai/index.js';
|
||||||
|
import { Get as get } from '../../get/index.js';
|
||||||
|
import { Game as game } from '../../game/index.js';
|
||||||
|
import { Library as lib } from "../index.js";
|
||||||
|
import { status as _status } from '../../status/index.js';
|
||||||
|
import { UI as ui } from '../../ui/index.js';
|
||||||
|
|
||||||
|
export class VCard {
|
||||||
|
/**
|
||||||
|
* @param {any} [suitOrCard]
|
||||||
|
* @param {number | Card[]} [numberOrCards]
|
||||||
|
* @param {string} [name]
|
||||||
|
* @param {string} [nature]
|
||||||
|
*/
|
||||||
|
constructor(suitOrCard, numberOrCards, name, nature) {
|
||||||
|
if (Array.isArray(suitOrCard)) {
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.suit = suitOrCard[0];
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.number = suitOrCard[1];
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.name = suitOrCard[2];
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.nature = suitOrCard[3];
|
||||||
|
}
|
||||||
|
else if (get.itemtype(suitOrCard) == 'card') {
|
||||||
|
this.name = get.name(suitOrCard);
|
||||||
|
this.suit = get.suit(suitOrCard);
|
||||||
|
this.color = get.color(suitOrCard);
|
||||||
|
this.number = get.number(suitOrCard);
|
||||||
|
this.nature = get.nature(suitOrCard);
|
||||||
|
this.isCard = true;
|
||||||
|
this.cardid = suitOrCard.cardid;
|
||||||
|
this.wunature = suitOrCard.wunature;
|
||||||
|
/**
|
||||||
|
* @type {Record<string, any>}
|
||||||
|
*/
|
||||||
|
this.storage = get.copy(suitOrCard.storage);
|
||||||
|
if (Array.isArray(numberOrCards)) this.cards = numberOrCards.slice();
|
||||||
|
else this.cards = [suitOrCard];
|
||||||
|
const info = get.info(this, false);
|
||||||
|
if (info) {
|
||||||
|
const autoViewAs = info.autoViewAs;
|
||||||
|
if (typeof autoViewAs == 'string') this.name = autoViewAs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (suitOrCard && typeof suitOrCard != 'string') {
|
||||||
|
Object.keys(suitOrCard).forEach(key => {
|
||||||
|
const propertyDescriptor = Object.getOwnPropertyDescriptor(suitOrCard, key), value = propertyDescriptor.value;
|
||||||
|
if (Array.isArray(value)) this[key] = value.slice();
|
||||||
|
else Object.defineProperty(this, key, propertyDescriptor);
|
||||||
|
});
|
||||||
|
if (Array.isArray(numberOrCards)) {
|
||||||
|
const noCards = !this.cards;
|
||||||
|
/**
|
||||||
|
* @type {Card[]}
|
||||||
|
*/
|
||||||
|
this.cards = numberOrCards.slice();
|
||||||
|
if (noCards) {
|
||||||
|
if (!lib.suits.includes(this.suit)) this.suit = get.suit(this);
|
||||||
|
if (!Object.keys(lib.color).includes(this.color)) this.color = get.color(this);
|
||||||
|
if (typeof this.number != 'number') this.number = get.number(this);
|
||||||
|
if (!this.nature) this.nature = get.nature(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const info = get.info(this, false);
|
||||||
|
if (info) {
|
||||||
|
const autoViewAs = info.autoViewAs;
|
||||||
|
if (typeof autoViewAs == 'string') this.name = autoViewAs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof suitOrCard == 'string') this.suit = suitOrCard;
|
||||||
|
if (typeof numberOrCards == 'number') this.number = numberOrCards;
|
||||||
|
if (typeof name == 'string') this.name = name;
|
||||||
|
if (typeof nature == 'string') this.nature = nature;
|
||||||
|
if (!this.storage) this.storage = {};
|
||||||
|
if (!this.cards) this.cards = [];
|
||||||
|
}
|
||||||
|
sameSuitAs(card) {
|
||||||
|
return get.suit(this) == get.suit(card);
|
||||||
|
}
|
||||||
|
differentSuitFrom(card) {
|
||||||
|
return get.suit(this) != get.suit(card);
|
||||||
|
}
|
||||||
|
sameNumberAs(card) {
|
||||||
|
return get.number(this) == get.number(card);
|
||||||
|
}
|
||||||
|
differentNumberFrom(card) {
|
||||||
|
return get.number(this) != get.number(card);
|
||||||
|
}
|
||||||
|
sameNameAs(card) {
|
||||||
|
return get.name(this) == get.name(card);
|
||||||
|
}
|
||||||
|
differentNameFrom(card) {
|
||||||
|
return get.name(this) != get.name(card);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {Player} player
|
||||||
|
*/
|
||||||
|
hasNature(nature, player) {
|
||||||
|
const natures = get.natureList(this, player);
|
||||||
|
if (!nature) return natures.length > 0;
|
||||||
|
if (nature == 'linked') return natures.some(n => lib.linked.includes(n));
|
||||||
|
return get.is.sameNature(natures, nature);
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -14,8 +14,8 @@ export class Uninstantable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {number} ms
|
* @param { number } ms
|
||||||
* @returns {Promise<void>}
|
* @returns { Promise<void> }
|
||||||
*/
|
*/
|
||||||
export function delay(ms) {
|
export function delay(ms) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
|
Loading…
Reference in New Issue