Merge branch 'PR-Branch' of https://github.com/libccy/noname into PR-Branch-eff

This commit is contained in:
kuangthree 2024-01-28 12:30:34 +08:00
commit 2c86495a6a
17 changed files with 2423 additions and 2171 deletions

View File

@ -3016,8 +3016,11 @@ game.import('character',function(lib,game,ui,get,ai,_status){
},
},
erika_yousheng:{
init:(player)=>{
player.addSkill('erika_yousheng_mamori');
},
dutySkill:true,
group:['erika_yousheng_achieve','erika_yousheng_fail','erika_yousheng_mamori'],
group:['erika_yousheng_achieve','erika_yousheng_fail'],
trigger:{global:'useCardToTarget'},
direct:true,
filter(event,player){

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -581,7 +581,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){
target.damage('nosource');
break;
case '鹰':
player.gain(target.getGainableCards(player,'he'),target,'giveAuto');
player.gain(target.getGainableCards(player,'he').randomGet(),target,'giveAuto');
break;
case '熊':
target.discard(target.getGainableCards(player,'e').randomGet()).discarder=player;

View File

@ -1579,14 +1579,15 @@ game.import('character',function(lib,game,ui,get,ai,_status){
},
async content(event,trigger,player){
const target=event.target;
const {result:{control}}=await target.chooseControl('heart2','diamond2','club2','spade2').set('ai',event=>{
const control=await target.chooseControl('heart2','diamond2','club2','spade2').set('ai',event=>{
switch(Math.floor(Math.random()*6)){
case 0:return 'heart2';
case 1:case 4:case 5:return 'diamond2';
case 2:return 'club2';
case 3:return 'spade2';
}
});
})
.forResultControl();
game.log(target,'选择了'+get.translation(control));
event.choice=control;
target.chat('我选'+get.translation(event.choice));
@ -1641,7 +1642,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){
});
},
async content(event,trigger,player){
const {result:{bool,targets,cards}}=await player.chooseCardTarget({
const [bool,targets,cards]=await player.chooseCardTarget({
position:'he',
filterCard:lib.filter.cardDiscardable,
filterTarget:(card,player,target)=>{
@ -1671,7 +1672,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
prompt2:'弃置一张牌,将此【杀】转移给攻击范围内的一名其他角色',
source:trigger.player,
card:trigger.card,
}).setHiddenSkill(event.name);
})
.setHiddenSkill(event.name)
.forResult('bool','targets','cards');
if(bool){
const target=targets[0];
player.logSkill(event.name,target);
@ -2210,7 +2213,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){
async content(event,trigger,player){
const list=['弃牌','摸牌','取消'];
if(!player.countCards('he')) list.remove('弃牌');
const {result:{control}}=await player.chooseControl(list,()=>{
const control=await player.chooseControl(list,()=>{
const player=_status.event.player;
if(list.includes('弃牌')){
if(player.countCards('h')>3&&player.countCards('h','sha')>1){
@ -2224,7 +2227,10 @@ game.import('character',function(lib,game,ui,get,ai,_status){
return '摸牌';
}
return 'cancel2';
}).set('prompt',get.prompt2('new_jiangchi'));
})
.set('prompt',get.prompt2('new_jiangchi'))
.forResultControl();
if(control=='弃牌'){
player.chooseToDiscard(true,'he');
player.addTempSkill('jiangchi2','phaseUseEnd');

View File

@ -11905,6 +11905,10 @@ game.import('character',function(lib,game,ui,get,ai,_status){
}
},
ai:{
filterDamage:true,
skillTagFilter:(player,tag,arg)=>{
return arg&&arg.jiu==true;
},
effect:{
target:(card,player,target)=>{
if(target.hp<=0&&target.hasSkill('zhenlie_lose')&&get.tag(card,'recover')) return [1,1.2];

View File

@ -5,7 +5,7 @@ declare type CardBaseUIData = {
nature?: string;
//用于某些方法,用于过滤卡牌的额外结构
type?: string;
type?: string | string[];
subtype?: string;
color?: string;

View File

@ -291,6 +291,9 @@ declare interface Mod {
aiValue?(player: Player, card: Card, num: number): number | void;
aiUseful?(player: Player, card: Card, num: number): number | void;
attackRange?(player: Player, num: number): number | void;
}
/** 技能 */
@ -790,7 +793,7 @@ declare interface Skill {
*
*
*/
content?: string | ThreeParmFun<GameStorageItem, Player, string, string>;
content?: string | ((storage: GameStorageItem, player: Player, skill: string) => string | void);
/**
*
*
@ -808,7 +811,7 @@ declare interface Skill {
*
*
*/
onunmark?: TwoParmFun<GameStorageItem, Player, void> | string;
onunmark?: TwoParmFun<GameStorageItem, Player, void> | string | boolean;
// id?:string; //id名字需带“subplayer”用于特殊模式显示信息用
};
@ -937,9 +940,9 @@ declare interface Skill {
*
*
*/
prepare?: string | ThreeParmFun<Card[], Player, Target[], string>;
prepare?: string | ((cards: Card[], player: Player, targets: Target[]) => string | void);
/** 在lose事件中使用触发执行“lose_卡牌名”事件的content */
onLose?: ContentFunc | ContentFunc[];
onLose?: OldContentFuncByAll | OldContentFuncByAll[];
/**
* lose事件中使用equipsonLose才生效
* lose_卡牌名onLose
@ -1033,7 +1036,7 @@ declare interface Skill {
* 线
* fireFF9244thunder8DD8FFgreen8DFFD8
*/
line?: string | { color: number[] };
line?: string | { color: number[] } | boolean;
/** 是否显示多条指引线 */
multiline?: boolean;
@ -1109,7 +1112,7 @@ declare interface Skill {
*
*
*/
selectTarget?: number | Select | NoneParmFum<number | Select>;
selectTarget?: number | Select | (() => number | Select);
/**
*
*
@ -1147,11 +1150,8 @@ declare interface Skill {
ignoreMod?: boolean;
/**
*
* @param card
* @param player
* @param target
*/
filterTarget?(card: Card, player: Player, target: Player): boolean;
filterTarget?: ((card: Card, player: Player, target: Player) => boolean) | boolean;
/**
*
* 'h', 'e', 'j'
@ -1211,7 +1211,7 @@ declare interface Skill {
* @param player
* @param name
*/
hiddenCard?(player: Player, name: string): boolean;
hiddenCard?(player: Player, name: string): boolean | void;
/** 录像相关game.videoContent.skill中相关 */
video?(player: Player, data: string | any[]): void;
@ -1282,7 +1282,7 @@ declare interface Skill {
*
* prompt
*/
logTarget?: string | TwoParmFun<Trigger, Player, string | Player>;
logTarget?: string | TwoParmFun<GameEventPromise, Player, string | Player | Player[] | null>;
/**
* logTarget显示触发者的目标日志
*
@ -1365,9 +1365,9 @@ declare interface Skill {
*
*
*/
check?: OneParmFun<Card, number | boolean>;
check?: TwoParmFun<GameEventPromise, Player, number | boolean>;
check?: NoneParmFum<number | boolean>;
check?: (card: Card) => number | boolean | void;
check?: (event: GameEventPromise, player: Player) => number | boolean | void;
check?: () => number | boolean | void;
// check?(...any:any):number|boolean;
// /** ai用于检测的方法用于主动使用触发技能 */
// check?(card:Card):number|boolean;
@ -1593,7 +1593,7 @@ declare interface SkillAI {
*
* ,1,0~4(threaten值为3)
*/
threaten?: number | TwoParmFun<Player, Target, number>;
threaten?: number | ((player: Player, target: Target) => number | void);
/**
*
* identity决定att不同
@ -1669,14 +1669,14 @@ declare interface SkillAI {
* "zeroplayer","zerotarget","zeroplayertarget",指定最终结果的:对使用者的收益值,0
* @param result1 ai.result.player的结果
*/
player?(card: Card, player: Player, target: Player, result1: number): string | number | number[] | void;
player?(card: Card, player: Player, target: Player, result1: number): string | number | number[] | void | boolean;
/**
* /
*
* "zeroplayer","zerotarget","zeroplayertarget",指定最终结果的:对使用者的收益值,0
* @param result2 ai.result.target的结果
*/
target?(card: Card, player: Player, target: Player, result2: number): string | number | number[] | void;
target?(card: Card, player: Player, target: Player, result2: number): string | number | number[] | void | boolean;
};
/**
*
@ -1694,21 +1694,21 @@ declare interface SkillAI {
* ;
* player(player){}player可以在这里进行判断......
*/
target?: ThreeParmFun<Player, Target, Card, number> | number;
target?: number | ((player: Player, taregt: Player, card: Card) => number | void | boolean);
/**
* get.effect_use中target
*/
target_use?: ThreeParmFun<Player, Target, Card, number> | number;
target_use?: number | ((player: Player, taregt: Player, card: Card) => number | void) | boolean;
/**
* ai是否发动此技能
* ;
*
*/
player?: ThreeParmFun<Player, Target, Card, number> | number;
player?: number | ((player: Player, taregt: Player, card: Card) => number | void | boolean);
/**
* get.effect_use中player
*/
player_use?: ThreeParmFun<Player, Target, Card, number> | number;
player_use?: number | ((player: Player, taregt: Player, card: Card) => number | void | boolean);
/**
* true时equipcard.ai.result.target

Binary file not shown.

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

@ -1362,16 +1362,29 @@ export class Get extends Uninstantable {
if (func._filter_args) {
return '_noname_func:' + JSON.stringify(get.stringifiedResult(func._filter_args, 3));
}
return '_noname_func:' + func.toString();
const str = func.toString();
// js内置的函数
if ((/\{\s*\[native code\]\s*\}/).test(str)) return '_noname_func:function () {}';
return '_noname_func:' + str;
}
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

@ -162,4 +162,95 @@ export class GameEventPromise extends Promise {
game.promises.prompt('debugger调试').then(inputCallback);
});
}
/**
*
* 直接获得result中的信息
*
*
* @example
*
* let chooseCardResult = await player.chooseCard().forResult();
* 选择的卡牌chooseCardResult.cards
*
* let cards = await player.chooseCard().forResult('cards');
* 选择的卡牌cards
*
* let [success,cards,targets] = await player.chooseCardTarget().forResult('bool','cards','targets');
* success:是否做出选择
* cards:选择的牌
* targets:选择的目标
*/
forResult(){
if(arguments.length == 0){
return this.then(event=>{
return Promise.resolve(event.result);
});
}else if(arguments.length == 1){
return this.then(event=>{
return Promise.resolve(event.result[arguments[0]]);
});
}else{
return this.then(event=>{
return Promise.resolve(Array.from(arguments).map(key=>event.result[key]));
});
}
}
/**
* 返回result中的bool项
*
* @returns {boolean} 返回的bool项
*/
forResultBool(){
return this.forResult('bool');
}
/**
* 返回result中的targets项
*
* @returns {lib.element.Player[]} 返回的targets项
*
*/
forResultTargets(){
return this.forResult('targets');
}
/**
* 返回result中的cards项
*
* @returns {lib.element.Card[]} 返回的cards项
*
*/
forResultCards(){
return this.forResult('cards');
}
/**
* 返回result中的card项
*
* @returns {lib.element.VCard|lib.element.Card} 返回的card项
*
*/
forResultCard(){
return this.forResult('card');
}
/**
* 返回result中的control项
*
* @returns {string} 返回的control项
*/
forResultControl(){
return this.forResult('control');
}
/**
* 返回result中的links项
*
* @returns {Array<?>} 返回的links项
*/
forResultLinks(){
return this.forResult('links');
}
}

View File

@ -27,163 +27,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;
throw new Error('Do not call this method');
}
build(noclick) {
let player = this;
player.buildNode();
@ -194,6 +37,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(),
@ -220,7 +64,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();
}
@ -243,7 +89,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);
}
@ -305,7 +153,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;
@ -354,22 +332,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;
@ -387,17 +365,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;
},
@ -446,6 +428,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, {
@ -471,37 +454,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') {
@ -510,11 +514,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的第一个参数必须为对象';
@ -533,13 +543,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) {
@ -572,44 +585,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;
@ -629,13 +662,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;
@ -649,21 +692,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);
@ -671,55 +730,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;
}
@ -728,45 +812,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';
@ -774,18 +870,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';
@ -793,7 +893,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') {

View File

@ -3703,7 +3703,13 @@ class Create extends Uninstantable {
// if(!get.config('menu_loadondemand')) node._initLink();
return node;
};
for (var i in lib.extensionMenu) {
let extensionsInMenu = Object.keys(lib.extensionMenu);
if(lib.config.extensionSort && Array.isArray(lib.config.extensionSort)){
extensionsInMenu.sort((a,b)=>{
return lib.config.extensionSort.indexOf(a) - lib.config.extensionSort.indexOf(b);
});
}
for (let i of extensionsInMenu) {
if (lib.config.all.stockextension.includes(i) && !lib.config.all.plays.includes(i)) continue;
if (lib.config.hiddenPlayPack.includes(i)) continue;
createModeConfig(i, start.firstChild);