尝试修正get.funcInfoOL和get.infoFuncOL,为Player类添加部分类型注释

This commit is contained in:
nonameShijian 2024-01-27 20:55:31 +08:00
parent 1e5a2fbb61
commit 6af2e91560
4 changed files with 384 additions and 252 deletions

View File

@ -42,6 +42,10 @@ export class Game extends Uninstantable {
static roundNumber = 0;
static shuffleNumber = 0;
static promises = GamePromises;
/**
* @type {string}
*/
static layout;
static globalEventHandlers = new class {
constructor() {
this._handlers = {};

View File

@ -1361,16 +1361,29 @@ export class Get extends Uninstantable {
if (func._filter_args) {
return '_noname_func:' + JSON.stringify(get.stringifiedResult(func._filter_args, 3));
}
const str = func.toString();
// js内置的函数
if ((/\{\s*\[native code\]\s*\}/).test(str)) return '_noname_func:function () {}';
return '_noname_func:' + func.toString();
}
return '';
}
static infoFuncOL(info) {
var func;
let func;
const str = info.slice(13).trim();
try {
// js内置的函数
if ((/\{\s*\[native code\]\s*\}/).test(str)) return function () {};
// 一般fun和数组形式
if (str.startsWith("function") || str.startsWith("(")) eval(`func=(${str});`);
else eval(`func=(function ${str});`);
// 其他奇形怪状的fun
else {
try {
eval(`func = ${str}`);
} catch {
eval(`let obj = {${str}}; func = obj[Object.keys(obj)[0]]`);
}
}
} catch (e) {
console.error(`${e} in \n${str}`);
return function () {};

View File

@ -26,168 +26,6 @@ export class Player extends HTMLDivElement {
player._args = [position];
return player;
}
/**
* Do not call this method
*
* @returns { never }
*/
typeAnnotation() {
/**
* @type { SMap<HTMLDivElement> }
*/
// @ts-ignore
this.node;
/**
* @type { number }
*/
// @ts-ignore
this.phaseNumber;
/**
* @type { string[] }
*/
// @ts-ignore
this.skipList;
/**
* @type { string[] }
*/
// @ts-ignore
this.skills;
/**
* @type { string[] }
*/
// @ts-ignore
this.invisibleSkills;
/**
* @type { string[] }
*/
// @ts-ignore
this.initedSkills;
/**
* @type { SMap<string[]> }
*/
// @ts-ignore
this.additionalSkills;
/**
* @type { SMap<string[]> }
*/
// @ts-ignore
this.disabledSkills;
/**
* @type { string[] }
*/
// @ts-ignore
this.hiddenSkills;
/**
* @type { string[] }
*/
// @ts-ignore
this.awakenedSkills;
/**
* @type { SMap<string[]> }
*/
// @ts-ignore
this.forbiddenSkills = {};
/**
* @type { [] }
*/
// @ts-ignore
this.popups;
/**
* @type { [] }
*/
// @ts-ignore
this.damagepopups;
/**
* @type { Card[] }
*/
// @ts-ignore
this.judging;
/**
* @type { { card:{}, skill: {} }[] }
*/
// @ts-ignore
this.stat;
/**
* @type { {
* useCard: GameEventPromise[],
* respond: GameEventPromise[],
* skipped: GameEventPromise[],
* lose: GameEventPromise[],
* gain: GameEventPromise[],
* sourceDamage: GameEventPromise[],
* damage: GameEventPromise[],
* custom: GameEventPromise[],
* useSkill: GameEventPromise[],
* }[] }
*/
// @ts-ignore
this.actionHistory;
/**
* @type { SMap<string[]> }
*/
// @ts-ignore
this.tempSkills;
/**
* @type { SMap<any> }
*/
// @ts-ignore
this.storage;
/**
* @type { SMap<HTMLDivElement> }
*/
// @ts-ignore
this.marks;
/**
* @type { SMap<number> }
*/
// @ts-ignore
this.expandedSlots;
/**
* @type { SMap<number> }
*/
// @ts-ignore
this.disabledSlots;
/**
* @type { {
* friend: [],
* enemy: [],
* neutral: [],
* handcards: {
* global: [],
* source: [],
* viewed: []
* }
* } }
*/
// @ts-ignore
this.ai;
/**
* @type { number }
*/
// @ts-ignore
this.queueCount;
/**
* @type { number }
*/
// @ts-ignore
this.outCount;
/**
* @type { number }
*/
// @ts-ignore
this.maxHp;
/**
* @type { number }
*/
// @ts-ignore
this.hp;
/**
* @type { number }
*/
// @ts-ignore
this.hujia;
throw new Error('Do not call this method');
}
build(noclick) {
let player = this;
player.buildNode();
@ -198,6 +36,7 @@ export class Player extends HTMLDivElement {
}
buildNode() {
let player = this;
/** @type { SMap<HTMLDivElement> } */
const node = player.node = {
avatar: ui.create.div('.avatar', player, ui.click.avatar).hide(),
avatar2: ui.create.div('.avatar2', player, ui.click.avatar2).hide(),
@ -224,7 +63,9 @@ export class Player extends HTMLDivElement {
if (mutation.type === 'childList') {
const addedNodes = Array.from(mutation.addedNodes);
const removedNodes = Array.from(mutation.removedNodes);
// @ts-ignore
if(addedNodes.some(card=>!card.classList.contains('emptyequip')) ||
// @ts-ignore
removedNodes.some(card=>!card.classList.contains('emptyequip'))){
player.$handleEquipChange();
}
@ -247,7 +88,9 @@ export class Player extends HTMLDivElement {
node.link = player.mark(' ', {
mark: get.linkintro
});
// @ts-ignore
node.link.firstChild.setBackgroundImage('image/card/tiesuo_mark.png');
// @ts-ignore
node.link.firstChild.style.backgroundSize = 'cover';
ui.create.div(node.identity);
}
@ -309,7 +152,137 @@ export class Player extends HTMLDivElement {
if (lib.config.touchscreen) player.addEventListener('touchstart', ui.click.playertouchstart);
}
}
/** @type { SMap<HTMLDivElement> } */
node;
/**
* @type { number }
*/
phaseNumber;
/**
* @type { string[] }
*/
skipList;
/**
* @type { string[] }
*/
skills;
/**
* @type { string[] }
*/
invisibleSkills;
/**
* @type { string[] }
*/
initedSkills;
/**
* @type { SMap<string[]> }
*/
additionalSkills;
/**
* @type { SMap<string[]> }
*/
disabledSkills;
/**
* @type { string[] }
*/
hiddenSkills;
/**
* @type { string[] }
*/
awakenedSkills;
/**
* @type { SMap<string[]> }
*/
forbiddenSkills;
/**
* @type { any[] }
*/
popups;
/**
* @type { any[] }
*/
damagepopups;
/**
* @type { Card[] }
*/
judging;
/**
* @type { { card:{}, skill: {} }[] }
*/
stat;
/**
* @type { {
* useCard: GameEventPromise[],
* respond: GameEventPromise[],
* skipped: GameEventPromise[],
* lose: GameEventPromise[],
* gain: GameEventPromise[],
* sourceDamage: GameEventPromise[],
* damage: GameEventPromise[],
* custom: GameEventPromise[],
* useSkill: GameEventPromise[],
* }[] }
*/
actionHistory;
/**
* @type { SMap<string[]> }
*/
tempSkills;
/**
* @type { SMap<any> }
*/
storage;
/**
* @type { SMap<HTMLDivElement> }
*/
marks;
/**
* @type { SMap<number> }
*/
expandedSlots;
/**
* @type { SMap<number> }
*/
disabledSlots;
/**
* @type { {
* friend: [],
* enemy: [],
* neutral: [],
* handcards: {
* global: [],
* source: [],
* viewed: []
* }
* } }
*/
ai;
/**
* @type { number }
*/
queueCount;
/**
* @type { number }
*/
outCount;
/**
* @type { number }
*/
maxHp;
/**
* @type { number }
*/
hp;
/**
* @type { number }
*/
hujia;
//新函数
/**
* 怒气
* @param { number } amount
* @param { boolean } [limit]
*/
changeFury(amount, limit) {
if (typeof this.storage.stratagem_fury != 'number') this.storage.stratagem_fury = 0;
if (!amount) return;
@ -358,22 +331,22 @@ export class Player extends HTMLDivElement {
let triggerNames = Array.from(arguments);
let trigger;
if (triggerNames.length == 0) throw 'player.when的参数数量应大于0';
//add other triggerNames
//arguments.length = 1
// add other triggerNames
// arguments.length = 1
if (triggerNames.length == 1) {
//以下两种情况:
//triggerNames = [ ['xxAfter', ...args] ]
//triggerNames = [ 'xxAfter' ]
// 以下两种情况:
// triggerNames = [ ['xxAfter', ...args] ]
// triggerNames = [ 'xxAfter' ]
if (Array.isArray(triggerNames[0]) || typeof triggerNames[0] == 'string') trigger = { player: triggerNames[0] };
//triggerNames = [ {player:'xxx'} ]
// triggerNames = [ {player:'xxx'} ]
else if (get.is.object(triggerNames[0])) trigger = triggerNames[0];
}
//arguments.length > 1
// arguments.length > 1
else {
//triggerNames = [ 'xxAfter', 'yyBegin' ]
// triggerNames = [ 'xxAfter', 'yyBegin' ]
if (triggerNames.every(t => typeof t == 'string')) trigger = { player: triggerNames };
//triggerNames = [ {player: 'xxAfter'}, {global: 'yyBegin'} ]
//此处不做特殊的合并处理,由使用者自行把握,同名属性后者覆盖前者
// triggerNames = [ {player: 'xxAfter'}, {global: 'yyBegin'} ]
// 此处不做特殊的合并处理,由使用者自行把握,同名属性后者覆盖前者
else if (triggerNames.every(t => get.is.object(t))) trigger = triggerNames.reduce((pre, cur) => Object.assign(pre, cur));
}
if (!trigger) throw 'player.when传参数类型错误:' + triggerNames;
@ -391,17 +364,21 @@ export class Player extends HTMLDivElement {
* @type { (code: string) => any }
*/
let scope;
/** @type { Skill } */
let skill = {
trigger: trigger,
forced: true,
charlotte: true,
popup: false,
//必要条件
// 必要条件
/** @type { Required<Skill>['filter'][] } */
filterFuns: [],
//充分条件
// 充分条件
/** @type { Required<Skill>['filter'][] } */
filter2Funs: [],
/** @type { Required<Skill>['content'][] } */
contentFuns: [],
//外部变量
// 外部变量
get vars() {
return vars;
},
@ -450,6 +427,7 @@ export class Player extends HTMLDivElement {
str += `'step ${i}'\n\t${str2}\n\t`;
}
skill.content = lib.init.parsex((scope || eval)(str + `\n};content;`), scope);
// @ts-ignore
skill.content._parsed = true;
};
Object.defineProperty(lib.skill, skillName, {
@ -475,37 +453,58 @@ export class Player extends HTMLDivElement {
this.addSkill(skillName);
_status.postReconnect.player_when[1][skillName] = true;
return {
/**
* @param { Required<Skill>['filter'] } fun
*/
filter(fun) {
if (lib.skill[skillName] != skill) throw `This skill has been destroyed`;
skill.filterFuns.push(fun);
return this;
},
/**
* @param { Required<Skill>['filter'] } fun
*/
removeFilter(fun) {
if (lib.skill[skillName] != skill) throw `This skill has been destroyed`;
skill.filterFuns.remove(fun);
return this;
},
/**
* @param { Required<Skill>['filter'] } fun
*/
filter2(fun) {
if (lib.skill[skillName] != skill) throw `This skill has been destroyed`;
skill.filter2Funs.push(fun);
return this;
},
/**
* @param { Required<Skill>['filter'] } fun
*/
removeFilter2(fun) {
if (lib.skill[skillName] != skill) throw `This skill has been destroyed`;
skill.filter2Funs.remove(fun);
return this;
},
/**
* @param { Required<Skill>['content'] } fun
*/
then(fun) {
if (lib.skill[skillName] != skill) throw `This skill has been destroyed`;
skill.contentFuns.push(fun);
createContent();
return this;
},
/**
* @param { string } str
*/
popup(str) {
if (lib.skill[skillName] != skill) throw `This skill has been destroyed`;
if (typeof str == 'string') skill.popup = str;
return this;
},
/**
* @param { string } translation
*/
translation(translation) {
if (lib.skill[skillName] != skill) throw `This skill has been destroyed`;
if (typeof translation == 'string') {
@ -514,11 +513,17 @@ export class Player extends HTMLDivElement {
}
return this;
},
/**
* @param { SMap<any> } obj
*/
assign(obj) {
if (lib.skill[skillName] != skill) throw `This skill has been destroyed`;
if (typeof obj == 'object' && obj !== null) Object.assign(skill, obj);
return this;
},
/**
* @param { SMap<any> } arg
*/
vars(arg) {
if (lib.skill[skillName] != skill) throw `This skill has been destroyed`;
if (!get.is.object(arg)) throw 'vars的第一个参数必须为对象';
@ -537,13 +542,16 @@ export class Player extends HTMLDivElement {
*/
apply(_scope) {
if (lib.skill[skillName] != skill) throw `This skill has been destroyed`;
// @ts-ignore
scope = _scope;
if (skill.contentFuns.length > 0) createContent();
return this;
}
};
}
//让一名角色明置一些手牌
/**
* 让一名角色明置一些手牌
*/
addShownCards() {
const cards = [], tags = [];
for (const argument of arguments) {
@ -576,44 +584,64 @@ export class Player extends HTMLDivElement {
next.setContent('hideShownCards');
return next;
}
//获取角色所有的明置手牌
/**
* 获取角色所有的明置手牌
*/
getShownCards() {
return this.getCards('h', function (card) {
return this.getCards('h', card => {
return get.is.shownCard(card);
});
}
//获取该角色被other所知的牌。
getKnownCards(other, filter) {
if (!other) other = _status.event.player;
/**
* 获取该角色被other所知的牌
* @param { Player } [other]
* @param { (card: Card) => boolean } [filter]
*/
getKnownCards(other = _status.event.player, filter = card => true) {
if (!other) other = this;
if (!filter) filter = (card) => { return true; };
return this.getCards('h', function (card) {
return this.getCards('h', card => {
return card.isKnownBy(other) && filter(card);
});
}
//判断此角色的手牌是否已经被看光了。
isAllCardsKnown(other) {
if (!other) other = _status.event.player;
/**
* 判断此角色的手牌是否已经被看光了
* @param { Player } [other]
*/
isAllCardsKnown(other = _status.event.player) {
if (!other) other = this;
return this.countCards('h', function (card) {
return this.countCards('h', card => {
return !card.isKnownBy(other);
}) == 0;
}
//判断此角色是否有被知的牌。
hasKnownCards(other, filter) {
if (!other) other = _status.event.player;
/**
* 判断此角色是否有被知的牌
* @param { Player } [other]
* @param { (card: Card) => boolean } [filter]
*/
hasKnownCards(other = _status.event.player, filter = card => true) {
if (!other) other = this;
if (!filter) filter = (card) => { return true; };
return this.countCards('h', function (card) {
return this.countCards('h', card => {
return card.isKnownBy(other) && filter(card);
}) > 0;
}
//数此角色被知道的牌。
/**
* 数此角色被知道的牌
* @param { Player } [other]
* @param { (card: Card) => boolean } [filter]
*/
countKnownCards(other, filter) {
return this.getKnownCards(other, filter).length;
}
//Execute the delay card effect
//执行延时锦囊牌效果
/**
* Execute the delay card effect
*
* 执行延时锦囊牌效果
* @param { Card | string } card
* @param { Player } target
* @param {*} judge
* @param {*} judge2
* @returns
*/
executeDelayCardEffect(card, target, judge, judge2) {
const executeDelayCardEffect = game.createEvent('executeDelayCardEffect');
executeDelayCardEffect.player = this;
@ -633,13 +661,23 @@ export class Player extends HTMLDivElement {
executeDelayCardEffect._args = Array.from(arguments);
return executeDelayCardEffect;
}
//Check if the card does not count toward hand limit
//检测此牌是否不计入手牌上限
/**
* Check if the card does not count toward hand limit
*
* 检测此牌是否不计入手牌上限
* @param { Card } card
*/
canIgnoreHandcard(card) {
return lib.filter.ignoredHandcard(card, this);
}
//Gift
//赠予
/**
* Gift
*
* 赠予
* @param { Card | Card[] } cards
* @param { Player } target
*/
gift(cards, target) {
const gift = game.createEvent('gift');
gift.player = this;
@ -653,21 +691,37 @@ export class Player extends HTMLDivElement {
gift._args = Array.from(arguments);
return gift;
}
//Check if the player can gift the card
//检测角色是否能赠予此牌
/**
* Check if the player can gift the card
*
* 检测角色是否能赠予此牌
* @param { Card } card
* @param { Player } target
* @param { boolean } [strict]
*/
canGift(card, target, strict) {
return lib.filter.cardGiftable(card, this, target, strict);
}
//Check if the player refuses gifts
//检测角色是否拒绝赠予
/**
* Check if the player refuses gifts
*
* 检测角色是否拒绝赠予
* @param { Card } card
* @param { Player } player
*/
refuseGifts(card, player) {
return this.hasSkillTag('refuseGifts', null, {
player: player,
card: card
});
}
//Gift AI related
//赠予AI相关
/**
* Gift AI related
*
* 赠予AI相关
* @param { Card } card
* @param { Player } target
*/
getGiftAIResultTarget(card, target) {
if (!card || target.refuseGifts(card, this)) return 0;
if (get.type(card, false) == 'equip') return get.effect(target, card, target, target);
@ -675,55 +729,80 @@ export class Player extends HTMLDivElement {
if (target.hasSkillTag('nogain')) return 0;
return Math.max(1, get.value(card, this) - get.value(card, target));
}
/**
* @param { Card } card
* @param { Player } target
*/
getGiftEffect(card, target) {
return this.getGiftAIResultTarget(card, target) * get.attitude(this, target);
}
//Recast
//重铸
recast(cards, recastingLose, recastingGain) {
/**
* 重铸
* @param { Card | Card[] } cards
* @param { (player: Player, cards: Card[]) => any } [recastingLose]
* @param { (player: Player, cards: Card[]) => any } [recastingGain]
*/
recast(cards,
recastingLose = (player, cards) => player.loseToDiscardpile(cards).log = false,
recastingGain = (player, cards) => player.draw(cards.length).log = false) {
const recast = game.createEvent('recast');
recast.player = this;
const isArray = Array.isArray(cards);
if (cards && !isArray) recast.cards = [cards];
else if (isArray && cards.length) recast.cards = cards;
else _status.event.next.remove(recast);
if (typeof recastingLose != 'function') recastingLose = (player, cards) => player.loseToDiscardpile(cards).log = false;
// if (typeof recastingLose != 'function') recastingLose = (player, cards) => player.loseToDiscardpile(cards).log = false;
recast.recastingLose = recastingLose;
recast.recastingLosingEvents = [];
if (typeof recastingGain != 'function') recastingGain = (player, cards) => player.draw(cards.length).log = false;
// if (typeof recastingGain != 'function') recastingGain = (player, cards) => player.draw(cards.length).log = false;
recast.recastingGain = recastingGain;
recast.recastingGainingEvents = [];
recast.setContent('recast');
recast._args = Array.from(arguments);
return recast;
}
//Check if the player can recast the card
//检测角色是否能重铸此牌
/**
* Check if the player can recast the card
*
* 检测角色是否能重铸此牌
* @param { Card } card
* @param { Player } [source]
* @param { boolean } [strict]
*/
canRecast(card, source, strict) {
return lib.filter.cardRecastable(card, this, source, strict);
}
//装备栏相关
//判断一名角色的某个区域是否被废除
//type为要判断的区域 若为空 则判断玩家是否有任意一个被废除的区域
/**
* 判断一名角色的某个区域是否被废除
*
* type为要判断的区域 若为空 则判断玩家是否有任意一个被废除的区域
* @param { string | number } [type]
* @returns { boolean }
*/
hasDisabledSlot(type) {
var player = this;
if (type == 'horse' || type == 'equip3_4') {
return player.hasDisabledSlot(3) && (get.is.mountCombined() || player.hasDisabledSlot(4));
return this.hasDisabledSlot(3) && (get.is.mountCombined() || this.hasDisabledSlot(4));
}
else if (get.is.mountCombined() && type == 'equip4') {
return false;
}
return player.countDisabledSlot(type) > 0;
return this.countDisabledSlot(type) > 0;
}
//判断一名角色的某个区域被废除的数量
//用法同上
/**
* 判断一名角色的某个区域被废除的数量
*
* 用法同 {@link hasDisabledSlot}
* @param { string | number } [type]
*/
countDisabledSlot(type) {
var player = this;
var map = (player.disabledSlots || {});
const map = (this.disabledSlots || {});
let num;
if (type == undefined) {
num = 0;
for (var i = 1; i <= 5; i++) {
num += player.countDisabledSlot(i);
num += this.countDisabledSlot(i);
}
return num;
}
@ -732,45 +811,57 @@ export class Player extends HTMLDivElement {
if (get.is.mountCombined() && type == 'equip4') {
return 0;
}
var num = map[type];
num = map[type];
if (typeof num == 'number' && num > 0) return num;
return 0;
}
}
//判断一名角色是否有某个装备栏空着
/**
* 判断一名角色是否有某个装备栏空着
* @param { string | number } [type]
* @returns { boolean }
*/
hasEmptySlot(type) {
var player = this;
if (type == 'horse' || type == 'equip3_4') {
return player.hasEmptySlot(3) && (get.is.mountCombined() || player.hasEmptySlot(4));
return this.hasEmptySlot(3) && (get.is.mountCombined() || this.hasEmptySlot(4));
}
else if (get.is.mountCombined() && type == 'equip4') {
return false;
}
return player.countEmptySlot(type) > 0;
return this.countEmptySlot(type) > 0;
}
//判断一名角色的某个装备栏空位的数量
/**
* 判断一名角色的某个装备栏空位的数量
* @param { string | number } [type]
*/
countEmptySlot(type) {
if (!type) return 0;
var player = this;
if (typeof type == 'number') type = ('equip' + type);
else if (type == 'equip3_4') {
type = 'equip3';
}
return Math.max(0, player.countEnabledSlot(type) - player.getEquips(type).reduce(function (num, card) {
var types = get.subtypes(card, false);
return Math.max(0, this.countEnabledSlot(type) - this.getEquips(type).reduce(function (num, card) {
let types = get.subtypes(card, false);
return num + get.numOf(types, type);
}, 0));
}
//判断一名角色是否有可以用于装备新装备牌的区域(排除金箍棒和六龙等“不可被替换装备”)
//用法同下
/**
* 判断一名角色是否有可以用于装备新装备牌的区域排除金箍棒和六龙等不可被替换装备
*
* 用法同 {@link hasEnabledSlot}
* @param { string | number } [type]
*/
hasEquipableSlot(type) {
return this.countEquipableSlot(type) > 0;
}
//统计一名角色有多少个可以用于装备新的装备牌的区域
//用法同下
/**
* 统计一名角色有多少个可以用于装备新的装备牌的区域
*
* 用法同 {@link hasEnabledSlot}
* @param { string | number } [type]
*/
countEquipableSlot(type) {
if (!type) return 0;
var player = this;
if (typeof type == 'number') type = ('equip' + type);
else if (type == 'equip3_4') {
type = 'equip3';
@ -778,18 +869,22 @@ export class Player extends HTMLDivElement {
else if (get.is.mountCombined() && type == 'equip4') {
return 0;
}
return Math.max(0, player.countEnabledSlot(type) - player.getEquips(type).reduce(function (num, card) {
var types = get.subtypes(card, false);
if (!lib.filter.canBeReplaced(card, player)) num += get.numOf(types, type);
return Math.max(0, this.countEnabledSlot(type) - this.getEquips(type).reduce(function (num, card) {
let types = get.subtypes(card, false);
if (!lib.filter.canBeReplaced(card, this)) num += get.numOf(types, type);
return num;
}, 0));
}
//判断一名角色是否拥有未被废除的某个区域
//type为要判断的区域 若为空 则判断玩家是否有任意一个未被废除的区域
/**
* 判断一名角色是否拥有未被废除的某个区域
*
* type为要判断的区域 若为空 则判断玩家是否有任意一个未被废除的区域
* @param { string | number } [type]
* @returns { boolean }
*/
hasEnabledSlot(type) {
var player = this;
if (type == 'horse' || type == 'equip3_4') {
return player.hasEnabledSlot(3) && (get.is.mountCombined() || player.hasEnabledSlot(4));
return this.hasEnabledSlot(3) && (get.is.mountCombined() || this.hasEnabledSlot(4));
}
// else if(type=='equip3_4'){
// type='equip3';
@ -797,7 +892,7 @@ export class Player extends HTMLDivElement {
else if (get.is.mountCombined() && type == 'equip4') {
return false;
}
return player.countEnabledSlot(type) > 0;
return this.countEnabledSlot(type) > 0;
}
//判断一名角色的某个区域未被废除的数量
//用法同上

View File

@ -9638,20 +9638,40 @@ export class Library extends Uninstantable {
static filter = {
all: () => true,
none: () => false,
//Check if the card does not count toward the player's hand limit
//检测此牌是否不计入此角色的手牌上限
/**
* Check if the card does not count toward the player's hand limit
*
* 检测此牌是否不计入此角色的手牌上限
* @param { Card } card
* @param { Player } player
* @returns { boolean }
*/
ignoredHandcard: (card, player) => game.checkMod(card, player, false, 'ignoredHandcard', player),
//Check if the card is giftable
//检测此牌是否可赠予
/**
* Check if the card is giftable
*
* 检测此牌是否可赠予
* @param { Card } card
* @param { Player } player
* @param { Player } target
* @param { boolean } [strict]
*/
cardGiftable: (card, player, target, strict) => {
const mod = game.checkMod(card, player, target, 'unchanged', 'cardGiftable', player);
if (!mod || strict && (mod == 'unchanged' && (get.position(card) != 'h' || !get.cardtag(card, 'gifts')) || player == target)) return false;
return get.type(card, false) != 'equip' || target.canEquip(card, true);
},
//Check if the card is recastable
//检查此牌是否可重铸
cardRecastable: (card, player, source, strict) => {
if (typeof player == 'undefined') player = get.owner(card);
/**
* Check if the card is recastable
*
* 检查此牌是否可重铸
* @param { Card } card
* @param { Player } player
* @param { Player } [source]
* @param { boolean } [strict]
*/
cardRecastable: (card, player = get.owner(card), source, strict) => {
// if (typeof player == 'undefined') player = get.owner(card);
const mod = game.checkMod(card, player, source, 'unchanged', 'cardRecastable', player);
if (!mod) return false;
if (strict && mod == 'unchanged') {