Merge pull request #869 from PZ157/PR-Branch

AI优化
This commit is contained in:
Spmario233 2024-01-28 14:22:46 +08:00 committed by GitHub
commit d2df39e347
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 217 additions and 141 deletions

View File

@ -235,7 +235,9 @@ game.import('card',function(lib,game,ui,get,ai,_status){
if(get.cardtag(card,'yingbian_hit')){ if(get.cardtag(card,'yingbian_hit')){
hit=true; hit=true;
if(targets.some(target=>{ if(targets.some(target=>{
return target.mayHaveShan(viewer,'use')&&get.attitude(viewer,target)<0&&get.damageEffect(target,player,viewer,get.natureList(card))>0; return target.mayHaveShan(viewer,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))&&get.attitude(viewer,target)<0&&get.damageEffect(target,player,viewer,get.natureList(card))>0;
})) base+=5; })) base+=5;
} }
if(get.cardtag(card,'yingbian_add')){ if(get.cardtag(card,'yingbian_add')){
@ -245,7 +247,9 @@ game.import('card',function(lib,game,ui,get,ai,_status){
} }
if(get.cardtag(card,'yingbian_damage')){ if(get.cardtag(card,'yingbian_damage')){
if(targets.some(target=>{ if(targets.some(target=>{
return get.attitude(player,target)<0&&(hit||!target.mayHaveShan(viewer,'use')||player.hasSkillTag('directHit_ai',true,{ return get.attitude(player,target)<0&&(hit||!target.mayHaveShan(viewer,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))||player.hasSkillTag('directHit_ai',true,{
target:target, target:target,
card:card, card:card,
},true))&&!target.hasSkillTag('filterDamage',null,{ },true))&&!target.hasSkillTag('filterDamage',null,{

View File

@ -3516,7 +3516,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
list.remove(player.storage.kyou_zhidian); list.remove(player.storage.kyou_zhidian);
player.chooseControl(list).set('prompt','掷典:请为'+get.translation(trigger.card)+'选择一种效果').set('choice',function(){ player.chooseControl(list).set('prompt','掷典:请为'+get.translation(trigger.card)+'选择一种效果').set('choice',function(){
if(list.includes('不计入次数')&&player.hasSha()) return '不计入次数'; if(list.includes('不计入次数')&&player.hasSha()) return '不计入次数';
if(list.includes('不可被响应')&&trigger.target.mayHaveShan()) return '不可被响应'; if(list.includes('不可被响应')&&trigger.target.mayHaveShan(player,'use',trigger.target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))) return '不可被响应';
if(list.includes('伤害+1')) return '伤害+1'; if(list.includes('伤害+1')) return '伤害+1';
return list.randomGet(); return list.randomGet();
}()).set('ai',()=>_status.event.choice); }()).set('ai',()=>_status.event.choice);

View File

@ -1257,7 +1257,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
} }
} }
var hasRuanshizi=game.hasPlayer(function(target){ var hasRuanshizi=game.hasPlayer(function(target){
return target!=player&&player.canUse('sha',target,null,true)&&!target.mayHaveShan(player,'use')&&get.attitude(player,target)<0&&get.effect(target,{name:'sha'},player,player)>0; return target!=player&&player.canUse('sha',target,null,true)&&!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))&&get.attitude(player,target)<0&&get.effect(target,{name:'sha'},player,player)>0;
}) })
for(var card of hs){ for(var card of hs){
var name=get.name(card); var name=get.name(card);
@ -5664,17 +5666,6 @@ game.import('character',function(lib,game,ui,get,ai,_status){
} }
return 0.7; return 0.7;
} }
},
player(card,player){
if(_status.currentPhase!=player) return;
if(_status.event.name!='chooseToUse'||_status.event.player!=player) return;
if(get.type(card)=='basic') return;
if(get.tag(card,'gain')) return;
if(get.value(card,player,'raw')>=7) return;
if(player.hp<=2) return;
if(!player.hasSkill('jilue')||player.storage.renjie==0){
return 'zeroplayertarget';
}
} }
} }
} }
@ -5683,7 +5674,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){
audio:2, audio:2,
mod:{ mod:{
aiOrder:(player,card,num)=>{ aiOrder:(player,card,num)=>{
if(num<=0||typeof card!=='object'||!player.isPhaseUsing()) return 0; if(num<=0||typeof card!=='object'||!player.isPhaseUsing()) return num;
if(player.awakenedSkills.includes('sbaiyin')){ if(player.awakenedSkills.includes('sbaiyin')){
if(player.countMark('renjie')<3&&player.getUseValue(card)<Math.min(1.8,0.18*player.hp*player.hp)) return 0; if(player.countMark('renjie')<3&&player.getUseValue(card)<Math.min(1.8,0.18*player.hp*player.hp)) return 0;
} }
@ -5854,7 +5845,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){
player:1 player:1
}, },
effect:{ effect:{
player:(card,player,target)=>{ player(card,player,target){
if(target&&player.hasSkill('rewansha')&&target.hp<=1&&get.tag(card,'damage')) return [1,0,1.5,-1.5]; if(target&&player.hasSkill('rewansha')&&target.hp<=1&&get.tag(card,'damage')) return [1,0,1.5,-1.5];
} }
} }

View File

@ -4847,7 +4847,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
var d1=true; var d1=true;
if(trigger.player.hasSkill('jueqing')||trigger.player.hasSkill('gangzhi')) d1=false if(trigger.player.hasSkill('jueqing')||trigger.player.hasSkill('gangzhi')) d1=false
for(var target of trigger.targets){ for(var target of trigger.targets){
if(!target.mayHaveShan(player,'use')||trigger.player.hasSkillTag('directHit_ai',true,{ if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))||trigger.player.hasSkillTag('directHit_ai',true,{
target:target, target:target,
card:trigger.card, card:trigger.card,
},true)){ },true)){
@ -11113,7 +11115,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
let ph=player.countCards('h'); let ph=player.countCards('h');
if(game.hasPlayer(i=>{ if(game.hasPlayer(i=>{
if(!player.canUse('sha',i,true,true)||get.effect(i,{name:'sha'},player,player)<=0) return false; if(!player.canUse('sha',i,true,true)||get.effect(i,{name:'sha'},player,player)<=0) return false;
return !ph||!i.mayHaveShan(player,'use'); return !ph||!i.mayHaveShan(player,'use',i.getCards(i=>{
return i.hasGaintag('sha_notshan');
}));
})) return 1; })) return 1;
} }
return 0; return 0;

View File

@ -4269,7 +4269,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
result:{ result:{
target:function(player,target){ target:function(player,target){
var eff=get.effect(target,{name:'sha',nature:'fire'},player,target)/30; var eff=get.effect(target,{name:'sha',nature:'fire'},player,target)/30;
if(!target.mayHaveShan(player,'use')) eff*=2; if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))) eff*=2;
var del=target.countCards('h')-player.countCards('h')+1.5; var del=target.countCards('h')-player.countCards('h')+1.5;
eff*=Math.sqrt(del); eff*=Math.sqrt(del);
return eff; return eff;
@ -7121,7 +7123,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
if(_status.event.all) return 1; if(_status.event.all) return 1;
if(ui.selected.buttons.length) return 0; if(ui.selected.buttons.length) return 0;
return Math.random(); return Math.random();
}).set('all',!target.mayHaveShan(player,'use')&&Math.random()<0.75).set('forceAuto',true); }).set('all',!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))&&Math.random()<0.75).set('forceAuto',true);
'step 1' 'step 1'
if(result.bool){ if(result.bool){
var cards=result.cards; var cards=result.cards;

View File

@ -9137,7 +9137,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
]).set('ai',function(){ ]).set('ai',function(){
var target=_status.event.getTrigger().target; var target=_status.event.getTrigger().target;
var player=_status.event.player; var player=_status.event.player;
var num=target.mayHaveShan(player,'use')?0:1; var num=target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))?0:1;
if(get.attitude(player,target)>0) num=1-num; if(get.attitude(player,target)>0) num=1-num;
return num; return num;
}); });

View File

@ -168,7 +168,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
d1=true; d1=true;
if(trigger.player.hasSkill('jueqing')||trigger.player.hasSkill('gangzhi')) d1=false; if(trigger.player.hasSkill('jueqing')||trigger.player.hasSkill('gangzhi')) d1=false;
for(var target of trigger.targets){ for(var target of trigger.targets){
if(!target.mayHaveShan(player,'use')||trigger.player.hasSkillTag('directHit_ai',true,{ if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))||trigger.player.hasSkillTag('directHit_ai',true,{
target:target, target:target,
card:trigger.card, card:trigger.card,
},true)){ },true)){
@ -297,7 +299,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
var effect=0; var effect=0;
for(var target of trigger.targets){ for(var target of trigger.targets){
var eff=get.effect(target,trigger.card,trigger.player,player); var eff=get.effect(target,trigger.card,trigger.player,player);
if(!target.mayHaveShan(player,'use')||trigger.player.hasSkillTag('directHit_ai',true,{ if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))||trigger.player.hasSkillTag('directHit_ai',true,{
target:target, target:target,
card:trigger.card, card:trigger.card,
},true)){ },true)){

View File

@ -11141,7 +11141,12 @@ game.import('character',function(lib,game,ui,get,ai,_status){
} }
if(!target.isHealthy()) club+=2; if(!target.isHealthy()) club+=2;
if(!club&&!spade) return 1; if(!club&&!spade) return 1;
if(!target.mayHaveShan(player)) return 1-0.1*Math.min(5,target.countCards('hs')); if(name==='sha'){
if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))) return;
}
else if(!target.mayHaveShan(player)) return 1-0.1*Math.min(5,target.countCards('hs'));
if(!target.hasSkillTag('rejudge')) return [1,(club+spade)/4]; if(!target.hasSkillTag('rejudge')) return [1,(club+spade)/4];
let pos=(player==target||player.hasSkillTag('viewHandcard',null,target,true))?'hes':'e',better=club>spade?'club':'spade',max=0; let pos=(player==target||player.hasSkillTag('viewHandcard',null,target,true))?'hes':'e',better=club>spade?'club':'spade',max=0;
target.hasCard(function(cardx){ target.hasCard(function(cardx){
@ -11735,6 +11740,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){
for(var i in event.given_map){ for(var i in event.given_map){
var source=(_status.connectMode?lib.playerOL:game.playerMap)[i]; var source=(_status.connectMode?lib.playerOL:game.playerMap)[i];
player.line(source,'green'); player.line(source,'green');
if(player!==source&&(get.mode()!=='identity'||player.identity!=='nei')) player.addExpose(0.18);
map.push([source,event.given_map[i]]); map.push([source,event.given_map[i]]);
cards.addArray(event.given_map[i]); cards.addArray(event.given_map[i]);
} }

View File

@ -3676,7 +3676,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
ai:{ ai:{
effect:{ effect:{
target:function(card,player,target,current){ target:function(card,player,target,current){
if(typeof card==='object'&&get.name(card)==='sha'&&target.mayHaveShan(player,'use')) return [0.6,0.75]; if(typeof card==='object'&&get.name(card)==='sha'&&target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))) return [0.6,0.75];
if(!target.hasFriend()&&!player.hasUnknown()) return; if(!target.hasFriend()&&!player.hasUnknown()) return;
if(_status.currentPhase==target||get.type(card)==='delay') return; if(_status.currentPhase==target||get.type(card)==='delay') return;
if(card.name!='shuiyanqijunx'&&get.tag(card,'loseCard')&&target.countCards('he')){ if(card.name!='shuiyanqijunx'&&get.tag(card,'loseCard')&&target.countCards('he')){
@ -6218,7 +6220,12 @@ game.import('character',function(lib,game,ui,get,ai,_status){
} }
if(!target.isHealthy()) club+=2; if(!target.isHealthy()) club+=2;
if(!club&&!spade) return 1; if(!club&&!spade) return 1;
if(!target.mayHaveShan(player)) return 1-0.1*Math.min(5,target.countCards('hs')); if(card.name==='sha'){
if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))) return;
}
else if(!target.mayHaveShan(player)) return 1-0.1*Math.min(5,target.countCards('hs'));
if(!target.hasSkillTag('rejudge')) return [1,(club+spade)/4]; if(!target.hasSkillTag('rejudge')) return [1,(club+spade)/4];
let pos=player.hasSkillTag('viewHandcard',null,target,true)?'hes':'e',better=club>spade?'club':'spade',max=0; let pos=player.hasSkillTag('viewHandcard',null,target,true)?'hes':'e',better=club>spade?'club':'spade',max=0;
target.hasCard(function(cardx){ target.hasCard(function(cardx){
@ -7201,7 +7208,12 @@ game.import('character',function(lib,game,ui,get,ai,_status){
},true)&&game.hasPlayer(function(current){ },true)&&game.hasPlayer(function(current){
return get.attitude(target,current)<0&&get.damageEffect(current,target,target,'thunder')>0; return get.attitude(target,current)<0&&get.damageEffect(current,target,target,'thunder')>0;
})){ })){
if(!target.mayHaveShan(player)) return 1-0.1*Math.min(5,target.countCards('hs')); if(card.name==='sha'){
if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))) return;
}
else if(!target.mayHaveShan(player)) return 1-0.1*Math.min(5,target.countCards('hs'));
if(!target.hasSkillTag('rejudge')) return [1,1]; if(!target.hasSkillTag('rejudge')) return [1,1];
let pos=player.hasSkillTag('viewHandcard',null,target,true)?'hes':'e'; let pos=player.hasSkillTag('viewHandcard',null,target,true)?'hes':'e';
if(target.hasCard(function(cardx){ if(target.hasCard(function(cardx){

View File

@ -5453,25 +5453,41 @@ game.import('character',function(lib,game,ui,get,ai,_status){
}, },
result:{ result:{
target:function(player,target,card,isLink){ target:function(player,target,card,isLink){
var eff = function () { let eff=-1.5,odds=1.35,num=1;
if(!isLink && player.hasSkill('jiu')) { if(isLink){
if(!target.hasSkillTag('filterDamage', null, { let cache=_status.event.getTempCache('sha_result','eff');
player: player, if(typeof cache!=='object'||cache.card!==get.translation(card)) return eff;
card: card, if(cache.odds<1.35&&cache.bool) return 1.35*cache.eff;
jiu: true return cache.odds*cache.eff;
})){ }
if(get.attitude(player, target) > 0) return -7; if(player.hasSkill('jiu')||player.hasSkillTag('damageBonus',true,{
return -4; target:target,
} card:card
return -0.5; })){
if(target.hasSkillTag('filterDamage',null,{
player:player,
card:card,
jiu:true,
})) eff=-0.5;
else{
num=2;
if(get.attitude(player,target)>0) eff=-7;
else eff=-4;
} }
return -1.5; }
}(); if(!player.hasSkillTag('directHit_ai',true,{
if(!isLink && target.mayHaveShan(player,'use') && !player.hasSkillTag('directHit_ai', true, { target:target,
target: target, card:card,
card: card },true)) odds-=0.7*target.mayHaveShan(player,'use',target.getCards(i=>{
}, true)) return eff * 0.6; return i.hasGaintag('sha_notshan');
return eff; }),'odds');
_status.event.putTempCache('sha_result','eff',{
bool:target.hp>num&&get.attitude(player,target)>0,
card:get.translation(card),
eff:eff,
odds:odds
});
return odds*eff;
} }
}, },
respondSha:true, respondSha:true,
@ -7258,7 +7274,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
} }
else{ else{
var target=trigger.target; var target=trigger.target;
if(trigger.targets.length>1||target.mayHaveShan(player,'use')) return 0; if(trigger.targets.length>1||target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))) return 0;
} }
var num=trigger.getParent().baseDamage; var num=trigger.getParent().baseDamage;
var map=trigger.getParent().customArgs,id=target.playerid; var map=trigger.getParent().customArgs,id=target.playerid;
@ -14756,14 +14774,18 @@ game.import('character',function(lib,game,ui,get,ai,_status){
if(num>=delta) return 'zeroplayertarget'; if(num>=delta) return 'zeroplayertarget';
} }
else if(get.tag(card,'respondShan')>0){ else if(get.tag(card,'respondShan')>0){
if(current<0&&used==target.getAttackRange()-1&&target.mayHaveShan(player)){ if(current<0&&used==target.getAttackRange()-1){
return 0.6; if(card.name==='sha'){
if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))) return;
}
else if(!target.mayHaveShan(player)) return 0.9;
return [1,(used+1)/2];
} }
} }
else if(get.tag(card,'respondSha')>0){ else if(get.tag(card,'respondSha')>0){
if(current<0&&used==target.getAttackRange()-1&&target.mayHaveSha(player)){ if(current<0&&used==target.getAttackRange()-1&&target.mayHaveSha(player)) return [1,(used+1)/2];
return 0.6;
}
} }
}, },
}, },

View File

@ -5030,7 +5030,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
})) return 3; })) return 3;
return Math.sqrt(target.countCards('he')); return Math.sqrt(target.countCards('he'));
} }
if(target.mayHaveShan(player,'use')&&player.countCards('hs',function(card){ if(target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))&&player.countCards('hs',function(card){
return !ui.selected.cards.includes(card)&&get.name(card)=='sha'&&player.canUse(card,target)&&get.effect(target,card,player,player)!=0; return !ui.selected.cards.includes(card)&&get.name(card)=='sha'&&player.canUse(card,target)&&get.effect(target,card,player,player)!=0;
})) return -Math.sqrt(Math.abs(get.attitude(player,target)))/2; })) return -Math.sqrt(Math.abs(get.attitude(player,target)))/2;
return 0.1; return 0.1;
@ -5362,7 +5364,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
player.addSkill('mouni2'); player.addSkill('mouni2');
player.chooseTarget(get.prompt2('mouni'),lib.filter.notMe).set('ai',function(target){ player.chooseTarget(get.prompt2('mouni'),lib.filter.notMe).set('ai',function(target){
var player=_status.event.player,cards=player.getCards('h','sha'); var player=_status.event.player,cards=player.getCards('h','sha');
if(get.attitude(player,target)>=0||!player.canUse(cards[0],target,false)||(!player.hasJudge('lebu')&&target.mayHaveShan(player,'use')&&!player.hasSkillTag('directHit_ai',true,{ if(get.attitude(player,target)>=0||!player.canUse(cards[0],target,false)||(!player.hasJudge('lebu')&&target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))&&!player.hasSkillTag('directHit_ai',true,{
target:target, target:target,
card:cards[0], card:cards[0],
},true))) return 0; },true))) return 0;

View File

@ -590,6 +590,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){
for(const i in event.given_map){ for(const i in event.given_map){
const source=(_status.connectMode?lib.playerOL:game.playerMap)[i]; const source=(_status.connectMode?lib.playerOL:game.playerMap)[i];
player.line(source,'green'); player.line(source,'green');
if(player!==source&&(get.mode()!=='identity'||player.identity!=='nei')) player.addExpose(0.2);
list.push([source, event.given_map[i]]); list.push([source, event.given_map[i]]);
} }
game.loseAsync({ game.loseAsync({
@ -2230,7 +2231,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){
}) })
.set('prompt',get.prompt2('new_jiangchi')) .set('prompt',get.prompt2('new_jiangchi'))
.forResultControl(); .forResultControl();
if(control=='弃牌'){ if(control=='弃牌'){
player.chooseToDiscard(true,'he'); player.chooseToDiscard(true,'he');
player.addTempSkill('jiangchi2','phaseUseEnd'); player.addTempSkill('jiangchi2','phaseUseEnd');

View File

@ -512,7 +512,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
}).set('goon',function(){ }).set('goon',function(){
var d1=true; var d1=true;
if(player.hasSkill('jueqing')||player.hasSkill('gangzhi')) d1=false; if(player.hasSkill('jueqing')||player.hasSkill('gangzhi')) d1=false;
if(!target.mayHaveShan(player,'use')||player.hasSkillTag('directHit_ai',true,{ if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))||player.hasSkillTag('directHit_ai',true,{
target:target, target:target,
card:trigger.card, card:trigger.card,
},true)){ },true)){
@ -3112,7 +3114,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
expose:0.2, expose:0.2,
result:{ result:{
target:function(player,target){ target:function(player,target){
if(target.countCards('h')<=target.hp&&!target.mayHaveShan(player,'use')&&get.effect(target,{name:'sha',isCard:true},player,player)>0) return -1; if(target.countCards('h')<=target.hp&&!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))&&get.effect(target,{name:'sha',isCard:true},player,player)>0) return -1;
else if(target.countCards('h')>target.hp&&target.hp>2&&target.hasShan()) return 1; else if(target.countCards('h')>target.hp&&target.hp>2&&target.hasShan()) return 1;
return 0; return 0;
}, },
@ -6686,7 +6690,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
var player=_status.event.player; var player=_status.event.player;
if(player.hp+player.countCards('hs',{name:['tao','jiu']})<=1) return -1; if(player.hp+player.countCards('hs',{name:['tao','jiu']})<=1) return -1;
var num=1; var num=1;
if((!target.mayHaveShan(player,'use')||player.hasSkillTag('directHit_ai',true,{ if((!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))||player.hasSkillTag('directHit_ai',true,{
target:target, target:target,
card:{name:'sha'}, card:{name:'sha'},
},true))&&!target.hasSkillTag('filterDamage',null,{ },true))&&!target.hasSkillTag('filterDamage',null,{
@ -11203,7 +11209,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
var d1=true; var d1=true;
if(trigger.player.hasSkill('jueqing')||trigger.player.hasSkill('gangzhi')) d1=false; if(trigger.player.hasSkill('jueqing')||trigger.player.hasSkill('gangzhi')) d1=false;
for(var target of trigger.targets){ for(var target of trigger.targets){
if(!target.mayHaveShan(player,'use')||trigger.player.hasSkillTag('directHit_ai',true,{ if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))||trigger.player.hasSkillTag('directHit_ai',true,{
target:target, target:target,
card:trigger.card, card:trigger.card,
},true)){ },true)){
@ -13403,7 +13411,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
var d1=true; var d1=true;
if(trigger.player.hasSkill('jueqing')||trigger.player.hasSkill('gangzhi')) d1=false if(trigger.player.hasSkill('jueqing')||trigger.player.hasSkill('gangzhi')) d1=false
for(var target of trigger.targets){ for(var target of trigger.targets){
if(!target.mayHaveShan(player,'use')||trigger.player.hasSkillTag('directHit_ai',true,{ if(!target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))||trigger.player.hasSkillTag('directHit_ai',true,{
target:target, target:target,
card:trigger.card, card:trigger.card,
},true)){ },true)){

View File

@ -2228,7 +2228,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){
case 2:{ case 2:{
var num=1.3; var num=1.3;
if(event.card.name=='sha'&&event.targets.filter(function(current){ if(event.card.name=='sha'&&event.targets.filter(function(current){
if(current.mayHaveShan(player,'use')&&get.attitude(player,current)<=0){ if(current.mayHaveShan(player,'use',current.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))&&get.attitude(player,current)<=0){
if(current.hasSkillTag('useShan')) num=1.9; if(current.hasSkillTag('useShan')) num=1.9;
return true; return true;
} }

View File

@ -3530,7 +3530,9 @@ game.import('mode',function(lib,game,ui,get,ai,_status){
]).set('prompt',get.prompt('gzliegong',trigger.target)).setHiddenSkill('gzliegong').set('ai',function(){ ]).set('prompt',get.prompt('gzliegong',trigger.target)).setHiddenSkill('gzliegong').set('ai',function(){
var player=_status.event.player,target=_status.event.getTrigger().target; var player=_status.event.player,target=_status.event.getTrigger().target;
if(get.attitude(player,target)>0) return 2; if(get.attitude(player,target)>0) return 2;
return target.mayHaveShan(player,'use')?1:0; return target.mayHaveShan(player,'use',target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))?1:0;
}); });
'step 1' 'step 1'
if(result.control!='cancel2'){ if(result.control!='cancel2'){
@ -10656,7 +10658,9 @@ game.import('mode',function(lib,game,ui,get,ai,_status){
goon=false; goon=false;
} }
else if(trigger.card.name=='sha'){ else if(trigger.card.name=='sha'){
if(trigger.target.mayHaveShan(player,'use')||trigger.target.hp>=3){ if(trigger.target.mayHaveShan(player,'use',trigger.target.getCards(i=>{
return i.hasGaintag('sha_notshan');
}))||trigger.target.hp>=3){
goon=false; goon=false;
} }
} }

View File

@ -307,22 +307,22 @@ export class Library extends Uninstantable {
/** /**
* **无名杀频道推送机制** * **无名杀频道推送机制**
* *
* 鉴于`Javascript`的特性及自身对所需功能的思考这是一个参考`Golang``channel`设计的完全和`go channel`不一样的异步消息传递对象 * 鉴于`Javascript`的特性及自身对所需功能的思考这是一个参考`Golang``channel`设计的完全和`go channel`不一样的异步消息传递对象
* *
* 当且仅当接收方和发送方均存在时进行消息传递完全保证信息传递的单一性发送方/接收方一旦确定则无法更改和准确性发送方必然将消息发送给接收方 * 当且仅当接收方和发送方均存在时进行消息传递完全保证信息传递的单一性发送方/接收方一旦确定则无法更改和准确性发送方必然将消息发送给接收方
* *
* 若存在发送方/接收方时调用`send`/`receive`将报错 * 若存在发送方/接收方时调用`send`/`receive`将报错
* *
* 若需要异步/不报错发送信息请等待`lib.actor` * 若需要异步/不报错发送信息请等待`lib.actor`
* *
* @example * @example
* // 创建一个频道 * // 创建一个频道
* const channel = new lib.channel(); * const channel = new lib.channel();
* *
* // 从某个角落接收channel发出的消息若无消息则等待 * // 从某个角落接收channel发出的消息若无消息则等待
* const message = await channel.receive(); * const message = await channel.receive();
* *
* // 从某个角落向channel发消息若无消息接收则等待 * // 从某个角落向channel发消息若无消息接收则等待
* await channel.send(item); * await channel.send(item);
*/ */
@ -330,12 +330,12 @@ export class Library extends Uninstantable {
/** /**
* **无名杀消息推送库** * **无名杀消息推送库**
* *
* 通过`EventTarget`机制实现消息推送和接收的解耦 * 通过`EventTarget`机制实现消息推送和接收的解耦
* 从而使消息接收方无需依赖发布方发布方也无需考虑接收方 * 从而使消息接收方无需依赖发布方发布方也无需考虑接收方
* *
* > `lib.announce`不是`actor`模型若不存在订阅者则消息发送将无意义 * > `lib.announce`不是`actor`模型若不存在订阅者则消息发送将无意义
* *
* @example * @example
* // 甲扩展(如《千幻聆音》)在角色皮肤切换后,调用: * // 甲扩展(如《千幻聆音》)在角色皮肤切换后,调用:
* lib.announce.publish("skinChange", { * lib.announce.publish("skinChange", {
@ -344,12 +344,12 @@ export class Library extends Uninstantable {
* originSkin: "image/xxx.jpg", * originSkin: "image/xxx.jpg",
* currentSkin: "image/yyy.jpg" * currentSkin: "image/yyy.jpg"
* }); * });
* *
* // 乙扩展监听此`skinChange`事件,并修改自己扩展相关界面的图片: * // 乙扩展监听此`skinChange`事件,并修改自己扩展相关界面的图片:
* const method = lib.announce.subscribe("skinChange", (e) => { * const method = lib.announce.subscribe("skinChange", (e) => {
* div.setBackgroundImage(e.currentSkin); * div.setBackgroundImage(e.currentSkin);
* }); * });
* *
* // 若此时乙扩展不想继续订阅`skinChange`事件,可以通过`unsubscribe`解除订阅 * // 若此时乙扩展不想继续订阅`skinChange`事件,可以通过`unsubscribe`解除订阅
* lib.announce.unsubscribe("skinChange", method); * lib.announce.unsubscribe("skinChange", method);
*/ */
@ -389,7 +389,7 @@ export class Library extends Uninstantable {
}; };
/** /**
* Yingbian * Yingbian
* *
* 应变 * 应变
*/ */
static yingbian = { static yingbian = {
@ -565,7 +565,7 @@ export class Library extends Uninstantable {
}; };
/** /**
* Stratagem buff * Stratagem buff
* *
* 谋攻强化 * 谋攻强化
*/ */
static stratagemBuff = { static stratagemBuff = {
@ -655,7 +655,7 @@ export class Library extends Uninstantable {
}; };
/** /**
* The actual card name * The actual card name
* *
* 实际的卡牌名称 * 实际的卡牌名称
*/ */
static actualCardName = new Map([ static actualCardName = new Map([
@ -3056,11 +3056,11 @@ export class Library extends Uninstantable {
lib.init.cssstyles(); lib.init.cssstyles();
} }
}, },
equip_span:{ equip_span: {
name: '装备牌占位', name: '装备牌占位',
intro:'打开后,没有装备的装备区将在装备栏占据空白位置。', intro: '打开后,没有装备的装备区将在装备栏占据空白位置。',
init: false, init: false,
unfrequent:false, unfrequent: false,
}, },
fold_card: { fold_card: {
name: '折叠手牌', name: '折叠手牌',
@ -8312,7 +8312,7 @@ export class Library extends Uninstantable {
static cheat = { static cheat = {
/** /**
* 将游戏内部的对象暴露到全局中 * 将游戏内部的对象暴露到全局中
* *
* lib.cheat, game, ui, get, ai, lib, _status * lib.cheat, game, ui, get, ai, lib, _status
*/ */
i() { i() {
@ -8339,15 +8339,15 @@ export class Library extends Uninstantable {
}, },
/** /**
* 在控制台输出每个扩展文件夹内的所有文件 * 在控制台输出每个扩展文件夹内的所有文件
* *
* 需要node环境 * 需要node环境
* *
* @param { ...string } args 只需要显示的文件夹首字符 * @param { ...string } args 只需要显示的文件夹首字符
*/ */
x(...args) { x(...args) {
/** /**
* @param { string } dir * @param { string } dir
* @param { (folders: string[], files: string[]) => any } callback * @param { (folders: string[], files: string[]) => any } callback
*/ */
const gl = function (dir, callback) { const gl = function (dir, callback) {
const files = [], folders = []; const files = [], folders = [];
@ -8494,10 +8494,10 @@ export class Library extends Uninstantable {
}, },
/** /**
* 将卡牌的样式在simple和default之间切换 * 将卡牌的样式在simple和default之间切换
* *
* 有参数时改为获得指定的牌 * 有参数时改为获得指定的牌
* *
* @param { ...string } args * @param { ...string } args
*/ */
q(...args) { q(...args) {
// if(lib.config.layout!='mobile') lib.init.layout('mobile'); // if(lib.config.layout!='mobile') lib.init.layout('mobile');
@ -8753,7 +8753,7 @@ export class Library extends Uninstantable {
/** /**
* 炉石模式可用使用`spell_${name}`卡牌 * 炉石模式可用使用`spell_${name}`卡牌
* @param { string } [name] * @param { string } [name]
* @param { boolean } [act] * @param { boolean } [act]
*/ */
gs(name = 'yexinglanghun', act) { gs(name = 'yexinglanghun', act) {
const card = game.createCard('spell_' + name); const card = game.createCard('spell_' + name);
@ -8770,7 +8770,7 @@ export class Library extends Uninstantable {
/** /**
* 炉石模式可用获得`stone_${name}_stonecharacter`卡牌 * 炉石模式可用获得`stone_${name}_stonecharacter`卡牌
* @param { string } [name] * @param { string } [name]
* @param { boolean } [act] * @param { boolean } [act]
*/ */
gc(name = 'falifulong', act) { gc(name = 'falifulong', act) {
var card = game.createCard('stone_' + name + '_stonecharacter'); var card = game.createCard('stone_' + name + '_stonecharacter');
@ -8786,7 +8786,7 @@ export class Library extends Uninstantable {
}, },
/** /**
* 进入/关闭快速自动测试模式(游戏速度最快)只有游戏记录界面 * 进入/关闭快速自动测试模式(游戏速度最快)只有游戏记录界面
* @param { boolean | string } [bool] * @param { boolean | string } [bool]
*/ */
a(bool) { a(bool) {
if (lib.config.test_game) { if (lib.config.test_game) {
@ -8809,7 +8809,7 @@ export class Library extends Uninstantable {
}, },
/** /**
* 临时去掉自动测试模式带来的css效果 * 临时去掉自动测试模式带来的css效果
* *
* 如果要彻底关闭需要再执行一次lib.cheat.a * 如果要彻底关闭需要再执行一次lib.cheat.a
*/ */
as() { as() {
@ -8828,8 +8828,8 @@ export class Library extends Uninstantable {
}, },
/** /**
* 下家对你使用一张牌 * 下家对你使用一张牌
* @param {...Player | Player[] | string | VCard } args * @param {...Player | Player[] | string | VCard } args
* *
* @example * @example
* ```js * ```js
* // 传入player是卡牌的使用者 * // 传入player是卡牌的使用者
@ -8912,14 +8912,14 @@ export class Library extends Uninstantable {
}, },
/** /**
* 打印目标玩家的手牌 * 打印目标玩家的手牌
* @param { Player } player * @param { Player } player
*/ */
h(player) { h(player) {
console.log(get.translation(player.getCards('h'))); console.log(get.translation(player.getCards('h')));
}, },
/** /**
* 给自己立刻添加手牌 * 给自己立刻添加手牌
* *
* @example * @example
* ```js * ```js
* // 获得3张杀和1张闪 * // 获得3张杀和1张闪
@ -8940,10 +8940,10 @@ export class Library extends Uninstantable {
}, },
/** /**
* 立即获得指定类型的牌各一张 * 立即获得指定类型的牌各一张
* *
* 会添加到不属于当前模式的牌和某些角色专属牌 * 会添加到不属于当前模式的牌和某些角色专属牌
* *
* @param { string } type * @param { string } type
*/ */
ga(type) { ga(type) {
for (let i in lib.card) { for (let i in lib.card) {
@ -8954,7 +8954,7 @@ export class Library extends Uninstantable {
}, },
/** /**
* 给所有玩家立刻添加一张或多张指定的牌 * 给所有玩家立刻添加一张或多张指定的牌
* @param {...string} args * @param {...string} args
* @example * @example
* ```js * ```js
* // 给所有玩家立刻添加一张杀和一张闪 * // 给所有玩家立刻添加一张杀和一张闪
@ -8970,7 +8970,7 @@ export class Library extends Uninstantable {
}, },
/** /**
* 给目标立即添加一张手牌 * 给目标立即添加一张手牌
* @param { string } name * @param { string } name
* @param { Player } target * @param { Player } target
*/ */
gx(name, target = game.me) { gx(name, target = game.me) {
@ -8986,10 +8986,10 @@ export class Library extends Uninstantable {
}, },
/** /**
* 创建卡牌 * 创建卡牌
* *
* 如果lib.card里没有对应卡牌名返回null * 如果lib.card里没有对应卡牌名返回null
* *
* @param { string } name * @param { string } name
* @returns { Card } * @returns { Card }
* @example * @example
* ```js * ```js
@ -9041,7 +9041,7 @@ export class Library extends Uninstantable {
}, },
/** /**
* 指定的玩家或自己立即获得诸葛连弩青龙刀八卦阵的卢赤兔木牛 * 指定的玩家或自己立即获得诸葛连弩青龙刀八卦阵的卢赤兔木牛
* @param { Player } [target] * @param { Player } [target]
*/ */
ge(target) { ge(target) {
if (target) { if (target) {
@ -9084,8 +9084,8 @@ export class Library extends Uninstantable {
}, },
/** /**
* 自己立刻获取牌堆顶num张牌 * 自己立刻获取牌堆顶num张牌
* @param { number } [num] * @param { number } [num]
* @param { Player } [target] * @param { Player } [target]
*/ */
d(num = 1, target) { d(num = 1, target) {
const cards = get.cards(num); const cards = get.cards(num);
@ -9115,10 +9115,10 @@ export class Library extends Uninstantable {
}, },
/** /**
* 弃置指定位置玩家的所有牌 * 弃置指定位置玩家的所有牌
* *
* 不传入num默认为弃置所有玩家的所有牌 * 不传入num默认为弃置所有玩家的所有牌
* *
* @param { number | Player } [num] * @param { number | Player } [num]
*/ */
t(num) { t(num) {
if (game.players.includes(num)) { if (game.players.includes(num)) {
@ -9161,7 +9161,7 @@ export class Library extends Uninstantable {
}, },
/** /**
* 重新设置当前的主公的武将牌且血量上限+1(不论当局人数是否大于3) * 重新设置当前的主公的武将牌且血量上限+1(不论当局人数是否大于3)
* @param { string } name * @param { string } name
*/ */
z(name) { z(name) {
switch (name) { switch (name) {
@ -9640,21 +9640,21 @@ export class Library extends Uninstantable {
none: () => false, 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 { Card } card
* @param { Player } player * @param { Player } player
* @returns { boolean } * @returns { boolean }
*/ */
ignoredHandcard: (card, player) => game.checkMod(card, player, false, 'ignoredHandcard', player), 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 { Card } card
* @param { Player } player * @param { Player } player
* @param { Player } target * @param { Player } target
* @param { boolean } [strict] * @param { boolean } [strict]
*/ */
cardGiftable: (card, player, target, strict) => { cardGiftable: (card, player, target, strict) => {
const mod = game.checkMod(card, player, target, 'unchanged', 'cardGiftable', player); const mod = game.checkMod(card, player, target, 'unchanged', 'cardGiftable', player);
@ -9663,12 +9663,12 @@ export class Library extends Uninstantable {
}, },
/** /**
* Check if the card is recastable * Check if the card is recastable
* *
* 检查此牌是否可重铸 * 检查此牌是否可重铸
* @param { Card } card * @param { Card } card
* @param { Player } player * @param { Player } player
* @param { Player } [source] * @param { Player } [source]
* @param { boolean } [strict] * @param { boolean } [strict]
*/ */
cardRecastable: (card, player = get.owner(card), source, strict) => { cardRecastable: (card, player = get.owner(card), source, strict) => {
// if (typeof player == 'undefined') player = get.owner(card); // if (typeof player == 'undefined') player = get.owner(card);
@ -9711,11 +9711,11 @@ export class Library extends Uninstantable {
return savable; return savable;
}, },
/** /**
* *
* @param {GameEvent} event * @param {GameEvent} event
* @param {Player} player * @param {Player} player
* @param {string} triggername * @param {string} triggername
* @param {string} skill * @param {string} skill
* @returns {boolean} * @returns {boolean}
*/ */
filterTrigger: function (event, player, triggername, skill) { filterTrigger: function (event, player, triggername, skill) {
@ -9748,11 +9748,11 @@ export class Library extends Uninstantable {
if (info.round && (info.round - (game.roundNumber - player.storage[skill + '_roundcount']) > 0)) return false; if (info.round && (info.round - (game.roundNumber - player.storage[skill + '_roundcount']) > 0)) return false;
for (const item in player.storage) { for (const item in player.storage) {
if (item.startsWith('temp_ban_')) { if (item.startsWith('temp_ban_')) {
if(player.storage[item] !== true) continue; if (player.storage[item] !== true) continue;
const skillName = item.slice(9); const skillName = item.slice(9);
if (lib.skill[skillName]) { if (lib.skill[skillName]) {
const skills=game.expandSkills([skillName]); const skills = game.expandSkills([skillName]);
if(skills.includes(skill)) return false; if (skills.includes(skill)) return false;
} }
} }
} }
@ -10325,7 +10325,9 @@ export class Library extends Uninstantable {
if (game.hasPlayer(current => { if (game.hasPlayer(current => {
if (!player.canUse(card, current)) return false; if (!player.canUse(card, current)) return false;
const storage = player.storage, zhibi = storage.zhibi; const storage = player.storage, zhibi = storage.zhibi;
return (zhibi && !zhibi.includes(current) || get.effect(current, card, player, player) >= 2 - Math.max(0, (storage.stratagem_fury || 0) - 1)) && current.mayHaveShan(player, 'use') && player.hasSkill('jiu'); return (zhibi && !zhibi.includes(current) || get.effect(current, card, player, player) >= 2 - Math.max(0, (storage.stratagem_fury || 0) - 1)) && current.mayHaveShan(player, 'use', current.getCards(i => {
return i.hasGaintag('sha_notshan');
})) && player.hasSkill('jiu');
})) return 1; })) return 1;
return 0; return 0;
} }
@ -10396,7 +10398,9 @@ export class Library extends Uninstantable {
if (game.hasPlayer(current => { if (game.hasPlayer(current => {
if (!player.canUse(card, current)) return false; if (!player.canUse(card, current)) return false;
const storage = player.storage, zhibi = storage.zhibi; const storage = player.storage, zhibi = storage.zhibi;
return (zhibi && !zhibi.includes(current) || (get.effect(current, card, player, player) >= 2 - Math.max(0, (storage.stratagem_fury || 0) - 1))) && current.mayHaveShan(player, 'use'); return (zhibi && !zhibi.includes(current) || (get.effect(current, card, player, player) >= 2 - Math.max(0, (storage.stratagem_fury || 0) - 1))) && current.mayHaveShan(player, 'use', current.getCards(i => {
return i.hasGaintag('sha_notshan');
}));
})) return get.order(card, player) + 0.5; })) return get.order(card, player) + 0.5;
} }
else if (cardName == 'tao' && player.hp <= 2 && player.getDamagedHp() >= 2) return get.order(card, player) + 0.5; else if (cardName == 'tao' && player.hp <= 2 && player.getDamagedHp() >= 2) return get.order(card, player) + 0.5;
@ -11283,7 +11287,7 @@ export class Library extends Uninstantable {
charlotte: true, charlotte: true,
priority: -100, priority: -100,
lastDo: true, lastDo: true,
silent:true, silent: true,
content: function () { content: function () {
player.removeSkill('counttrigger'); player.removeSkill('counttrigger');
delete player.storage.counttrigger; delete player.storage.counttrigger;
@ -11309,7 +11313,7 @@ export class Library extends Uninstantable {
priority: 100, priority: 100,
firstDo: true, firstDo: true,
popup: false, popup: false,
silent:true, silent: true,
filter: function (event, player) { filter: function (event, player) {
return player.hp >= player.maxHp; return player.hp >= player.maxHp;
}, },
@ -11398,7 +11402,7 @@ export class Library extends Uninstantable {
popup: false, popup: false,
priority: -100, priority: -100,
lastDo: true, lastDo: true,
silent:true, silent: true,
filter: function (event) { filter: function (event) {
return !event._cleared && event.card.name != 'wuxie'; return !event._cleared && event.card.name != 'wuxie';
}, },
@ -11415,7 +11419,7 @@ export class Library extends Uninstantable {
popup: false, popup: false,
priority: -100, priority: -100,
lastDo: true, lastDo: true,
silent:true, silent: true,
filter: function (event) { filter: function (event) {
return ui.todiscard[event.discardid] ? true : false; return ui.todiscard[event.discardid] ? true : false;
}, },
@ -11445,7 +11449,7 @@ export class Library extends Uninstantable {
priority: 5, priority: 5,
forced: true, forced: true,
popup: false, popup: false,
silent:true, silent: true,
filter: function (event, player) { filter: function (event, player) {
//if(!event.player.isDying()) return false; //if(!event.player.isDying()) return false;
//if(event.source&&event.source.isIn()&&event.source!=player) return false; //if(event.source&&event.source.isIn()&&event.source!=player) return false;
@ -11599,7 +11603,7 @@ export class Library extends Uninstantable {
popup: false, popup: false,
logv: false, logv: false,
forceDie: true, forceDie: true,
silent:true, silent: true,
//priority:-5, //priority:-5,
content: function () { content: function () {
"step 0"; "step 0";
@ -11628,7 +11632,7 @@ export class Library extends Uninstantable {
forced: true, forced: true,
popup: false, popup: false,
forceDie: true, forceDie: true,
silent:true, silent: true,
filter: function (event, player) { filter: function (event, player) {
var evt = event.getParent(); var evt = event.getParent();
return evt && evt.name == 'damage' && evt.hasNature('linked') && player.isLinked(); return evt && evt.name == 'damage' && evt.hasNature('linked') && player.isLinked();